cognite-neat 0.123.18__py3-none-any.whl → 0.123.20__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/_version.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "0.123.18"
1
+ __version__ = "0.123.20"
2
2
  __engine__ = "^2.0.4"
@@ -5,13 +5,13 @@ from cognite.neat.core._data_model.models import (
5
5
  ConceptualDataModel,
6
6
  PhysicalDataModel,
7
7
  )
8
+ from cognite.neat.core._data_model.models._import_contexts import ImportContext
8
9
  from cognite.neat.core._data_model.models.conceptual._unverified import (
9
10
  UnverifiedConceptualDataModel,
10
11
  )
11
12
  from cognite.neat.core._data_model.models.physical._unverified import (
12
13
  UnverifiedPhysicalDataModel,
13
14
  )
14
- from cognite.neat.core._utils.spreadsheet import SpreadsheetRead
15
15
 
16
16
  VerifiedDataModel: TypeAlias = ConceptualDataModel | PhysicalDataModel
17
17
 
@@ -32,7 +32,7 @@ class ImportedDataModel(Generic[T_UnverifiedDataModel]):
32
32
  """
33
33
 
34
34
  unverified_data_model: T_UnverifiedDataModel | None
35
- context: dict[str, SpreadsheetRead]
35
+ context: ImportContext | None = None
36
36
 
37
37
  @classmethod
38
38
  def display_type_name(cls) -> str:
@@ -1,6 +1,7 @@
1
1
  from ._base import BaseImporter
2
2
  from ._dict2data_model import DictImporter
3
3
  from ._dms2data_model import DMSImporter
4
+ from ._graph2data_model import GraphImporter
4
5
  from ._rdf import InferenceImporter, OWLImporter, SubclassInferenceImporter
5
6
  from ._spreadsheet2data_model import ExcelImporter
6
7
 
@@ -9,13 +10,20 @@ __all__ = [
9
10
  "DMSImporter",
10
11
  "DictImporter",
11
12
  "ExcelImporter",
13
+ "GraphImporter",
12
14
  "InferenceImporter",
13
15
  "OWLImporter",
14
16
  "SubclassInferenceImporter",
15
17
  ]
16
18
 
17
19
  DataModelImporters = (
18
- OWLImporter | DMSImporter | ExcelImporter | DictImporter | InferenceImporter | SubclassInferenceImporter
20
+ OWLImporter
21
+ | DMSImporter
22
+ | ExcelImporter
23
+ | DictImporter
24
+ | InferenceImporter
25
+ | SubclassInferenceImporter
26
+ | GraphImporter
19
27
  )
20
28
 
21
29
 
@@ -128,4 +128,4 @@ class DictImporter(BaseImporter[T_UnverifiedDataModel]):
128
128
  if self._read_issues.has_errors:
129
129
  raise MultiValueError(self._read_issues.errors)
130
130
 
131
- return ImportedDataModel[T_UnverifiedDataModel](data_model, {})
131
+ return ImportedDataModel[T_UnverifiedDataModel](data_model)
@@ -276,7 +276,7 @@ class DMSImporter(BaseImporter[UnverifiedPhysicalDataModel]):
276
276
  self.issue_list.trigger_warnings()
277
277
  if self.issue_list.has_errors:
278
278
  raise MultiValueError(self.issue_list.errors)
279
- return ImportedDataModel(user_data_model, {})
279
+ return ImportedDataModel(user_data_model, None)
280
280
 
281
281
  def _create_data_model_components(
282
282
  self,
@@ -0,0 +1,299 @@
1
+ import itertools
2
+ import urllib.parse
3
+ import warnings
4
+ from collections import defaultdict
5
+ from collections.abc import Iterable
6
+ from dataclasses import dataclass
7
+ from datetime import datetime, timezone
8
+ from typing import cast
9
+
10
+ from cognite.client.data_classes.data_modeling import DataModelId, DataModelIdentifier
11
+ from rdflib import RDF, RDFS, Namespace, URIRef
12
+ from rdflib import Literal as RdfLiteral
13
+ from rdflib.query import ResultRow
14
+
15
+ from cognite.neat.core._config import GLOBAL_CONFIG
16
+ from cognite.neat.core._constants import NEAT
17
+ from cognite.neat.core._data_model._shared import ImportedDataModel
18
+ from cognite.neat.core._data_model.models import UnverifiedConceptualDataModel
19
+ from cognite.neat.core._data_model.models._import_contexts import GraphContext
20
+ from cognite.neat.core._data_model.models.conceptual import (
21
+ UnverifiedConcept,
22
+ UnverifiedConceptualMetadata,
23
+ UnverifiedConceptualProperty,
24
+ )
25
+ from cognite.neat.core._data_model.models.entities import UnknownEntity
26
+ from cognite.neat.core._issues.errors import NeatValueError
27
+ from cognite.neat.core._issues.warnings import NeatValueWarning
28
+ from cognite.neat.core._store import NeatInstanceStore
29
+ from cognite.neat.core._utils.collection_ import iterate_progress_bar
30
+ from cognite.neat.core._utils.rdf_ import split_uri
31
+
32
+ from ._base import BaseImporter
33
+
34
+
35
+ # Internal helper class
36
+ @dataclass
37
+ class _ReadProperties:
38
+ type_uri: URIRef
39
+ property_uri: URIRef
40
+ value_type: URIRef
41
+ parent_uri: URIRef | None
42
+ max_occurrence: int
43
+ instance_count: int
44
+
45
+
46
+ class GraphImporter(BaseImporter[UnverifiedConceptualDataModel]):
47
+ """Infers a data model from the triples in a Graph Store.
48
+ Args:
49
+ store: The graph store to read from.
50
+ data_model_id: The data model id to be used for the imported rules.
51
+ """
52
+
53
+ _ORDERED_CONCEPTS_QUERY = """SELECT DISTINCT ?concept (count(?s) as ?instances )
54
+ WHERE { ?s a ?concept }
55
+ group by ?concept order by DESC(?instances)"""
56
+
57
+ _TYPE_PARENT_QUERY = f"""SELECT ?parent ?type
58
+ WHERE {{ ?s a ?type .
59
+ ?type <{RDFS.subClassOf}> ?parent }}"""
60
+
61
+ _PROPERTIES_QUERY = """SELECT DISTINCT ?property ?valueType
62
+ WHERE {{
63
+ ?s a <{type}> .
64
+ ?s ?property ?object .
65
+ OPTIONAL {{ ?object a ?objectType }}
66
+ BIND(
67
+ IF(
68
+ isLiteral(?object), datatype(?object),
69
+ IF(BOUND(?objectType), ?objectType, <{unknown_type}>)
70
+ ) AS ?valueType
71
+ )
72
+ }}"""
73
+
74
+ _MAX_OCCURRENCE_QUERY = """SELECT (MAX(?count) AS ?maxCount)
75
+ WHERE {{
76
+ {{
77
+ SELECT ?subject (COUNT(?object) AS ?count)
78
+ WHERE {{
79
+ ?subject a <{type}> .
80
+ ?subject <{property}> ?object .
81
+ }}
82
+ GROUP BY ?subject
83
+ }}
84
+ }}"""
85
+
86
+ def __init__(
87
+ self,
88
+ store: NeatInstanceStore,
89
+ data_model_id: DataModelIdentifier = ("neat_space", "NeatInferredDataModel", "v1"),
90
+ ) -> None:
91
+ self.store = store
92
+ self.data_model_id = DataModelId.load(data_model_id)
93
+ if self.data_model_id.version is None:
94
+ raise NeatValueError("Version is required when setting a Data Model ID")
95
+
96
+ def to_data_model(self) -> ImportedDataModel[UnverifiedConceptualDataModel]:
97
+ metadata = self._create_default_metadata()
98
+ if not self.store.queries.select.has_data():
99
+ warnings.warn(NeatValueWarning("Cannot infer data model. No data found in the graph."), stacklevel=2)
100
+ return ImportedDataModel(UnverifiedConceptualDataModel(metadata, [], [], {}), None)
101
+
102
+ parent_by_child = self._read_parent_by_child_from_graph()
103
+ count_by_type = self._read_types_with_counts_from_graph()
104
+ if not count_by_type:
105
+ warnings.warn(
106
+ NeatValueWarning("Cannot infer data model. No RDF.type triples found in the graph."), stacklevel=2
107
+ )
108
+ return ImportedDataModel(UnverifiedConceptualDataModel(metadata, [], [], {}), None)
109
+
110
+ read_properties = self._read_concept_properties_from_graph(count_by_type, parent_by_child)
111
+
112
+ prefixes: dict[str, Namespace] = {}
113
+ concepts, properties = self._create_concepts_properties(read_properties, prefixes)
114
+
115
+ return ImportedDataModel(
116
+ UnverifiedConceptualDataModel(
117
+ metadata=metadata,
118
+ concepts=concepts,
119
+ properties=properties,
120
+ prefixes=prefixes,
121
+ ),
122
+ context=GraphContext({"inferred_from": count_by_type}),
123
+ )
124
+
125
+ def _read_parent_by_child_from_graph(self) -> dict[URIRef, URIRef]:
126
+ parent_by_child: dict[URIRef, URIRef] = {}
127
+ for result_row in self.store.dataset.query(self._TYPE_PARENT_QUERY):
128
+ parent_uri, child_uri = cast(tuple[URIRef, URIRef], result_row)
129
+ parent_by_child[child_uri] = parent_uri
130
+ return parent_by_child
131
+
132
+ def _read_types_with_counts_from_graph(self) -> dict[URIRef, int]:
133
+ count_by_type: dict[URIRef, int] = {}
134
+ # Reads all types and their instance counts from the graph
135
+ for result_row in self.store.dataset.query(self._ORDERED_CONCEPTS_QUERY):
136
+ type_uri, instance_count_literal = cast(tuple[URIRef, RdfLiteral], result_row)
137
+ count_by_type[type_uri] = instance_count_literal.toPython()
138
+ return count_by_type
139
+
140
+ def _read_concept_properties_from_graph(
141
+ self, count_by_type: dict[URIRef, int], parent_by_child: dict[URIRef, URIRef]
142
+ ) -> list[_ReadProperties]:
143
+ read_properties: list[_ReadProperties] = []
144
+
145
+ total_instance_count = sum(count_by_type.values())
146
+ iterable = count_by_type.items()
147
+ if GLOBAL_CONFIG.use_iterate_bar_threshold and total_instance_count > GLOBAL_CONFIG.use_iterate_bar_threshold:
148
+ iterable = iterate_progress_bar(iterable, len(count_by_type), "Inferring types...") # type: ignore[assignment]
149
+
150
+ for type_uri, instance_count in iterable:
151
+ property_query = self._PROPERTIES_QUERY.format(type=type_uri, unknown_type=NEAT.UnknownType)
152
+ for result_row in self.store.dataset.query(property_query):
153
+ property_uri, value_type_uri = cast(tuple[URIRef, URIRef], result_row)
154
+ if property_uri == RDF.type:
155
+ continue
156
+ occurrence_query = self._MAX_OCCURRENCE_QUERY.format(type=type_uri, property=property_uri)
157
+ max_occurrence = 1 # default value
158
+ # We know that the _MAX_OCCURRENCE_QUERY will return a ResultRow
159
+ occurrence_results = list(cast(ResultRow, self.store.dataset.query(occurrence_query)))
160
+ if occurrence_results and occurrence_results[0] and occurrence_results[0][0]:
161
+ max_occurrence_literal = cast(RdfLiteral, occurrence_results[0][0])
162
+ max_occurrence = int(max_occurrence_literal.toPython())
163
+ read_properties.append(
164
+ _ReadProperties(
165
+ type_uri=type_uri,
166
+ property_uri=property_uri,
167
+ parent_uri=parent_by_child.get(type_uri),
168
+ value_type=value_type_uri,
169
+ max_occurrence=max_occurrence,
170
+ instance_count=instance_count,
171
+ )
172
+ )
173
+ return read_properties
174
+
175
+ def _create_concepts_properties(
176
+ self, read_properties: list[_ReadProperties], prefixes: dict[str, Namespace]
177
+ ) -> tuple[list[UnverifiedConcept], list[UnverifiedConceptualProperty]]:
178
+ concepts: list[UnverifiedConcept] = []
179
+ properties: list[UnverifiedConceptualProperty] = []
180
+
181
+ # Help for IDE
182
+ type_uri: URIRef
183
+ parent_uri: URIRef
184
+ for parent_uri, parent_concepts_properties_iterable in itertools.groupby(
185
+ sorted(read_properties, key=lambda x: x.parent_uri or NEAT.EmptyType),
186
+ key=lambda x: x.parent_uri or NEAT.EmptyType,
187
+ ):
188
+ parent_str: str | None = None
189
+ if parent_uri != NEAT.EmptyType:
190
+ parent_str, parent_cls = self._create_concept(parent_uri, set_instance_source=False, prefixes=prefixes)
191
+ concepts.append(parent_cls)
192
+
193
+ properties_by_concept_by_property = self._get_properties_by_concept_by_property(
194
+ parent_concepts_properties_iterable
195
+ )
196
+ for type_uri, properties_by_property_uri in properties_by_concept_by_property.items():
197
+ concept_str, concept = self._create_concept(
198
+ type_uri, set_instance_source=True, prefixes=prefixes, implements=parent_str
199
+ )
200
+ concepts.append(concept)
201
+ for property_uri, read_properties in properties_by_property_uri.items():
202
+ namespace, property_suffix = split_uri(property_uri)
203
+ (self._add_uri_namespace_to_prefixes(namespace, prefixes),)
204
+ properties.append(
205
+ self._create_property(
206
+ read_properties, concept_str, property_uri, urllib.parse.unquote(property_suffix), prefixes
207
+ )
208
+ )
209
+ return concepts, properties
210
+
211
+ @staticmethod
212
+ def _get_properties_by_concept_by_property(
213
+ parent_concept_properties_iterable: Iterable[_ReadProperties],
214
+ ) -> dict[URIRef, dict[URIRef, list[_ReadProperties]]]:
215
+ properties_by_concept_by_property: dict[URIRef, dict[URIRef, list[_ReadProperties]]] = {}
216
+ for concept_uri, concept_properties_iterable in itertools.groupby(
217
+ sorted(parent_concept_properties_iterable, key=lambda x: x.type_uri), key=lambda x: x.type_uri
218
+ ):
219
+ properties_by_concept_by_property[concept_uri] = defaultdict(list)
220
+ for read_prop in concept_properties_iterable:
221
+ properties_by_concept_by_property[concept_uri][read_prop.property_uri].append(read_prop)
222
+ return properties_by_concept_by_property
223
+
224
+ @classmethod
225
+ def _create_concept(
226
+ cls, type_uri: URIRef, set_instance_source: bool, prefixes: dict[str, Namespace], implements: str | None = None
227
+ ) -> tuple[str, UnverifiedConcept]:
228
+ namespace, suffix = split_uri(type_uri)
229
+ cls._add_uri_namespace_to_prefixes(namespace, prefixes)
230
+ concept_str = urllib.parse.unquote(suffix)
231
+ return concept_str, UnverifiedConcept(
232
+ concept=concept_str, implements=implements, instance_source=type_uri if set_instance_source else None
233
+ )
234
+
235
+ def _create_property(
236
+ self,
237
+ read_properties: list[_ReadProperties],
238
+ concept_str: str,
239
+ property_uri: URIRef,
240
+ property_id: str,
241
+ prefixes: dict[str, Namespace],
242
+ ) -> UnverifiedConceptualProperty:
243
+ first = read_properties[0]
244
+ value_type = self._get_value_type(read_properties, prefixes)
245
+ return UnverifiedConceptualProperty(
246
+ concept=concept_str,
247
+ property_=property_id,
248
+ max_count=first.max_occurrence,
249
+ value_type=value_type,
250
+ instance_source=[property_uri],
251
+ )
252
+
253
+ @classmethod
254
+ def _get_value_type(
255
+ cls, read_properties: list[_ReadProperties], prefixes: dict[str, Namespace]
256
+ ) -> str | UnknownEntity:
257
+ value_types = {prop.value_type for prop in read_properties}
258
+ if len(value_types) == 1:
259
+ uri_ref = value_types.pop()
260
+ if uri_ref == NEAT.UnknownType:
261
+ return UnknownEntity()
262
+ namespace, suffix = split_uri(uri_ref)
263
+ cls._add_uri_namespace_to_prefixes(namespace, prefixes)
264
+ return suffix
265
+ uri_refs: list[str] = []
266
+ for uri_ref in value_types:
267
+ if uri_ref == NEAT.UnknownType:
268
+ return UnknownEntity()
269
+ namespace, suffix = split_uri(uri_ref)
270
+ cls._add_uri_namespace_to_prefixes(namespace, prefixes)
271
+ uri_refs.append(suffix)
272
+ # Sort the URIs to ensure deterministic output
273
+ return ", ".join(sorted(uri_refs))
274
+
275
+ def _create_default_metadata(self) -> UnverifiedConceptualMetadata:
276
+ now = datetime.now(timezone.utc)
277
+ name = self.data_model_id.external_id.replace("_", " ").title()
278
+ return UnverifiedConceptualMetadata(
279
+ space=self.data_model_id.space,
280
+ external_id=self.data_model_id.external_id,
281
+ # Validated in the constructor
282
+ version=cast(str, self.data_model_id.version),
283
+ name=name,
284
+ creator="NEAT",
285
+ created=now,
286
+ updated=now,
287
+ description="Inferred model from knowledge graph",
288
+ )
289
+
290
+ @classmethod
291
+ def _add_uri_namespace_to_prefixes(cls, namespace: str, prefixes: dict[str, Namespace]) -> None:
292
+ """Add URI to prefixes dict if not already present
293
+
294
+ Args:
295
+ URI: URI from which namespace is being extracted
296
+ prefixes: Dict of prefixes and namespaces
297
+ """
298
+ if Namespace(namespace) not in prefixes.values():
299
+ prefixes[f"prefix_{len(prefixes) + 1}"] = Namespace(namespace)
@@ -130,7 +130,7 @@ class BaseRDFImporter(BaseImporter[UnverifiedConceptualDataModel]):
130
130
 
131
131
  data_model = UnverifiedConceptualDataModel.load(data_model_dict)
132
132
  self.issue_list.trigger_warnings()
133
- return ImportedDataModel(data_model, {})
133
+ return ImportedDataModel(data_model)
134
134
 
135
135
  def _to_data_model_components(self) -> dict:
136
136
  raise NotImplementedError()
@@ -22,6 +22,7 @@ from cognite.neat.core._data_model.models import (
22
22
  RoleTypes,
23
23
  SchemaCompleteness,
24
24
  )
25
+ from cognite.neat.core._data_model.models._import_contexts import SpreadsheetContext
25
26
  from cognite.neat.core._issues import IssueList, MultiValueError
26
27
  from cognite.neat.core._issues.errors import (
27
28
  FileMissingRequiredFieldError,
@@ -271,7 +272,7 @@ class ExcelImporter(BaseImporter[T_UnverifiedDataModel]):
271
272
  raise MultiValueError(issue_list.errors)
272
273
 
273
274
  if user_read is None:
274
- return ImportedDataModel(None, {})
275
+ return ImportedDataModel(None, None)
275
276
 
276
277
  sheets = user_read.sheets
277
278
  original_role = user_read.role
@@ -287,7 +288,7 @@ class ExcelImporter(BaseImporter[T_UnverifiedDataModel]):
287
288
  except Exception as e:
288
289
  issue_list.append(FileReadError(self.filepath, f"Failed to delete temporary file: {e}"))
289
290
 
290
- return ImportedDataModel(data_model, read_info_by_sheet)
291
+ return ImportedDataModel(data_model, SpreadsheetContext(read_info_by_sheet))
291
292
 
292
293
  @property
293
294
  def description(self) -> str:
@@ -0,0 +1,82 @@
1
+ from collections.abc import Hashable, ItemsView, Iterator, KeysView, Mapping, ValuesView
2
+ from typing import TypeVar
3
+
4
+ from rdflib import URIRef
5
+
6
+ from cognite.neat.core._utils.spreadsheet import SpreadsheetRead
7
+
8
+ T_Key = TypeVar("T_Key", bound=Hashable)
9
+ T_Value = TypeVar("T_Value")
10
+
11
+
12
+ class ImportContext(dict, Mapping[T_Key, T_Value]):
13
+ def __init__(self, data: Mapping[T_Key, T_Value] | None = None) -> None:
14
+ super().__init__(data or {})
15
+
16
+ # The below methods are included to make better type hints in the IDE
17
+ def __getitem__(self, k: T_Key) -> T_Value:
18
+ return super().__getitem__(k)
19
+
20
+ def __setitem__(self, k: T_Key, v: T_Value) -> None:
21
+ super().__setitem__(k, v)
22
+
23
+ def __delitem__(self, k: T_Key) -> None:
24
+ super().__delitem__(k)
25
+
26
+ def __iter__(self) -> Iterator[T_Key]:
27
+ return super().__iter__()
28
+
29
+ def keys(self) -> KeysView[T_Key]: # type: ignore[override]
30
+ return super().keys()
31
+
32
+ def values(self) -> ValuesView[T_Value]: # type: ignore[override]
33
+ return super().values()
34
+
35
+ def items(self) -> ItemsView[T_Key, T_Value]: # type: ignore[override]
36
+ return super().items()
37
+
38
+ def get(self, __key: T_Key, __default: T_Value | None = None) -> T_Value: # type: ignore[override]
39
+ return super().get(__key, __default)
40
+
41
+ def pop(self, __key: T_Key, __default: T_Value | None = None) -> T_Value: # type: ignore[override]
42
+ return super().pop(__key, __default)
43
+
44
+ def popitem(self) -> tuple[T_Key, T_Value]:
45
+ return super().popitem()
46
+
47
+
48
+ class SpreadsheetContext(ImportContext[str, SpreadsheetRead]):
49
+ def __init__(self, data: dict[str, SpreadsheetRead] | None = None) -> None:
50
+ """Initialize the SpreadsheetContext with a dictionary of SpreadsheetRead objects.
51
+
52
+ Args:
53
+ data (dict[str, SpreadsheetRead]): A dictionary where keys are sheet names and values are
54
+ SpreadsheetRead objects containing the read data.
55
+ """
56
+ super().__init__(data or {})
57
+ for k, v in self.items():
58
+ if not isinstance(k, str):
59
+ raise TypeError(f"Expected string key, got {type(k).__name__}")
60
+ if not isinstance(v, SpreadsheetRead):
61
+ raise TypeError(f"Expected SpreadsheetRead for key '{k}', got {type(v).__name__}")
62
+
63
+
64
+ class GraphContext(ImportContext[str, Mapping[URIRef, int]]):
65
+ def __init__(self, data: dict[str, Mapping[URIRef, int]] | None = None) -> None:
66
+ """Initialize the GraphContext with a dictionary of mappings from URIRef to int.
67
+
68
+ Args:
69
+ data (dict[str, Mapping[URIRef, int]]): A dictionary where keys are graph names and values are
70
+ mappings of URIRef to integer identifiers.
71
+ """
72
+ super().__init__(data or {})
73
+ for k, v in self.items():
74
+ if not isinstance(k, str):
75
+ raise TypeError(f"Expected string key, got {type(k).__name__}")
76
+ if not isinstance(v, Mapping):
77
+ raise TypeError(f"Expected Mapping[URIRef, int] for key '{k}', got {type(v).__name__}")
78
+ for uri, value in v.items():
79
+ if not isinstance(uri, URIRef):
80
+ raise TypeError(f"Expected URIRef key in mapping for '{k}', got {type(uri).__name__}")
81
+ if not isinstance(value, int):
82
+ raise TypeError(f"Expected int value in mapping for '{k}', got {type(value).__name__}")
@@ -3,6 +3,7 @@ from collections import Counter, defaultdict
3
3
 
4
4
  from cognite.neat.core._constants import get_base_concepts
5
5
  from cognite.neat.core._data_model._constants import PATTERNS, EntityTypes
6
+ from cognite.neat.core._data_model.models._import_contexts import ImportContext, SpreadsheetContext
6
7
  from cognite.neat.core._data_model.models.entities import ConceptEntity, UnknownEntity
7
8
  from cognite.neat.core._data_model.models.entities._multi_value import MultiValueTypeInfo
8
9
  from cognite.neat.core._issues import IssueList
@@ -21,7 +22,6 @@ from cognite.neat.core._issues.warnings._resources import (
21
22
  ResourceNotDefinedWarning,
22
23
  ResourceRegexViolationWarning,
23
24
  )
24
- from cognite.neat.core._utils.spreadsheet import SpreadsheetRead
25
25
  from cognite.neat.core._utils.text import humanize_collection
26
26
 
27
27
  from ._verified import ConceptualDataModel
@@ -34,14 +34,14 @@ class ConceptualValidation:
34
34
  def __init__(
35
35
  self,
36
36
  data_model: ConceptualDataModel,
37
- read_info_by_spreadsheet: dict[str, SpreadsheetRead] | None = None,
37
+ context: ImportContext | None = None,
38
38
  ):
39
39
  # import here to avoid circular import issues
40
40
  from cognite.neat.core._data_model.analysis._base import DataModelAnalysis
41
41
 
42
42
  self.data_model = data_model
43
43
  self.analysis = DataModelAnalysis(self.data_model)
44
- self._read_info_by_spreadsheet = read_info_by_spreadsheet or {}
44
+ self._read_info_by_spreadsheet = context if isinstance(context, SpreadsheetContext) else SpreadsheetContext({})
45
45
  self._metadata = data_model.metadata
46
46
  self._properties = data_model.properties
47
47
  self._concepts = data_model.concepts
@@ -21,7 +21,9 @@ from cognite.neat.core._constants import (
21
21
  COGNITE_SPACES,
22
22
  DMS_CONTAINER_PROPERTY_SIZE_LIMIT,
23
23
  DMS_VIEW_CONTAINER_SIZE_LIMIT,
24
+ get_base_concepts,
24
25
  )
26
+ from cognite.neat.core._data_model.models._import_contexts import ImportContext, SpreadsheetContext
25
27
  from cognite.neat.core._data_model.models.data_types import DataType
26
28
  from cognite.neat.core._data_model.models.entities import ContainerEntity, RawFilter
27
29
  from cognite.neat.core._data_model.models.entities._single_value import (
@@ -47,12 +49,12 @@ from cognite.neat.core._issues.warnings import (
47
49
  UndefinedViewWarning,
48
50
  user_modeling,
49
51
  )
52
+ from cognite.neat.core._issues.warnings._models import ViewWithoutPropertiesWarning
50
53
  from cognite.neat.core._issues.warnings.user_modeling import (
51
54
  ContainerPropertyLimitWarning,
52
55
  DirectRelationMissingSourceWarning,
53
56
  NotNeatSupportedFilterWarning,
54
57
  )
55
- from cognite.neat.core._utils.spreadsheet import SpreadsheetRead
56
58
  from cognite.neat.core._utils.text import humanize_collection
57
59
 
58
60
  from ._verified import PhysicalDataModel, PhysicalProperty
@@ -81,15 +83,23 @@ class PhysicalValidation:
81
83
  self,
82
84
  data_model: PhysicalDataModel,
83
85
  client: NeatClient | None = None,
84
- read_info_by_spreadsheet: dict[str, SpreadsheetRead] | None = None,
86
+ context: ImportContext | None = None,
85
87
  ) -> None:
88
+ # import here to avoid circular import issues
89
+ from cognite.neat.core._data_model.analysis._base import DataModelAnalysis
90
+
86
91
  self._data_model = data_model
87
92
  self._client = client
88
93
  self._metadata = data_model.metadata
89
94
  self._properties = data_model.properties
90
95
  self._containers = data_model.containers
91
96
  self._views = data_model.views
92
- self._read_info_by_spreadsheet = read_info_by_spreadsheet or {}
97
+ self._read_info_by_spreadsheet = context if isinstance(context, SpreadsheetContext) else SpreadsheetContext()
98
+
99
+ self.analysis = DataModelAnalysis(physical=self._data_model)
100
+ self._cdf_concepts = {
101
+ ViewEntity.load(concept_as_string) for concept_as_string in get_base_concepts(base_model="CogniteCore")
102
+ }
93
103
 
94
104
  def imported_views_and_containers_ids(
95
105
  self, include_views_with_no_properties: bool = True
@@ -170,6 +180,9 @@ class PhysicalValidation:
170
180
  # Validated for duplicated resource
171
181
  issue_list.extend(self._duplicated_resources())
172
182
 
183
+ # Validate if views are defined (i.e. have at least one property defined, or inherited)
184
+ issue_list.extend(self._views_without_properties_exist())
185
+
173
186
  # Neat DMS classes Validation
174
187
  # These are errors that can only happen due to the format of the Neat DMS classes
175
188
  issue_list.extend(self._validate_raw_filter())
@@ -192,6 +205,23 @@ class PhysicalValidation:
192
205
  issue_list.extend(self._same_space_views_and_data_model())
193
206
  return issue_list
194
207
 
208
+ def _views_without_properties_exist(self) -> IssueList:
209
+ """Check if there are views that do not have any properties defined directly or inherited."""
210
+ issue_list = IssueList()
211
+ views = {view.view for view in self._views}
212
+ ancestors_by_view = self.analysis.implements_by_view(include_ancestors=True, include_different_space=True)
213
+ views_with_properties = self.analysis.defined_views().union(self._cdf_concepts)
214
+
215
+ if candidate_views := views.difference(views_with_properties):
216
+ for view in candidate_views:
217
+ # Here we check if at least one of the ancestors of the view has properties
218
+ if (ancestors := ancestors_by_view.get(view)) and ancestors.intersection(views_with_properties):
219
+ continue
220
+
221
+ issue_list.append_if_not_exist(ViewWithoutPropertiesWarning(view_id=view.as_id()))
222
+
223
+ return issue_list
224
+
195
225
  def _same_space_views_and_data_model(self) -> IssueList:
196
226
  issue_list = IssueList()
197
227
 
@@ -31,6 +31,7 @@ from cognite.neat.core._constants import (
31
31
  )
32
32
  from cognite.neat.core._data_model._constants import PATTERNS, get_reserved_words
33
33
  from cognite.neat.core._data_model._shared import (
34
+ ImportContext,
34
35
  ImportedDataModel,
35
36
  ImportedUnverifiedDataModel,
36
37
  VerifiedDataModel,
@@ -93,7 +94,6 @@ from cognite.neat.core._issues.warnings._models import (
93
94
  SolutionModelBuildOnTopOfCDMWarning,
94
95
  )
95
96
  from cognite.neat.core._utils.rdf_ import get_inheritance_path
96
- from cognite.neat.core._utils.spreadsheet import SpreadsheetRead
97
97
  from cognite.neat.core._utils.text import (
98
98
  NamingStandardization,
99
99
  humanize_collection,
@@ -2412,13 +2412,13 @@ class AddCogniteProperties(
2412
2412
  concepts=new_classes,
2413
2413
  prefixes=input_.prefixes,
2414
2414
  ),
2415
- context={},
2415
+ context=None,
2416
2416
  )
2417
2417
 
2418
2418
  @staticmethod
2419
2419
  def _get_properties_by_concepts(
2420
2420
  properties: list[UnverifiedConceptualProperty],
2421
- read_context: dict[str, SpreadsheetRead],
2421
+ read_context: ImportContext | None,
2422
2422
  default_space: str,
2423
2423
  ) -> dict[ConceptEntity, dict[str, UnverifiedConceptualProperty]]:
2424
2424
  issues = IssueList()
@@ -2438,7 +2438,7 @@ class AddCogniteProperties(
2438
2438
  @staticmethod
2439
2439
  def _get_dependencies_by_concepts(
2440
2440
  concepts: list[UnverifiedConcept],
2441
- read_context: dict[str, SpreadsheetRead],
2441
+ read_context: ImportContext | None,
2442
2442
  default_space: str,
2443
2443
  ) -> dict[ConceptEntity, set[ConceptEntity]]:
2444
2444
  dependencies_by_concepts: dict[ConceptEntity, set[ConceptEntity]] = {}
@@ -1,14 +1,16 @@
1
1
  import warnings
2
2
  from collections.abc import Iterator
3
3
  from contextlib import contextmanager
4
+ from typing import TYPE_CHECKING
4
5
 
5
6
  from pydantic import ValidationError
6
7
 
7
- from cognite.neat.core._utils.spreadsheet import SpreadsheetRead
8
-
9
8
  from ._base import IssueList, MultiValueError, NeatError
10
9
  from ._factory import from_pydantic_errors, from_warning
11
10
 
11
+ if TYPE_CHECKING:
12
+ from cognite.neat.core._data_model.models._import_contexts import ImportContext
13
+
12
14
 
13
15
  @contextmanager
14
16
  def catch_warnings() -> Iterator[IssueList]:
@@ -26,12 +28,12 @@ def catch_warnings() -> Iterator[IssueList]:
26
28
 
27
29
 
28
30
  @contextmanager
29
- def catch_issues(read_info_by_sheet: dict[str, SpreadsheetRead] | None = None) -> Iterator[IssueList]:
31
+ def catch_issues(context: "ImportContext | None" = None) -> Iterator[IssueList]:
30
32
  """This is an internal help function to handle issues and warnings.
31
33
 
32
34
  Args:
33
- read_info_by_sheet (dict[str, SpreadsheetRead]): The read information by sheet. This is used to adjust
34
- the row numbers in the errors/warnings.
35
+ context (ImportContext): The read context. This is used to adjust
36
+ the row numbers in the errors/warnings if the data is read from a spreadsheet.
35
37
 
36
38
  Returns:
37
39
  IssueList: The list of issues.
@@ -41,7 +43,7 @@ def catch_issues(read_info_by_sheet: dict[str, SpreadsheetRead] | None = None) -
41
43
  try:
42
44
  yield issues
43
45
  except ValidationError as e:
44
- issues.extend(from_pydantic_errors(e.errors(), read_info_by_sheet))
46
+ issues.extend(from_pydantic_errors(e.errors(), context))
45
47
  except NeatError as single:
46
48
  issues.append(single)
47
49
  except MultiValueError as multi:
@@ -1,18 +1,21 @@
1
- from typing import cast
1
+ from typing import TYPE_CHECKING, cast
2
2
  from warnings import WarningMessage
3
3
 
4
4
  from pydantic_core import ErrorDetails
5
5
 
6
6
  from cognite.neat.core._issues._base import NeatError, NeatWarning
7
- from cognite.neat.core._utils.spreadsheet import SpreadsheetRead
8
7
 
9
8
  from .errors import NeatValueError, SpreadsheetError
10
9
 
10
+ if TYPE_CHECKING:
11
+ from cognite.neat.core._data_model.models._import_contexts import ImportContext, SpreadsheetContext
11
12
 
12
- def from_pydantic_errors(
13
- errors: list[ErrorDetails], read_info_by_sheet: dict[str, SpreadsheetRead] | None = None
14
- ) -> list[NeatError]:
15
- read_info_by_sheet = read_info_by_sheet or {}
13
+
14
+ def from_pydantic_errors(errors: list[ErrorDetails], context: "ImportContext | None" = None) -> list[NeatError]:
15
+ # To avoid circular import, we import SpreadsheetContext here.
16
+ from cognite.neat.core._data_model.models._import_contexts import SpreadsheetContext
17
+
18
+ read_info_by_sheet = context if isinstance(context, SpreadsheetContext) else SpreadsheetContext({})
16
19
  return [
17
20
  _from_pydantic_error(error, read_info_by_sheet)
18
21
  for error in errors
@@ -29,7 +32,7 @@ def from_warning(warning: WarningMessage) -> NeatWarning | None:
29
32
  return None
30
33
 
31
34
 
32
- def _from_pydantic_error(error: ErrorDetails, read_info_by_sheet: dict[str, SpreadsheetRead]) -> NeatError:
35
+ def _from_pydantic_error(error: ErrorDetails, read_info_by_sheet: "SpreadsheetContext") -> NeatError:
33
36
  neat_error = _create_neat_value_error(error)
34
37
  location = error["loc"]
35
38
 
@@ -92,6 +92,15 @@ class NotSupportedHasDataFilterLimitWarning(CDFNotSupportedWarning):
92
92
  limit: int = DMS_VIEW_CONTAINER_SIZE_LIMIT
93
93
 
94
94
 
95
+ @dataclass(unsafe_hash=True)
96
+ class ViewWithoutPropertiesWarning(UserModelingWarning):
97
+ """View {view_id} has neither explicit properties nor implements views that have properties."""
98
+
99
+ fix = "Define properties for view or inherit properties by implementing view(s) that has properties."
100
+
101
+ view_id: ViewId
102
+
103
+
95
104
  @dataclass(unsafe_hash=True)
96
105
  class UndefinedConceptWarning(UserModelingWarning):
97
106
  """Concept {concept_id} has no explicit properties neither implements concepts that have properties."""
@@ -347,7 +347,7 @@ class NeatInstanceStore:
347
347
  )
348
348
  return issue_list
349
349
  _start = datetime.now(timezone.utc)
350
- with catch_issues({}) as transform_issues:
350
+ with catch_issues() as transform_issues:
351
351
  transformer.transform(self.graph(named_graph))
352
352
  issue_list.extend(transform_issues)
353
353
  self.provenance.append(
@@ -11,7 +11,7 @@ from typing import Any
11
11
 
12
12
  from cognite.client.exceptions import CogniteDuplicatedError, CogniteReadTimeout
13
13
 
14
- from cognite.neat.core._issues.errors import NeatImportError
14
+ from cognite.neat.core._issues.errors._general import NeatImportError
15
15
 
16
16
 
17
17
  def local_import(module: str, extra: str) -> ModuleType:
@@ -33,6 +33,7 @@ from ._mapping import MappingAPI
33
33
  from ._plugin import PluginAPI
34
34
  from ._prepare import PrepareAPI
35
35
  from ._read import ReadAPI
36
+ from ._session._data_model import DataModelAPI
36
37
  from ._set import SetAPI
37
38
  from ._show import ShowAPI
38
39
  from ._state import SessionState
@@ -115,6 +116,9 @@ class NeatSession:
115
116
  if load_engine != "skip" and (engine_version := load_neat_engine(client, load_engine)):
116
117
  print(f"Neat Engine {engine_version} loaded.")
117
118
 
119
+ # new API for data model operations
120
+ self.data_model = DataModelAPI(self._state)
121
+
118
122
  def _select_most_performant_store(self) -> Literal["memory", "oxigraph"]:
119
123
  """Select the most performant store based on the current environment."""
120
124
 
File without changes
@@ -0,0 +1,154 @@
1
+ from typing import Any, Literal
2
+ from zipfile import Path
3
+
4
+ from cognite.neat.core._data_model import importers
5
+ from cognite.neat.core._data_model.importers._base import BaseImporter
6
+ from cognite.neat.core._issues._base import IssueList
7
+ from cognite.neat.core._issues.errors._general import NeatValueError
8
+ from cognite.neat.core._issues.warnings._general import MissingCogniteClientWarning
9
+ from cognite.neat.core._utils.reader._base import NeatReader
10
+ from cognite.neat.plugins._manager import get_plugin_manager
11
+ from cognite.neat.plugins.data_model.importers._base import DataModelImporterPlugin
12
+ from cognite.neat.session._state import SessionState
13
+ from cognite.neat.session.exceptions import NeatSessionError, session_class_wrapper
14
+
15
+
16
+ @session_class_wrapper
17
+ class DataModelAPI:
18
+ """API for managing data models in NEAT session."""
19
+
20
+ def __init__(self, state: SessionState) -> None:
21
+ self._state = state
22
+ self.read = ReadAPI(state)
23
+
24
+
25
+ @session_class_wrapper
26
+ class ReadAPI:
27
+ def __init__(self, state: SessionState) -> None:
28
+ self._state = state
29
+
30
+ def __call__(self, name: str, io: str | Path, **kwargs: Any) -> IssueList:
31
+ """Provides access to the external plugins for data model importing.
32
+
33
+ Args:
34
+ name (str): The name of format (e.g. Excel) plugin is handling.
35
+ io (str | Path | None): The input/output interface for the plugin.
36
+ **kwargs (Any): Additional keyword arguments for the plugin.
37
+
38
+ !!! note "kwargs"
39
+ Users must consult the documentation of the plugin to understand
40
+ what keyword arguments are supported.
41
+ """
42
+
43
+ # These are internal readers that are not plugins
44
+ if name.strip().lower() == "excel":
45
+ return self.excel(io, **kwargs)
46
+ elif name.strip().lower() == "ontology":
47
+ return self.ontology(io)
48
+ elif name.strip().lower() == "yaml":
49
+ return self.yaml(io, **kwargs)
50
+ else:
51
+ return self._plugin(name, io, **kwargs)
52
+
53
+ def _plugin(self, name: str, io: str | Path, **kwargs: Any) -> IssueList:
54
+ """Provides access to the external plugins for data model importing.
55
+
56
+ Args:
57
+ name (str): The name of format (e.g. Excel) plugin is handling.
58
+ io (str | Path | None): The input/output interface for the plugin.
59
+ **kwargs (Any): Additional keyword arguments for the plugin.
60
+
61
+ !!! note "kwargs"
62
+ Users must consult the documentation of the plugin to understand
63
+ what keyword arguments are supported.
64
+ """
65
+
66
+ # Some plugins may not support the io argument
67
+ reader = NeatReader.create(io)
68
+ path = reader.materialize_path()
69
+
70
+ self._state._raise_exception_if_condition_not_met(
71
+ "Data Model Read",
72
+ empty_data_model_store_required=True,
73
+ )
74
+
75
+ plugin_manager = get_plugin_manager()
76
+ plugin = plugin_manager.get(name, DataModelImporterPlugin)
77
+
78
+ print(
79
+ f"You are using an external plugin {plugin.__name__}, which is not developed by the NEAT team."
80
+ "\nUse it at your own risk."
81
+ )
82
+
83
+ return self._state.data_model_import(plugin().configure(io=path, **kwargs))
84
+
85
+ def excel(self, io: str | Path, *, enable_manual_edit: bool = False) -> IssueList:
86
+ """Reads a Neat Excel Data Model to the data model store.
87
+ The data model spreadsheets may contain conceptual or physical data model definitions.
88
+
89
+ Args:
90
+ io: file path to the Excel sheet
91
+ enable_manual_edit: If True, the user will be able to re-import data model
92
+ which where edit outside of NeatSession
93
+ """
94
+ reader = NeatReader.create(io)
95
+ path = reader.materialize_path()
96
+
97
+ self._state._raise_exception_if_condition_not_met(
98
+ "Read Excel Data Model",
99
+ empty_data_model_store_required=not enable_manual_edit,
100
+ )
101
+
102
+ return self._state.data_model_import(importers.ExcelImporter(path), enable_manual_edit)
103
+
104
+ def ontology(self, io: str | Path) -> IssueList:
105
+ """Reads an OWL ontology source into NeatSession.
106
+
107
+ Args:
108
+ io: file path or url to the OWL file
109
+ """
110
+
111
+ self._state._raise_exception_if_condition_not_met(
112
+ "Read Ontology",
113
+ empty_data_model_store_required=True,
114
+ )
115
+
116
+ reader = NeatReader.create(io)
117
+ importer = importers.OWLImporter.from_file(reader.materialize_path(), source_name=f"file {reader!s}")
118
+ return self._state.data_model_import(importer)
119
+
120
+ def yaml(self, io: str | Path, *, format: Literal["neat", "toolkit"] = "neat") -> IssueList:
121
+ """Reads a yaml with either neat data mode, or several toolkit yaml files to
122
+ import Data Model(s) into NeatSession.
123
+
124
+ Args:
125
+ io: File path to the Yaml file in the case of "neat" yaml, or path to a zip folder or directory with several
126
+ Yaml files in the case of "toolkit".
127
+ format: The format of the yaml file(s). Can be either "neat" or "toolkit".
128
+
129
+ Example:
130
+ ```python
131
+ neat.read.yaml("path_to_toolkit_yamls")
132
+ ```
133
+ """
134
+ self._state._raise_exception_if_condition_not_met(
135
+ "Read YAML data model",
136
+ empty_data_model_store_required=True,
137
+ )
138
+ reader = NeatReader.create(io)
139
+ path = reader.materialize_path()
140
+ importer: BaseImporter
141
+ if format == "neat":
142
+ importer = importers.DictImporter.from_yaml_file(path, source_name=f"{reader!s}")
143
+ elif format == "toolkit":
144
+ dms_importer = importers.DMSImporter.from_path(path, self._state.client)
145
+ if dms_importer.issue_list.has_warning_type(MissingCogniteClientWarning):
146
+ raise NeatSessionError(
147
+ "No client provided. You are referencing Cognite containers in your data model, "
148
+ "NEAT needs a client to lookup the container definitions. "
149
+ "Please set the client in the session, NeatSession(client=client)."
150
+ )
151
+ importer = dms_importer
152
+ else:
153
+ raise NeatValueError(f"Unsupported YAML format: {format}")
154
+ return self._state.data_model_import(importer)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cognite-neat
3
- Version: 0.123.18
3
+ Version: 0.123.20
4
4
  Summary: Knowledge graph transformation
5
5
  Project-URL: Documentation, https://cognite-neat.readthedocs-hosted.com/
6
6
  Project-URL: Homepage, https://cognite-neat.readthedocs-hosted.com/
@@ -1,5 +1,5 @@
1
1
  cognite/neat/__init__.py,sha256=12StS1dzH9_MElqxGvLWrNsxCJl9Hv8A2a9D0E5OD_U,193
2
- cognite/neat/_version.py,sha256=fuTI2lcJbM6-5HASu5MdGJw07hZcivY-3tNoqelvUs0,47
2
+ cognite/neat/_version.py,sha256=tUfZIhsXsTuZtKqqfKwmQe_3linzeB0aoFlEj2fZHAQ,47
3
3
  cognite/neat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  cognite/neat/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  cognite/neat/core/_config.py,sha256=WT1BS8uADcFvGoUYOOfwFOVq_VBl472TisdoA3wLick,280
@@ -20,7 +20,7 @@ cognite/neat/core/_client/data_classes/schema.py,sha256=SpkBGbC2SUJG38Ixf1vYJINI
20
20
  cognite/neat/core/_client/data_classes/statistics.py,sha256=GU-u41cOTig0Y5pYhW5KqzCsuAUIX9tOmdizMEveYuw,4487
21
21
  cognite/neat/core/_data_model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  cognite/neat/core/_data_model/_constants.py,sha256=ssiOprhd4bamglQnLTNjmqYn9mCBW-VOUbn08qDBbsM,5857
23
- cognite/neat/core/_data_model/_shared.py,sha256=gLEEMofI9prZLRNjHpwQe0uX9WoKd5qUt5pT1i_KAYo,2072
23
+ cognite/neat/core/_data_model/_shared.py,sha256=at3-TT6pkdwtsjuz94P1lj1W7dO6_Sb3nQ3JSDBNLCY,2088
24
24
  cognite/neat/core/_data_model/analysis/__init__.py,sha256=v3hSfz7AEEqcmdjL71I09tP8Hl-gPZYOiDYMp_CW4vg,70
25
25
  cognite/neat/core/_data_model/analysis/_base.py,sha256=VT1orVf0xSSZrKnJoc-cJR1F1mtMn9Ybjk7UDO71aFA,24448
26
26
  cognite/neat/core/_data_model/catalog/__init__.py,sha256=zWG1-GONe8m05lV3gLAK_Xp7EJvcy6qLLl2B-RHHBjw,260
@@ -34,25 +34,27 @@ cognite/neat/core/_data_model/exporters/_data_model2excel.py,sha256=88ReyrsRqoIR
34
34
  cognite/neat/core/_data_model/exporters/_data_model2instance_template.py,sha256=9k8A70b1paeOHjvJRtbl6Xror1GD8AIMdo3cCx5aejE,6103
35
35
  cognite/neat/core/_data_model/exporters/_data_model2ontology.py,sha256=sZRxvbnv2reav3xUUZl6NIX-KqngoKr4qLmzTUvkhYk,22615
36
36
  cognite/neat/core/_data_model/exporters/_data_model2yaml.py,sha256=1dlb-v4sV8BArnX_6J4wpjQT7r-FinFAvoPDoMNkHYw,3284
37
- cognite/neat/core/_data_model/importers/__init__.py,sha256=5KqFRDz69FlXRcmqu7ejQl3YVXrpLXx-Q-HpwAeDbfA,1184
37
+ cognite/neat/core/_data_model/importers/__init__.py,sha256=jkDKSGv5VdJgl44lmn7VQtD6-rqo09VFOr-tTB5Lfyc,1290
38
38
  cognite/neat/core/_data_model/importers/_base.py,sha256=pKe2OK86Wdj6CTj5bUgjY33ejZhRfD2eJbjcCapHD58,2013
39
39
  cognite/neat/core/_data_model/importers/_base_file_reader.py,sha256=m7CwMujEybYMfHWbTQOb7wBvLl2X1TmROkPelJMSaDA,1621
40
- cognite/neat/core/_data_model/importers/_dict2data_model.py,sha256=-1zmo8JkxJ9qiWuC7sUH7oSlpnPPKTMxZtm4WrRPO5A,4709
41
- cognite/neat/core/_data_model/importers/_dms2data_model.py,sha256=1luEyqEu51rNcFcEh-MjTnUY_5mnQU0761MDVHOuteo,29132
42
- cognite/neat/core/_data_model/importers/_spreadsheet2data_model.py,sha256=2QqrxQ9AI3LT9toH_gryIR52UecMsR-v44ljXedDCp4,11972
40
+ cognite/neat/core/_data_model/importers/_dict2data_model.py,sha256=GEAD0Gs69rH-i-TjHV3Px-7Wo1Z7PfUqESsZt_58xUU,4705
41
+ cognite/neat/core/_data_model/importers/_dms2data_model.py,sha256=X2iQ2VQvrruj1lEFVYN3Hl7J1R7NK3WT6FyXyl-ruyE,29134
42
+ cognite/neat/core/_data_model/importers/_graph2data_model.py,sha256=yWi6Vlrc8rrcFM8hxHOVesr9D3etwJ0rbL6TJULrW9U,13684
43
+ cognite/neat/core/_data_model/importers/_spreadsheet2data_model.py,sha256=wPb1ie_nmWNuHO0X6NW53pvqUDYGvNkHLvT8_UKFJIw,12079
43
44
  cognite/neat/core/_data_model/importers/_rdf/__init__.py,sha256=1yOjV2PKCxwH7uCTXVZhSdxtn5etmFX40cksvwtKcZ8,199
44
- cognite/neat/core/_data_model/importers/_rdf/_base.py,sha256=FKceKumKmhEGpMZvo1BwEewnUvfAsTF3Ax9fo1nxsGE,6020
45
+ cognite/neat/core/_data_model/importers/_rdf/_base.py,sha256=XTdKqN4nf0d2Vvk56LShrDoyCQCg9MXvKwxXT0uMnGg,6016
45
46
  cognite/neat/core/_data_model/importers/_rdf/_inference2rdata_model.py,sha256=PCgM9-qGSLlupN7tYCFLHjivgICtMiahNry1ub8JCYk,28934
46
47
  cognite/neat/core/_data_model/importers/_rdf/_owl2data_model.py,sha256=l_89N1LewZVjSttcJkFAJj63JW8wI-THKJYjAxcNiDg,3093
47
48
  cognite/neat/core/_data_model/importers/_rdf/_shared.py,sha256=qibq94dFoy_g1ED5nIFYwHC_LYI4jI67HFVcMy7abrM,6665
48
49
  cognite/neat/core/_data_model/models/__init__.py,sha256=hmF7MDR1XmpLxYdMkOEuPuHUqOQKE4AgsuUqdc-ySSQ,1249
49
50
  cognite/neat/core/_data_model/models/_base_unverified.py,sha256=1Wfbp-tJaEF6hd1bFdp2FhTgPkInf-1ZokuEoVJRPxQ,6842
50
51
  cognite/neat/core/_data_model/models/_base_verified.py,sha256=nzPrlj7ZvYull_Fdh2zeDXz98hux-eQOdTGy9jhUtYA,15127
52
+ cognite/neat/core/_data_model/models/_import_contexts.py,sha256=LAQbgwTbyIAY3at2hk6OksfK_CKavBwgwPcRFcszJcc,3436
51
53
  cognite/neat/core/_data_model/models/_types.py,sha256=70E8fiLdZkVF2sDUGPuDhzXNA5niVECkVDI7YN0NF60,5488
52
54
  cognite/neat/core/_data_model/models/data_types.py,sha256=uQ_u9KxCetLjxo-VtFzOXSxQuuf97Kg-9lfTTGzY6hc,10150
53
55
  cognite/neat/core/_data_model/models/conceptual/__init__.py,sha256=9A6myEV8s0-LqdXejaljqPj8S0pIpUL75rNdRDZzyR8,585
54
56
  cognite/neat/core/_data_model/models/conceptual/_unverified.py,sha256=VswgnTSjSCRzBX3z5HvintBGaWBPexxIs-7z7S4J57c,6298
55
- cognite/neat/core/_data_model/models/conceptual/_validation.py,sha256=u-BngcU1Bfe846CxJM-z_uu7En1bLJd7NBzeKOmS9RA,13806
57
+ cognite/neat/core/_data_model/models/conceptual/_validation.py,sha256=CF1jYALTCQFAr5KUwplAzOLdxJGknIeJo-HpxVZsgMY,13859
56
58
  cognite/neat/core/_data_model/models/conceptual/_verified.py,sha256=BUB4Ur4kpBoWiwTf57tjxJ2l0tDTSbY7zGrg1g0yVNQ,13716
57
59
  cognite/neat/core/_data_model/models/entities/__init__.py,sha256=UsW-_6fwd-TW0WcnShPKf40h75l1elVn80VurUwRAic,1567
58
60
  cognite/neat/core/_data_model/models/entities/_constants.py,sha256=GXRzVfArwxF3C67VCkzy0JWTZRkRJUYXBQaaecrqcWc,351
@@ -67,11 +69,11 @@ cognite/neat/core/_data_model/models/mapping/_classic2core.yaml,sha256=ei-nuivNW
67
69
  cognite/neat/core/_data_model/models/physical/__init__.py,sha256=ONE_xLw1cxfw88rICG_RtbjCYUZm8yS2kBQ4Di3EGnA,987
68
70
  cognite/neat/core/_data_model/models/physical/_exporter.py,sha256=DPOytV-sIzpGJtfDEfi7G4RWnSCVNRLWe1KzY26ewmc,30083
69
71
  cognite/neat/core/_data_model/models/physical/_unverified.py,sha256=VyI-JULAu6kHJygUclDPH1JYjhf_XcO58tI9BkXORC0,18430
70
- cognite/neat/core/_data_model/models/physical/_validation.py,sha256=icgNNmvc60lIxI91NGGL5Bs7rR9evNtEubYYMMeKBVg,39529
72
+ cognite/neat/core/_data_model/models/physical/_validation.py,sha256=AuBAecOTAVRbGh9VXZ6W91HsU7-B75ko7oaxlX4Mmqw,41140
71
73
  cognite/neat/core/_data_model/models/physical/_verified.py,sha256=4_7XUj6-x74DhL8qe-duXhlNnq6ANmShB7UpICjbQW4,26783
72
74
  cognite/neat/core/_data_model/transformers/__init__.py,sha256=N6yRBplAkrwwxoTAre_1BE_fdSZL5jihr7xTQjW3KnM,1876
73
75
  cognite/neat/core/_data_model/transformers/_base.py,sha256=7adUBJgDkXgRq_h7l1q2VsLQo3lE7-xmzmHdcF4QHq8,3133
74
- cognite/neat/core/_data_model/transformers/_converters.py,sha256=OazYC7DgAXXEvxdiaPfJSe2ZNkYn2mRqWhtvtvWK59g,111575
76
+ cognite/neat/core/_data_model/transformers/_converters.py,sha256=Nyq2Iy2BYV0QMwpqLtdwHqpftl9sF1KvX5YVkIMPguc,111519
75
77
  cognite/neat/core/_data_model/transformers/_mapping.py,sha256=GwmTRnhiUPIG37CgUSIbjT7ZpWOwdWuBZ_HAIIBiKYY,19024
76
78
  cognite/neat/core/_data_model/transformers/_union_conceptual.py,sha256=sg-VGjrK7PwZS1U18ov-8Or00uR3pFLOaPOYT1edD8Q,8852
77
79
  cognite/neat/core/_data_model/transformers/_verification.py,sha256=yyPK6irhMGjVtwKxRIElSsPLUvLLVfk1lBAGny6jN5w,5193
@@ -120,8 +122,8 @@ cognite/neat/core/_instances/transformers/_rdfpath.py,sha256=4PIVpjlng59oTjoToS6
120
122
  cognite/neat/core/_instances/transformers/_value_type.py,sha256=-d18yefiGrx8CaVNLgJe0dF0zsMxtCQxlD2q2ZFGJ8U,15820
121
123
  cognite/neat/core/_issues/__init__.py,sha256=NQ-PN3fqp-hBPlpG2AZEND4cDn3_3UXAPfhLNtF5mtc,457
122
124
  cognite/neat/core/_issues/_base.py,sha256=LZhTF_QOQvCxFrGUnWmF9gQnuyr7nM3MqXf_r8KG7GY,12003
123
- cognite/neat/core/_issues/_contextmanagers.py,sha256=5-QXVmfplt4S_k2csrQ2xuezOOuE5_FxSA9GVGVG1s4,1582
124
- cognite/neat/core/_issues/_factory.py,sha256=ifEzHZcvPyO0ZGJo8T8CE20F5L4yRzrrGPxl9d87oIs,2829
125
+ cognite/neat/core/_issues/_contextmanagers.py,sha256=EiLW9h60ZJ80GAsbEGvwf9LoID1ZPAUh-7KNn6i9cGk,1621
126
+ cognite/neat/core/_issues/_factory.py,sha256=mcBaIF1H5SPkw9X80VsTgL1SHlZN6P2kXE75k3Y1WN8,3079
125
127
  cognite/neat/core/_issues/formatters.py,sha256=k2h_6wHW0ve52gXeuRoEcGwrxqqSe5sYFa_HycPiqW8,3323
126
128
  cognite/neat/core/_issues/errors/__init__.py,sha256=YkJeNnB1FDhYYTUbsb6iIm2rzI7usDYdjQDb4qrfFR4,2492
127
129
  cognite/neat/core/_issues/errors/_external.py,sha256=AaKwO5-AvX01d7Hd83vqYl1qNmMtgsmShmvyH8ioZAM,2354
@@ -132,18 +134,18 @@ cognite/neat/core/_issues/errors/_wrapper.py,sha256=clhuSwUuHy-FQXQopFIQRY8c_NZM
132
134
  cognite/neat/core/_issues/warnings/__init__.py,sha256=3MQS_elyRD3SG3iEWMWLRJDabth7upT3oX4WD0xxOh4,3263
133
135
  cognite/neat/core/_issues/warnings/_external.py,sha256=w-1R7ea6DXTIWqwlwMMjY0YxKDMSJ8gKAbp_nIIM1AI,1324
134
136
  cognite/neat/core/_issues/warnings/_general.py,sha256=_6dAFaMz-LIv7GsBBIBq2d-kmbuxVXKvU4jZeb7tjAo,972
135
- cognite/neat/core/_issues/warnings/_models.py,sha256=zTQuj2eAQOaX4CO8NljhX50Y8i9FUy3nc3x4l42YHmM,5479
137
+ cognite/neat/core/_issues/warnings/_models.py,sha256=3AGdCteVRq7iK4TcGUYy7RxLIKGgc32NyigG8G489jA,5795
136
138
  cognite/neat/core/_issues/warnings/_properties.py,sha256=I3vqc1aL-ce_FRQNgQQy34RW7kQxcjbwhZIIVtGVmg8,3807
137
139
  cognite/neat/core/_issues/warnings/_resources.py,sha256=_iPRq0pRMmRu3LFjqZTaG3OqOzw4f8-Vc9G4Im__FHc,3578
138
140
  cognite/neat/core/_issues/warnings/user_modeling.py,sha256=Qn_S8TLw7MMYQaJcZBScJA48kz_PrTWz0NaepSR70Fk,4144
139
141
  cognite/neat/core/_store/__init__.py,sha256=wpsF8xjIQ5V21NOh45XQV813n_EzgyPOt0VVinYjnDI,140
140
142
  cognite/neat/core/_store/_data_model.py,sha256=6Eg_QH1ZlS4AO3c0_Ye8M-Y4_Ycf3mQPJBKyardGu9w,19646
141
- cognite/neat/core/_store/_instance.py,sha256=QFrhOyaVA-mOtRaKZDE0aYyEJlSYx1jImKC8iE3b75E,17406
143
+ cognite/neat/core/_store/_instance.py,sha256=FzNtu_G9_VavrZLIhUZUqBGUs5Mknbbfi1hC0qFs5yQ,17404
142
144
  cognite/neat/core/_store/_provenance.py,sha256=aMEsq27dZ4NZ6XEC8hA0fIDF13i1ZP3QwnclLCRaNk4,7326
143
145
  cognite/neat/core/_store/exceptions.py,sha256=jcd1Gv65mfTdC4cipFAMWUNghEmdLS_lwPH1FB_ebxI,1656
144
146
  cognite/neat/core/_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
145
147
  cognite/neat/core/_utils/auth.py,sha256=tP_diUZdtacUkM8TLlbSOyHlNcq9VGh-4o_7myWRU_o,14763
146
- cognite/neat/core/_utils/auxiliary.py,sha256=0A5dE0oLahErqAClF3OjRge_RFqnq3GBK6L3t-GpmuM,6850
148
+ cognite/neat/core/_utils/auxiliary.py,sha256=nQAvIysrtigDTefuxTRGFiNUUBYy-iSDJPhvw-6RB50,6859
147
149
  cognite/neat/core/_utils/collection_.py,sha256=zVrSmm4045pjw6Pt6y4VPTIJ4dXdMJPyOV70LdFyDBM,2376
148
150
  cognite/neat/core/_utils/graph_transformations_report.py,sha256=ORVH7lw357TPOq4elU5lH46Qx6GCLVrSj-1nX6Ggk1U,1235
149
151
  cognite/neat/core/_utils/io_.py,sha256=D2Mg8sOxfBoDg3fC0jBzaxO3vkXmr0QvZSgYIv6xRkM,386
@@ -163,7 +165,7 @@ cognite/neat/plugins/data_model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
163
165
  cognite/neat/plugins/data_model/importers/__init__.py,sha256=d4UJNCFR1DXPY7lv5LdCW2hiStEhvXiu2g_bRSIp1y0,89
164
166
  cognite/neat/plugins/data_model/importers/_base.py,sha256=M9zXp7tEu1SfJZRAJAtLmqpssdFcoi2X-5e25q_n_h8,1034
165
167
  cognite/neat/session/__init__.py,sha256=fxQ5URVlUnmEGYyB8Baw7IDq-uYacqkigbc4b-Pr9Fw,58
166
- cognite/neat/session/_base.py,sha256=6P63Kq4JJSi3S1CpcVLiG-dfKsN9Ml3o5GqZXjcLVvo,12937
168
+ cognite/neat/session/_base.py,sha256=yxAItY6663wcmlrwxmzWkJorrrrm9oahpYOP-5RGwvQ,13081
167
169
  cognite/neat/session/_collector.py,sha256=-icWXOT9YBjAOVZfpPtBx-D39kpRP2RaQKdPtcr7Xm8,4233
168
170
  cognite/neat/session/_drop.py,sha256=ipD8RS_ZebPNpeIkhC7yqSSeo7e57TXMRxrh5_6IRik,4239
169
171
  cognite/neat/session/_experimental.py,sha256=0peZPZ9JpmzQE05wHbng2tWmPPLLTAVfWZEEUhdnI6o,1274
@@ -182,12 +184,14 @@ cognite/neat/session/_template.py,sha256=NCgrrwLT98DpLYoo3Wybr_OUXrEXpsJZjrJ83Kq
182
184
  cognite/neat/session/_to.py,sha256=_R-UB3iEIQoa12kTD7tuSrRDdbySQXQg_mzbn5t-7bg,19399
183
185
  cognite/neat/session/_wizard.py,sha256=hARNNzD5Zfkk_V147rIjOLVvrFaqzXGXWhZuH1NJG3M,1486
184
186
  cognite/neat/session/exceptions.py,sha256=z5jxwfVTXDCCFZKTTYVIaksNKqb9CMa2tyIZgyNL3Us,3475
187
+ cognite/neat/session/_session/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
188
+ cognite/neat/session/_session/_data_model.py,sha256=id2chqUIA8tkxc9tTT7RiGWs-GzHC4LnzNkq-mfBIW4,6347
185
189
  cognite/neat/session/_state/README.md,sha256=o6N7EL98lgyWffw8IoEUf2KG5uSKveD5__TW45YzVjA,902
186
190
  cognite/neat/session/engine/__init__.py,sha256=D3MxUorEs6-NtgoICqtZ8PISQrjrr4dvca6n48bu_bI,120
187
191
  cognite/neat/session/engine/_import.py,sha256=1QxA2_EK613lXYAHKQbZyw2yjo5P9XuiX4Z6_6-WMNQ,169
188
192
  cognite/neat/session/engine/_interface.py,sha256=3W-cYr493c_mW3P5O6MKN1xEQg3cA7NHR_ev3zdF9Vk,533
189
193
  cognite/neat/session/engine/_load.py,sha256=g52uYakQM03VqHt_RDHtpHso1-mFFifH5M4T2ScuH8A,5198
190
- cognite_neat-0.123.18.dist-info/METADATA,sha256=q22nT23r2NuAAxf3lXnDcYch4KrhEl7ZPVptlcYiGm0,9172
191
- cognite_neat-0.123.18.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
192
- cognite_neat-0.123.18.dist-info/licenses/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
193
- cognite_neat-0.123.18.dist-info/RECORD,,
194
+ cognite_neat-0.123.20.dist-info/METADATA,sha256=O8qdN1hncWgpZrnj6h4aeeoZlbtTG2Loe7qTGpHUuzA,9172
195
+ cognite_neat-0.123.20.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
196
+ cognite_neat-0.123.20.dist-info/licenses/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
197
+ cognite_neat-0.123.20.dist-info/RECORD,,