cognite-neat 0.107.0__py3-none-any.whl → 0.109.0__py3-none-any.whl
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.
Potentially problematic release.
This version of cognite-neat might be problematic. Click here for more details.
- cognite/neat/_constants.py +35 -1
- cognite/neat/_graph/_shared.py +4 -0
- cognite/neat/_graph/extractors/_classic_cdf/_base.py +115 -14
- cognite/neat/_graph/extractors/_classic_cdf/_classic.py +87 -6
- cognite/neat/_graph/extractors/_classic_cdf/_relationships.py +48 -12
- cognite/neat/_graph/extractors/_classic_cdf/_sequences.py +19 -1
- cognite/neat/_graph/extractors/_dms.py +162 -47
- cognite/neat/_graph/extractors/_dms_graph.py +54 -4
- cognite/neat/_graph/extractors/_mock_graph_generator.py +1 -1
- cognite/neat/_graph/extractors/_rdf_file.py +3 -2
- cognite/neat/_graph/loaders/__init__.py +1 -3
- cognite/neat/_graph/loaders/_rdf2dms.py +20 -10
- cognite/neat/_graph/queries/_base.py +144 -84
- cognite/neat/_graph/queries/_construct.py +1 -1
- cognite/neat/_graph/transformers/__init__.py +3 -1
- cognite/neat/_graph/transformers/_base.py +4 -4
- cognite/neat/_graph/transformers/_classic_cdf.py +13 -13
- cognite/neat/_graph/transformers/_prune_graph.py +3 -3
- cognite/neat/_graph/transformers/_rdfpath.py +3 -4
- cognite/neat/_graph/transformers/_value_type.py +71 -13
- cognite/neat/_issues/errors/__init__.py +2 -0
- cognite/neat/_issues/errors/_external.py +8 -0
- cognite/neat/_issues/errors/_resources.py +1 -1
- cognite/neat/_issues/warnings/__init__.py +0 -2
- cognite/neat/_issues/warnings/_models.py +1 -1
- cognite/neat/_issues/warnings/_properties.py +0 -8
- cognite/neat/_issues/warnings/_resources.py +1 -1
- cognite/neat/_rules/catalog/classic_model.xlsx +0 -0
- cognite/neat/_rules/exporters/_rules2instance_template.py +3 -3
- cognite/neat/_rules/exporters/_rules2yaml.py +1 -1
- cognite/neat/_rules/importers/__init__.py +3 -1
- cognite/neat/_rules/importers/_dtdl2rules/spec.py +1 -2
- cognite/neat/_rules/importers/_rdf/__init__.py +2 -2
- cognite/neat/_rules/importers/_rdf/_base.py +2 -2
- cognite/neat/_rules/importers/_rdf/_inference2rules.py +310 -26
- cognite/neat/_rules/models/_base_rules.py +22 -11
- cognite/neat/_rules/models/dms/_exporter.py +5 -4
- cognite/neat/_rules/models/dms/_rules.py +1 -8
- cognite/neat/_rules/models/dms/_rules_input.py +4 -0
- cognite/neat/_rules/models/information/_rules_input.py +5 -0
- cognite/neat/_rules/transformers/__init__.py +10 -3
- cognite/neat/_rules/transformers/_base.py +6 -1
- cognite/neat/_rules/transformers/_converters.py +530 -364
- cognite/neat/_rules/transformers/_mapping.py +4 -4
- cognite/neat/_session/_base.py +100 -47
- cognite/neat/_session/_create.py +133 -0
- cognite/neat/_session/_drop.py +60 -2
- cognite/neat/_session/_fix.py +28 -0
- cognite/neat/_session/_inspect.py +22 -7
- cognite/neat/_session/_mapping.py +8 -8
- cognite/neat/_session/_prepare.py +3 -247
- cognite/neat/_session/_read.py +138 -17
- cognite/neat/_session/_set.py +50 -1
- cognite/neat/_session/_show.py +16 -43
- cognite/neat/_session/_state.py +53 -52
- cognite/neat/_session/_to.py +11 -4
- cognite/neat/_session/_wizard.py +1 -1
- cognite/neat/_session/exceptions.py +8 -1
- cognite/neat/_store/_graph_store.py +301 -146
- cognite/neat/_store/_provenance.py +36 -20
- cognite/neat/_store/_rules_store.py +253 -267
- cognite/neat/_store/exceptions.py +40 -4
- cognite/neat/_utils/auth.py +5 -3
- cognite/neat/_version.py +1 -1
- {cognite_neat-0.107.0.dist-info → cognite_neat-0.109.0.dist-info}/METADATA +1 -1
- {cognite_neat-0.107.0.dist-info → cognite_neat-0.109.0.dist-info}/RECORD +69 -67
- {cognite_neat-0.107.0.dist-info → cognite_neat-0.109.0.dist-info}/LICENSE +0 -0
- {cognite_neat-0.107.0.dist-info → cognite_neat-0.109.0.dist-info}/WHEEL +0 -0
- {cognite_neat-0.107.0.dist-info → cognite_neat-0.109.0.dist-info}/entry_points.txt +0 -0
cognite/neat/_session/_show.py
CHANGED
|
@@ -98,22 +98,15 @@ class ShowDataModelAPI(ShowBaseAPI):
|
|
|
98
98
|
self.implements = ShowDataModelImplementsAPI(self._state)
|
|
99
99
|
|
|
100
100
|
def __call__(self) -> Any:
|
|
101
|
-
if
|
|
102
|
-
raise NeatSessionError(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
rules = self._state.rule_store.last_verified_rule
|
|
101
|
+
if self._state.rule_store.empty:
|
|
102
|
+
raise NeatSessionError("No data model available. Try using [bold].read[/bold] to read a new data model.")
|
|
103
|
+
last_target = self._state.rule_store.provenance[-1].target_entity
|
|
104
|
+
rules = last_target.dms or last_target.information
|
|
107
105
|
|
|
108
|
-
if
|
|
109
|
-
di_graph = self._generate_dms_di_graph(
|
|
110
|
-
elif isinstance(rules, InformationRules):
|
|
111
|
-
di_graph = self._generate_info_di_graph(rules)
|
|
106
|
+
if last_target.dms is not None:
|
|
107
|
+
di_graph = self._generate_dms_di_graph(last_target.dms)
|
|
112
108
|
else:
|
|
113
|
-
|
|
114
|
-
raise NeatSessionError(
|
|
115
|
-
f"Unsupported type {type(rules) }. Make sure you have either information or DMS rules."
|
|
116
|
-
)
|
|
109
|
+
di_graph = self._generate_info_di_graph(last_target.information)
|
|
117
110
|
identifier = to_directory_compatible(str(rules.metadata.identifier))
|
|
118
111
|
name = f"{identifier}.html"
|
|
119
112
|
|
|
@@ -187,22 +180,16 @@ class ShowDataModelImplementsAPI(ShowBaseAPI):
|
|
|
187
180
|
self._state = state
|
|
188
181
|
|
|
189
182
|
def __call__(self) -> Any:
|
|
190
|
-
if
|
|
191
|
-
raise NeatSessionError(
|
|
192
|
-
"No verified data model available. Try using [bold].verify()[/bold] to verify data model."
|
|
193
|
-
)
|
|
183
|
+
if self._state.rule_store.empty:
|
|
184
|
+
raise NeatSessionError("No data model available. Try using [bold].read[/bold] to read a data model.")
|
|
194
185
|
|
|
195
|
-
|
|
186
|
+
last_target = self._state.rule_store.provenance[-1].target_entity
|
|
187
|
+
rules = last_target.dms or last_target.information
|
|
196
188
|
|
|
197
|
-
if
|
|
198
|
-
di_graph = self._generate_dms_di_graph(
|
|
199
|
-
elif isinstance(rules, InformationRules):
|
|
200
|
-
di_graph = self._generate_info_di_graph(rules)
|
|
189
|
+
if last_target.dms is not None:
|
|
190
|
+
di_graph = self._generate_dms_di_graph(last_target.dms)
|
|
201
191
|
else:
|
|
202
|
-
|
|
203
|
-
raise NeatSessionError(
|
|
204
|
-
f"Unsupported type {type(rules) }. Make sure you have either information or DMS rules."
|
|
205
|
-
)
|
|
192
|
+
di_graph = self._generate_info_di_graph(last_target.information)
|
|
206
193
|
identifier = to_directory_compatible(str(rules.metadata.identifier))
|
|
207
194
|
name = f"{identifier}_implements.html"
|
|
208
195
|
return self._generate_visualization(di_graph, name)
|
|
@@ -325,20 +312,6 @@ class ShowDataModelProvenanceAPI(ShowBaseAPI):
|
|
|
325
312
|
)
|
|
326
313
|
di_graph.add_edge(source_shorten, export_id, label="exported", color="grey")
|
|
327
314
|
|
|
328
|
-
for pruned_lists in self._state.rule_store.pruned_by_source_entity_id.values():
|
|
329
|
-
for prune_path in pruned_lists:
|
|
330
|
-
for change in prune_path:
|
|
331
|
-
source = uri_display_name(change.source_entity.id_)
|
|
332
|
-
target = uri_display_name(change.target_entity.id_)
|
|
333
|
-
di_graph.add_node(
|
|
334
|
-
target,
|
|
335
|
-
label=target,
|
|
336
|
-
type="Pruned",
|
|
337
|
-
title="Pruned",
|
|
338
|
-
color=hex_colored_types["Pruned"],
|
|
339
|
-
)
|
|
340
|
-
di_graph.add_edge(source, target, label="pruned", color="grey")
|
|
341
|
-
|
|
342
315
|
return di_graph
|
|
343
316
|
|
|
344
317
|
|
|
@@ -364,7 +337,7 @@ class ShowInstanceAPI(ShowBaseAPI):
|
|
|
364
337
|
'Try setting [bold]NeatSession(storage="oxigraph")[/bold] enable Oxigraph store.'
|
|
365
338
|
)
|
|
366
339
|
|
|
367
|
-
if not self._state.instances.store.
|
|
340
|
+
if not self._state.instances.store.dataset:
|
|
368
341
|
raise NeatSessionError("No instances available. Try using [bold].read[/bold] to load instances.")
|
|
369
342
|
|
|
370
343
|
di_graph = self._generate_instance_di_graph_and_types()
|
|
@@ -395,7 +368,7 @@ class ShowInstanceAPI(ShowBaseAPI):
|
|
|
395
368
|
object,
|
|
396
369
|
subject_type,
|
|
397
370
|
object_type,
|
|
398
|
-
) in self._state.instances.store.
|
|
371
|
+
) in self._state.instances.store.dataset.query(query):
|
|
399
372
|
subject = remove_namespace_from_uri(subject)
|
|
400
373
|
property_ = remove_namespace_from_uri(property_)
|
|
401
374
|
object = remove_namespace_from_uri(object)
|
cognite/neat/_session/_state.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from
|
|
1
|
+
from pathlib import Path
|
|
2
2
|
from typing import Literal, cast
|
|
3
3
|
|
|
4
4
|
from cognite.neat._client import NeatClient
|
|
@@ -6,55 +6,46 @@ from cognite.neat._graph.extractors import KnowledgeGraphExtractor
|
|
|
6
6
|
from cognite.neat._issues import IssueList
|
|
7
7
|
from cognite.neat._rules.importers import BaseImporter, InferenceImporter
|
|
8
8
|
from cognite.neat._rules.models import DMSRules, InformationRules
|
|
9
|
-
from cognite.neat._rules.transformers import
|
|
9
|
+
from cognite.neat._rules.transformers import (
|
|
10
|
+
VerifiedRulesTransformer,
|
|
11
|
+
)
|
|
10
12
|
from cognite.neat._store import NeatGraphStore, NeatRulesStore
|
|
11
|
-
from cognite.neat._store._rules_store import ModelEntity
|
|
12
|
-
from cognite.neat._utils.rdf_ import uri_display_name
|
|
13
|
-
from cognite.neat._utils.text import humanize_collection
|
|
14
13
|
from cognite.neat._utils.upload import UploadResultList
|
|
15
14
|
|
|
16
|
-
from .exceptions import NeatSessionError
|
|
15
|
+
from .exceptions import NeatSessionError, _session_method_wrapper
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
class SessionState:
|
|
20
|
-
def __init__(
|
|
21
|
-
self
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
store_type: Literal["memory", "oxigraph"],
|
|
22
|
+
storage_path: Path | None = None,
|
|
23
|
+
client: NeatClient | None = None,
|
|
24
|
+
) -> None:
|
|
25
|
+
self.instances = InstancesState(store_type, storage_path=storage_path)
|
|
22
26
|
self.rule_store = NeatRulesStore()
|
|
23
27
|
self.last_reference: DMSRules | InformationRules | None = None
|
|
24
28
|
self.client = client
|
|
29
|
+
self.quoted_source_identifiers = False
|
|
25
30
|
|
|
26
|
-
def rule_transform(self, *transformer:
|
|
31
|
+
def rule_transform(self, *transformer: VerifiedRulesTransformer) -> IssueList:
|
|
27
32
|
if not transformer:
|
|
28
33
|
raise NeatSessionError("No transformers provided.")
|
|
29
|
-
first_transformer = transformer[0]
|
|
30
|
-
pruned = self.rule_store.prune_until_compatible(first_transformer)
|
|
31
|
-
if pruned:
|
|
32
|
-
type_hint = first_transformer.transform_type_hint()
|
|
33
|
-
action = uri_display_name(first_transformer.agent.id_)
|
|
34
|
-
location = cast(ModelEntity, self.rule_store.provenance[-1].target_entity).display_name
|
|
35
|
-
expected = humanize_collection([hint.display_type_name() for hint in type_hint]) # type: ignore[attr-defined]
|
|
36
|
-
step_str = "step" if len(pruned) == 1 else "steps"
|
|
37
|
-
print(
|
|
38
|
-
f"The {action} actions expects a {expected}. "
|
|
39
|
-
f"Moving back {len(pruned)} {step_str} to the last {location}."
|
|
40
|
-
)
|
|
41
|
-
if (
|
|
42
|
-
any(isinstance(t, ToExtensionModel) for t in transformer)
|
|
43
|
-
and isinstance(self.rule_store.provenance[-1].target_entity, ModelEntity)
|
|
44
|
-
and isinstance(self.rule_store.provenance[-1].target_entity.result, DMSRules | InformationRules)
|
|
45
|
-
):
|
|
46
|
-
self.last_reference = self.rule_store.provenance[-1].target_entity.result
|
|
47
34
|
|
|
48
|
-
start =
|
|
35
|
+
start = self.rule_store.provenance[-1].target_entity.display_name
|
|
49
36
|
issues = self.rule_store.transform(*transformer)
|
|
50
|
-
|
|
51
|
-
issues.action = f"{start} → {
|
|
37
|
+
last_entity = self.rule_store.provenance[-1].target_entity
|
|
38
|
+
issues.action = f"{start} → {last_entity.display_name}"
|
|
52
39
|
issues.hint = "Use the .inspect.issues() for more details."
|
|
40
|
+
self.instances.store.add_rules(last_entity.information)
|
|
53
41
|
return issues
|
|
54
42
|
|
|
55
43
|
def rule_import(self, importer: BaseImporter) -> IssueList:
|
|
56
|
-
issues = self.rule_store.
|
|
57
|
-
|
|
44
|
+
issues = self.rule_store.import_rules(importer, client=self.client)
|
|
45
|
+
if self.rule_store.empty:
|
|
46
|
+
result = "failed"
|
|
47
|
+
else:
|
|
48
|
+
result = self.rule_store.provenance[-1].target_entity.display_name
|
|
58
49
|
if isinstance(importer, InferenceImporter):
|
|
59
50
|
issues.action = f"Inferred {result}"
|
|
60
51
|
else:
|
|
@@ -64,36 +55,46 @@ class SessionState:
|
|
|
64
55
|
return issues
|
|
65
56
|
|
|
66
57
|
def write_graph(self, extractor: KnowledgeGraphExtractor) -> IssueList:
|
|
67
|
-
self.instances.store.write(extractor)
|
|
68
|
-
|
|
58
|
+
extract_issues = self.instances.store.write(extractor)
|
|
59
|
+
issues = self.rule_store.import_graph(extractor)
|
|
69
60
|
self.instances.store.add_rules(self.rule_store.last_verified_information_rules)
|
|
70
|
-
|
|
61
|
+
issues.extend(extract_issues)
|
|
62
|
+
return issues
|
|
71
63
|
|
|
72
64
|
|
|
73
|
-
@dataclass
|
|
74
65
|
class InstancesState:
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
66
|
+
def __init__(
|
|
67
|
+
self,
|
|
68
|
+
store_type: Literal["memory", "oxigraph"],
|
|
69
|
+
storage_path: Path | None = None,
|
|
70
|
+
) -> None:
|
|
71
|
+
self.store_type = store_type
|
|
72
|
+
self.storage_path = storage_path
|
|
73
|
+
self.issue_lists = IssueList()
|
|
74
|
+
self.outcome = UploadResultList()
|
|
79
75
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
76
|
+
# Ensure that error handling is done in the constructor
|
|
77
|
+
self.store = _session_method_wrapper(self._create_store, "NeatSession")()
|
|
78
|
+
|
|
79
|
+
if self.storage_path:
|
|
80
|
+
print("Remember to close neat session .close() once you are done to avoid oxigraph lock.")
|
|
81
|
+
|
|
82
|
+
def _create_store(self) -> NeatGraphStore:
|
|
83
|
+
if self.store_type == "oxigraph":
|
|
84
|
+
if self.storage_path:
|
|
85
|
+
self.storage_path.mkdir(parents=True, exist_ok=True)
|
|
86
|
+
return NeatGraphStore.from_oxi_local_store(storage_dir=self.storage_path)
|
|
87
|
+
else:
|
|
88
|
+
return NeatGraphStore.from_memory_store()
|
|
88
89
|
|
|
89
90
|
@property
|
|
90
|
-
def
|
|
91
|
-
return self.
|
|
91
|
+
def empty(self) -> bool:
|
|
92
|
+
return self.store.empty
|
|
92
93
|
|
|
93
94
|
@property
|
|
94
95
|
def last_outcome(self) -> UploadResultList:
|
|
95
96
|
if not self.outcome:
|
|
96
97
|
raise NeatSessionError(
|
|
97
|
-
"No outcome available. Try using [bold].to.cdf.instances[/bold] to upload a data
|
|
98
|
+
"No outcome available. Try using [bold].to.cdf.instances[/bold] to upload a data instance."
|
|
98
99
|
)
|
|
99
|
-
return self.outcome[-1]
|
|
100
|
+
return cast(UploadResultList, self.outcome[-1])
|
cognite/neat/_session/_to.py
CHANGED
|
@@ -4,7 +4,7 @@ from collections.abc import Collection
|
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
from typing import Any, Literal, overload
|
|
6
6
|
|
|
7
|
-
from cognite.client
|
|
7
|
+
from cognite.client import data_modeling as dm
|
|
8
8
|
|
|
9
9
|
from cognite.neat._constants import COGNITE_MODELS
|
|
10
10
|
from cognite.neat._graph import loaders
|
|
@@ -104,7 +104,7 @@ class ToAPI:
|
|
|
104
104
|
|
|
105
105
|
with zipfile.ZipFile(filepath, "w") as zip_ref:
|
|
106
106
|
zip_ref.writestr(
|
|
107
|
-
"neat-session/instances/instances.
|
|
107
|
+
"neat-session/instances/instances.trig",
|
|
108
108
|
self._state.instances.store.serialize(),
|
|
109
109
|
)
|
|
110
110
|
|
|
@@ -194,7 +194,10 @@ class CDFToAPI:
|
|
|
194
194
|
self._state = state
|
|
195
195
|
self._verbose = verbose
|
|
196
196
|
|
|
197
|
-
def instances(
|
|
197
|
+
def instances(
|
|
198
|
+
self,
|
|
199
|
+
space: str | None = None,
|
|
200
|
+
) -> UploadResultList:
|
|
198
201
|
"""Export the verified DMS instances to CDF.
|
|
199
202
|
|
|
200
203
|
Args:
|
|
@@ -213,14 +216,18 @@ class CDFToAPI:
|
|
|
213
216
|
raise NeatSessionError("Please provide a valid space name. {PATTERNS.space_compliance.pattern}")
|
|
214
217
|
|
|
215
218
|
if not client.data_modeling.spaces.retrieve(space):
|
|
216
|
-
client.data_modeling.spaces.apply(SpaceApply(space=space))
|
|
219
|
+
client.data_modeling.spaces.apply(dm.SpaceApply(space=space))
|
|
217
220
|
|
|
218
221
|
loader = loaders.DMSLoader.from_rules(
|
|
219
222
|
self._state.rule_store.last_verified_dms_rules,
|
|
220
223
|
self._state.instances.store,
|
|
221
224
|
instance_space=space,
|
|
222
225
|
client=client,
|
|
226
|
+
# In case urllib.parse.quote() was run on the extraction, we need to run
|
|
227
|
+
# urllib.parse.unquote() on the load.
|
|
228
|
+
unquote_external_ids=self._state.quoted_source_identifiers,
|
|
223
229
|
)
|
|
230
|
+
|
|
224
231
|
result = loader.load_into_cdf(client)
|
|
225
232
|
self._state.instances.outcome.append(result)
|
|
226
233
|
print("You can inspect the details with the .inspect.outcome.instances(...) method.")
|
cognite/neat/_session/_wizard.py
CHANGED
|
@@ -26,7 +26,7 @@ _T_Option = TypeVar("_T_Option")
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
def _selection(message: str, options: Sequence[_T_Option]) -> _T_Option:
|
|
29
|
-
option_text = "\n ".join([f"{i+1}) {option}" for i, option in enumerate(options)])
|
|
29
|
+
option_text = "\n ".join([f"{i + 1}) {option}" for i, option in enumerate(options)])
|
|
30
30
|
selected_index = (
|
|
31
31
|
IntPrompt().ask(f"{message}\n {option_text}\n", choices=list(map(str, range(1, len(options) + 1)))) - 1
|
|
32
32
|
)
|
|
@@ -3,6 +3,8 @@ from collections.abc import Callable
|
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
5
|
from cognite.neat._issues.errors import CDFMissingClientError, NeatImportError
|
|
6
|
+
from cognite.neat._issues.errors._external import OxigraphStorageLockedError
|
|
7
|
+
from cognite.neat._issues.errors._general import NeatValueError
|
|
6
8
|
|
|
7
9
|
from ._collector import _COLLECTOR
|
|
8
10
|
|
|
@@ -33,7 +35,12 @@ def _session_method_wrapper(func: Callable, cls_name: str):
|
|
|
33
35
|
except NeatSessionError as e:
|
|
34
36
|
action = _get_action()
|
|
35
37
|
print(f"{_PREFIX} Cannot {action}: {e}")
|
|
36
|
-
except (
|
|
38
|
+
except (
|
|
39
|
+
CDFMissingClientError,
|
|
40
|
+
NeatImportError,
|
|
41
|
+
NeatValueError,
|
|
42
|
+
OxigraphStorageLockedError,
|
|
43
|
+
) as e:
|
|
37
44
|
print(f"{_PREFIX} {escape(e.as_message())}")
|
|
38
45
|
except ModuleNotFoundError as e:
|
|
39
46
|
if e.name == "neatengine":
|