cmem-plugin-validation 1.2.0__tar.gz → 1.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cmem_plugin_validation-1.2.0 → cmem_plugin_validation-1.3.1}/LICENSE +1 -1
- {cmem_plugin_validation-1.2.0 → cmem_plugin_validation-1.3.1}/PKG-INFO +6 -6
- {cmem_plugin_validation-1.2.0 → cmem_plugin_validation-1.3.1}/README-public.md +2 -2
- {cmem_plugin_validation-1.2.0 → cmem_plugin_validation-1.3.1}/cmem_plugin_validation/validate_entities/task.py +15 -27
- cmem_plugin_validation-1.3.1/cmem_plugin_validation/validate_graph/state.py +31 -0
- {cmem_plugin_validation-1.2.0 → cmem_plugin_validation-1.3.1}/cmem_plugin_validation/validate_graph/task.py +43 -30
- {cmem_plugin_validation-1.2.0 → cmem_plugin_validation-1.3.1}/pyproject.toml +32 -18
- cmem_plugin_validation-1.2.0/cmem_plugin_validation/validate_graph/state.py +0 -28
- {cmem_plugin_validation-1.2.0 → cmem_plugin_validation-1.3.1}/cmem_plugin_validation/__init__.py +0 -0
- {cmem_plugin_validation-1.2.0 → cmem_plugin_validation-1.3.1}/cmem_plugin_validation/validate_entities/__init__.py +0 -0
- {cmem_plugin_validation-1.2.0 → cmem_plugin_validation-1.3.1}/cmem_plugin_validation/validate_entities/icon.svg +0 -0
- {cmem_plugin_validation-1.2.0 → cmem_plugin_validation-1.3.1}/cmem_plugin_validation/validate_entities/state.py +0 -0
- {cmem_plugin_validation-1.2.0 → cmem_plugin_validation-1.3.1}/cmem_plugin_validation/validate_graph/__init__.py +0 -0
- {cmem_plugin_validation-1.2.0 → cmem_plugin_validation-1.3.1}/cmem_plugin_validation/validate_graph/icon.svg +0 -0
|
@@ -186,7 +186,7 @@
|
|
|
186
186
|
same "printed page" as the copyright notice for easier
|
|
187
187
|
identification within third-party archives.
|
|
188
188
|
|
|
189
|
-
Copyright
|
|
189
|
+
Copyright eccenca GmbH
|
|
190
190
|
|
|
191
191
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
192
|
you may not use this file except in compliance with the License.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cmem-plugin-validation
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.1
|
|
4
4
|
Summary: Validate graph and data structures.
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -14,10 +14,10 @@ Classifier: License :: OSI Approved :: Apache Software License
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.13
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
-
Requires-Dist: cmem-
|
|
18
|
-
Requires-Dist: cmem-plugin-base (>=4.
|
|
17
|
+
Requires-Dist: cmem-client (>=1.0.0,<2.0.0)
|
|
18
|
+
Requires-Dist: cmem-plugin-base (>=4.20.0,<5.0.0)
|
|
19
|
+
Requires-Dist: httpx (>=0.27.0,<0.28.0)
|
|
19
20
|
Requires-Dist: jsonschema (>=4.25.1,<5.0.0)
|
|
20
|
-
Requires-Dist: requests (>=2.0.1)
|
|
21
21
|
Project-URL: Homepage, https://github.com/eccenca/cmem-plugin-validation
|
|
22
22
|
Description-Content-Type: text/markdown
|
|
23
23
|
|
|
@@ -27,7 +27,7 @@ Validate graph and data structures.
|
|
|
27
27
|
|
|
28
28
|
[![eccenca Corporate Memory][cmem-shield]][cmem-link]
|
|
29
29
|
|
|
30
|
-
This is a plugin for [eccenca
|
|
30
|
+
This is a plugin for [eccenca Corporate Memory](https://documentation.eccenca.com). You can install it with the [cmemc](https://eccenca.com/go/cmemc) command line client like this:
|
|
31
31
|
|
|
32
32
|
```
|
|
33
33
|
cmemc admin workspace python install cmem-plugin-validation
|
|
@@ -36,7 +36,7 @@ cmemc admin workspace python install cmem-plugin-validation
|
|
|
36
36
|
[![poetry][poetry-shield]][poetry-link] [![ruff][ruff-shield]][ruff-link] [![mypy][mypy-shield]][mypy-link] [![copier][copier-shield]][copier]
|
|
37
37
|
|
|
38
38
|
[cmem-link]: https://documentation.eccenca.com
|
|
39
|
-
[cmem-shield]: https://img.shields.io/endpoint?url=https://
|
|
39
|
+
[cmem-shield]: https://img.shields.io/endpoint?url=https://documentation.eccenca.com/latest/badge.json
|
|
40
40
|
[poetry-link]: https://python-poetry.org/
|
|
41
41
|
[poetry-shield]: https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json
|
|
42
42
|
[ruff-link]: https://docs.astral.sh/ruff/
|
|
@@ -4,7 +4,7 @@ Validate graph and data structures.
|
|
|
4
4
|
|
|
5
5
|
[![eccenca Corporate Memory][cmem-shield]][cmem-link]
|
|
6
6
|
|
|
7
|
-
This is a plugin for [eccenca
|
|
7
|
+
This is a plugin for [eccenca Corporate Memory](https://documentation.eccenca.com). You can install it with the [cmemc](https://eccenca.com/go/cmemc) command line client like this:
|
|
8
8
|
|
|
9
9
|
```
|
|
10
10
|
cmemc admin workspace python install cmem-plugin-validation
|
|
@@ -13,7 +13,7 @@ cmemc admin workspace python install cmem-plugin-validation
|
|
|
13
13
|
[![poetry][poetry-shield]][poetry-link] [![ruff][ruff-shield]][ruff-link] [![mypy][mypy-shield]][mypy-link] [![copier][copier-shield]][copier]
|
|
14
14
|
|
|
15
15
|
[cmem-link]: https://documentation.eccenca.com
|
|
16
|
-
[cmem-shield]: https://img.shields.io/endpoint?url=https://
|
|
16
|
+
[cmem-shield]: https://img.shields.io/endpoint?url=https://documentation.eccenca.com/latest/badge.json
|
|
17
17
|
[poetry-link]: https://python-poetry.org/
|
|
18
18
|
[poetry-shield]: https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json
|
|
19
19
|
[ruff-link]: https://docs.astral.sh/ruff/
|
|
@@ -7,12 +7,10 @@ from collections.abc import Generator, Sequence
|
|
|
7
7
|
from types import SimpleNamespace
|
|
8
8
|
from typing import Any
|
|
9
9
|
|
|
10
|
-
from
|
|
11
|
-
from cmem.cmempy.workspace.tasks import get_task
|
|
10
|
+
from cmem_client.client import Client
|
|
12
11
|
from cmem_plugin_base.dataintegration.context import (
|
|
13
12
|
ExecutionContext,
|
|
14
13
|
ExecutionReport,
|
|
15
|
-
UserContext,
|
|
16
14
|
)
|
|
17
15
|
from cmem_plugin_base.dataintegration.description import Icon, Plugin, PluginParameter
|
|
18
16
|
from cmem_plugin_base.dataintegration.entity import Entities
|
|
@@ -24,11 +22,6 @@ from cmem_plugin_base.dataintegration.ports import (
|
|
|
24
22
|
FlexibleNumberOfInputs,
|
|
25
23
|
UnknownSchemaPort,
|
|
26
24
|
)
|
|
27
|
-
from cmem_plugin_base.dataintegration.utils import (
|
|
28
|
-
setup_cmempy_user_access,
|
|
29
|
-
split_task_id,
|
|
30
|
-
write_to_dataset,
|
|
31
|
-
)
|
|
32
25
|
from cmem_plugin_base.dataintegration.utils.entity_builder import build_entities_from_data
|
|
33
26
|
from jsonschema import validate
|
|
34
27
|
from jsonschema.exceptions import ValidationError
|
|
@@ -77,13 +70,6 @@ The error handling behavior is configurable through the `Fail on violations` par
|
|
|
77
70
|
|
|
78
71
|
DEFAULT_FAIL_ON_VIOLATION = False
|
|
79
72
|
|
|
80
|
-
|
|
81
|
-
def get_task_metadata(project: str, task: str, context: UserContext) -> dict:
|
|
82
|
-
"""Get metadata information of a task"""
|
|
83
|
-
setup_cmempy_user_access(context=context)
|
|
84
|
-
return dict(get_task(project=project, task=task))
|
|
85
|
-
|
|
86
|
-
|
|
87
73
|
SOURCE = SimpleNamespace()
|
|
88
74
|
SOURCE.entities = "entities"
|
|
89
75
|
SOURCE.dataset = "dataset"
|
|
@@ -172,7 +158,7 @@ class ValidateEntity(WorkflowPlugin):
|
|
|
172
158
|
inputs: Sequence[Entities]
|
|
173
159
|
execution_context: ExecutionContext
|
|
174
160
|
|
|
175
|
-
def __init__( # noqa: PLR0913
|
|
161
|
+
def __init__( # noqa: PLR0913 PLR0917
|
|
176
162
|
self,
|
|
177
163
|
source_mode: str,
|
|
178
164
|
target_mode: str,
|
|
@@ -297,10 +283,10 @@ class ValidateEntity(WorkflowPlugin):
|
|
|
297
283
|
)
|
|
298
284
|
)
|
|
299
285
|
if self.target_mode == TARGET.dataset:
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
286
|
+
Client.from_context(context=context).datasets.post_file_resource(
|
|
287
|
+
project_id=context.task.project_id(),
|
|
288
|
+
dataset_id=self.target_dataset,
|
|
289
|
+
file_resource=io.BytesIO(json.dumps(valid_json_objects).encode("utf-8")),
|
|
304
290
|
)
|
|
305
291
|
return None
|
|
306
292
|
|
|
@@ -319,16 +305,18 @@ class ValidateEntity(WorkflowPlugin):
|
|
|
319
305
|
@staticmethod
|
|
320
306
|
def _get_json_dataset_content(context: ExecutionContext, dataset: str) -> dict | list[dict]:
|
|
321
307
|
"""Get json dataset content"""
|
|
322
|
-
|
|
323
|
-
project_id
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
308
|
+
client = Client.from_context(context=context)
|
|
309
|
+
project_id = context.task.project_id()
|
|
310
|
+
resource_name = str(
|
|
311
|
+
client.datasets.get_item(project_id=project_id, dataset_id=dataset).data.parameters[
|
|
312
|
+
"file"
|
|
313
|
+
]
|
|
314
|
+
)
|
|
315
|
+
return json.loads(client.files.read(f"{project_id}:{resource_name}")) # type: ignore[no-any-return]
|
|
328
316
|
|
|
329
317
|
def _convert_entities_to_json(
|
|
330
318
|
self, inputs: Sequence[Entities], path_to_entities: dict[str, Entities], path: str = ""
|
|
331
|
-
) -> Generator[dict[str, Any]
|
|
319
|
+
) -> Generator[dict[str, Any]]:
|
|
332
320
|
"""Convert a sequence of Entities into JSON-like dictionaries using recursive traversal."""
|
|
333
321
|
for entities in inputs:
|
|
334
322
|
# Initialize path-to-entities map for the root level
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Graph validation process state"""
|
|
2
|
+
|
|
3
|
+
from cmem_client.client import Client
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class State:
|
|
7
|
+
"""State of a validation process"""
|
|
8
|
+
|
|
9
|
+
client: Client
|
|
10
|
+
id_: str
|
|
11
|
+
data: dict
|
|
12
|
+
status: str
|
|
13
|
+
completed: int
|
|
14
|
+
total: int
|
|
15
|
+
with_violations: int
|
|
16
|
+
violations: int
|
|
17
|
+
|
|
18
|
+
def __init__(self, client: Client, id_: str):
|
|
19
|
+
self.client = client
|
|
20
|
+
self.id_ = id_
|
|
21
|
+
self.refresh()
|
|
22
|
+
|
|
23
|
+
def refresh(self) -> None:
|
|
24
|
+
"""Refresh state of validation process"""
|
|
25
|
+
aggregation = self.client.validations.get_aggregation(batch_id=self.id_)
|
|
26
|
+
self.data = aggregation.model_dump(by_alias=True, exclude_none=True)
|
|
27
|
+
self.status = aggregation.state
|
|
28
|
+
self.completed = aggregation.resource_processed_count
|
|
29
|
+
self.total = aggregation.resource_count
|
|
30
|
+
self.with_violations = aggregation.resources_with_violations_count
|
|
31
|
+
self.violations = aggregation.violations_count
|
|
@@ -4,9 +4,9 @@ import json
|
|
|
4
4
|
from collections.abc import Sequence
|
|
5
5
|
from time import sleep
|
|
6
6
|
|
|
7
|
-
from
|
|
8
|
-
from
|
|
9
|
-
from
|
|
7
|
+
from cmem_client.client import Client
|
|
8
|
+
from cmem_client.models.query_catalog import Query
|
|
9
|
+
from cmem_client.models.validation import STATUS_RUNNING, STATUS_SCHEDULED, ValidationViolation
|
|
10
10
|
from cmem_plugin_base.dataintegration.context import ExecutionContext, ExecutionReport
|
|
11
11
|
from cmem_plugin_base.dataintegration.description import Icon, Plugin, PluginParameter
|
|
12
12
|
from cmem_plugin_base.dataintegration.entity import (
|
|
@@ -21,9 +21,8 @@ from cmem_plugin_base.dataintegration.ports import (
|
|
|
21
21
|
FixedNumberOfInputs,
|
|
22
22
|
FixedSchemaPort,
|
|
23
23
|
)
|
|
24
|
-
from cmem_plugin_base.dataintegration.utils import setup_cmempy_user_access
|
|
25
24
|
from cmem_plugin_base.dataintegration.utils.entity_builder import build_entities_from_data
|
|
26
|
-
from
|
|
25
|
+
from httpx import HTTPStatusError
|
|
27
26
|
|
|
28
27
|
from cmem_plugin_validation.validate_graph.state import State
|
|
29
28
|
|
|
@@ -32,6 +31,12 @@ Start a graph validation process which verifies, that resources in a specific gr
|
|
|
32
31
|
according to the node shapes in a shape catalog graph.
|
|
33
32
|
"""
|
|
34
33
|
|
|
34
|
+
CONTEXT_GRAPH_CLASSES = [
|
|
35
|
+
"https://vocab.eccenca.com/di/Dataset",
|
|
36
|
+
"http://rdfs.org/ns/void#Dataset",
|
|
37
|
+
"https://vocab.eccenca.com/shui/QueryCatalog",
|
|
38
|
+
"http://www.w3.org/2002/07/owl#Ontology",
|
|
39
|
+
]
|
|
35
40
|
DEFAULT_SHAPE_GRAPH = "https://vocab.eccenca.com/shacl/"
|
|
36
41
|
DEFAULT_RESULT_GRAPH = ""
|
|
37
42
|
DEFAULT_CLEAR_RESULT_GRAPH = False
|
|
@@ -55,6 +60,7 @@ WHERE { ?resource a ?class . FILTER isIRI(?resource) }
|
|
|
55
60
|
label="Context Graph",
|
|
56
61
|
description="This graph holds the resources you want to validate.",
|
|
57
62
|
param_type=GraphParameterType(
|
|
63
|
+
classes=CONTEXT_GRAPH_CLASSES,
|
|
58
64
|
show_di_graphs=False,
|
|
59
65
|
show_graphs_without_class=True,
|
|
60
66
|
show_system_graphs=True,
|
|
@@ -111,7 +117,7 @@ WHERE { ?resource a ?class . FILTER isIRI(?resource) }
|
|
|
111
117
|
class ValidateGraph(WorkflowPlugin):
|
|
112
118
|
"""Validate resources in a graph"""
|
|
113
119
|
|
|
114
|
-
def __init__( # noqa: PLR0913
|
|
120
|
+
def __init__( # noqa: PLR0913 PLR0917
|
|
115
121
|
self,
|
|
116
122
|
context_graph: str,
|
|
117
123
|
shape_graph: str = DEFAULT_SHAPE_GRAPH,
|
|
@@ -156,33 +162,29 @@ class ValidateGraph(WorkflowPlugin):
|
|
|
156
162
|
) -> Entities | None:
|
|
157
163
|
"""Run the workflow operator."""
|
|
158
164
|
self.log.info("Start validation task.")
|
|
159
|
-
|
|
165
|
+
client = Client.from_context(context=context)
|
|
160
166
|
if self.clear_result_graph and self.result_graph:
|
|
161
|
-
|
|
162
|
-
query =
|
|
163
|
-
|
|
167
|
+
client.graphs.delete_item(key=self.result_graph, skip_if_missing=True)
|
|
168
|
+
query = Query(text=self.sparql_query).fill_placeholders(
|
|
169
|
+
placeholders={"context_graph": self.context_graph}
|
|
164
170
|
)
|
|
165
171
|
try:
|
|
166
|
-
process_id =
|
|
172
|
+
process_id = client.validations.start(
|
|
167
173
|
context_graph=self.context_graph,
|
|
168
174
|
shape_graph=self.shape_graph,
|
|
169
|
-
result_graph=self.result_graph
|
|
175
|
+
result_graph=self.result_graph or None,
|
|
170
176
|
query=query,
|
|
171
177
|
)
|
|
172
|
-
except
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
)
|
|
178
|
-
raise RuntimeError(json.loads(error.response.text)["detail"]) from error
|
|
179
|
-
state = State(id_=process_id)
|
|
178
|
+
except HTTPStatusError as error:
|
|
179
|
+
detail = json.loads(error.response.text)["detail"]
|
|
180
|
+
context.report.update(ExecutionReport(error=detail))
|
|
181
|
+
raise RuntimeError(detail) from error
|
|
182
|
+
state = State(client=client, id_=process_id)
|
|
180
183
|
while True:
|
|
181
184
|
sleep(1)
|
|
182
|
-
setup_cmempy_user_access(context=context.user)
|
|
183
185
|
state.refresh()
|
|
184
186
|
if context.workflow and context.workflow.status() != "Running":
|
|
185
|
-
|
|
187
|
+
client.validations.cancel(batch_id=process_id)
|
|
186
188
|
context.report.update(
|
|
187
189
|
ExecutionReport(
|
|
188
190
|
entity_count=state.completed,
|
|
@@ -192,7 +194,7 @@ class ValidateGraph(WorkflowPlugin):
|
|
|
192
194
|
)
|
|
193
195
|
self.log.info("End validation task (Cancelled Workflow).")
|
|
194
196
|
return None
|
|
195
|
-
if state.status in (
|
|
197
|
+
if state.status in (STATUS_SCHEDULED, STATUS_RUNNING):
|
|
196
198
|
# when reported as running or scheduled, start another loop
|
|
197
199
|
context.report.update(
|
|
198
200
|
ExecutionReport(
|
|
@@ -224,11 +226,22 @@ class ValidateGraph(WorkflowPlugin):
|
|
|
224
226
|
if not self.output_results:
|
|
225
227
|
return None
|
|
226
228
|
|
|
227
|
-
violations = [
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
for
|
|
231
|
-
|
|
232
|
-
violation["resourceIri"] = resource_iri
|
|
233
|
-
violations.append(violation)
|
|
229
|
+
violations = [
|
|
230
|
+
self._as_violation_data(violation, resource_iri=result.resource_iri)
|
|
231
|
+
for result in client.validations.get_result(batch_id=process_id).results
|
|
232
|
+
for violation in result.violations
|
|
233
|
+
]
|
|
234
234
|
return build_entities_from_data(data=violations)
|
|
235
|
+
|
|
236
|
+
def _as_violation_data(self, violation: ValidationViolation, resource_iri: str) -> dict:
|
|
237
|
+
"""Turn a violation into a plain dict ordered like the output schema
|
|
238
|
+
|
|
239
|
+
The entity paths of the returned entities are derived from the key order of these
|
|
240
|
+
dicts, so the keys of the output schema come first, followed by any additional key
|
|
241
|
+
the API delivers and the IRI of the validated resource.
|
|
242
|
+
"""
|
|
243
|
+
data: dict = violation.model_dump(by_alias=True, exclude_none=True)
|
|
244
|
+
ordered: dict = {
|
|
245
|
+
_.path: data.pop(_.path) for _ in self.output_schema.paths if _.path in data
|
|
246
|
+
}
|
|
247
|
+
return ordered | data | {"resourceIri": resource_iri}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "cmem-plugin-validation"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.3.1"
|
|
4
4
|
license = "Apache-2.0"
|
|
5
5
|
description = "Validate graph and data structures."
|
|
6
6
|
authors = ["eccenca GmbH <cmempy-developer@eccenca.com>"]
|
|
@@ -13,32 +13,36 @@ keywords = [
|
|
|
13
13
|
]
|
|
14
14
|
homepage = "https://github.com/eccenca/cmem-plugin-validation"
|
|
15
15
|
|
|
16
|
+
[tool.poetry.requires-plugins]
|
|
17
|
+
poetry-plugin-export = "^1.10.0"
|
|
18
|
+
poetry-plugin-shell = "^1.0.1"
|
|
19
|
+
poetry-dynamic-versioning = "^1.10.0"
|
|
20
|
+
|
|
16
21
|
[tool.poetry.dependencies]# if you need to change python version here, change it also in .python-version
|
|
17
22
|
python = "^3.13"
|
|
18
23
|
jsonschema = "^4.25.1"
|
|
19
|
-
cmem-
|
|
20
|
-
|
|
24
|
+
cmem-client = "^1.0.0"
|
|
25
|
+
httpx = "^0.27.0"
|
|
21
26
|
|
|
22
27
|
[tool.poetry.dependencies.cmem-plugin-base]
|
|
23
|
-
version = "^4.
|
|
28
|
+
version = "^4.20.0"
|
|
24
29
|
allow-prereleases = false
|
|
25
30
|
|
|
26
31
|
[tool.poetry.group.dev.dependencies.cmem-cmemc]
|
|
27
32
|
version = ">=24.2.0"
|
|
28
33
|
|
|
29
34
|
[tool.poetry.group.dev.dependencies]
|
|
30
|
-
deptry = "^0.
|
|
31
|
-
genbadge = {extras = ["coverage"], version = "^1.1.
|
|
32
|
-
mypy = "^
|
|
33
|
-
pip = "^
|
|
34
|
-
pytest = "^
|
|
35
|
-
pytest-cov = "^7.
|
|
35
|
+
deptry = "^0.25.1"
|
|
36
|
+
genbadge = {extras = ["coverage"], version = "^1.1.3"}
|
|
37
|
+
mypy = "^2.3.0"
|
|
38
|
+
pip = "^26"
|
|
39
|
+
pytest = "^9.1.1"
|
|
40
|
+
pytest-cov = "^7.1.0"
|
|
36
41
|
pytest-dotenv = "^0.5.2"
|
|
37
|
-
pytest-html = "^4.
|
|
38
|
-
pytest-memray = { version = "^1.
|
|
39
|
-
ruff = "^0.
|
|
40
|
-
|
|
41
|
-
types-requests = "^2.31.0.20240406"
|
|
42
|
+
pytest-html = "^4.2.0"
|
|
43
|
+
pytest-memray = { version = "^1.10.0", markers = "platform_system != 'Windows'" }
|
|
44
|
+
ruff = "^0.16.2"
|
|
45
|
+
trivy-py-ecc = "^0.73.0.1"
|
|
42
46
|
|
|
43
47
|
[build-system]
|
|
44
48
|
requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning"]
|
|
@@ -54,8 +58,12 @@ bump = true
|
|
|
54
58
|
warn_return_any = true
|
|
55
59
|
ignore_missing_imports = true
|
|
56
60
|
|
|
61
|
+
# Deliberately empty. pytest walks upward until a file *loads* a configuration,
|
|
62
|
+
# and only the presence of this table makes pyproject.toml one - without it the
|
|
63
|
+
# walk carries on into the parent directories, where any pytest.ini, tox.ini or
|
|
64
|
+
# setup.cfg, even an empty one, would set this project's rootdir and could push
|
|
65
|
+
# its own addopts into this test suite. Do not tidy it away.
|
|
57
66
|
[tool.pytest.ini_options]
|
|
58
|
-
addopts = ""
|
|
59
67
|
|
|
60
68
|
[tool.coverage.report]
|
|
61
69
|
exclude_also = [
|
|
@@ -71,7 +79,7 @@ exclude_also = [
|
|
|
71
79
|
|
|
72
80
|
[tool.ruff]
|
|
73
81
|
line-length = 100
|
|
74
|
-
target-version = "
|
|
82
|
+
target-version = "py313"
|
|
75
83
|
|
|
76
84
|
[tool.ruff.format]
|
|
77
85
|
line-ending = "lf" # Use `\n` line endings for all files
|
|
@@ -81,6 +89,7 @@ select = ["ALL"]
|
|
|
81
89
|
ignore = [
|
|
82
90
|
"ANN204", # Missing return type annotation for special method `__init__`
|
|
83
91
|
"COM812", # missing-trailing-comma
|
|
92
|
+
"CPY001", # Missing copyright notice
|
|
84
93
|
"D107", # Missing docstring in __init__
|
|
85
94
|
"D203", # [*] 1 blank line required before class docstring
|
|
86
95
|
"D211", # No blank lines allowed before class docstring
|
|
@@ -93,6 +102,11 @@ ignore = [
|
|
|
93
102
|
"G004", # Logging statement uses f-string
|
|
94
103
|
"ISC001", # single-line-implicit-string-concatenation
|
|
95
104
|
"PD", # opinionated linting for pandas code
|
|
96
|
-
"S101", # use of assert detected
|
|
97
105
|
"TRY003", # Avoid specifying long messages outside the exception class
|
|
98
106
|
]
|
|
107
|
+
|
|
108
|
+
[tool.ruff.lint.per-file-ignores]
|
|
109
|
+
"tests/**/*.py" = [
|
|
110
|
+
"S101", # asserts allowed in tests
|
|
111
|
+
"ARG", # unused function args (pytest fixtures)
|
|
112
|
+
]
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"""Graph validation process state"""
|
|
2
|
-
|
|
3
|
-
from cmem.cmempy.dp.shacl import validation
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class State:
|
|
7
|
-
"""State of a validation process"""
|
|
8
|
-
|
|
9
|
-
id_: str
|
|
10
|
-
data: dict
|
|
11
|
-
status: str
|
|
12
|
-
completed: int
|
|
13
|
-
total: int
|
|
14
|
-
with_violations: int
|
|
15
|
-
violations: int
|
|
16
|
-
|
|
17
|
-
def __init__(self, id_: str):
|
|
18
|
-
self.id_ = id_
|
|
19
|
-
self.refresh()
|
|
20
|
-
|
|
21
|
-
def refresh(self) -> None:
|
|
22
|
-
"""Refresh state of validation process"""
|
|
23
|
-
self.data = validation.get_aggregation(batch_id=self.id_)
|
|
24
|
-
self.status = self.data.get("state", "UNKNOWN")
|
|
25
|
-
self.completed = self.data.get("resourceProcessedCount", 0)
|
|
26
|
-
self.total = self.data.get("resourceCount", 0)
|
|
27
|
-
self.with_violations = self.data.get("resourcesWithViolationsCount", 0)
|
|
28
|
-
self.violations = self.data.get("violationsCount", 0)
|
{cmem_plugin_validation-1.2.0 → cmem_plugin_validation-1.3.1}/cmem_plugin_validation/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|