cognite-neat 0.107.0__py3-none-any.whl → 0.108.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 +83 -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 +140 -84
- cognite/neat/_graph/queries/_construct.py +1 -1
- cognite/neat/_graph/transformers/__init__.py +3 -1
- cognite/neat/_graph/transformers/_value_type.py +54 -3
- 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/_rules/catalog/classic_model.xlsx +0 -0
- cognite/neat/_rules/exporters/_rules2instance_template.py +3 -3
- 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 +241 -18
- cognite/neat/_rules/models/_base_rules.py +13 -3
- 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 +6 -0
- cognite/neat/_rules/transformers/_converters.py +98 -7
- cognite/neat/_session/_base.py +55 -4
- cognite/neat/_session/_drop.py +5 -1
- cognite/neat/_session/_inspect.py +3 -2
- cognite/neat/_session/_read.py +61 -14
- cognite/neat/_session/_set.py +27 -0
- cognite/neat/_session/_show.py +4 -4
- cognite/neat/_session/_state.py +8 -4
- cognite/neat/_session/_to.py +4 -1
- cognite/neat/_session/_wizard.py +1 -1
- cognite/neat/_session/exceptions.py +2 -1
- cognite/neat/_store/_graph_store.py +287 -133
- cognite/neat/_store/_rules_store.py +108 -1
- cognite/neat/_utils/auth.py +1 -1
- cognite/neat/_version.py +1 -1
- {cognite_neat-0.107.0.dist-info → cognite_neat-0.108.0.dist-info}/METADATA +1 -1
- {cognite_neat-0.107.0.dist-info → cognite_neat-0.108.0.dist-info}/RECORD +52 -52
- {cognite_neat-0.107.0.dist-info → cognite_neat-0.108.0.dist-info}/LICENSE +0 -0
- {cognite_neat-0.107.0.dist-info → cognite_neat-0.108.0.dist-info}/WHEEL +0 -0
- {cognite_neat-0.107.0.dist-info → cognite_neat-0.108.0.dist-info}/entry_points.txt +0 -0
cognite/neat/_session/_base.py
CHANGED
|
@@ -7,11 +7,21 @@ from cognite.neat import _version
|
|
|
7
7
|
from cognite.neat._client import NeatClient
|
|
8
8
|
from cognite.neat._issues import IssueList
|
|
9
9
|
from cognite.neat._issues.errors import RegexViolationError
|
|
10
|
+
from cognite.neat._issues.errors._general import NeatImportError
|
|
10
11
|
from cognite.neat._rules import importers
|
|
11
12
|
from cognite.neat._rules.models._base_input import InputRules
|
|
12
13
|
from cognite.neat._rules.models.information._rules import InformationRules
|
|
13
|
-
from cognite.neat._rules.transformers import
|
|
14
|
-
|
|
14
|
+
from cognite.neat._rules.transformers import (
|
|
15
|
+
ConversionTransformer,
|
|
16
|
+
ConvertToRules,
|
|
17
|
+
InformationToDMS,
|
|
18
|
+
MergeDMSRules,
|
|
19
|
+
MergeInformationRules,
|
|
20
|
+
VerifyAnyRules,
|
|
21
|
+
VerifyInformationRules,
|
|
22
|
+
)
|
|
23
|
+
from cognite.neat._store._rules_store import ModelEntity
|
|
24
|
+
from cognite.neat._utils.auxiliary import local_import
|
|
15
25
|
|
|
16
26
|
from ._collector import _COLLECTOR, Collector
|
|
17
27
|
from ._drop import DropAPI
|
|
@@ -70,12 +80,15 @@ class NeatSession:
|
|
|
70
80
|
def __init__(
|
|
71
81
|
self,
|
|
72
82
|
client: CogniteClient | None = None,
|
|
73
|
-
storage: Literal["memory", "oxigraph"] =
|
|
83
|
+
storage: Literal["memory", "oxigraph"] | None = None,
|
|
74
84
|
verbose: bool = True,
|
|
75
85
|
load_engine: Literal["newest", "cache", "skip"] = "cache",
|
|
76
86
|
) -> None:
|
|
77
87
|
self._verbose = verbose
|
|
78
|
-
self._state = SessionState(
|
|
88
|
+
self._state = SessionState(
|
|
89
|
+
store_type=storage or self._select_most_performant_store(),
|
|
90
|
+
client=NeatClient(client) if client else None,
|
|
91
|
+
)
|
|
79
92
|
self.read = ReadAPI(self._state, verbose)
|
|
80
93
|
self.to = ToAPI(self._state, verbose)
|
|
81
94
|
self.prepare = PrepareAPI(self._state, verbose)
|
|
@@ -89,6 +102,16 @@ class NeatSession:
|
|
|
89
102
|
if load_engine != "skip" and (engine_version := load_neat_engine(client, load_engine)):
|
|
90
103
|
print(f"Neat Engine {engine_version} loaded.")
|
|
91
104
|
|
|
105
|
+
def _select_most_performant_store(self) -> Literal["memory", "oxigraph"]:
|
|
106
|
+
"""Select the most performant store based on the current environment."""
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
local_import("pyoxigraph", "oxi")
|
|
110
|
+
local_import("oxrdflib", "oxi")
|
|
111
|
+
return "oxigraph"
|
|
112
|
+
except NeatImportError:
|
|
113
|
+
return "memory"
|
|
114
|
+
|
|
92
115
|
@property
|
|
93
116
|
def version(self) -> str:
|
|
94
117
|
"""Get the current version of neat.
|
|
@@ -199,6 +222,34 @@ class NeatSession:
|
|
|
199
222
|
)
|
|
200
223
|
return self._state.rule_import(importer)
|
|
201
224
|
|
|
225
|
+
def _infer_subclasses(self) -> IssueList:
|
|
226
|
+
"""Infer the subclass of instances."""
|
|
227
|
+
last_information = self._state.rule_store.last_verified_information_rules
|
|
228
|
+
issue_list = IssueList()
|
|
229
|
+
importer = importers.SubclassInferenceImporter(
|
|
230
|
+
issue_list=issue_list,
|
|
231
|
+
graph=self._state.instances.store.graph(),
|
|
232
|
+
rules=last_information,
|
|
233
|
+
max_number_of_instance=-1,
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
unverified_information = importer.to_rules()
|
|
237
|
+
verified_information = VerifyInformationRules().transform(unverified_information)
|
|
238
|
+
|
|
239
|
+
# Hack into the last information rules to merge the rules with the last verified information rules.
|
|
240
|
+
# This is to be able to populate the instances store with the inferred subclasses.
|
|
241
|
+
provenance = self._state.rule_store.provenance
|
|
242
|
+
for change in reversed(provenance):
|
|
243
|
+
target_entity = change.target_entity
|
|
244
|
+
if isinstance(target_entity, ModelEntity) and isinstance(target_entity.result, InformationRules):
|
|
245
|
+
last_information_rules = change.target_entity.result
|
|
246
|
+
new_information_rules = MergeInformationRules(verified_information).transform(last_information_rules)
|
|
247
|
+
object.__setattr__(change.target_entity, "result", new_information_rules)
|
|
248
|
+
break
|
|
249
|
+
|
|
250
|
+
dms_rules = InformationToDMS(reserved_properties="skip").transform(verified_information)
|
|
251
|
+
return self._state.rule_transform(MergeDMSRules(dms_rules))
|
|
252
|
+
|
|
202
253
|
def _repr_html_(self) -> str:
|
|
203
254
|
state = self._state
|
|
204
255
|
if (
|
cognite/neat/_session/_drop.py
CHANGED
|
@@ -31,7 +31,11 @@ class DropAPI:
|
|
|
31
31
|
```
|
|
32
32
|
"""
|
|
33
33
|
type_list = type if isinstance(type, list) else [type]
|
|
34
|
-
|
|
34
|
+
|
|
35
|
+
# Temporary solution until we agree on the form of specifying named graphs
|
|
36
|
+
# it will default to the default named graph
|
|
37
|
+
named_graph = self._state.instances.store.default_named_graph
|
|
38
|
+
uri_type_type = dict((v, k) for k, v in self._state.instances.store.queries.types(named_graph).items())
|
|
35
39
|
selected_uri_by_type: dict[URIRef, str] = {}
|
|
36
40
|
for type_item in type_list:
|
|
37
41
|
if type_item not in uri_type_type:
|
|
@@ -94,7 +94,8 @@ class InspectIssues:
|
|
|
94
94
|
if self._state.rule_store.provenance:
|
|
95
95
|
issues = self._state.rule_store.last_issues
|
|
96
96
|
elif self._state.instances.store.provenance:
|
|
97
|
-
|
|
97
|
+
last_change = self._state.instances.store.provenance[-1]
|
|
98
|
+
issues = last_change.target_entity.issues
|
|
98
99
|
else:
|
|
99
100
|
self._print("No issues found.")
|
|
100
101
|
return pd.DataFrame() if return_dataframe else None
|
|
@@ -231,7 +232,7 @@ class InspectUploadOutcome:
|
|
|
231
232
|
if i < 50:
|
|
232
233
|
lines.append(f" * {v}")
|
|
233
234
|
elif i == 50 and total > 50:
|
|
234
|
-
lines.append(f" * ... {total-50} more")
|
|
235
|
+
lines.append(f" * ... {total - 50} more")
|
|
235
236
|
elif i == 50 and total == 50:
|
|
236
237
|
lines.append(f" * {v}")
|
|
237
238
|
else:
|
cognite/neat/_session/_read.py
CHANGED
|
@@ -7,7 +7,7 @@ from cognite.neat._client import NeatClient
|
|
|
7
7
|
from cognite.neat._constants import CLASSIC_CDF_NAMESPACE
|
|
8
8
|
from cognite.neat._graph import examples as instances_examples
|
|
9
9
|
from cognite.neat._graph import extractors
|
|
10
|
-
from cognite.neat._graph.transformers import ConvertLiteral, LiteralToEntity
|
|
10
|
+
from cognite.neat._graph.transformers import ConvertLiteral, LiteralToEntity
|
|
11
11
|
from cognite.neat._issues import IssueList
|
|
12
12
|
from cognite.neat._issues.errors import NeatValueError
|
|
13
13
|
from cognite.neat._issues.warnings import MissingCogniteClientWarning
|
|
@@ -99,20 +99,41 @@ class CDFReadAPI(BaseReadAPI):
|
|
|
99
99
|
return self._state.rule_import(importer)
|
|
100
100
|
|
|
101
101
|
def graph(
|
|
102
|
-
self,
|
|
102
|
+
self,
|
|
103
|
+
data_model_id: DataModelIdentifier,
|
|
104
|
+
instance_space: str | SequenceNotStr[str] | None = None,
|
|
105
|
+
skip_cognite_views: bool = True,
|
|
103
106
|
) -> IssueList:
|
|
104
107
|
"""Reads a knowledge graph from Cognite Data Fusion (CDF).
|
|
105
108
|
|
|
106
109
|
Args:
|
|
107
110
|
data_model_id: Tuple of strings with the id of a CDF Data Model.
|
|
108
111
|
instance_space: The instance spaces to extract. If None, all instance spaces are extracted.
|
|
112
|
+
skip_cognite_views: If True, all Cognite Views are skipped. For example, if you have the CogniteAsset
|
|
113
|
+
view in you data model, it will ont be used to extract instances.
|
|
109
114
|
|
|
110
115
|
Returns:
|
|
111
116
|
IssueList: A list of issues that occurred during the extraction.
|
|
112
117
|
|
|
113
118
|
"""
|
|
119
|
+
return self._graph(data_model_id, instance_space, skip_cognite_views, unpack_json=False)
|
|
120
|
+
|
|
121
|
+
def _graph(
|
|
122
|
+
self,
|
|
123
|
+
data_model_id: DataModelIdentifier,
|
|
124
|
+
instance_space: str | SequenceNotStr[str] | None = None,
|
|
125
|
+
skip_cognite_views: bool = True,
|
|
126
|
+
unpack_json: bool = False,
|
|
127
|
+
str_to_ideal_type: bool = False,
|
|
128
|
+
) -> IssueList:
|
|
114
129
|
extractor = extractors.DMSGraphExtractor.from_data_model_id(
|
|
115
|
-
|
|
130
|
+
# We are skipping the Cognite Views
|
|
131
|
+
data_model_id,
|
|
132
|
+
self._get_client,
|
|
133
|
+
instance_space=instance_space,
|
|
134
|
+
skip_cognite_views=skip_cognite_views,
|
|
135
|
+
unpack_json=unpack_json,
|
|
136
|
+
str_to_ideal_type=str_to_ideal_type,
|
|
116
137
|
)
|
|
117
138
|
return self._state.write_graph(extractor)
|
|
118
139
|
|
|
@@ -130,7 +151,12 @@ class CDFClassicAPI(BaseReadAPI):
|
|
|
130
151
|
raise ValueError("No client provided. Please provide a client to read a data model.")
|
|
131
152
|
return self._state.client
|
|
132
153
|
|
|
133
|
-
def graph(
|
|
154
|
+
def graph(
|
|
155
|
+
self,
|
|
156
|
+
root_asset_external_id: str,
|
|
157
|
+
limit_per_type: int | None = None,
|
|
158
|
+
identifier: Literal["id", "externalId"] = "id",
|
|
159
|
+
) -> IssueList:
|
|
134
160
|
"""Reads the classic knowledge graph from CDF.
|
|
135
161
|
|
|
136
162
|
The Classic Graph consists of the following core resource type.
|
|
@@ -165,6 +191,8 @@ class CDFClassicAPI(BaseReadAPI):
|
|
|
165
191
|
Args:
|
|
166
192
|
root_asset_external_id: The external id of the root asset
|
|
167
193
|
limit_per_type: The maximum number of nodes to extract per core node type. If None, all nodes are extracted.
|
|
194
|
+
identifier: The identifier to use for the core nodes. Note selecting "id" can cause issues if the external
|
|
195
|
+
ID of the core nodes is missing. Default is "id".
|
|
168
196
|
|
|
169
197
|
Returns:
|
|
170
198
|
IssueList: A list of issues that occurred during the extraction.
|
|
@@ -174,6 +202,18 @@ class CDFClassicAPI(BaseReadAPI):
|
|
|
174
202
|
neat.read.cdf.graph("root_asset_external_id")
|
|
175
203
|
```
|
|
176
204
|
"""
|
|
205
|
+
return self._graph(
|
|
206
|
+
root_asset_external_id, limit_per_type, identifier, reference_timeseries=False, reference_files=False
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
def _graph(
|
|
210
|
+
self,
|
|
211
|
+
root_asset_external_id: str,
|
|
212
|
+
limit_per_type: int | None = None,
|
|
213
|
+
identifier: Literal["id", "externalId"] = "id",
|
|
214
|
+
reference_timeseries: bool = False,
|
|
215
|
+
reference_files: bool = False,
|
|
216
|
+
) -> IssueList:
|
|
177
217
|
namespace = CLASSIC_CDF_NAMESPACE
|
|
178
218
|
extractor = extractors.ClassicGraphExtractor(
|
|
179
219
|
self._get_client,
|
|
@@ -181,14 +221,12 @@ class CDFClassicAPI(BaseReadAPI):
|
|
|
181
221
|
limit_per_type=limit_per_type,
|
|
182
222
|
namespace=namespace,
|
|
183
223
|
prefix="Classic",
|
|
224
|
+
identifier=identifier,
|
|
184
225
|
)
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
print("Use the .inspect.issues() for more details")
|
|
226
|
+
extract_issues = self._state.write_graph(extractor)
|
|
227
|
+
if identifier == "externalId":
|
|
228
|
+
self._state.quoted_source_identifiers = True
|
|
189
229
|
|
|
190
|
-
# Converting the instances from classic to core
|
|
191
|
-
self._state.instances.store.transform(LookupRelationshipSourceTarget(namespace, "Classic"))
|
|
192
230
|
self._state.instances.store.transform(
|
|
193
231
|
ConvertLiteral(
|
|
194
232
|
namespace["ClassicTimeSeries"],
|
|
@@ -200,11 +238,21 @@ class CDFClassicAPI(BaseReadAPI):
|
|
|
200
238
|
LiteralToEntity(None, namespace["source"], "ClassicSourceSystem", "name"),
|
|
201
239
|
)
|
|
202
240
|
# Updating the information model.
|
|
203
|
-
self._state.rule_store.transform(
|
|
241
|
+
prepare_issues = self._state.rule_store.transform(
|
|
242
|
+
ClassicPrepareCore(namespace, reference_timeseries, reference_files)
|
|
243
|
+
)
|
|
204
244
|
# Update the instance store with the latest rules
|
|
205
245
|
information_rules = self._state.rule_store.last_verified_information_rules
|
|
206
|
-
self._state.instances.store.rules = information_rules
|
|
207
|
-
|
|
246
|
+
self._state.instances.store.rules[self._state.instances.store.default_named_graph] = information_rules
|
|
247
|
+
|
|
248
|
+
all_issues = IssueList(extract_issues + prepare_issues)
|
|
249
|
+
# Update the provenance with all issue.
|
|
250
|
+
object.__setattr__(self._state.instances.store.provenance[-1].target_entity, "issues", all_issues)
|
|
251
|
+
all_issues.action = "Read Classic Graph"
|
|
252
|
+
if all_issues:
|
|
253
|
+
print("Use the .inspect.issues() for more details")
|
|
254
|
+
|
|
255
|
+
return all_issues
|
|
208
256
|
|
|
209
257
|
|
|
210
258
|
@session_class_wrapper
|
|
@@ -241,7 +289,6 @@ class ExcelReadAPI(BaseReadAPI):
|
|
|
241
289
|
class ExcelExampleAPI(BaseReadAPI):
|
|
242
290
|
"""Used as example for reading some data model into the NeatSession."""
|
|
243
291
|
|
|
244
|
-
@property
|
|
245
292
|
def pump_example(self) -> IssueList:
|
|
246
293
|
"""Reads the Hello World pump example into the NeatSession."""
|
|
247
294
|
importer: importers.ExcelImporter = importers.ExcelImporter(catalog.hello_world_pump)
|
cognite/neat/_session/_set.py
CHANGED
|
@@ -3,9 +3,12 @@ from cognite.client import data_modeling as dm
|
|
|
3
3
|
|
|
4
4
|
from cognite.neat._client import NeatClient
|
|
5
5
|
from cognite.neat._constants import COGNITE_MODELS
|
|
6
|
+
from cognite.neat._graph.transformers import SetNeatType
|
|
6
7
|
from cognite.neat._issues import IssueList
|
|
8
|
+
from cognite.neat._issues.errors import NeatValueError
|
|
7
9
|
from cognite.neat._rules.models import DMSRules
|
|
8
10
|
from cognite.neat._rules.transformers import SetIDDMSModel
|
|
11
|
+
from cognite.neat._utils.text import humanize_collection
|
|
9
12
|
|
|
10
13
|
from ._state import SessionState
|
|
11
14
|
from .exceptions import NeatSessionError, session_class_wrapper
|
|
@@ -44,3 +47,27 @@ class SetAPI:
|
|
|
44
47
|
if self._verbose:
|
|
45
48
|
print(f"Client set to {self._state.client.config.project} CDF project.")
|
|
46
49
|
return None
|
|
50
|
+
|
|
51
|
+
def _instance_sub_type(self, type: str, property: str, drop_property: bool = False) -> None:
|
|
52
|
+
"""Sets the sub type of an instance based on the property."""
|
|
53
|
+
type_uri = self._state.instances.store.queries.type_uri(type)
|
|
54
|
+
property_uri = self._state.instances.store.queries.property_uri(property)
|
|
55
|
+
|
|
56
|
+
if not type_uri:
|
|
57
|
+
raise NeatValueError(f"Type {type} does not exist in the graph.")
|
|
58
|
+
elif len(type_uri) > 1:
|
|
59
|
+
raise NeatValueError(f"{type} has multiple ids found in the graph: {humanize_collection(type_uri)}.")
|
|
60
|
+
|
|
61
|
+
if not property_uri:
|
|
62
|
+
raise NeatValueError(f"Property {property} does not exist in the graph.")
|
|
63
|
+
elif len(type_uri) > 1:
|
|
64
|
+
raise NeatValueError(
|
|
65
|
+
f"{property} has multiple ids found in the graph: {humanize_collection(property_uri)}."
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
if not self._state.instances.store.queries.type_with_property(type_uri[0], property_uri[0]):
|
|
69
|
+
raise NeatValueError(f"Property {property} is not defined for type {type}.")
|
|
70
|
+
|
|
71
|
+
self._state.instances.store.transform(SetNeatType(type_uri[0], property_uri[0], drop_property))
|
|
72
|
+
|
|
73
|
+
return None
|
cognite/neat/_session/_show.py
CHANGED
|
@@ -112,7 +112,7 @@ class ShowDataModelAPI(ShowBaseAPI):
|
|
|
112
112
|
else:
|
|
113
113
|
# This should never happen, but we need to handle it to satisfy mypy
|
|
114
114
|
raise NeatSessionError(
|
|
115
|
-
f"Unsupported type {type(rules)
|
|
115
|
+
f"Unsupported type {type(rules)}. Make sure you have either information or DMS rules."
|
|
116
116
|
)
|
|
117
117
|
identifier = to_directory_compatible(str(rules.metadata.identifier))
|
|
118
118
|
name = f"{identifier}.html"
|
|
@@ -201,7 +201,7 @@ class ShowDataModelImplementsAPI(ShowBaseAPI):
|
|
|
201
201
|
else:
|
|
202
202
|
# This should never happen, but we need to handle it to satisfy mypy
|
|
203
203
|
raise NeatSessionError(
|
|
204
|
-
f"Unsupported type {type(rules)
|
|
204
|
+
f"Unsupported type {type(rules)}. Make sure you have either information or DMS rules."
|
|
205
205
|
)
|
|
206
206
|
identifier = to_directory_compatible(str(rules.metadata.identifier))
|
|
207
207
|
name = f"{identifier}_implements.html"
|
|
@@ -364,7 +364,7 @@ class ShowInstanceAPI(ShowBaseAPI):
|
|
|
364
364
|
'Try setting [bold]NeatSession(storage="oxigraph")[/bold] enable Oxigraph store.'
|
|
365
365
|
)
|
|
366
366
|
|
|
367
|
-
if not self._state.instances.store.
|
|
367
|
+
if not self._state.instances.store.dataset:
|
|
368
368
|
raise NeatSessionError("No instances available. Try using [bold].read[/bold] to load instances.")
|
|
369
369
|
|
|
370
370
|
di_graph = self._generate_instance_di_graph_and_types()
|
|
@@ -395,7 +395,7 @@ class ShowInstanceAPI(ShowBaseAPI):
|
|
|
395
395
|
object,
|
|
396
396
|
subject_type,
|
|
397
397
|
object_type,
|
|
398
|
-
) in self._state.instances.store.
|
|
398
|
+
) in self._state.instances.store.dataset.query(query):
|
|
399
399
|
subject = remove_namespace_from_uri(subject)
|
|
400
400
|
property_ = remove_namespace_from_uri(property_)
|
|
401
401
|
object = remove_namespace_from_uri(object)
|
cognite/neat/_session/_state.py
CHANGED
|
@@ -22,11 +22,14 @@ class SessionState:
|
|
|
22
22
|
self.rule_store = NeatRulesStore()
|
|
23
23
|
self.last_reference: DMSRules | InformationRules | None = None
|
|
24
24
|
self.client = client
|
|
25
|
+
self.quoted_source_identifiers = False
|
|
25
26
|
|
|
26
27
|
def rule_transform(self, *transformer: RulesTransformer) -> IssueList:
|
|
27
28
|
if not transformer:
|
|
28
29
|
raise NeatSessionError("No transformers provided.")
|
|
29
30
|
first_transformer = transformer[0]
|
|
31
|
+
|
|
32
|
+
# This should not be allowed to be done automatically
|
|
30
33
|
pruned = self.rule_store.prune_until_compatible(first_transformer)
|
|
31
34
|
if pruned:
|
|
32
35
|
type_hint = first_transformer.transform_type_hint()
|
|
@@ -64,10 +67,11 @@ class SessionState:
|
|
|
64
67
|
return issues
|
|
65
68
|
|
|
66
69
|
def write_graph(self, extractor: KnowledgeGraphExtractor) -> IssueList:
|
|
67
|
-
self.instances.store.write(extractor)
|
|
68
|
-
|
|
70
|
+
extract_issues = self.instances.store.write(extractor)
|
|
71
|
+
issues = self.rule_store.import_graph(extractor)
|
|
69
72
|
self.instances.store.add_rules(self.rule_store.last_verified_information_rules)
|
|
70
|
-
|
|
73
|
+
issues.extend(extract_issues)
|
|
74
|
+
return issues
|
|
71
75
|
|
|
72
76
|
|
|
73
77
|
@dataclass
|
|
@@ -81,7 +85,7 @@ class InstancesState:
|
|
|
81
85
|
def store(self) -> NeatGraphStore:
|
|
82
86
|
if not self.has_store:
|
|
83
87
|
if self.store_type == "oxigraph":
|
|
84
|
-
self._store = NeatGraphStore.
|
|
88
|
+
self._store = NeatGraphStore.from_oxi_local_store()
|
|
85
89
|
else:
|
|
86
90
|
self._store = NeatGraphStore.from_memory_store()
|
|
87
91
|
return cast(NeatGraphStore, self._store)
|
cognite/neat/_session/_to.py
CHANGED
|
@@ -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
|
|
|
@@ -220,6 +220,9 @@ class CDFToAPI:
|
|
|
220
220
|
self._state.instances.store,
|
|
221
221
|
instance_space=space,
|
|
222
222
|
client=client,
|
|
223
|
+
# In case urllib.parse.quote() was run on the extraction, we need to run
|
|
224
|
+
# urllib.parse.unquote() on the load.
|
|
225
|
+
unquote_external_ids=self._state.quoted_source_identifiers,
|
|
223
226
|
)
|
|
224
227
|
result = loader.load_into_cdf(client)
|
|
225
228
|
self._state.instances.outcome.append(result)
|
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,7 @@ 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._general import NeatValueError
|
|
6
7
|
|
|
7
8
|
from ._collector import _COLLECTOR
|
|
8
9
|
|
|
@@ -33,7 +34,7 @@ def _session_method_wrapper(func: Callable, cls_name: str):
|
|
|
33
34
|
except NeatSessionError as e:
|
|
34
35
|
action = _get_action()
|
|
35
36
|
print(f"{_PREFIX} Cannot {action}: {e}")
|
|
36
|
-
except (CDFMissingClientError, NeatImportError) as e:
|
|
37
|
+
except (CDFMissingClientError, NeatImportError, NeatValueError) as e:
|
|
37
38
|
print(f"{_PREFIX} {escape(e.as_message())}")
|
|
38
39
|
except ModuleNotFoundError as e:
|
|
39
40
|
if e.name == "neatengine":
|