cognite-neat 0.122.3__py3-none-any.whl → 0.123.1__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.

Files changed (26) hide show
  1. cognite/neat/_version.py +1 -1
  2. cognite/neat/core/_client/_api/neat_instances.py +30 -0
  3. cognite/neat/core/_constants.py +10 -1
  4. cognite/neat/core/_data_model/_constants.py +1 -0
  5. cognite/neat/core/_data_model/importers/_dms2data_model.py +16 -5
  6. cognite/neat/core/_data_model/models/entities/__init__.py +2 -0
  7. cognite/neat/core/_data_model/models/entities/_single_value.py +24 -4
  8. cognite/neat/core/_data_model/models/entities/_types.py +11 -0
  9. cognite/neat/core/_data_model/models/physical/_exporter.py +18 -5
  10. cognite/neat/core/_data_model/models/physical/_unverified.py +22 -1
  11. cognite/neat/core/_data_model/models/physical/_validation.py +3 -1
  12. cognite/neat/core/_data_model/models/physical/_verified.py +2 -2
  13. cognite/neat/core/_instances/loaders/_rdf2dms.py +8 -0
  14. cognite/neat/core/_issues/errors/__init__.py +2 -1
  15. cognite/neat/core/_issues/errors/_general.py +14 -0
  16. cognite/neat/plugins/__init__.py +3 -0
  17. cognite/neat/plugins/_issues.py +25 -0
  18. cognite/neat/plugins/_manager.py +99 -0
  19. cognite/neat/plugins/data_model/__init__.py +0 -0
  20. cognite/neat/plugins/data_model/importers/__init__.py +5 -0
  21. cognite/neat/plugins/data_model/importers/_base.py +27 -0
  22. cognite/neat/session/exceptions.py +2 -1
  23. {cognite_neat-0.122.3.dist-info → cognite_neat-0.123.1.dist-info}/METADATA +1 -1
  24. {cognite_neat-0.122.3.dist-info → cognite_neat-0.123.1.dist-info}/RECORD +26 -20
  25. {cognite_neat-0.122.3.dist-info → cognite_neat-0.123.1.dist-info}/WHEEL +0 -0
  26. {cognite_neat-0.122.3.dist-info → cognite_neat-0.123.1.dist-info}/licenses/LICENSE +0 -0
cognite/neat/_version.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "0.122.3"
1
+ __version__ = "0.123.1"
2
2
  __engine__ = "^2.0.4"
@@ -7,6 +7,11 @@ from cognite.client.data_classes.filters import Filter
7
7
  from cognite.client.exceptions import CogniteAPIError
8
8
  from cognite.client.utils.useful_types import SequenceNotStr
9
9
 
10
+ from cognite.neat.core._constants import DMS_INSTANCE_LIMIT_MARGIN
11
+ from cognite.neat.core._issues import NeatIssue
12
+ from cognite.neat.core._issues.errors import WillExceedLimitError
13
+ from cognite.neat.core._issues.warnings import NeatValueWarning
14
+
10
15
  if TYPE_CHECKING:
11
16
  from cognite.neat.core._client._api_client import NeatClient
12
17
 
@@ -69,3 +74,28 @@ class NeatInstancesAPI:
69
74
  if (time.perf_counter() - last_limit_change) > 30.0 and body["limit"] < 1_000:
70
75
  body["limit"] = min(int(body["limit"] * 1.5), 1_000)
71
76
  last_limit_change = time.perf_counter()
77
+
78
+ def validate_cdf_project_capacity(self, total_instances: int) -> NeatIssue | None:
79
+ """Validates if the current project instance capacity can accommodate the given number of instances.
80
+
81
+ Args:
82
+ total_instances (int): The total number of instances to check against the project's capacity.
83
+
84
+ Returns:
85
+ NeatIssue | None: Returns a warning if the capacity is exceeded, otherwise None.
86
+
87
+ Raises:
88
+ WillExceedLimitError: If the total instances exceed the project's instance capacity.
89
+
90
+ """
91
+ try:
92
+ stats = self._client.instance_statistics.project()
93
+ except CogniteAPIError as e:
94
+ # This endpoint is not yet in alpha, it may change or not be available.
95
+ return NeatValueWarning(f"Cannot check project instance capacity. Endpoint not available: {e}")
96
+ instance_capacity = stats.instances.instances_limit - stats.instances.instances
97
+ if total_instances + DMS_INSTANCE_LIMIT_MARGIN > instance_capacity:
98
+ raise WillExceedLimitError(
99
+ "instances", total_instances, stats.project, instance_capacity, DMS_INSTANCE_LIMIT_MARGIN
100
+ )
101
+ return None
@@ -9,7 +9,6 @@ from rdflib import DC, DCTERMS, FOAF, OWL, RDF, RDFS, SH, SKOS, XSD, Namespace,
9
9
  from rdflib.namespace import DefinedNamespace
10
10
 
11
11
  from cognite import neat
12
- from cognite.neat.core._issues.errors._general import NeatValueError
13
12
 
14
13
  if TYPE_CHECKING:
15
14
  from cognite.neat.core._data_model.models.physical import PhysicalProperty
@@ -161,6 +160,14 @@ DMS_DIRECT_RELATION_LIST_DEFAULT_LIMIT = 100
161
160
  DMS_PRIMITIVE_LIST_DEFAULT_LIMIT = 1000
162
161
  DMS_CONTAINER_LIST_MAX_LIMIT = 2000
163
162
 
163
+ # The number of instances that should be left as a margin when Neat writes to CDF through the DMS API.
164
+ # This is currently set conservatively to 1 million. The reasoning for this is that there are CDF
165
+ # applications such as Infield and Industrial Canvas that can write to the DMS API, as well as likely third-party
166
+ # applications that can write to the DMS API. If Neat fills up the entire capacity, these type of data gathering
167
+ # applications will experience data loss. The limit of 1 million is chosen such that it will trigger alarms in the
168
+ # CDF projects, such that admins can take action to increase or clean up the capacity before it is too late.
169
+ DMS_INSTANCE_LIMIT_MARGIN = 1_000_000
170
+
164
171
  _ASSET_ROOT_PROPERTY = {
165
172
  "connection": "direct",
166
173
  "container": "cdf_cdm:CogniteAsset",
@@ -211,6 +218,8 @@ def get_base_concepts(
211
218
  base_model: The base model to get the concepts for.
212
219
  total_concepts: The number of concepts to get. If None, all concepts are returned.
213
220
  """
221
+ # Local import to avoid circular dependency issues
222
+ from cognite.neat.core._issues.errors._general import NeatValueError
214
223
 
215
224
  if base_model == "CogniteCore":
216
225
  return [f"cdf_cdm:{concept}(version=v1)" for concept in COGNITE_CONCEPTS][:total_concepts]
@@ -42,6 +42,7 @@ class EntityTypes(StrEnum):
42
42
  version = "version"
43
43
  prefix = "prefix"
44
44
  space = "space"
45
+ container_index = "container_index"
45
46
 
46
47
 
47
48
  def get_reserved_words(
@@ -47,6 +47,7 @@ from cognite.neat.core._data_model.models.data_types import DataType, Enum, Stri
47
47
  from cognite.neat.core._data_model.models.entities import (
48
48
  ConceptEntity,
49
49
  ContainerEntity,
50
+ ContainerIndexEntity,
50
51
  DMSNodeEntity,
51
52
  EdgeEntity,
52
53
  PhysicalUnknownEntity,
@@ -385,7 +386,9 @@ class DMSImporter(BaseImporter[UnverifiedPhysicalDataModel]):
385
386
  ),
386
387
  view=str(view_entity),
387
388
  view_property=prop_id,
388
- index=self._get_index(prop, prop_id),
389
+ # MyPy fails to understand that list[ContainerIndexEntity] | None is valid even though
390
+ # the index expects str | list[ContainerIndexEntity | str] | None.
391
+ index=self._get_index(prop, prop_id), # type: ignore[arg-type]
389
392
  constraint=self._get_constraint(prop, prop_id),
390
393
  )
391
394
 
@@ -548,14 +551,22 @@ class DMSImporter(BaseImporter[UnverifiedPhysicalDataModel]):
548
551
  return str(default)
549
552
  return None
550
553
 
551
- def _get_index(self, prop: ViewPropertyApply, prop_id: str) -> list[str] | None:
554
+ def _get_index(self, prop: ViewPropertyApply, prop_id: str) -> list[ContainerIndexEntity] | None:
552
555
  if not isinstance(prop, dm.MappedPropertyApply):
553
556
  return None
554
557
  container = self._all_containers_by_id[prop.container]
555
- index: list[str] = []
558
+ index: list[ContainerIndexEntity] = []
556
559
  for index_name, index_obj in (container.indexes or {}).items():
557
- if isinstance(index_obj, BTreeIndex | InvertedIndex) and prop_id in index_obj.properties:
558
- index.append(index_name)
560
+ if isinstance(index_obj, BTreeIndex) and prop_id in index_obj.properties:
561
+ order = None if len(index_obj.properties) == 1 else index_obj.properties.index(prop_id)
562
+ index.append(
563
+ ContainerIndexEntity(
564
+ prefix="btree", suffix=index_name, cursorable=index_obj.cursorable, order=order
565
+ )
566
+ )
567
+ elif isinstance(index_obj, InvertedIndex) and prop_id in index_obj.properties:
568
+ order = None if len(index_obj.properties) == 1 else index_obj.properties.index(prop_id)
569
+ index.append(ContainerIndexEntity(prefix="inverted", suffix=index_name, order=order))
559
570
  return index or None
560
571
 
561
572
  def _get_constraint(self, prop: ViewPropertyApply, prop_id: str) -> list[str] | None:
@@ -7,6 +7,7 @@ from ._single_value import (
7
7
  ConceptEntity,
8
8
  ConceptualEntity,
9
9
  ContainerEntity,
10
+ ContainerIndexEntity,
10
11
  DataModelEntity,
11
12
  DMSNodeEntity,
12
13
  DMSVersionedEntity,
@@ -33,6 +34,7 @@ __all__ = [
33
34
  "ConceptualEntity",
34
35
  "ContainerEntity",
35
36
  "ContainerEntityList",
37
+ "ContainerIndexEntity",
36
38
  "DMSFilter",
37
39
  "DMSNodeEntity",
38
40
  "DMSVersionedEntity",
@@ -172,8 +172,8 @@ class ConceptualEntity(BaseModel, extra="ignore"):
172
172
  extra: tuple[str, ...] = tuple(
173
173
  [
174
174
  str(v or "")
175
- for field_name in self.model_fields
176
- if isinstance(v := getattr(self, field_name), str | None) and field_name not in {"prefix", "suffix"}
175
+ for field_name in self.model_fields.keys()
176
+ if (v := getattr(self, field_name)) and field_name not in {"prefix", "suffix"}
177
177
  ]
178
178
  )
179
179
  if isinstance(self.prefix, _UndefinedType):
@@ -225,8 +225,8 @@ class ConceptualEntity(BaseModel, extra="ignore"):
225
225
  continue
226
226
  if model_dump[key] == value:
227
227
  to_delete.append(key)
228
- elif isinstance(self, EdgeEntity):
229
- # Exception is edge entity, then, we remove all the defaults we can.
228
+ elif isinstance(self, EdgeEntity | ContainerIndexEntity):
229
+ # Exception is edge and container index entities, then we remove all the defaults we can.
230
230
  continue
231
231
  else:
232
232
  # Not all fields are default. We should not remove any of them.
@@ -549,3 +549,23 @@ class ReferenceEntity(ConceptEntity):
549
549
 
550
550
  def as_concept_entity(self) -> ConceptEntity:
551
551
  return ConceptEntity(prefix=self.prefix, suffix=self.suffix, version=self.version)
552
+
553
+
554
+ class ContainerIndexEntity(PhysicalEntity[None]):
555
+ type_: ClassVar[EntityTypes] = EntityTypes.container_index
556
+ prefix: _UndefinedType | Literal["btree", "inverted"] = Undefined # type: ignore[assignment]
557
+ suffix: str
558
+ order: int | None = Field(None, description="The order of the index. None indicates the value is not set.")
559
+ cursorable: bool | None = Field(
560
+ None, description="Whether the index is cursorable. None indicates the value is not set."
561
+ )
562
+ by_space: bool | None = Field(
563
+ None, alias="bySpace", description="Whether the index is by space. None indicates the value is not set."
564
+ )
565
+
566
+ def as_id(self) -> None:
567
+ return None
568
+
569
+ @classmethod
570
+ def from_id(cls, id: None) -> Self:
571
+ return cls(suffix="dummy")
@@ -10,6 +10,7 @@ from ._single_value import (
10
10
  AssetEntity,
11
11
  ConceptEntity,
12
12
  ContainerEntity,
13
+ ContainerIndexEntity,
13
14
  RelationshipEntity,
14
15
  ViewEntity,
15
16
  )
@@ -66,6 +67,16 @@ ContainerEntityList = Annotated[
66
67
  BeforeValidator(_split_str),
67
68
  ]
68
69
 
70
+ ContainerIndexListType = Annotated[
71
+ list[ContainerIndexEntity],
72
+ BeforeValidator(_split_str),
73
+ PlainSerializer(
74
+ _join_str,
75
+ return_type=str,
76
+ when_used="unless-none",
77
+ ),
78
+ ]
79
+
69
80
  ViewEntityList = Annotated[
70
81
  list[ViewEntity],
71
82
  BeforeValidator(_split_str),
@@ -4,7 +4,7 @@ from collections.abc import Collection, Hashable, Sequence
4
4
  from typing import Any, cast
5
5
 
6
6
  from cognite.client.data_classes import data_modeling as dm
7
- from cognite.client.data_classes.data_modeling.containers import BTreeIndex
7
+ from cognite.client.data_classes.data_modeling.containers import BTreeIndex, InvertedIndex
8
8
  from cognite.client.data_classes.data_modeling.data_types import EnumValue as DMSEnumValue
9
9
  from cognite.client.data_classes.data_modeling.data_types import ListablePropertyType
10
10
  from cognite.client.data_classes.data_modeling.views import (
@@ -29,6 +29,7 @@ from cognite.neat.core._data_model.models.data_types import DataType, Double, En
29
29
  from cognite.neat.core._data_model.models.entities import (
30
30
  ConceptEntity,
31
31
  ContainerEntity,
32
+ ContainerIndexEntity,
32
33
  DMSFilter,
33
34
  DMSNodeEntity,
34
35
  EdgeEntity,
@@ -36,6 +37,7 @@ from cognite.neat.core._data_model.models.entities import (
36
37
  NodeTypeFilter,
37
38
  PhysicalUnknownEntity,
38
39
  ReverseConnectionEntity,
40
+ Undefined,
39
41
  UnitEntity,
40
42
  ViewEntity,
41
43
  )
@@ -380,14 +382,25 @@ class _DMSExporter:
380
382
  container.constraints = container.constraints or {}
381
383
  container.constraints[constraint_name] = dm.UniquenessConstraint(properties=list(properties))
382
384
 
383
- index_properties: dict[str, set[str]] = defaultdict(set)
385
+ index_properties: dict[tuple[str, bool], list[tuple[str, ContainerIndexEntity]]] = defaultdict(list)
384
386
  for prop in container_properties:
385
387
  if prop.container_property is not None:
386
388
  for index in prop.index or []:
387
- index_properties[index].add(prop.container_property)
388
- for index_name, properties in index_properties.items():
389
+ index_properties[(index.suffix, prop.is_list or False)].append((prop.container_property, index))
390
+ for (index_name, is_list), properties in index_properties.items():
389
391
  container.indexes = container.indexes or {}
390
- container.indexes[index_name] = BTreeIndex(properties=list(properties))
392
+ index_property_list = [prop_id for prop_id, _ in sorted(properties, key=lambda x: x[1].order or 0)]
393
+ index_entity = properties[0][1]
394
+ if index_entity.prefix == "inverted" or (index_entity.prefix is Undefined and is_list):
395
+ container.indexes[index_name] = InvertedIndex(properties=index_property_list)
396
+ elif index_entity.prefix == "btree" or (index_entity.prefix is Undefined and not is_list):
397
+ container.indexes[index_name] = BTreeIndex(
398
+ properties=index_property_list, cursorable=index_entity.cursorable or False
399
+ )
400
+ else:
401
+ raise NeatValueError(
402
+ f"Invalid index prefix {index_entity.prefix!r} in {container_id}.{index_entity.suffix!r}"
403
+ )
391
404
 
392
405
  # We might drop containers we convert direct relations of list into multi-edge connections
393
406
  # which do not have a container.
@@ -21,6 +21,7 @@ from cognite.neat.core._data_model.models._base_unverified import (
21
21
  from cognite.neat.core._data_model.models.data_types import DataType
22
22
  from cognite.neat.core._data_model.models.entities import (
23
23
  ContainerEntity,
24
+ ContainerIndexEntity,
24
25
  DMSNodeEntity,
25
26
  EdgeEntity,
26
27
  PhysicalUnknownEntity,
@@ -135,7 +136,7 @@ class UnverifiedPhysicalProperty(UnverifiedComponent[PhysicalProperty]):
135
136
  default: str | int | float | bool | dict | None = None
136
137
  container: str | None = None
137
138
  container_property: str | None = None
138
- index: str | list[str] | None = None
139
+ index: str | list[str | ContainerIndexEntity] | ContainerIndexEntity | None = None
139
140
  constraint: str | list[str] | None = None
140
141
  neatId: str | URIRef | None = None
141
142
  conceptual: str | URIRef | None = None
@@ -167,6 +168,26 @@ class UnverifiedPhysicalProperty(UnverifiedComponent[PhysicalProperty]):
167
168
  if self.container
168
169
  else None
169
170
  )
171
+ if isinstance(self.index, ContainerIndexEntity) or (isinstance(self.index, str) and "," not in self.index):
172
+ output["Index"] = [ContainerIndexEntity.load(self.index)]
173
+ elif isinstance(self.index, str) and "," in self.index:
174
+ output["Index"] = [
175
+ ContainerIndexEntity.load(index.strip()) for index in self.index.split(",") if index.strip()
176
+ ]
177
+ elif isinstance(self.index, list):
178
+ index_list: list[ContainerIndexEntity | PhysicalUnknownEntity] = []
179
+ for index in self.index:
180
+ if isinstance(index, ContainerIndexEntity):
181
+ index_list.append(index)
182
+ elif isinstance(index, str) and "," in index:
183
+ index_list.extend(
184
+ [ContainerIndexEntity.load(idx.strip()) for idx in index.split(",") if idx.strip()]
185
+ )
186
+ elif isinstance(index, str):
187
+ index_list.append(ContainerIndexEntity.load(index.strip()))
188
+ else:
189
+ raise TypeError(f"Unexpected type for index: {type(index)}")
190
+ output["Index"] = index_list
170
191
  return output
171
192
 
172
193
  def referenced_view(self, default_space: str, default_version: str) -> ViewEntity:
@@ -391,7 +391,9 @@ class PhysicalValidation:
391
391
  "rows",
392
392
  )
393
393
  )
394
- index_definitions = {",".join(prop.index) for _, prop in properties if prop.index is not None}
394
+ index_definitions = {
395
+ ",".join([index.suffix for index in prop.index]) for _, prop in properties if prop.index is not None
396
+ }
395
397
  if len(index_definitions) > 1:
396
398
  errors.append(
397
399
  PropertyDefinitionDuplicatedError[dm.ContainerId](
@@ -32,7 +32,6 @@ from cognite.neat.core._data_model.models._types import (
32
32
  from cognite.neat.core._data_model.models.data_types import DataType
33
33
  from cognite.neat.core._data_model.models.entities import (
34
34
  ConceptualEntity,
35
- ContainerEntityList,
36
35
  DMSNodeEntity,
37
36
  EdgeEntity,
38
37
  HasDataFilter,
@@ -44,6 +43,7 @@ from cognite.neat.core._data_model.models.entities import (
44
43
  ViewEntity,
45
44
  ViewEntityList,
46
45
  )
46
+ from cognite.neat.core._data_model.models.entities._types import ContainerEntityList, ContainerIndexListType
47
47
  from cognite.neat.core._issues.errors import NeatValueError
48
48
  from cognite.neat.core._issues.warnings._general import NeatValueWarning
49
49
 
@@ -142,7 +142,7 @@ class PhysicalProperty(SheetRow):
142
142
  alias="Container Property",
143
143
  description="Specifies property in the container where the property is stored. Only applies to primitive type.",
144
144
  )
145
- index: StrListType | None = Field(
145
+ index: ContainerIndexListType | None = Field(
146
146
  None,
147
147
  alias="Index",
148
148
  description="The names of the indexes (comma separated) that should be created for the property.",
@@ -159,6 +159,14 @@ class DMSLoader(CDFLoader[dm.InstanceApply]):
159
159
  if self.neat_prefix_by_type_uri:
160
160
  self._lookup_identifier_by_uri()
161
161
 
162
+ if self._client:
163
+ validate_issue = self._client.instances.validate_cdf_project_capacity(
164
+ sum(it.instance_count for it in view_iterations)
165
+ )
166
+ if validate_issue:
167
+ yield validate_issue
168
+ return
169
+
162
170
  for it in view_iterations:
163
171
  view = it.view
164
172
  if view is None:
@@ -12,7 +12,7 @@ from ._external import (
12
12
  NeatYamlError,
13
13
  OxigraphStorageLockedError,
14
14
  )
15
- from ._general import NeatImportError, NeatTypeError, NeatValueError, RegexViolationError
15
+ from ._general import NeatImportError, NeatTypeError, NeatValueError, RegexViolationError, WillExceedLimitError
16
16
  from ._properties import (
17
17
  PropertyDefinitionDuplicatedError,
18
18
  PropertyDefinitionError,
@@ -82,6 +82,7 @@ __all__ = [
82
82
  "ReversedConnectionNotFeasibleError",
83
83
  "SpreadsheetError",
84
84
  "ViewValueError",
85
+ "WillExceedLimitError",
85
86
  ]
86
87
 
87
88
  _NEAT_ERRORS_BY_NAME = {error.__name__: error for error in _get_subclasses(NeatError, include_base=True)}
@@ -1,4 +1,5 @@
1
1
  from dataclasses import dataclass
2
+ from typing import Literal
2
3
 
3
4
  from cognite.neat.core._issues import NeatError
4
5
 
@@ -35,3 +36,16 @@ class NeatImportError(NeatError, ImportError):
35
36
 
36
37
  module: str
37
38
  neat_extra: str
39
+
40
+
41
+ @dataclass(unsafe_hash=True)
42
+ class WillExceedLimitError(NeatError, RuntimeError):
43
+ """Cannot write {resource_count} {resource_type} to project {project} as the current available capacity
44
+ is {available_capacity} {resource_type}. Neat requires a capacity of at least {margin} {resource_type} are
45
+ left for future writes, {available_capacity}-{resource_count} < {margin}."""
46
+
47
+ resource_type: Literal["instances"]
48
+ resource_count: int
49
+ project: str
50
+ available_capacity: int
51
+ margin: int
@@ -0,0 +1,3 @@
1
+ from ._manager import get_plugin_manager
2
+
3
+ __all__ = ["get_plugin_manager"]
@@ -0,0 +1,25 @@
1
+ from dataclasses import dataclass
2
+
3
+ from cognite.neat.core._issues._base import NeatError
4
+
5
+
6
+ @dataclass(unsafe_hash=True)
7
+ class PluginError(NeatError, ImportError):
8
+ """No plugin of type '{plugin_type}' registered under name '{plugin_name}'"""
9
+
10
+ plugin_name: str
11
+ plugin_type: str
12
+
13
+
14
+ @dataclass(unsafe_hash=True)
15
+ class PluginLoadingError(PluginError):
16
+ """Unable to load plugin of type '{plugin_type}' registered under name '{plugin_name}' due to: {exception}"""
17
+
18
+ exception: str
19
+
20
+
21
+ @dataclass(unsafe_hash=True)
22
+ class PluginDuplicateError(PluginError):
23
+ """Plugin of type '{plugin_type}' registered for under name '{plugin_name}' already exists"""
24
+
25
+ ...
@@ -0,0 +1,99 @@
1
+ """Plugin manager for external plugins."""
2
+
3
+ from importlib import metadata
4
+ from typing import Any, ClassVar, TypeAlias
5
+
6
+ from ._issues import PluginDuplicateError, PluginError, PluginLoadingError
7
+ from .data_model.importers import DataModelImporterPlugin
8
+
9
+ # Here we configure entry points where external plugins are going to be registered.
10
+ plugins_entry_points = {
11
+ "cognite.neat.plugins.data_model.importers": DataModelImporterPlugin,
12
+ }
13
+
14
+ #: Type alias for all supported plugin types
15
+ NeatPlugin: TypeAlias = DataModelImporterPlugin
16
+
17
+
18
+ class Plugin:
19
+ """Plugin class for registering plugins registered via entry points (i.e. external plugins).
20
+
21
+ Args:
22
+ name (str): The name of format (e.g. Excel) or action (e.g. merge) plugin is handling.
23
+ type_ (type): The type of the plugin.
24
+ entry_point (EntryPoint): The entry point for the plugin.
25
+
26
+ !!! note "name uniqueness"
27
+ The name of the plugin must be lower case and unique across all plugins of the same kind.
28
+ If two plugins have the same name, the exception will be raised.
29
+ """
30
+
31
+ def __init__(self, name: str, type_: type[NeatPlugin], entry_point: metadata.EntryPoint):
32
+ self.name = name
33
+ self.type_ = type_
34
+ self.entry_point = entry_point
35
+
36
+ def load(self) -> Any:
37
+ try:
38
+ return self.entry_point.load()
39
+ except Exception as e:
40
+ raise PluginLoadingError(self.name, self.type_.__name__, str(e)) from e
41
+
42
+
43
+ class PluginManager:
44
+ """Plugin manager for external plugins."""
45
+
46
+ _plugins_entry_points: ClassVar[dict[str, type[NeatPlugin]]] = {
47
+ "cognite.neat.plugins.data_model.importers": DataModelImporterPlugin,
48
+ }
49
+
50
+ def __init__(self, plugins: dict[tuple[str, type[NeatPlugin]], Any]) -> None:
51
+ self._plugins = plugins
52
+
53
+ def get(self, name: str, type_: type[NeatPlugin]) -> Any:
54
+ """
55
+ Returns desired plugin
56
+
57
+ Args:
58
+ name (str): The name of format (e.g. Excel) or action (e.g. merge) plugin is handling.
59
+ type_ (type): The type of the plugin.
60
+ """
61
+ try:
62
+ return self._plugins[(name, type_)]
63
+ except KeyError:
64
+ raise PluginError(plugin_name=name, plugin_type=type_.__name__) from None
65
+
66
+ @classmethod
67
+ def load_plugins(cls, entry_points: metadata.EntryPoints | None = None) -> "PluginManager":
68
+ """Load plugins from entry points and register them to the manager.
69
+ This method scans the provided entry points for plugins defined in the
70
+ `_plugins_entry_points` dictionary and registers them.
71
+
72
+ Args:
73
+ entry_points: Entry points to load plugins from. If None, uses the default entry points.
74
+ """
75
+ _plugins: dict[tuple[str, type[NeatPlugin]], Any] = {}
76
+
77
+ entry_points = entry_points or metadata.entry_points()
78
+ if hasattr(entry_points, "select"):
79
+ for group, type_ in cls._plugins_entry_points.items():
80
+ for entry_point in entry_points.select(group=group):
81
+ # Check for duplicate plugins
82
+ if (entry_point.name, type_) in _plugins:
83
+ raise PluginDuplicateError(plugin_name=entry_point.name, plugin_type=type_.__name__)
84
+
85
+ # Register the plugin
86
+ _plugins[(entry_point.name, type_)] = Plugin(entry_point.name, type_, entry_point).load()
87
+
88
+ return cls(_plugins)
89
+
90
+
91
+ _manager_instance: PluginManager | None = None
92
+
93
+
94
+ def get_plugin_manager(force_reload: bool = False) -> PluginManager:
95
+ """Get or create a singleton PluginManager instance."""
96
+ global _manager_instance
97
+ if force_reload or _manager_instance is None:
98
+ _manager_instance = PluginManager.load_plugins()
99
+ return _manager_instance
File without changes
@@ -0,0 +1,5 @@
1
+ from ._base import DataModelImporterPlugin
2
+
3
+ __all__ = [
4
+ "DataModelImporterPlugin",
5
+ ]
@@ -0,0 +1,27 @@
1
+ from typing import Any
2
+
3
+ from cognite.neat.core._data_model.importers._base import BaseImporter
4
+
5
+
6
+ class DataModelImporterPlugin:
7
+ """This class is used an interface for data model import plugins.
8
+ Any plugin that is used for importing data models should inherit from this class.
9
+ It is expected to implement the `configure` method which returns a configured importer.
10
+ """
11
+
12
+ def configure(self, io: Any, **kwargs: Any) -> BaseImporter:
13
+ """Return a configure plugin for data model import.
14
+
15
+ Args:
16
+ io (Any): The input/output interface for the plugin.
17
+ **kwargs (Any): Additional keyword arguments for configuration.
18
+
19
+ Returns:
20
+ BaseImporter: A configured instance of the BaseImporter.
21
+
22
+ !!! note "Returns"
23
+ The method must return an instance of `BaseImporter` or its subclasses
24
+ meaning it must implement the `BaseImporter` interface.
25
+ """
26
+
27
+ raise NotImplementedError()
@@ -5,7 +5,7 @@ from typing import Any, TypeVar
5
5
 
6
6
  from cognite.neat.core._issues.errors import CDFMissingClientError, NeatImportError
7
7
  from cognite.neat.core._issues.errors._external import OxigraphStorageLockedError
8
- from cognite.neat.core._issues.errors._general import NeatValueError
8
+ from cognite.neat.core._issues.errors._general import NeatValueError, WillExceedLimitError
9
9
  from cognite.neat.session._experimental import ExperimentalFeatureWarning
10
10
 
11
11
  from ._collector import _COLLECTOR
@@ -50,6 +50,7 @@ def _session_method_wrapper(func: Callable, cls_name: str) -> Any:
50
50
  NeatImportError,
51
51
  NeatValueError,
52
52
  OxigraphStorageLockedError,
53
+ WillExceedLimitError,
53
54
  ) as e:
54
55
  print(f"{_ERROR_PREFIX} {escape(e.as_message())}")
55
56
  except ModuleNotFoundError as e:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cognite-neat
3
- Version: 0.122.3
3
+ Version: 0.123.1
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,16 +1,16 @@
1
1
  cognite/neat/__init__.py,sha256=12StS1dzH9_MElqxGvLWrNsxCJl9Hv8A2a9D0E5OD_U,193
2
- cognite/neat/_version.py,sha256=9fKctwX-_c2LYzEGFYewc_Bfl-r-r0K_n7MBXcEGzzg,46
2
+ cognite/neat/_version.py,sha256=9xSFXBm0153-WkCC4TsK5hz4FpM0Eo8Z2KVqo6ptqSA,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
6
- cognite/neat/core/_constants.py,sha256=IaYEVDDHyQ2g3fys_8lqUtYaQSWw6PBkT4sgS9EwHl8,8113
6
+ cognite/neat/core/_constants.py,sha256=Cc7p1QbpbzPSjlf-PB_Ow2pKRhWQL-K8VJma96HzU3A,8863
7
7
  cognite/neat/core/_shared.py,sha256=Ov59SWYboRRsncB_5V1ZC_BAoACfNLjo80vqE5Ru6wo,2325
8
8
  cognite/neat/core/_client/__init__.py,sha256=RQ7MwL8mwGqGHokRzsPqO3XStDzmI4-c12_gz1UPJ74,177
9
9
  cognite/neat/core/_client/_api_client.py,sha256=CqgG4kEArI9jiKAh82YrRZv_SzeMKA5guIZOvDg2R5I,860
10
10
  cognite/neat/core/_client/testing.py,sha256=rZGd-TFwNtfUqT8LV0u3FT0kHwNrjnvDNZU_Mcd5yx4,1329
11
11
  cognite/neat/core/_client/_api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  cognite/neat/core/_client/_api/data_modeling_loaders.py,sha256=YEZP0V_RXenzzFSxDzt4SbVnpzB4VP0fcI-Bab1VLw8,39815
13
- cognite/neat/core/_client/_api/neat_instances.py,sha256=2rSt4FVPvLA0lzwwOvCC9fJk87jTF1vudLO9Z6pgpk4,3354
13
+ cognite/neat/core/_client/_api/neat_instances.py,sha256=8HcQO1sp8zjXdnRBRQ4yeQzt1O906HNSrDDCgrgTe8A,4805
14
14
  cognite/neat/core/_client/_api/schema.py,sha256=lbA8Cka_7K_RjmaxdeqkVkIwKPfWeDvpYvvEOGI07xo,6967
15
15
  cognite/neat/core/_client/_api/statistics.py,sha256=M0JpCHD6WMfggoe-HyXfeigwRCvZJjVF-xNB9CgB4UE,3796
16
16
  cognite/neat/core/_client/data_classes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -19,7 +19,7 @@ cognite/neat/core/_client/data_classes/neat_sequence.py,sha256=QZWSfWnwk6KlYJvsI
19
19
  cognite/neat/core/_client/data_classes/schema.py,sha256=SpkBGbC2SUJG38Ixf1vYJINI66i_OZaT03q4XKRtK54,25067
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
- cognite/neat/core/_data_model/_constants.py,sha256=RAQMEt0zuXKlnz6tKlvW97NDaMG6ycwKV929C_fVOAY,6018
22
+ cognite/neat/core/_data_model/_constants.py,sha256=h6jfkE4tr-POO7C_L4SxcffbwHj53mb-CEo08l8RcwY,6058
23
23
  cognite/neat/core/_data_model/_shared.py,sha256=gLEEMofI9prZLRNjHpwQe0uX9WoKd5qUt5pT1i_KAYo,2072
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=baqgY-66zOUxw8s-PA1KGAOs2R1gJDAo2UWWc8LlHGU,24257
@@ -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=SoyVwMX__7UIFHZbrt9aLux4dVZx6KHrhkHQLS7eIf4,28308
41
+ cognite/neat/core/_data_model/importers/_dms2data_model.py,sha256=1luEyqEu51rNcFcEh-MjTnUY_5mnQU0761MDVHOuteo,29132
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
@@ -60,21 +60,21 @@ cognite/neat/core/_data_model/models/conceptual/__init__.py,sha256=9A6myEV8s0-Lq
60
60
  cognite/neat/core/_data_model/models/conceptual/_unverified.py,sha256=apisgtXMb50dOs7rxZ-jcCW4JqxCdAWGtsYtRe3ssfs,6282
61
61
  cognite/neat/core/_data_model/models/conceptual/_validation.py,sha256=I55RJC3EfQjVkRSYzK6M3UK9aFT-TSIsaWD8JAVzwPo,13000
62
62
  cognite/neat/core/_data_model/models/conceptual/_verified.py,sha256=e5Qs7n1np4g6inHQwuLUk2rCwgLf129je54xLnzENpw,13659
63
- cognite/neat/core/_data_model/models/entities/__init__.py,sha256=iQqfJay1j3PgSlZbW4X6nKReGxy3f3BayymqSBQJ6jo,1513
63
+ cognite/neat/core/_data_model/models/entities/__init__.py,sha256=UsW-_6fwd-TW0WcnShPKf40h75l1elVn80VurUwRAic,1567
64
64
  cognite/neat/core/_data_model/models/entities/_constants.py,sha256=GXRzVfArwxF3C67VCkzy0JWTZRkRJUYXBQaaecrqcWc,351
65
65
  cognite/neat/core/_data_model/models/entities/_loaders.py,sha256=PkrVtGlZWYLvAVIRABrgVSgkMvJYpBqdrHBfz-H0Ut8,2783
66
66
  cognite/neat/core/_data_model/models/entities/_multi_value.py,sha256=4507L7dr_CL4vo1En6EyMiHhUDOWPTDVR1aYZns6S38,2792
67
- cognite/neat/core/_data_model/models/entities/_single_value.py,sha256=DRASB2OHj7evMYKNvO1BloKIIfLC2enPjY5PsZ-4ByU,20226
68
- cognite/neat/core/_data_model/models/entities/_types.py,sha256=AJti5ZtK4CUmsNczkqrIECQmPgO0lFVAmZHbVkChIPk,1948
67
+ cognite/neat/core/_data_model/models/entities/_single_value.py,sha256=DO_u8dLLD8xabVZFXilZELv_Fzs6dcMs6msoszw32iY,21034
68
+ cognite/neat/core/_data_model/models/entities/_types.py,sha256=MqrCovqI_nvpMB4UqiUk4eUlKANvr8P7wr8k3y8lXlQ,2183
69
69
  cognite/neat/core/_data_model/models/entities/_wrapped.py,sha256=hOvdyxCNFgv1UdfaasviKnbEN4yN09Iip0ggQiaXgB4,7993
70
70
  cognite/neat/core/_data_model/models/mapping/__init__.py,sha256=T68Hf7rhiXa7b03h4RMwarAmkGnB-Bbhc1H07b2PyC4,100
71
71
  cognite/neat/core/_data_model/models/mapping/_classic2core.py,sha256=FRDpYP_CX-CfptdFCZmfqsbKCYQ9BQPUbKoifTICe30,1415
72
72
  cognite/neat/core/_data_model/models/mapping/_classic2core.yaml,sha256=ei-nuivNWVW9HmvzDBKIPF6ZdgaMq64XHw_rKm0CMxg,22584
73
73
  cognite/neat/core/_data_model/models/physical/__init__.py,sha256=ONE_xLw1cxfw88rICG_RtbjCYUZm8yS2kBQ4Di3EGnA,987
74
- cognite/neat/core/_data_model/models/physical/_exporter.py,sha256=D2g2eXabydUfQCjuDNkQ83ZSijTdynzwIXBDVQVIWdE,29157
75
- cognite/neat/core/_data_model/models/physical/_unverified.py,sha256=vDA6yNl0nwA3EudobqhHbr6e2vQZ13EWCAlyqXG03oA,16971
76
- cognite/neat/core/_data_model/models/physical/_validation.py,sha256=i0YHDE2c09OeuTbICqb8mqNYaEJk2JWvxPnZeYAWdPE,33121
77
- cognite/neat/core/_data_model/models/physical/_verified.py,sha256=UsfzuIyYRsdUPK9wJM9Wxs4VkD4GiGUQAjRjgDCmIHw,24237
74
+ cognite/neat/core/_data_model/models/physical/_exporter.py,sha256=WHYjWyiKpA7GWO2_vPN3AphpDr8OjzxI5JMyO7b3sYQ,30083
75
+ cognite/neat/core/_data_model/models/physical/_unverified.py,sha256=IP6dKJHS4itpOzUd893G6f8oFiTEUnkJc7bx6_RL9A4,18213
76
+ cognite/neat/core/_data_model/models/physical/_validation.py,sha256=uPzbcJmFj0g9ATVq86rUsmSGOfQ0iBeIevoKh1lCu98,33179
77
+ cognite/neat/core/_data_model/models/physical/_verified.py,sha256=Fvy0pOYk03nHDlRz_SECg9ALW3y0LaCZG6XNBduCi9Q,24332
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
80
  cognite/neat/core/_data_model/transformers/_converters.py,sha256=OazYC7DgAXXEvxdiaPfJSe2ZNkYn2mRqWhtvtvWK59g,111575
@@ -110,7 +110,7 @@ cognite/neat/core/_instances/extractors/_classic_cdf/_sequences.py,sha256=zwHM52
110
110
  cognite/neat/core/_instances/extractors/_classic_cdf/_timeseries.py,sha256=Py8MDcn82MJcsDPbeqDHMx4g2rQHmEOSHNe6gOi5gew,2044
111
111
  cognite/neat/core/_instances/loaders/__init__.py,sha256=qyOrKy0cJgYmgEuWVM-O1mpUemQE8EkfQYtJyEc8UVs,778
112
112
  cognite/neat/core/_instances/loaders/_base.py,sha256=jfik8xsdocMHVlodvgHpnDJfYdEjYuKdd0t7MGhzAHI,4337
113
- cognite/neat/core/_instances/loaders/_rdf2dms.py,sha256=PoNj77pxVoUpP7qxmMWf2nNul2PtlAlIFcVzUV2gyuE,29076
113
+ cognite/neat/core/_instances/loaders/_rdf2dms.py,sha256=Nel9ZZ560XAfqNapHSr-P_sk5F_Yv4Ffk9slCfB7dG4,29355
114
114
  cognite/neat/core/_instances/loaders/_rdf_to_instance_space.py,sha256=qVxRzEUyhv8AGvAO8whJWPCZ-8BppEy0mk1Ux_8gOzY,11937
115
115
  cognite/neat/core/_instances/queries/__init__.py,sha256=W477LMyB4l6HIRbQhJoFgA_MUBwVCh2GBvtFeZu0AUA,53
116
116
  cognite/neat/core/_instances/queries/_base.py,sha256=APevHeeWQDEoOQ0MlBtVlPf9hbZukVkI5fOvt5oPJCE,543
@@ -128,9 +128,9 @@ cognite/neat/core/_issues/_base.py,sha256=iZcqGd5R6nnTBvVDGJ5VV67vQNvDuUzSQGtl2Z
128
128
  cognite/neat/core/_issues/_contextmanagers.py,sha256=5-QXVmfplt4S_k2csrQ2xuezOOuE5_FxSA9GVGVG1s4,1582
129
129
  cognite/neat/core/_issues/_factory.py,sha256=ifEzHZcvPyO0ZGJo8T8CE20F5L4yRzrrGPxl9d87oIs,2829
130
130
  cognite/neat/core/_issues/formatters.py,sha256=k2h_6wHW0ve52gXeuRoEcGwrxqqSe5sYFa_HycPiqW8,3323
131
- cognite/neat/core/_issues/errors/__init__.py,sha256=Qx70RN1C6JjYj16NtSz191DAUPzM5XxD6OqWSSM_uss,2368
131
+ cognite/neat/core/_issues/errors/__init__.py,sha256=yIW5cntr-OA0BplqEtUJaaxTZpnwq-bAcTKhY-SSawc,2418
132
132
  cognite/neat/core/_issues/errors/_external.py,sha256=AaKwO5-AvX01d7Hd83vqYl1qNmMtgsmShmvyH8ioZAM,2354
133
- cognite/neat/core/_issues/errors/_general.py,sha256=R6TNBmvCsicqadC56ehiEc9lS18K5DMyK2_UXfv74uA,854
133
+ cognite/neat/core/_issues/errors/_general.py,sha256=QEgTp_bvzGjmpRtr09Lj_SBeD9IVdql5_JmP02P7PfM,1391
134
134
  cognite/neat/core/_issues/errors/_properties.py,sha256=XkMLO4tkFX8vmGRixLdsmDAnlcipc78lypGccMYVAQk,2541
135
135
  cognite/neat/core/_issues/errors/_resources.py,sha256=lBK65tJZMhV3z3_xi8zJeo7Nt_agXsOklH_RPKQu28s,4002
136
136
  cognite/neat/core/_issues/errors/_wrapper.py,sha256=clhuSwUuHy-FQXQopFIQRY8c_NZM5u-QB9ncoc6Hrbo,2320
@@ -160,6 +160,12 @@ cognite/neat/core/_utils/upload.py,sha256=yR-BvvrWPh0XHoIGByXMEVi3JONzmc5xwXbmED
160
160
  cognite/neat/core/_utils/xml_.py,sha256=FQkq84u35MUsnKcL6nTMJ9ajtG9D5i1u4VBnhGqP2DQ,1710
161
161
  cognite/neat/core/_utils/reader/__init__.py,sha256=fPkrNB_9hLB7CyHTCFV_xEbIfOMqUQzNly5JN33-QfM,146
162
162
  cognite/neat/core/_utils/reader/_base.py,sha256=fRXxUWW8a3UFedeCLxDTDgFntWGlHaEGxmKLcITtiWE,5417
163
+ cognite/neat/plugins/__init__.py,sha256=Q7r1FFbybOt71N9TjHjjk-1HguLRfHieLeiGVSG5HTY,75
164
+ cognite/neat/plugins/_issues.py,sha256=Xd3YsIN0EZakvgCLm5ilantTv17dVUabXc61nFxriQM,671
165
+ cognite/neat/plugins/_manager.py,sha256=LQlEGjRgn55nu-dad9LKpqIaYqM12OoKRYBepCQz_1c,3769
166
+ cognite/neat/plugins/data_model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
167
+ cognite/neat/plugins/data_model/importers/__init__.py,sha256=d4UJNCFR1DXPY7lv5LdCW2hiStEhvXiu2g_bRSIp1y0,89
168
+ cognite/neat/plugins/data_model/importers/_base.py,sha256=S8VOw0eYJ94CDeOx7aTjBbBebNlpoWoGatpU5eOohtQ,981
163
169
  cognite/neat/session/__init__.py,sha256=fxQ5URVlUnmEGYyB8Baw7IDq-uYacqkigbc4b-Pr9Fw,58
164
170
  cognite/neat/session/_base.py,sha256=DqujVyC19Jg8hGxnw9TfCeF3BYOFuauk4yTTuAsjJz4,12807
165
171
  cognite/neat/session/_collector.py,sha256=-icWXOT9YBjAOVZfpPtBx-D39kpRP2RaQKdPtcr7Xm8,4233
@@ -178,13 +184,13 @@ cognite/neat/session/_subset.py,sha256=p7n6WmL0gZlUbqpVBgyPncQ6uWn_pi7FDSixDFrm7
178
184
  cognite/neat/session/_template.py,sha256=NCgrrwLT98DpLYoo3Wybr_OUXrEXpsJZjrJ83KqfyWc,9908
179
185
  cognite/neat/session/_to.py,sha256=_R-UB3iEIQoa12kTD7tuSrRDdbySQXQg_mzbn5t-7bg,19399
180
186
  cognite/neat/session/_wizard.py,sha256=hARNNzD5Zfkk_V147rIjOLVvrFaqzXGXWhZuH1NJG3M,1486
181
- cognite/neat/session/exceptions.py,sha256=KJ7UUjmuGb_1O6FIamkwe4z0bCroAwn-AwX---hEudY,3341
187
+ cognite/neat/session/exceptions.py,sha256=lcO-qQcWkKeF2lvlIZngs358ClcNIH8i6LVW7ioSinQ,3397
182
188
  cognite/neat/session/_state/README.md,sha256=o6N7EL98lgyWffw8IoEUf2KG5uSKveD5__TW45YzVjA,902
183
189
  cognite/neat/session/engine/__init__.py,sha256=D3MxUorEs6-NtgoICqtZ8PISQrjrr4dvca6n48bu_bI,120
184
190
  cognite/neat/session/engine/_import.py,sha256=1QxA2_EK613lXYAHKQbZyw2yjo5P9XuiX4Z6_6-WMNQ,169
185
191
  cognite/neat/session/engine/_interface.py,sha256=3W-cYr493c_mW3P5O6MKN1xEQg3cA7NHR_ev3zdF9Vk,533
186
192
  cognite/neat/session/engine/_load.py,sha256=g52uYakQM03VqHt_RDHtpHso1-mFFifH5M4T2ScuH8A,5198
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,,
193
+ cognite_neat-0.123.1.dist-info/METADATA,sha256=4NPwnKYbAwVmCTktDxLB82sU6BtQKaqOA9vRTxUJveU,9171
194
+ cognite_neat-0.123.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
195
+ cognite_neat-0.123.1.dist-info/licenses/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
196
+ cognite_neat-0.123.1.dist-info/RECORD,,