cognite-neat 0.122.1__py3-none-any.whl → 0.122.3__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.122.1"
1
+ __version__ = "0.122.3"
2
2
  __engine__ = "^2.0.4"
@@ -68,6 +68,7 @@ from cognite.neat.core._issues import (
68
68
  catch_issues,
69
69
  )
70
70
  from cognite.neat.core._issues.errors import (
71
+ FileNotFoundNeatError,
71
72
  FileTypeUnexpectedError,
72
73
  NeatValueError,
73
74
  PropertyTypeNotSupportedError,
@@ -254,7 +255,7 @@ class DMSImporter(BaseImporter[UnverifiedPhysicalDataModel]):
254
255
  elif path.is_dir():
255
256
  return cls.from_directory(path, client)
256
257
  else:
257
- raise NeatValueError(f"Unsupported YAML format: {format}")
258
+ raise FileNotFoundNeatError(path)
258
259
 
259
260
  def to_data_model(self) -> ImportedDataModel[UnverifiedPhysicalDataModel]:
260
261
  if self.issue_list.has_errors:
@@ -269,14 +270,14 @@ class DMSImporter(BaseImporter[UnverifiedPhysicalDataModel]):
269
270
 
270
271
  model = self.schema.data_model
271
272
 
272
- user_data_model = self._create_rule_components(model, self.schema, self.metadata)
273
+ user_data_model = self._create_data_model_components(model, self.schema, self.metadata)
273
274
 
274
275
  self.issue_list.trigger_warnings()
275
276
  if self.issue_list.has_errors:
276
277
  raise MultiValueError(self.issue_list.errors)
277
278
  return ImportedDataModel(user_data_model, {})
278
279
 
279
- def _create_rule_components(
280
+ def _create_data_model_components(
280
281
  self,
281
282
  data_model: dm.DataModelApply,
282
283
  schema: DMSSchema,
@@ -2346,7 +2346,7 @@ class AddCogniteProperties(
2346
2346
  ) -> ImportedDataModel[UnverifiedConceptualDataModel]:
2347
2347
  input_ = data_model.unverified_data_model
2348
2348
  if input_ is None:
2349
- raise NeatValueError("Rule read failed. Cannot add cognite properties to None data_model.")
2349
+ raise NeatValueError("Data model read failed. Cannot add cognite properties to None data_model.")
2350
2350
 
2351
2351
  default_space = input_.metadata.space
2352
2352
  default_version = input_.metadata.version
@@ -29,7 +29,7 @@ from ._base import VerifiedDataModelTransformer
29
29
 
30
30
 
31
31
  class MapOntoTransformers(VerifiedDataModelTransformer[PhysicalDataModel, PhysicalDataModel], ABC):
32
- """Base class for transformers that map one rule onto another."""
32
+ """Base class for transformers that map one data model onto another."""
33
33
 
34
34
  ...
35
35
 
@@ -54,7 +54,7 @@ class VerificationTransformer(DataModelTransformer[T_ImportedUnverifiedDataModel
54
54
  elif issubclass(validation_cls, ConceptualValidation):
55
55
  validation_issues = ConceptualValidation(verified_data_model, data_model.context).validate() # type: ignore[arg-type]
56
56
  else:
57
- raise NeatValueError("Unsupported rule type")
57
+ raise NeatValueError("Unsupported data model type")
58
58
  issues.extend(validation_issues)
59
59
 
60
60
  # Raise issues which is expected to be handled outside of this method
@@ -1,7 +1,8 @@
1
1
  from ._base import BaseLoader, CDFLoader
2
2
  from ._rdf2dms import DMSLoader
3
+ from ._rdf_to_instance_space import InstanceSpaceLoader
3
4
 
4
- __all__ = ["BaseLoader", "CDFLoader", "DMSLoader"]
5
+ __all__ = ["BaseLoader", "CDFLoader", "DMSLoader", "InstanceSpaceLoader"]
5
6
 
6
7
 
7
8
  def _repr_html_() -> str:
@@ -3,12 +3,11 @@ from collections.abc import Hashable, Iterable
3
3
  from pathlib import Path
4
4
  from typing import ClassVar, Generic, TypeVar
5
5
 
6
- from cognite.client import CogniteClient
7
6
  from cognite.client.data_classes.capabilities import Capability
8
7
 
8
+ from cognite.neat.core._client import NeatClient
9
9
  from cognite.neat.core._issues import IssueList, NeatIssue
10
10
  from cognite.neat.core._issues.errors import AuthorizationError
11
- from cognite.neat.core._store import NeatInstanceStore
12
11
  from cognite.neat.core._utils.auxiliary import class_html_doc
13
12
  from cognite.neat.core._utils.upload import UploadResult, UploadResultList
14
13
 
@@ -29,9 +28,6 @@ class BaseLoader(ABC, Generic[T_Output]):
29
28
  _new_line = "\n"
30
29
  _encoding = "utf-8"
31
30
 
32
- def __init__(self, instance_store: NeatInstanceStore):
33
- self.instance_store = instance_store
34
-
35
31
  @abstractmethod
36
32
  def write_to_file(self, filepath: Path) -> None:
37
33
  raise NotImplementedError
@@ -59,9 +55,7 @@ class BaseLoader(ABC, Generic[T_Output]):
59
55
  class CDFLoader(BaseLoader[T_Output]):
60
56
  _UPLOAD_BATCH_SIZE: ClassVar[int] = 1000
61
57
 
62
- def load_into_cdf(
63
- self, client: CogniteClient, dry_run: bool = False, check_client: bool = True
64
- ) -> UploadResultList:
58
+ def load_into_cdf(self, client: NeatClient, dry_run: bool = False, check_client: bool = True) -> UploadResultList:
65
59
  upload_result_by_name: dict[str, UploadResult] = {}
66
60
  for upload_result in self.load_into_cdf_iterable(client, dry_run, check_client):
67
61
  if last_result := upload_result_by_name.get(upload_result.name):
@@ -72,7 +66,7 @@ class CDFLoader(BaseLoader[T_Output]):
72
66
  return UploadResultList(upload_result_by_name.values())
73
67
 
74
68
  def load_into_cdf_iterable(
75
- self, client: CogniteClient, dry_run: bool = False, check_client: bool = True
69
+ self, client: NeatClient, dry_run: bool = False, check_client: bool = True
76
70
  ) -> Iterable[UploadResult]:
77
71
  if check_client:
78
72
  missing_capabilities = client.iam.verify_capabilities(self._get_required_capabilities())
@@ -113,7 +107,7 @@ class CDFLoader(BaseLoader[T_Output]):
113
107
  @abstractmethod
114
108
  def _upload_to_cdf(
115
109
  self,
116
- client: CogniteClient,
110
+ client: NeatClient,
117
111
  items: list[T_Output],
118
112
  dry_run: bool,
119
113
  read_issues: IssueList,
@@ -6,7 +6,7 @@ from collections import defaultdict
6
6
  from collections.abc import Iterable, Sequence
7
7
  from dataclasses import dataclass
8
8
  from pathlib import Path
9
- from typing import Any, Literal, cast, get_args, overload
9
+ from typing import Any, Literal, cast, get_args
10
10
 
11
11
  import yaml
12
12
  from cognite.client import CogniteClient
@@ -39,13 +39,11 @@ from cognite.neat.core._data_model.models.data_types import (
39
39
  )
40
40
  from cognite.neat.core._issues import IssueList, NeatError, NeatIssue, catch_issues
41
41
  from cognite.neat.core._issues.errors import (
42
- AuthorizationError,
43
42
  ResourceCreationError,
44
43
  ResourceDuplicatedError,
45
44
  ResourceNotFoundError,
46
45
  )
47
46
  from cognite.neat.core._issues.warnings import (
48
- NeatValueWarning,
49
47
  PropertyDirectRelationLimitWarning,
50
48
  PropertyMultipleValueWarning,
51
49
  PropertyTypeNotSupportedWarning,
@@ -58,11 +56,8 @@ from cognite.neat.core._utils.collection_ import (
58
56
  iterate_progress_bar_if_above_config_threshold,
59
57
  )
60
58
  from cognite.neat.core._utils.rdf_ import (
61
- namespace_as_space,
62
59
  remove_namespace_from_uri,
63
- split_uri,
64
60
  )
65
- from cognite.neat.core._utils.text import NamingStandardization
66
61
  from cognite.neat.core._utils.upload import UploadResult
67
62
 
68
63
  from ._base import _END_OF_CLASS, _START_OF_CLASS, CDFLoader
@@ -104,14 +99,10 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
104
99
  conceptual_data_model (ConceptualDataModel): Conceptual data model,
105
100
  used to look+up the instances in the store.
106
101
  instance_store (NeatInstanceStore): The instance store to load the instances from.
107
- instance_space (str): The instance space to load the data into.
108
102
  create_issues (Sequence[NeatIssue] | None): A list of issues that occurred during reading. Defaults to None.
109
103
  client (NeatClient | None): This is used to lookup containers such that the loader
110
104
  creates instances in accordance with required constraints. Defaults to None.
111
105
  unquote_external_ids (bool): If True, the loader will unquote external ids before creating the instances.
112
- neat_prefix_by_predicate_uri (dict[URIRef, str] | None): A dictionary that maps a predicate URIRef to a
113
- prefix that Neat added to the object upon extraction. This is used to remove the prefix from the
114
- object before creating the instance.
115
106
  """
116
107
 
117
108
  def __init__(
@@ -119,24 +110,17 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
119
110
  physical_data_model: PhysicalDataModel,
120
111
  conceptual_data_model: ConceptualDataModel,
121
112
  instance_store: NeatInstanceStore,
122
- instance_space: str,
123
- space_property: str | None = None,
124
- use_source_space: bool = False,
113
+ space_by_instance_uri: dict[URIRef, str],
125
114
  client: NeatClient | None = None,
126
115
  create_issues: Sequence[NeatIssue] | None = None,
127
116
  unquote_external_ids: bool = False,
128
- neat_prefix_by_predicate_uri: dict[URIRef, str] | None = None,
129
117
  neat_prefix_by_type_uri: dict[URIRef, str] | None = None,
130
118
  ):
131
- super().__init__(instance_store)
119
+ self.instance_store = instance_store
132
120
  self.physical_data_model = physical_data_model
133
121
  self.conceptual_data_model = conceptual_data_model
134
- self.neat_prefix_by_predicate_uri = neat_prefix_by_predicate_uri or {}
135
122
  self.neat_prefix_by_type_uri = neat_prefix_by_type_uri or {}
136
- self._instance_space = instance_space
137
- self._space_property = space_property
138
- self._use_source_space = use_source_space
139
- self._space_by_instance_uri: dict[URIRef, str] = defaultdict(lambda: instance_space)
123
+ self._space_by_instance_uri = space_by_instance_uri
140
124
  self._external_id_by_uri: dict[URIRef, str] = {}
141
125
  self._issues = IssueList(create_issues or [])
142
126
  self._client = client
@@ -172,16 +156,6 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
172
156
  return
173
157
  view_iterations, issues = self._create_view_iterations()
174
158
  yield from issues
175
- if self._space_property:
176
- yield from self._lookup_space_by_uri(view_iterations, stop_on_exception)
177
-
178
- if self._client:
179
- space_creation = self._create_instance_space_if_not_exists()
180
- yield from space_creation.warnings
181
- if space_creation.has_errors and stop_on_exception:
182
- raise space_creation.as_exception()
183
- yield from space_creation.errors
184
-
185
159
  if self.neat_prefix_by_type_uri:
186
160
  self._lookup_identifier_by_uri()
187
161
 
@@ -280,46 +254,6 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
280
254
  view_iterations[view_id] = _ViewIterator(view_id, count, query)
281
255
  return view_iterations
282
256
 
283
- def _lookup_space_by_uri(self, view_iterations: list[_ViewIterator], stop_on_exception: bool = False) -> IssueList:
284
- issues = IssueList()
285
- if self._space_property is None:
286
- return issues
287
- total = sum(it.instance_count for it in view_iterations)
288
- properties_by_uriref = self.instance_store.queries.select.properties()
289
- space_property_uri = next((k for k, v in properties_by_uriref.items() if v == self._space_property), None)
290
- if space_property_uri is None:
291
- error: ResourceNotFoundError[str, str] = ResourceNotFoundError(
292
- self._space_property,
293
- "property",
294
- more=f"Could not find the {self._space_property} in the graph.",
295
- )
296
- if stop_on_exception:
297
- raise error
298
- issues.append(error)
299
- return issues
300
-
301
- instance_iterable = self.instance_store.queries.select.list_instances_ids_by_space(space_property_uri)
302
- instance_iterable = iterate_progress_bar_if_above_config_threshold(
303
- instance_iterable, total, f"Looking up spaces for {total} instances..."
304
- )
305
- neat_prefix = self.neat_prefix_by_predicate_uri.get(space_property_uri)
306
- warned_spaces: set[str] = set()
307
- for instance, space in instance_iterable:
308
- if neat_prefix:
309
- space = space.removeprefix(neat_prefix)
310
-
311
- clean_space = NamingStandardization.standardize_space_str(space)
312
- if clean_space != space and space not in warned_spaces:
313
- issues.append(
314
- NeatValueWarning(
315
- f"Invalid space in property {self._space_property}: {space}. Fixed to {clean_space}"
316
- )
317
- )
318
- warned_spaces.add(space)
319
-
320
- self._space_by_instance_uri[instance] = clean_space
321
- return issues
322
-
323
257
  def _lookup_identifier_by_uri(self) -> None:
324
258
  if not self.neat_prefix_by_type_uri:
325
259
  return
@@ -343,20 +277,6 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
343
277
  if len(uris) == 1:
344
278
  self._external_id_by_uri[uris[0]] = identifier
345
279
 
346
- def _create_instance_space_if_not_exists(self) -> IssueList:
347
- issues = IssueList()
348
- if not self._client:
349
- return issues
350
-
351
- instance_spaces = set(self._space_by_instance_uri.values()) - {self._instance_space}
352
- existing_spaces = {space.space for space in self._client.data_modeling.spaces.retrieve(list(instance_spaces))}
353
- if missing_spaces := (instance_spaces - existing_spaces):
354
- try:
355
- self._client.data_modeling.spaces.apply([dm.SpaceApply(space=space) for space in missing_spaces])
356
- except CogniteAPIError as e:
357
- issues.append(AuthorizationError(f"Creating {len(missing_spaces)} instance spaces.", str(e)))
358
- return issues
359
-
360
280
  def _create_projection(self, view: dm.View) -> tuple[_Projection, IssueList]:
361
281
  issues = IssueList()
362
282
  field_definitions: dict[str, tuple[type, Any]] = {}
@@ -473,12 +393,10 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
473
393
  )
474
394
  value = value[:limit]
475
395
 
476
- ids = (self._create_instance_id(v, "node", stop_on_exception=True) for v in value)
396
+ ids = (self._create_instance_id(v) for v in value)
477
397
  return [id_.dump(camel_case=True, include_instance_type=False) for id_ in ids]
478
398
  elif value:
479
- return self._create_instance_id(value[0], "node", stop_on_exception=True).dump(
480
- camel_case=True, include_instance_type=False
481
- )
399
+ return self._create_instance_id(value[0]).dump(camel_case=True, include_instance_type=False)
482
400
  return {}
483
401
 
484
402
  validators["parse_direct_relation"] = field_validator(*direct_relation_by_property.keys(), mode="before")( # type: ignore[assignment]
@@ -518,7 +436,7 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
518
436
  projection: _Projection,
519
437
  stop_on_exception: Literal[True, False] = False,
520
438
  ) -> Iterable[dm.InstanceApply | NeatIssue]:
521
- instance_id = self._create_instance_id(instance_uri, "node", stop_on_exception)
439
+ instance_id = self._create_instance_id(instance_uri)
522
440
  if not isinstance(instance_id, InstanceId):
523
441
  yield instance_id
524
442
  return
@@ -567,8 +485,8 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
567
485
  return
568
486
 
569
487
  if start_node and end_node:
570
- start = self._create_instance_id(start_node, "edge", stop_on_exception)
571
- end = self._create_instance_id(end_node, "edge", stop_on_exception)
488
+ start = self._create_instance_id(start_node)
489
+ end = self._create_instance_id(end_node)
572
490
  if isinstance(start, NeatError):
573
491
  yield start
574
492
  if isinstance(end, NeatError):
@@ -594,7 +512,7 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
594
512
  ),
595
513
  sources=sources,
596
514
  )
597
- yield from self._create_edges_without_properties(space, external_id, properties, projection, stop_on_exception)
515
+ yield from self._create_edges_without_properties(space, external_id, properties, projection)
598
516
 
599
517
  def _create_edges_without_properties(
600
518
  self,
@@ -602,7 +520,6 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
602
520
  identifier: str,
603
521
  properties: dict[str | InstanceType, list[str] | list[URIRef]],
604
522
  projection: _Projection,
605
- stop_on_exception: Literal[True, False],
606
523
  ) -> Iterable[dm.EdgeApply | NeatIssue]:
607
524
  for predicate, values in properties.items():
608
525
  if predicate in projection.edge_by_type:
@@ -620,10 +537,7 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
620
537
  yield error
621
538
  continue
622
539
  for target in values:
623
- target_id = self._create_instance_id(target, "edge", stop_on_exception) # type: ignore[call-overload]
624
- if not isinstance(target_id, InstanceId):
625
- yield target_id
626
- continue
540
+ target_id = self._create_instance_id(cast(URIRef, target))
627
541
  if isinstance(target, URIRef):
628
542
  target = remove_namespace_from_uri(target)
629
543
  external_id = f"{identifier}.{prop_id}.{target}"
@@ -656,43 +570,16 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
656
570
  return start_node, end_node # type: ignore[return-value]
657
571
  return None, None
658
572
 
659
- @overload
660
- def _create_instance_id(
661
- self, uri: URIRef, instance_type: str, stop_on_exception: Literal[False] = False
662
- ) -> InstanceId | NeatError: ...
663
-
664
- @overload
665
- def _create_instance_id(
666
- self, uri: URIRef, instance_type: str, stop_on_exception: Literal[True] = True
667
- ) -> InstanceId: ...
668
-
669
- def _create_instance_id(
670
- self, uri: URIRef, instance_type: str, stop_on_exception: bool = False
671
- ) -> InstanceId | NeatError:
672
- space: str | None = None
673
- external_id: str | None = None
674
- error: NeatError | None = None
675
- if self._use_source_space:
676
- namespace, external_id = split_uri(uri)
677
- space = namespace_as_space(namespace)
678
- if space is None:
679
- error = ResourceCreationError(uri, instance_type, f"Could not find space for {uri!s}.")
573
+ def _create_instance_id(self, uri: URIRef) -> InstanceId:
574
+ space = self._space_by_instance_uri[uri]
575
+ if uri in self._external_id_by_uri:
576
+ external_id = self._external_id_by_uri[uri]
680
577
  else:
681
- space = self._space_by_instance_uri[uri]
682
- if uri in self._external_id_by_uri:
683
- external_id = self._external_id_by_uri[uri]
684
- else:
685
- external_id = remove_namespace_from_uri(uri)
578
+ external_id = remove_namespace_from_uri(uri)
686
579
 
687
580
  if external_id and self._unquote_external_ids:
688
581
  external_id = urllib.parse.unquote(external_id)
689
- if space and external_id:
690
- return InstanceId(space, external_id)
691
- if error is None:
692
- raise ValueError(f"Bug in neat. Failed to create instance ID and determine error for {uri!r}")
693
- if stop_on_exception:
694
- raise error
695
- return error
582
+ return InstanceId(space, external_id)
696
583
 
697
584
  def _get_required_capabilities(self) -> list[Capability]:
698
585
  return [
@@ -702,7 +589,7 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
702
589
  DataModelInstancesAcl.Action.Write_Properties,
703
590
  DataModelInstancesAcl.Action.Read,
704
591
  ],
705
- scope=DataModelInstancesAcl.Scope.SpaceID([self._instance_space]),
592
+ scope=DataModelInstancesAcl.Scope.SpaceID(sorted(set(self._space_by_instance_uri.values()))),
706
593
  )
707
594
  ]
708
595
 
@@ -0,0 +1,249 @@
1
+ import itertools
2
+ import json
3
+ from collections import defaultdict
4
+ from collections.abc import Iterable
5
+ from pathlib import Path
6
+ from typing import cast
7
+
8
+ import yaml
9
+ from cognite.client import data_modeling as dm
10
+ from cognite.client.data_classes.capabilities import Capability, DataModelsAcl
11
+ from rdflib import URIRef
12
+
13
+ from cognite.neat.core._client import NeatClient
14
+ from cognite.neat.core._client._api.data_modeling_loaders import MultiCogniteAPIError
15
+ from cognite.neat.core._constants import COGNITE_SPACES
16
+ from cognite.neat.core._issues import IssueList, NeatIssue
17
+ from cognite.neat.core._issues.errors import ResourceCreationError, ResourceNotFoundError
18
+ from cognite.neat.core._issues.warnings import NeatValueWarning
19
+ from cognite.neat.core._store import NeatInstanceStore
20
+ from cognite.neat.core._utils.collection_ import iterate_progress_bar_if_above_config_threshold
21
+ from cognite.neat.core._utils.rdf_ import namespace_as_space, split_uri
22
+ from cognite.neat.core._utils.text import NamingStandardization
23
+ from cognite.neat.core._utils.upload import UploadResult
24
+
25
+ from ._base import _END_OF_CLASS, _START_OF_CLASS, CDFLoader
26
+
27
+
28
+ class InstanceSpaceLoader(CDFLoader[dm.SpaceApply]):
29
+ """Loads Instance Space into Cognite Data Fusion (CDF).
30
+
31
+ There are three ways to determine the space for each instance:
32
+ 1. If `instance_space` is provided, all instances will be assigned to that space, i.e., the space
33
+ is constant for all instances.
34
+ (If not it is set based on the triples (subject, predicate, object) in the graph store.)
35
+ 2. If `space_property` is provided, this is the predicate and the space is set to the object. The `instance_space`
36
+ is used as a fallback if the object is not a valid space.
37
+ 3. If `use_source_space` is set to True, the instances are assumed to be extracted from CDF and the space is part
38
+ of the subject.
39
+
40
+ This class exposes the `space_by_instance_uri` property used by the DMSLoader to lookup space for each instance URI.
41
+
42
+ Args:
43
+ graph_store (NeatInstanceStore): The graph store to load the data from.
44
+ instance_space (str): The instance space to load the data into.
45
+ space_property (str): The property to use to determine the space for each instance.
46
+ use_source_space (bool): If True, use the source space of the instances when extracted from CDF.
47
+ neat_prefix_by_predicate_uri (dict[URIRef, str] | None): A dictionary that maps a predicate URIRef to a
48
+ prefix that Neat added to the object upon extraction. This is used to remove the prefix from the
49
+ object before creating the instance.
50
+ """
51
+
52
+ def __init__(
53
+ self,
54
+ graph_store: NeatInstanceStore | None = None,
55
+ instance_space: str | None = None,
56
+ space_property: str | None = None,
57
+ use_source_space: bool = False,
58
+ neat_prefix_by_predicate_uri: dict[URIRef, str] | None = None,
59
+ ) -> None:
60
+ self.graph_store = graph_store
61
+ self.instance_space = instance_space
62
+ self.space_property = space_property
63
+ self.use_source_space = use_source_space
64
+ self.neat_prefix_by_predicate_uri = neat_prefix_by_predicate_uri or {}
65
+
66
+ self._lookup_issues = IssueList()
67
+
68
+ self._has_looked_up = False
69
+ # This is a dictionary mapping instance URIs to their respective spaces
70
+ # This is exposed through the property space_by_instance_uri. If the instance_space or space_property is
71
+ # set (1. and 2.) this is changed to a defaultdict with the instance_space as the default value.
72
+ self._space_by_instance_uri: dict[URIRef, str] = {}
73
+
74
+ @property
75
+ def space_by_instance_uri(self) -> dict[URIRef, str]:
76
+ """Returns a dictionary mapping instance URIs to their respective spaces."""
77
+ if not self._has_looked_up:
78
+ self._lookup_spaces()
79
+ self._has_looked_up = True
80
+ return self._space_by_instance_uri
81
+
82
+ def _get_required_capabilities(self) -> list[Capability]:
83
+ return [
84
+ DataModelsAcl(
85
+ actions=[
86
+ DataModelsAcl.Action.Write,
87
+ DataModelsAcl.Action.Read,
88
+ ],
89
+ scope=DataModelsAcl.Scope.All(),
90
+ )
91
+ ]
92
+
93
+ def _upload_to_cdf(
94
+ self,
95
+ client: NeatClient,
96
+ spaces: list[dm.SpaceApply],
97
+ dry_run: bool,
98
+ read_issues: IssueList,
99
+ class_name: str | None = None,
100
+ ) -> Iterable[UploadResult]:
101
+ cdf_spaces = client.data_modeling.spaces.retrieve([space.space for space in spaces])
102
+ cdf_space_by_id = {item.space: item for item in cdf_spaces}
103
+
104
+ to_create = dm.SpaceApplyList([])
105
+ to_update = dm.SpaceApplyList([])
106
+ unchanged = dm.SpaceApplyList([])
107
+
108
+ for local_space in spaces:
109
+ cdf_space = cdf_space_by_id.get(local_space.space)
110
+ if cdf_space is None:
111
+ to_create.append(local_space)
112
+ elif cdf_space != local_space.as_write():
113
+ to_update.append(local_space)
114
+ else:
115
+ unchanged.append(local_space)
116
+ loader = client.loaders.spaces
117
+ results: UploadResult[str] = UploadResult("instance spaces")
118
+ results.unchanged.update(unchanged.as_ids())
119
+ if dry_run:
120
+ results.created.update(to_create.as_ids())
121
+ results.changed.update(to_update.as_ids())
122
+ yield results
123
+ if to_create:
124
+ try:
125
+ client.loaders.spaces.create(to_create)
126
+ except MultiCogniteAPIError as e:
127
+ results.failed_created.update(to_create.as_ids())
128
+ for error in e.errors:
129
+ results.error_messages.append(f"Failed to create {loader.resource_name}: {error!s}")
130
+ else:
131
+ results.created.update(to_create.as_ids())
132
+
133
+ if to_update:
134
+ try:
135
+ client.loaders.spaces.update(to_update)
136
+ except MultiCogniteAPIError as e:
137
+ results.failed_changed.update(to_update.as_ids())
138
+ for error in e.errors:
139
+ results.error_messages.append(f"Failed to update {loader.resource_name}: {error!s}")
140
+ else:
141
+ results.changed.update(to_update.as_ids())
142
+
143
+ yield results
144
+
145
+ def write_to_file(self, filepath: Path) -> None:
146
+ """Dumps the instance spaces to file."""
147
+ if filepath.suffix not in [".json", ".yaml", ".yml"]:
148
+ raise ValueError(f"File format {filepath.suffix} is not supported")
149
+ dumped: dict[str, list] = {"spaces": [], "issues": []}
150
+ for item in self.load(stop_on_exception=False):
151
+ key = {
152
+ dm.SpaceApply: "spaces",
153
+ NeatIssue: "issues",
154
+ }.get(type(item))
155
+ if key is None:
156
+ # This should never happen, and is a bug in neat
157
+ raise ValueError(f"Item {item} is not supported. This is a bug in neat please report it.")
158
+ dumped[key].append(item.dump())
159
+ with filepath.open("w", encoding=self._encoding, newline=self._new_line) as f:
160
+ if filepath.suffix == ".json":
161
+ json.dump(dumped, f, indent=2)
162
+ else:
163
+ yaml.safe_dump(dumped, f, sort_keys=False)
164
+
165
+ def _load(
166
+ self, stop_on_exception: bool = False
167
+ ) -> Iterable[dm.SpaceApply | NeatIssue | type[_END_OF_CLASS] | _START_OF_CLASS]:
168
+ self._lookup_spaces()
169
+ if self._lookup_issues.has_errors and stop_on_exception:
170
+ raise self._lookup_issues.as_errors()
171
+ yield from self._lookup_issues
172
+ seen: set[str] = set()
173
+ for space_str in set(self.space_by_instance_uri.values()):
174
+ if space_str in seen or space_str in COGNITE_SPACES:
175
+ continue
176
+ yield dm.SpaceApply(space=space_str)
177
+ seen.add(space_str)
178
+
179
+ def _lookup_spaces(self) -> None:
180
+ # Case 1: Same instance space for all instances:
181
+ if isinstance(self.instance_space, str) and self.space_property is None and self.use_source_space is False:
182
+ self._space_by_instance_uri = defaultdict(lambda: cast(str, self.instance_space))
183
+ # Adding a dummy entry to ensure that the instance space is included
184
+ self._space_by_instance_uri[URIRef(self.instance_space)] = self.instance_space
185
+ return
186
+ if self.graph_store is None:
187
+ raise ValueError("Graph store must be provided to lookup spaces")
188
+ # Case 3: Use the source space, i.e., the space of the instances when extracted from CDF
189
+ if self.use_source_space and self.instance_space is None and self.space_property is None:
190
+ self._lookup_space_via_instance_uris(self.graph_store)
191
+ # Case 2: Use a property on each instance to determine the space.
192
+ elif self.space_property is not None and self.use_source_space is False:
193
+ if self.instance_space is None:
194
+ raise ValueError(
195
+ "Missing fallback instance space. This is required when "
196
+ f"using space_property='{self.space_property}'"
197
+ )
198
+ self._space_by_instance_uri = defaultdict(lambda: cast(str, self.instance_space))
199
+ self._lookup_space_via_property(self.graph_store, self.space_property)
200
+ else:
201
+ raise ValueError("Either 'instance_space', 'space_property', or 'use_source_space' must be provided.")
202
+
203
+ def _lookup_space_via_instance_uris(self, graph_store: NeatInstanceStore) -> None:
204
+ instance_iterable = itertools.chain(
205
+ (res[0] for res in graph_store.queries.select.list_instances_ids()),
206
+ graph_store.queries.select.list_instance_object_ids(),
207
+ )
208
+
209
+ for instance_uri in instance_iterable:
210
+ namespace, external_id = split_uri(instance_uri)
211
+ space = namespace_as_space(namespace)
212
+ if space is None:
213
+ error = ResourceCreationError(instance_uri, "instance", "This instance was not extracted from CDF.")
214
+ self._lookup_issues.append(error)
215
+ else:
216
+ self._space_by_instance_uri[instance_uri] = space
217
+
218
+ def _lookup_space_via_property(self, graph_store: NeatInstanceStore, space_property: str) -> None:
219
+ properties_by_uriref = graph_store.queries.select.properties()
220
+ space_property_uri = next((k for k, v in properties_by_uriref.items() if v == space_property), None)
221
+ if space_property_uri is None:
222
+ error: ResourceNotFoundError[str, str] = ResourceNotFoundError(
223
+ self.space_property,
224
+ "property",
225
+ more=f"Could not find the {space_property} in the graph.",
226
+ )
227
+ self._lookup_issues.append(error)
228
+ return
229
+
230
+ class_with_total_pair = graph_store.queries.select.summarize_instances()
231
+ total = sum([count for _, count in class_with_total_pair])
232
+ instance_iterable = graph_store.queries.select.list_instances_ids_by_space(space_property_uri)
233
+ instance_iterable = iterate_progress_bar_if_above_config_threshold(
234
+ instance_iterable, total, f"Looking up spaces for {total} instances..."
235
+ )
236
+ neat_prefix = self.neat_prefix_by_predicate_uri.get(space_property_uri)
237
+ warned_spaces: set[str] = set()
238
+ for instance, space in instance_iterable:
239
+ if neat_prefix:
240
+ space = space.removeprefix(neat_prefix)
241
+
242
+ clean_space = NamingStandardization.standardize_space_str(space)
243
+ if clean_space != space and space not in warned_spaces:
244
+ self._lookup_issues.append(
245
+ NeatValueWarning(f"Invalid space in property {space_property}: {space}. Fixed to {clean_space}")
246
+ )
247
+ warned_spaces.add(space)
248
+
249
+ self._space_by_instance_uri[instance] = clean_space
@@ -120,6 +120,18 @@ class SelectQueries(BaseQuery):
120
120
  # MyPy is not very happy with RDFLib, so just ignore the type hinting here
121
121
  return (tuple(res) if class_uri is None else res[0] for res in self.graph(named_graph).query(query)) # type: ignore[index, return-value, arg-type]
122
122
 
123
+ def list_instance_object_ids(self, limit: int = -1, named_graph: URIRef | None = None) -> Iterable[URIRef]:
124
+ query = (
125
+ "SELECT DISTINCT ?object WHERE { "
126
+ "?subject ?predicate ?object . FILTER(?predicate != rdf:type && isURI(?object))"
127
+ "}"
128
+ )
129
+ if limit != -1:
130
+ query += f" LIMIT {limit}"
131
+
132
+ # MyPy is not very happy with RDFLib, so just ignore the type hinting here
133
+ return cast(Iterable[URIRef], (res[0] for res in self.graph(named_graph).query(query))) # type: ignore[index]
134
+
123
135
  def type_with_property(self, type_: URIRef, property_uri: URIRef, named_graph: URIRef | None = None) -> bool:
124
136
  """Check if a property exists in the graph store
125
137
 
@@ -174,7 +174,7 @@ class NeatSession:
174
174
  )
175
175
  converter = ConceptualToPhysical(reserved_properties=reserved_properties, client=self._state.client)
176
176
 
177
- issues = self._state.rule_transform(converter)
177
+ issues = self._state.data_model_transform(converter)
178
178
 
179
179
  if self._verbose and not issues.has_errors:
180
180
  print("Conceptual data model converted to physical data model.")
@@ -222,7 +222,7 @@ class NeatSession:
222
222
  max_number_of_instance=max_number_of_instance,
223
223
  data_model_id=model_id,
224
224
  )
225
- return self._state.rule_import(importer)
225
+ return self._state.data_model_import(importer)
226
226
 
227
227
  def _infer_subclasses(
228
228
  self,
@@ -97,7 +97,7 @@ class DropDataModelAPI:
97
97
  f"{len(missing_views)} view(s) not found in the data model.\nDid you mean {', '.join(suggestions)}?"
98
98
  )
99
99
  before = len(last_dms.views)
100
- issues = self._state.rule_transform(DropModelViews(view_external_id, group))
100
+ issues = self._state.data_model_transform(DropModelViews(view_external_id, group))
101
101
  after = len(self._state.data_model_store.last_verified_physical_data_model.views)
102
102
  print(f"Dropped {before - after} views.")
103
103
  return issues
@@ -25,4 +25,4 @@ class DataModelFixAPI:
25
25
 
26
26
  def cdf_compliant_external_ids(self) -> IssueList:
27
27
  """Convert (information/logical) data model component external ids to CDF compliant entities."""
28
- return self._state.rule_transform(ToCompliantEntities())
28
+ return self._state.data_model_transform(ToCompliantEntities())
@@ -68,4 +68,4 @@ class DataModelMappingAPI:
68
68
  )
69
69
  if use_parent_property_name:
70
70
  transformers.append(AsParentPropertyId(self._state.client))
71
- return self._state.rule_transform(*transformers)
71
+ return self._state.data_model_transform(*transformers)
@@ -264,7 +264,7 @@ class DataModelPrepareAPI:
264
264
 
265
265
  """
266
266
 
267
- return self._state.rule_transform(PrefixEntities(prefix)) # type: ignore[arg-type]
267
+ return self._state.data_model_transform(PrefixEntities(prefix)) # type: ignore[arg-type]
268
268
 
269
269
  def standardize_naming(self) -> IssueList:
270
270
  """Standardize the naming of all views/classes/properties in the data model.
@@ -274,7 +274,7 @@ class DataModelPrepareAPI:
274
274
  """
275
275
  warnings.filterwarnings("default")
276
276
  ExperimentalFlags.standardize_naming.warn()
277
- return self._state.rule_transform(StandardizeNaming())
277
+ return self._state.data_model_transform(StandardizeNaming())
278
278
 
279
279
  def standardize_space_and_version(self) -> IssueList:
280
280
  """Standardize space and version in the data model.
@@ -283,4 +283,4 @@ class DataModelPrepareAPI:
283
283
  """
284
284
  warnings.filterwarnings("default")
285
285
  ExperimentalFlags.standardize_space_and_version.warn()
286
- return self._state.rule_transform(StandardizeSpaceAndVersion())
286
+ return self._state.data_model_transform(StandardizeSpaceAndVersion())
@@ -118,7 +118,7 @@ class CDFReadAPI(BaseReadAPI):
118
118
  )
119
119
 
120
120
  importer = importers.DMSImporter.from_data_model_id(cast(NeatClient, self._state.client), data_model_id)
121
- return self._state.rule_import(importer)
121
+ return self._state.data_model_import(importer)
122
122
 
123
123
  def core_data_model(self, concepts: str | list[str]) -> IssueList:
124
124
  """Subset the data model to the desired concepts.
@@ -159,7 +159,7 @@ class CDFReadAPI(BaseReadAPI):
159
159
  importer: importers.DMSImporter = importers.DMSImporter.from_data_model_id(
160
160
  cast(NeatClient, self._state.client), cdm_v1
161
161
  )
162
- issues = self._state.rule_import(importer)
162
+ issues = self._state.data_model_import(importer)
163
163
 
164
164
  if issues.has_errors:
165
165
  return issues
@@ -167,7 +167,7 @@ class CDFReadAPI(BaseReadAPI):
167
167
  cdm_data_model = self._state.data_model_store.last_verified_data_model
168
168
 
169
169
  issues.extend(
170
- self._state.rule_transform(
170
+ self._state.data_model_transform(
171
171
  ToEnterpriseModel(
172
172
  new_model_id=("my_space", "MyCDMSubset", "v1"),
173
173
  org_name="CopyOf",
@@ -181,7 +181,7 @@ class CDFReadAPI(BaseReadAPI):
181
181
  return issues
182
182
 
183
183
  issues.extend(
184
- self._state.rule_transform(
184
+ self._state.data_model_transform(
185
185
  _SubsetEditableCDMPhysicalDataModel(
186
186
  views={
187
187
  ViewEntity(
@@ -568,7 +568,7 @@ class ExcelReadAPI(BaseReadAPI):
568
568
  empty_data_model_store_required=True,
569
569
  )
570
570
 
571
- return self._state.rule_import(importers.ExcelImporter(path), enable_manual_edit)
571
+ return self._state.data_model_import(importers.ExcelImporter(path), enable_manual_edit)
572
572
 
573
573
 
574
574
  @session_class_wrapper
@@ -607,7 +607,7 @@ class YamlReadAPI(BaseReadAPI):
607
607
  importer = dms_importer
608
608
  else:
609
609
  raise NeatValueError(f"Unsupported YAML format: {format}")
610
- return self._state.rule_import(importer)
610
+ return self._state.data_model_import(importer)
611
611
 
612
612
 
613
613
  @session_class_wrapper
@@ -824,7 +824,7 @@ class RDFReadAPI(BaseReadAPI):
824
824
 
825
825
  reader = NeatReader.create(io)
826
826
  importer = importers.OWLImporter.from_file(reader.materialize_path(), source_name=f"file {reader!s}")
827
- return self._state.rule_import(importer)
827
+ return self._state.data_model_import(importer)
828
828
 
829
829
  def imf(self, io: Any) -> IssueList:
830
830
  """Reads IMF Types provided as SHACL shapes into NeatSession.
@@ -847,7 +847,7 @@ class RDFReadAPI(BaseReadAPI):
847
847
 
848
848
  reader = NeatReader.create(io)
849
849
  importer = importers.IMFImporter.from_file(reader.materialize_path(), source_name=f"file {reader!s}")
850
- return self._state.rule_import(importer)
850
+ return self._state.data_model_import(importer)
851
851
 
852
852
  def instances(self, io: Any) -> IssueList:
853
853
  self._state._raise_exception_if_condition_not_met(
@@ -915,7 +915,7 @@ class Examples:
915
915
  )
916
916
 
917
917
  importer: importers.ExcelImporter = importers.ExcelImporter(catalog.hello_world_pump)
918
- return self._state.rule_import(importer)
918
+ return self._state.data_model_import(importer)
919
919
 
920
920
  def core_data_model(self) -> IssueList:
921
921
  """Reads the core data model example into the NeatSession."""
@@ -930,4 +930,4 @@ class Examples:
930
930
  importer: importers.DMSImporter = importers.DMSImporter.from_data_model_id(
931
931
  cast(NeatClient, self._state.client), cdm_v1
932
932
  )
933
- return self._state.rule_import(importer)
933
+ return self._state.data_model_import(importer)
@@ -48,7 +48,7 @@ class SetAPI:
48
48
  "Cannot change the data model ID of a Cognite Data Model in NeatSession"
49
49
  " due to temporarily issue with the reverse direct relation interpretation"
50
50
  )
51
- return self._state.rule_transform(SetIDDMSModel(new_model_id, name))
51
+ return self._state.data_model_transform(SetIDDMSModel(new_model_id, name))
52
52
 
53
53
  def client(self, client: CogniteClient) -> None:
54
54
  """Sets the client to be used in the session."""
@@ -30,7 +30,7 @@ class SessionState:
30
30
  self.client = client
31
31
  self.quoted_source_identifiers = False
32
32
 
33
- def rule_transform(self, *transformer: VerifiedDataModelTransformer) -> IssueList:
33
+ def data_model_transform(self, *transformer: VerifiedDataModelTransformer) -> IssueList:
34
34
  if not transformer:
35
35
  raise NeatSessionError("No transformers provided.")
36
36
  start = self.data_model_store.provenance[-1].target_entity.display_name
@@ -40,7 +40,7 @@ class SessionState:
40
40
  issues.hint = "Use the .inspect.issues() for more details."
41
41
  return issues
42
42
 
43
- def rule_import(self, importer: BaseImporter, enable_manual_edit: bool = False) -> IssueList:
43
+ def data_model_import(self, importer: BaseImporter, enable_manual_edit: bool = False) -> IssueList:
44
44
  issues = self.data_model_store.import_data_model(
45
45
  importer,
46
46
  client=self.client,
@@ -68,14 +68,14 @@ class SubsetAPI:
68
68
  for concept in concepts
69
69
  }
70
70
 
71
- issues = self._state.rule_transform(SubsetPhysicalDataModel(views=views))
71
+ issues = self._state.data_model_transform(SubsetPhysicalDataModel(views=views))
72
72
  if not issues:
73
73
  after = len(self._state.data_model_store.last_verified_physical_data_model.views)
74
74
 
75
75
  elif information:
76
76
  classes = {ConceptEntity(prefix=information.metadata.space, suffix=concept) for concept in concepts}
77
77
 
78
- issues = self._state.rule_transform(SubsetConceptualDataModel(concepts=classes))
78
+ issues = self._state.data_model_transform(SubsetConceptualDataModel(concepts=classes))
79
79
  if not issues:
80
80
  after = len(self._state.data_model_store.last_verified_conceptual_data_model.concepts)
81
81
 
@@ -70,7 +70,7 @@ class TemplateAPI:
70
70
 
71
71
  """
72
72
  last_dm = self._state.data_model_store.last_verified_data_model
73
- issues = self._state.rule_transform(
73
+ issues = self._state.data_model_transform(
74
74
  ToEnterpriseModel(
75
75
  new_model_id=data_model_id,
76
76
  org_name=org_name,
@@ -122,7 +122,7 @@ class TemplateAPI:
122
122
 
123
123
  transformers.append(ToDataProductModel(new_model_id=data_model_id, include=include))
124
124
 
125
- issues = self._state.rule_transform(*transformers)
125
+ issues = self._state.data_model_transform(*transformers)
126
126
  if last_dm and not issues.has_errors:
127
127
  self._state.last_reference = last_dm
128
128
  return issues
@@ -202,7 +202,7 @@ class TemplateAPI:
202
202
  ExcelExporter(styling="maximal").export_to_file(info, output_path)
203
203
  issues.action = "Created extension template"
204
204
 
205
- # Adding issues to the state in the rule store
205
+ # Adding issues to the state in the data model store
206
206
  if issues:
207
207
  self._state.data_model_store._last_issues = issues
208
208
  return issues
@@ -311,34 +311,37 @@ class CDFToAPI:
311
311
 
312
312
  client = cast(NeatClient, self._state.client)
313
313
  physical_data_model = self._state.data_model_store.last_verified_physical_data_model
314
- instance_space = instance_space or f"{physical_data_model.metadata.space}_instances"
315
314
 
316
315
  if instance_space and instance_space == physical_data_model.metadata.space:
317
316
  raise NeatSessionError("Space for instances must be different from the data model space.")
318
317
  elif not PATTERNS.space_compliance.match(str(instance_space)):
319
318
  raise NeatSessionError("Please provide a valid space name. {PATTERNS.space_compliance.pattern}")
320
319
 
321
- if not client.data_modeling.spaces.retrieve(instance_space):
322
- client.data_modeling.spaces.apply(dm.SpaceApply(space=instance_space))
320
+ instance_space_loader = loaders.InstanceSpaceLoader(
321
+ self._state.instances.store,
322
+ instance_space=instance_space,
323
+ space_property=space_from_property,
324
+ use_source_space=use_source_space,
325
+ neat_prefix_by_predicate_uri=self._state.instances.neat_prefix_by_predicate_uri,
326
+ )
327
+ result = instance_space_loader.load_into_cdf(client)
323
328
 
324
329
  loader = loaders.DMSLoader(
325
330
  self._state.data_model_store.last_verified_physical_data_model,
326
331
  self._state.data_model_store.last_verified_conceptual_data_model,
327
332
  self._state.instances.store,
328
- instance_space=instance_space,
333
+ space_by_instance_uri=instance_space_loader.space_by_instance_uri,
329
334
  client=client,
330
- space_property=space_from_property,
331
- use_source_space=use_source_space,
332
335
  # In case urllib.parse.quote() was run on the extraction, we need to run
333
336
  # urllib.parse.unquote() on the load.
334
337
  unquote_external_ids=True,
335
- neat_prefix_by_predicate_uri=self._state.instances.neat_prefix_by_predicate_uri,
336
338
  neat_prefix_by_type_uri=self._state.instances.neat_prefix_by_type_uri,
337
339
  )
338
340
 
339
- result = loader.load_into_cdf(client)
340
- self._state.instances.outcome.append(result)
341
+ instance_result = loader.load_into_cdf(client)
341
342
  print("You can inspect the details with the .inspect.outcome.instances(...) method.")
343
+ result.extend(instance_result)
344
+ self._state.instances.outcome.append(result)
342
345
  return result
343
346
 
344
347
  def data_model(
@@ -419,22 +422,26 @@ class ToPythonAPI:
419
422
  ```
420
423
  """
421
424
  physical_data_model = self._state.data_model_store.last_verified_physical_data_model
422
- instance_space = instance_space or f"{physical_data_model.metadata.space}_instances"
423
425
 
424
426
  if instance_space and instance_space == physical_data_model.metadata.space:
425
427
  raise NeatSessionError("Space for instances must be different from the data model space.")
426
428
  elif not PATTERNS.space_compliance.match(str(instance_space)):
427
429
  raise NeatSessionError(f"Please provide a valid space name. {PATTERNS.space_compliance.pattern}")
428
430
 
429
- loader = loaders.DMSLoader(
430
- self._state.data_model_store.last_verified_physical_data_model,
431
- self._state.data_model_store.last_verified_conceptual_data_model,
431
+ instance_loader = loaders.InstanceSpaceLoader(
432
432
  self._state.instances.store,
433
433
  instance_space=instance_space,
434
434
  space_property=space_from_property,
435
435
  use_source_space=use_source_space,
436
- unquote_external_ids=True,
437
436
  neat_prefix_by_predicate_uri=self._state.instances.neat_prefix_by_predicate_uri,
437
+ )
438
+
439
+ loader = loaders.DMSLoader(
440
+ self._state.data_model_store.last_verified_physical_data_model,
441
+ self._state.data_model_store.last_verified_conceptual_data_model,
442
+ self._state.instances.store,
443
+ space_by_instance_uri=instance_loader.space_by_instance_uri,
444
+ unquote_external_ids=True,
438
445
  neat_prefix_by_type_uri=self._state.instances.neat_prefix_by_type_uri,
439
446
  )
440
447
  issue_list = IssueList()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cognite-neat
3
- Version: 0.122.1
3
+ Version: 0.122.3
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=hEX04Zd5WV2gLQgKwCOdCPXl2IszZNRZ4q4_HQXhmwM,46
2
+ cognite/neat/_version.py,sha256=9fKctwX-_c2LYzEGFYewc_Bfl-r-r0K_n7MBXcEGzzg,46
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
@@ -38,7 +38,7 @@ cognite/neat/core/_data_model/importers/__init__.py,sha256=ipImLDSse0vAHX4AWvtPI
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
40
  cognite/neat/core/_data_model/importers/_dict2data_model.py,sha256=-1zmo8JkxJ9qiWuC7sUH7oSlpnPPKTMxZtm4WrRPO5A,4709
41
- cognite/neat/core/_data_model/importers/_dms2data_model.py,sha256=wDtCikD2qEZgl1SWBQ6qIClPXOZVmHNN7HUNaChoWIQ,28294
41
+ cognite/neat/core/_data_model/importers/_dms2data_model.py,sha256=SoyVwMX__7UIFHZbrt9aLux4dVZx6KHrhkHQLS7eIf4,28308
42
42
  cognite/neat/core/_data_model/importers/_spreadsheet2data_model.py,sha256=2QqrxQ9AI3LT9toH_gryIR52UecMsR-v44ljXedDCp4,11972
43
43
  cognite/neat/core/_data_model/importers/_dtdl2data_model/__init__.py,sha256=CNR-sUihs2mnR1bPMKs3j3L4ds3vFTsrl6YycExZTfU,68
44
44
  cognite/neat/core/_data_model/importers/_dtdl2data_model/_unit_lookup.py,sha256=wW4saKva61Q_i17guY0dc4OseJDQfqHy_QZBtm0OD6g,12134
@@ -77,9 +77,9 @@ cognite/neat/core/_data_model/models/physical/_validation.py,sha256=i0YHDE2c09Oe
77
77
  cognite/neat/core/_data_model/models/physical/_verified.py,sha256=UsfzuIyYRsdUPK9wJM9Wxs4VkD4GiGUQAjRjgDCmIHw,24237
78
78
  cognite/neat/core/_data_model/transformers/__init__.py,sha256=_FPmPh0kA68SXR4arKKNmtWQ8B2-wSwWQeGAWnjoJAQ,1788
79
79
  cognite/neat/core/_data_model/transformers/_base.py,sha256=7adUBJgDkXgRq_h7l1q2VsLQo3lE7-xmzmHdcF4QHq8,3133
80
- cognite/neat/core/_data_model/transformers/_converters.py,sha256=JPUzZks6lqKd8hg809K8Anj7lC5cu3jTdmaShcZhDsc,111569
81
- cognite/neat/core/_data_model/transformers/_mapping.py,sha256=oIabTo7fN21wTq5Tlf2bour3xC52lqIrqrkH91nKHb4,19018
82
- cognite/neat/core/_data_model/transformers/_verification.py,sha256=CKeNMcOFFwUu9nAASLNySrfhWTkwxwkE0aOBZA5XqU8,5187
80
+ cognite/neat/core/_data_model/transformers/_converters.py,sha256=OazYC7DgAXXEvxdiaPfJSe2ZNkYn2mRqWhtvtvWK59g,111575
81
+ cognite/neat/core/_data_model/transformers/_mapping.py,sha256=GwmTRnhiUPIG37CgUSIbjT7ZpWOwdWuBZ_HAIIBiKYY,19024
82
+ cognite/neat/core/_data_model/transformers/_verification.py,sha256=yyPK6irhMGjVtwKxRIElSsPLUvLLVfk1lBAGny6jN5w,5193
83
83
  cognite/neat/core/_instances/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
84
84
  cognite/neat/core/_instances/_shared.py,sha256=6avH6mtjxjHI7JDLkXwICxGvZwooGBr6APs1_w1To-A,940
85
85
  cognite/neat/core/_instances/_tracking/__init__.py,sha256=WOwsYieZtCW-iW15YkxUFrfKVVdLWdXHOGGStTwvE8A,91
@@ -108,13 +108,14 @@ cognite/neat/core/_instances/extractors/_classic_cdf/_labels.py,sha256=7guTZdGFT
108
108
  cognite/neat/core/_instances/extractors/_classic_cdf/_relationships.py,sha256=kNzrqHQuIZMBecZ8957Qs3-Pp2m2-k2CCfiUZlVwaD0,5395
109
109
  cognite/neat/core/_instances/extractors/_classic_cdf/_sequences.py,sha256=zwHM52afnq-JHvLOTi4rH6DyfkTftxH6cmODwoZi8uw,11399
110
110
  cognite/neat/core/_instances/extractors/_classic_cdf/_timeseries.py,sha256=Py8MDcn82MJcsDPbeqDHMx4g2rQHmEOSHNe6gOi5gew,2044
111
- cognite/neat/core/_instances/loaders/__init__.py,sha256=XS6vwmxgBzntg7UuG_ct_1hfhShVnFH5u0gGrdA8WfA,699
112
- cognite/neat/core/_instances/loaders/_base.py,sha256=v2sSR8wc8_vt5X_VioXctHj9XUxWxapeE7LChL1fPQ0,4512
113
- cognite/neat/core/_instances/loaders/_rdf2dms.py,sha256=3QZzZ6oJn6toMk9-yWPtZiEEdW8wYW998nN6Drvu20I,34510
111
+ cognite/neat/core/_instances/loaders/__init__.py,sha256=qyOrKy0cJgYmgEuWVM-O1mpUemQE8EkfQYtJyEc8UVs,778
112
+ cognite/neat/core/_instances/loaders/_base.py,sha256=jfik8xsdocMHVlodvgHpnDJfYdEjYuKdd0t7MGhzAHI,4337
113
+ cognite/neat/core/_instances/loaders/_rdf2dms.py,sha256=PoNj77pxVoUpP7qxmMWf2nNul2PtlAlIFcVzUV2gyuE,29076
114
+ cognite/neat/core/_instances/loaders/_rdf_to_instance_space.py,sha256=qVxRzEUyhv8AGvAO8whJWPCZ-8BppEy0mk1Ux_8gOzY,11937
114
115
  cognite/neat/core/_instances/queries/__init__.py,sha256=W477LMyB4l6HIRbQhJoFgA_MUBwVCh2GBvtFeZu0AUA,53
115
116
  cognite/neat/core/_instances/queries/_base.py,sha256=APevHeeWQDEoOQ0MlBtVlPf9hbZukVkI5fOvt5oPJCE,543
116
117
  cognite/neat/core/_instances/queries/_queries.py,sha256=4BidSQXhdZYZ6_kyG7jMJ2iG0UtSrbQxfmwPM7V167A,466
117
- cognite/neat/core/_instances/queries/_select.py,sha256=ah4F03SJLUVsn_Fw4NHDi1KtiMXYNXpMYlalqW7eK_E,18533
118
+ cognite/neat/core/_instances/queries/_select.py,sha256=-iJnEddNCIr26D2QBBq_82G4l6YoYpTs2jd_CELvxB8,19096
118
119
  cognite/neat/core/_instances/queries/_update.py,sha256=j2hU62rEIYWvZ_ZAkm9Khc2lNddnww0W-1jR7MJJbFY,1290
119
120
  cognite/neat/core/_instances/transformers/__init__.py,sha256=YzC1Z8BuT77NwagWX4Z-F9R9BARLSS7zM4bCdxBbqKg,1761
120
121
  cognite/neat/core/_instances/transformers/_base.py,sha256=RYa9es5fEsjLpaok8liuy73ACPDWwHVfTm2Lq4HVCig,4695
@@ -160,22 +161,22 @@ cognite/neat/core/_utils/xml_.py,sha256=FQkq84u35MUsnKcL6nTMJ9ajtG9D5i1u4VBnhGqP
160
161
  cognite/neat/core/_utils/reader/__init__.py,sha256=fPkrNB_9hLB7CyHTCFV_xEbIfOMqUQzNly5JN33-QfM,146
161
162
  cognite/neat/core/_utils/reader/_base.py,sha256=fRXxUWW8a3UFedeCLxDTDgFntWGlHaEGxmKLcITtiWE,5417
162
163
  cognite/neat/session/__init__.py,sha256=fxQ5URVlUnmEGYyB8Baw7IDq-uYacqkigbc4b-Pr9Fw,58
163
- cognite/neat/session/_base.py,sha256=eR4E0xixBnTJ7OofnqCWXH7-84gv5iKQG06dP1_5LEE,12795
164
+ cognite/neat/session/_base.py,sha256=DqujVyC19Jg8hGxnw9TfCeF3BYOFuauk4yTTuAsjJz4,12807
164
165
  cognite/neat/session/_collector.py,sha256=-icWXOT9YBjAOVZfpPtBx-D39kpRP2RaQKdPtcr7Xm8,4233
165
- cognite/neat/session/_drop.py,sha256=mCJISS73e-q3Ioj2cGXZwCpEHzKGiJ8Z5D8Uuk0yWOQ,4233
166
+ cognite/neat/session/_drop.py,sha256=ipD8RS_ZebPNpeIkhC7yqSSeo7e57TXMRxrh5_6IRik,4239
166
167
  cognite/neat/session/_experimental.py,sha256=U_Wq3NWgnGaOJh5Fq8iO6HcYUhlG9RQIutT8e4LZL8o,1224
167
168
  cognite/neat/session/_explore.py,sha256=PLxpHDqBk5B0Q4a5tJKnF6KzL4heQ77b2qUETbf6iVQ,1599
168
- cognite/neat/session/_fix.py,sha256=9XrNIH1Zw4DI0HDH3XqnI2c-us4V0CyZpoM_Mtt2H0g,913
169
+ cognite/neat/session/_fix.py,sha256=oJRXuRI4f_HgLYHkjbtPAwHK0vSDUYd19hIZeFaE7rQ,919
169
170
  cognite/neat/session/_inspect.py,sha256=AESQd2SOidR_pDTFk5B_JdPnKZ5PNNskdAQBepH2Mv0,10175
170
- cognite/neat/session/_mapping.py,sha256=KlFjRq5JUZ_FV4AI7H6RSLZw6_fzhtTe0C1vzqkvSNg,2889
171
- cognite/neat/session/_prepare.py,sha256=xa-35JKgi1j8X347ub6komEMNGFjytPaQReFOgeFHnA,12760
172
- cognite/neat/session/_read.py,sha256=bzmsSUmap8IUit1bmwjip6h3is4nQSSIK8ygWVYxM_o,35289
173
- cognite/neat/session/_set.py,sha256=785duIx09hlC3JZGC7kd1qZOEa1Rh8yoTIXP5ppqypU,4587
171
+ cognite/neat/session/_mapping.py,sha256=ItEXhXo_8V3069hktHMxdpBsLNeTck3gZBvhlm12Oxw,2895
172
+ cognite/neat/session/_prepare.py,sha256=pskEVNgcnVJVRvYKk5xI55V89vKDO_kgjszj5flY8Zs,12778
173
+ cognite/neat/session/_read.py,sha256=sKtSw7Ub--vR6wfEexNzzaEHb0MZCHj3kzCEnF5wjf0,35349
174
+ cognite/neat/session/_set.py,sha256=PU4lKI-LGtKFVyvdtfZkk-zLw9e_rnFHzuV9IyrOrTM,4593
174
175
  cognite/neat/session/_show.py,sha256=YLt6K4ukG1s_I_FhuVrIVPtw_btvvOL50Rwrx-vo7VQ,10743
175
- cognite/neat/session/_state.py,sha256=rhH7LJvwcsdVUYB7BnLINItUjfuGHuTyfBPsjNhIV0w,6568
176
- cognite/neat/session/_subset.py,sha256=CwbO7wpAbNmD5rz8NYsUjx-1NS3fjZ2h9LJ7UwN1-mM,2836
177
- cognite/neat/session/_template.py,sha256=OjDD2HLQuCdKBevbaxLv2JAI1EQFB_EDIH5glq44L9o,9890
178
- cognite/neat/session/_to.py,sha256=zOguyrMtk08uMwzuXzAeRLQ_833EHKmwz6ovy3Si-Dc,19257
176
+ cognite/neat/session/_state.py,sha256=DLEm9wn3GtOuTGhy5-M1IK2v9qvLnTYEruWPidzAP_Q,6580
177
+ cognite/neat/session/_subset.py,sha256=p7n6WmL0gZlUbqpVBgyPncQ6uWn_pi7FDSixDFrm7DM,2848
178
+ cognite/neat/session/_template.py,sha256=NCgrrwLT98DpLYoo3Wybr_OUXrEXpsJZjrJ83KqfyWc,9908
179
+ cognite/neat/session/_to.py,sha256=_R-UB3iEIQoa12kTD7tuSrRDdbySQXQg_mzbn5t-7bg,19399
179
180
  cognite/neat/session/_wizard.py,sha256=hARNNzD5Zfkk_V147rIjOLVvrFaqzXGXWhZuH1NJG3M,1486
180
181
  cognite/neat/session/exceptions.py,sha256=KJ7UUjmuGb_1O6FIamkwe4z0bCroAwn-AwX---hEudY,3341
181
182
  cognite/neat/session/_state/README.md,sha256=o6N7EL98lgyWffw8IoEUf2KG5uSKveD5__TW45YzVjA,902
@@ -183,7 +184,7 @@ cognite/neat/session/engine/__init__.py,sha256=D3MxUorEs6-NtgoICqtZ8PISQrjrr4dvc
183
184
  cognite/neat/session/engine/_import.py,sha256=1QxA2_EK613lXYAHKQbZyw2yjo5P9XuiX4Z6_6-WMNQ,169
184
185
  cognite/neat/session/engine/_interface.py,sha256=3W-cYr493c_mW3P5O6MKN1xEQg3cA7NHR_ev3zdF9Vk,533
185
186
  cognite/neat/session/engine/_load.py,sha256=g52uYakQM03VqHt_RDHtpHso1-mFFifH5M4T2ScuH8A,5198
186
- cognite_neat-0.122.1.dist-info/METADATA,sha256=D25cVsvDJ6cWBPH9guOTr-xHC016LePV1cajgQFAwZ4,9171
187
- cognite_neat-0.122.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
188
- cognite_neat-0.122.1.dist-info/licenses/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
189
- cognite_neat-0.122.1.dist-info/RECORD,,
187
+ cognite_neat-0.122.3.dist-info/METADATA,sha256=Ne-zk3krkH-J9jOp0l4Ij84rkqkbs5Pt52EK65Jf-og,9171
188
+ cognite_neat-0.122.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
189
+ cognite_neat-0.122.3.dist-info/licenses/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
190
+ cognite_neat-0.122.3.dist-info/RECORD,,