cognite-neat 0.77.0__py3-none-any.whl → 0.77.2__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 +1 @@
1
- __version__ = "0.77.0"
1
+ __version__ = "0.77.2"
@@ -5,7 +5,14 @@ from typing import Literal, TypeAlias, cast
5
5
 
6
6
  from cognite.client import CogniteClient
7
7
  from cognite.client.data_classes._base import CogniteResource, CogniteResourceList
8
- from cognite.client.data_classes.data_modeling import DataModelApply, DataModelApplyList, DataModelId
8
+ from cognite.client.data_classes.data_modeling import (
9
+ ContainerApplyList,
10
+ DataModelApply,
11
+ DataModelApplyList,
12
+ DataModelId,
13
+ SpaceApplyList,
14
+ ViewApplyList,
15
+ )
9
16
  from cognite.client.exceptions import CogniteAPIError
10
17
 
11
18
  from cognite.neat.rules import issues
@@ -264,11 +271,11 @@ class DMSExporter(CDFExporter[DMSSchema]):
264
271
  schema = self.export(rules)
265
272
  to_export: list[tuple[CogniteResourceList, ResourceLoader]] = []
266
273
  if self.export_components.intersection({"all", "spaces"}):
267
- to_export.append((schema.spaces, SpaceLoader(client)))
274
+ to_export.append((SpaceApplyList(schema.spaces.values()), SpaceLoader(client)))
268
275
  if self.export_components.intersection({"all", "containers"}):
269
- to_export.append((schema.containers, ContainerLoader(client)))
276
+ to_export.append((ContainerApplyList(schema.containers.values()), ContainerLoader(client)))
270
277
  if self.export_components.intersection({"all", "views"}):
271
- to_export.append((schema.views, ViewLoader(client, self.existing_handling)))
278
+ to_export.append((ViewApplyList(schema.views.values()), ViewLoader(client, self.existing_handling)))
272
279
  if self.export_components.intersection({"all", "data_models"}):
273
280
  to_export.append((DataModelApplyList([schema.data_model]), DataModelLoader(client)))
274
281
  if isinstance(schema, PipelineSchema):
@@ -60,11 +60,9 @@ class DMSImporter(BaseImporter):
60
60
  self.metadata = metadata
61
61
  self.ref_metadata = ref_metadata
62
62
  self.issue_list = IssueList(read_issues)
63
- self._all_containers_by_id = {container.as_id(): container for container in schema.containers}
63
+ self._all_containers_by_id = schema.containers.copy()
64
64
  if self.root_schema.reference:
65
- self._all_containers_by_id.update(
66
- {container.as_id(): container for container in self.root_schema.reference.containers}
67
- )
65
+ self._all_containers_by_id.update(self.root_schema.reference.containers)
68
66
 
69
67
  @classmethod
70
68
  def from_data_model_id(
@@ -200,7 +198,7 @@ class DMSImporter(BaseImporter):
200
198
  **self._create_rule_components(
201
199
  ref_model,
202
200
  ref_schema,
203
- self.ref_metadata or self._create_default_metadata(ref_schema.views),
201
+ self.ref_metadata or self._create_default_metadata(list(ref_schema.views.values())),
204
202
  DataModelType.enterprise,
205
203
  )
206
204
  )
@@ -228,8 +226,7 @@ class DMSImporter(BaseImporter):
228
226
  schema_completeness: SchemaCompleteness | None = None,
229
227
  ) -> dict[str, Any]:
230
228
  properties = SheetList[DMSProperty]()
231
- for view in schema.views:
232
- view_id = view.as_id()
229
+ for view_id, view in schema.views.items():
233
230
  view_entity = ViewEntity.from_id(view_id)
234
231
  class_entity = view_entity.as_class()
235
232
  for prop_id, prop in (view.properties or {}).items():
@@ -250,10 +247,13 @@ class DMSImporter(BaseImporter):
250
247
  metadata=metadata,
251
248
  properties=properties,
252
249
  containers=SheetList[DMSContainer](
253
- data=[DMSContainer.from_container(container) for container in schema.containers]
250
+ data=[DMSContainer.from_container(container) for container in schema.containers.values()]
254
251
  ),
255
252
  views=SheetList[DMSView](
256
- data=[DMSView.from_view(view, in_model=view.as_id() in data_model_view_ids) for view in schema.views]
253
+ data=[
254
+ DMSView.from_view(view, in_model=view_id in data_model_view_ids)
255
+ for view_id, view in schema.views.items()
256
+ ]
257
257
  ),
258
258
  )
259
259
 
@@ -507,6 +507,26 @@ class HasDataFilterAppliedToTooManyContainersWarning(DMSSchemaWarning):
507
507
  return output
508
508
 
509
509
 
510
+ @dataclass(frozen=True)
511
+ class RawFilterAppliedToViewWarning(DMSSchemaWarning):
512
+ description = "Raw filter is applied to a view, which is against the neat data modeling lifecycle."
513
+ fix = "Do not use raw filter, instead use HasData filter or nodeType filter or change the data model design."
514
+ error_name: ClassVar[str] = "RawFilterAppliedToView"
515
+ view_id: dm.ViewId
516
+
517
+ def message(self) -> str:
518
+ return (
519
+ f"RawFilter applied to the view {self.view_id}."
520
+ " The usage of RawFilter is against the neat team recommendations and the neat data modeling lifecycle."
521
+ " When opting for raw filter, the user is responsible for any errors that arise in neat."
522
+ )
523
+
524
+ def dump(self) -> dict[str, Any]:
525
+ output = super().dump()
526
+ output["view_id"] = self.view_id.dump()
527
+ return output
528
+
529
+
510
530
  @dataclass(frozen=True)
511
531
  class NodeTypeFilterOnParentViewWarning(DMSSchemaWarning):
512
532
  description = (
@@ -22,6 +22,7 @@ from cognite.neat.rules.models.entities import (
22
22
  ViewPropertyEntity,
23
23
  )
24
24
  from cognite.neat.rules.models.wrapped_entities import DMSFilter, HasDataFilter, NodeTypeFilter
25
+ from cognite.neat.utils.cdf_classes import ContainerApplyDict, NodeApplyDict, SpaceApplyDict, ViewApplyDict
25
26
 
26
27
  from ._rules import DMSMetadata, DMSProperty, DMSRules, DMSView
27
28
  from ._schema import DMSSchema, PipelineSchema
@@ -51,7 +52,9 @@ class _DMSExporter:
51
52
  self._ref_schema = rules.reference.as_schema() if rules.reference else None
52
53
  if self._ref_schema:
53
54
  # We skip version as that will always be missing in the reference
54
- self._ref_views_by_id = {dm.ViewId(view.space, view.external_id): view for view in self._ref_schema.views}
55
+ self._ref_views_by_id = {
56
+ dm.ViewId(view.space, view.external_id): view for view in self._ref_schema.views.values()
57
+ }
55
58
  else:
56
59
  self._ref_views_by_id = {}
57
60
 
@@ -65,7 +68,7 @@ class _DMSExporter:
65
68
  views_not_in_model = {view.view.as_id() for view in rules.views if not view.in_model}
66
69
  data_model = rules.metadata.as_data_model()
67
70
  data_model.views = sorted(
68
- [view_id for view_id in views.as_ids() if view_id not in views_not_in_model],
71
+ [view_id for view_id in views.keys() if view_id not in views_not_in_model],
69
72
  key=lambda v: v.as_tuple(), # type: ignore[union-attr]
70
73
  )
71
74
 
@@ -89,31 +92,30 @@ class _DMSExporter:
89
92
  def _create_spaces(
90
93
  self,
91
94
  metadata: DMSMetadata,
92
- containers: dm.ContainerApplyList,
93
- views: dm.ViewApplyList,
95
+ containers: ContainerApplyDict,
96
+ views: ViewApplyDict,
94
97
  data_model: dm.DataModelApply,
95
- ) -> dm.SpaceApplyList:
96
- used_spaces = {container.space for container in containers} | {view.space for view in views}
98
+ ) -> SpaceApplyDict:
99
+ used_spaces = {container.space for container in containers.values()} | {view.space for view in views.values()}
97
100
  if len(used_spaces) == 1:
98
101
  # We skip the default space and only use this space for the data model
99
102
  data_model.space = used_spaces.pop()
100
- spaces = dm.SpaceApplyList([dm.SpaceApply(space=data_model.space)])
103
+ spaces = SpaceApplyDict([dm.SpaceApply(space=data_model.space)])
101
104
  else:
102
105
  used_spaces.add(metadata.space)
103
- spaces = dm.SpaceApplyList([dm.SpaceApply(space=space) for space in used_spaces])
104
- if self.instance_space and self.instance_space not in {space.space for space in spaces}:
105
- spaces.append(dm.SpaceApply(space=self.instance_space, name=self.instance_space))
106
+ spaces = SpaceApplyDict([dm.SpaceApply(space=space) for space in used_spaces])
107
+ if self.instance_space and self.instance_space not in spaces:
108
+ spaces[self.instance_space] = dm.SpaceApply(space=self.instance_space, name=self.instance_space)
106
109
  return spaces
107
110
 
108
111
  def _create_views_with_node_types(
109
112
  self,
110
113
  view_properties_by_id: dict[dm.ViewId, list[DMSProperty]],
111
- ) -> tuple[dm.ViewApplyList, dm.NodeApplyList]:
112
- views = dm.ViewApplyList([dms_view.as_view() for dms_view in self.rules.views])
114
+ ) -> tuple[ViewApplyDict, NodeApplyDict]:
115
+ views = ViewApplyDict([dms_view.as_view() for dms_view in self.rules.views])
113
116
  dms_view_by_id = {dms_view.view.as_id(): dms_view for dms_view in self.rules.views}
114
117
 
115
- for view in views:
116
- view_id = view.as_id()
118
+ for view_id, view in views.items():
117
119
  view.properties = {}
118
120
  if not (view_properties := view_properties_by_id.get(view_id)):
119
121
  continue
@@ -124,14 +126,13 @@ class _DMSExporter:
124
126
 
125
127
  data_model_type = self.rules.metadata.data_model_type
126
128
  unique_node_types: set[dm.NodeId] = set()
127
- parent_views = {parent for view in views for parent in view.implements or []}
128
- for view in views:
129
- dms_view = dms_view_by_id.get(view.as_id())
130
- dms_properties = view_properties_by_id.get(view.as_id(), [])
129
+ parent_views = {parent for view in views.values() for parent in view.implements or []}
130
+ for view_id, view in views.items():
131
+ dms_view = dms_view_by_id.get(view_id)
132
+ dms_properties = view_properties_by_id.get(view_id, [])
131
133
  view_filter = self._create_view_filter(view, dms_view, data_model_type, dms_properties)
132
134
 
133
135
  view.filter = view_filter.as_dms_filter()
134
-
135
136
  if isinstance(view_filter, NodeTypeFilter):
136
137
  unique_node_types.update(view_filter.nodes)
137
138
  if view.as_id() in parent_views:
@@ -151,7 +152,7 @@ class _DMSExporter:
151
152
  issues.dms.HasDataFilterOnViewWithReferencesWarning(view.as_id(), list(references)), stacklevel=2
152
153
  )
153
154
 
154
- return views, dm.NodeApplyList(
155
+ return views, NodeApplyDict(
155
156
  [dm.NodeApply(space=node.space, external_id=node.external_id) for node in unique_node_types]
156
157
  )
157
158
 
@@ -174,7 +175,7 @@ class _DMSExporter:
174
175
  def _create_containers(
175
176
  self,
176
177
  container_properties_by_id: dict[dm.ContainerId, list[DMSProperty]],
177
- ) -> dm.ContainerApplyList:
178
+ ) -> ContainerApplyDict:
178
179
  containers = dm.ContainerApplyList(
179
180
  [dms_container.as_container() for dms_container in self.rules.containers or []]
180
181
  )
@@ -229,9 +230,7 @@ class _DMSExporter:
229
230
  for name, const in container.constraints.items()
230
231
  if not (isinstance(const, dm.RequiresConstraint) and const.require in container_to_drop)
231
232
  }
232
- return dm.ContainerApplyList(
233
- [container for container in containers if container.as_id() not in container_to_drop]
234
- )
233
+ return ContainerApplyDict([container for container in containers if container.as_id() not in container_to_drop])
235
234
 
236
235
  def _gather_properties(self) -> tuple[dict[dm.ContainerId, list[DMSProperty]], dict[dm.ViewId, list[DMSProperty]]]:
237
236
  container_properties_by_id: dict[dm.ContainerId, list[DMSProperty]] = defaultdict(list)
@@ -254,6 +253,7 @@ class _DMSExporter:
254
253
  dms_properties: list[DMSProperty],
255
254
  ) -> DMSFilter:
256
255
  selected_filter_name = (dms_view and dms_view.filter_ and dms_view.filter_.name) or ""
256
+
257
257
  if dms_view and dms_view.filter_ and not dms_view.filter_.is_empty:
258
258
  # Has Explicit Filter, use it
259
259
  return dms_view.filter_
@@ -41,7 +41,7 @@ from cognite.neat.rules.models.entities import (
41
41
  ViewEntityList,
42
42
  ViewPropertyEntity,
43
43
  )
44
- from cognite.neat.rules.models.wrapped_entities import HasDataFilter, NodeTypeFilter
44
+ from cognite.neat.rules.models.wrapped_entities import HasDataFilter, NodeTypeFilter, RawFilter
45
45
 
46
46
  from ._schema import DMSSchema
47
47
 
@@ -257,7 +257,7 @@ class DMSView(SheetEntity):
257
257
  description: str | None = Field(alias="Description", default=None)
258
258
  implements: ViewEntityList | None = Field(None, alias="Implements")
259
259
  reference: URLEntity | ReferenceEntity | None = Field(alias="Reference", default=None, union_mode="left_to_right")
260
- filter_: HasDataFilter | NodeTypeFilter | None = Field(None, alias="Filter")
260
+ filter_: HasDataFilter | NodeTypeFilter | RawFilter | None = Field(None, alias="Filter")
261
261
  in_model: bool = Field(True, alias="In Model")
262
262
  class_: ClassEntity = Field(alias="Class (linage)")
263
263
 
@@ -237,7 +237,7 @@ class DMSViewInput:
237
237
  description: str | None = None
238
238
  implements: str | None = None
239
239
  reference: str | None = None
240
- filter_: Literal["hasData", "nodeType"] | None = None
240
+ filter_: Literal["hasData", "nodeType", "rawFilter"] | None = None
241
241
  in_model: bool = True
242
242
 
243
243
  @classmethod
@@ -3,7 +3,6 @@ import sys
3
3
  import warnings
4
4
  import zipfile
5
5
  from collections import Counter, defaultdict
6
- from collections.abc import Sequence
7
6
  from dataclasses import Field, dataclass, field, fields
8
7
  from pathlib import Path
9
8
  from typing import Any, ClassVar, cast
@@ -31,6 +30,13 @@ from cognite.neat.rules.issues.dms import (
31
30
  MissingViewError,
32
31
  )
33
32
  from cognite.neat.rules.models.data_types import _DATA_TYPE_BY_DMS_TYPE
33
+ from cognite.neat.utils.cdf_classes import (
34
+ CogniteResourceDict,
35
+ ContainerApplyDict,
36
+ NodeApplyDict,
37
+ SpaceApplyDict,
38
+ ViewApplyDict,
39
+ )
34
40
  from cognite.neat.utils.cdf_loaders import ViewLoader
35
41
  from cognite.neat.utils.cdf_loaders.data_classes import RawTableWrite, RawTableWriteList
36
42
  from cognite.neat.utils.text import to_camel
@@ -45,10 +51,10 @@ else:
45
51
  @dataclass
46
52
  class DMSSchema:
47
53
  data_model: dm.DataModelApply | None = None
48
- spaces: dm.SpaceApplyList = field(default_factory=lambda: dm.SpaceApplyList([]))
49
- views: dm.ViewApplyList = field(default_factory=lambda: dm.ViewApplyList([]))
50
- containers: dm.ContainerApplyList = field(default_factory=lambda: dm.ContainerApplyList([]))
51
- node_types: dm.NodeApplyList = field(default_factory=lambda: dm.NodeApplyList([]))
54
+ spaces: SpaceApplyDict = field(default_factory=SpaceApplyDict)
55
+ views: ViewApplyDict = field(default_factory=ViewApplyDict)
56
+ containers: ContainerApplyDict = field(default_factory=ContainerApplyDict)
57
+ node_types: NodeApplyDict = field(default_factory=NodeApplyDict)
52
58
  # The last schema is the previous version of the data model. In the case, extension=addition, this
53
59
  # should not be modified.
54
60
  last: "DMSSchema | None" = None
@@ -65,22 +71,21 @@ class DMSSchema:
65
71
 
66
72
  def _get_mapped_container_from_view(self, view_id: dm.ViewId) -> set[dm.ContainerId]:
67
73
  # index all views, including ones from reference
68
- indexed_views = {
69
- **{view.as_id(): view for view in self.views},
70
- **({view.as_id(): view for view in self.reference.views} if self.reference else {}),
71
- }
74
+ view_by_id = self.views.copy()
75
+ if self.reference:
76
+ view_by_id.update(self.reference.views)
72
77
 
73
- if view_id not in indexed_views:
78
+ if view_id not in view_by_id:
74
79
  raise ValueError(f"View {view_id} not found")
75
80
 
76
- indexed_implemented_views = {id_: view.implements for id_, view in indexed_views.items()}
81
+ indexed_implemented_views = {id_: view.implements for id_, view in view_by_id.items()}
77
82
  view_inheritance = get_inheritance_path(view_id, indexed_implemented_views)
78
83
 
79
- directly_referenced_containers = indexed_views[view_id].referenced_containers()
84
+ directly_referenced_containers = view_by_id[view_id].referenced_containers()
80
85
  inherited_referenced_containers = set()
81
86
 
82
87
  for view_id in view_inheritance:
83
- if implemented_view := indexed_views.get(view_id):
88
+ if implemented_view := view_by_id.get(view_id):
84
89
  inherited_referenced_containers |= implemented_view.referenced_containers()
85
90
  else:
86
91
  raise IncompleteSchemaError(missing_component=view_id).as_exception()
@@ -151,31 +156,39 @@ class DMSSchema:
151
156
  # as the read format contains all properties from all parents, while the write formate should not contain
152
157
  # properties from any parents.
153
158
  # The ViewLoader as_write method looks up parents and remove properties from them.
154
- view_write = dm.ViewApplyList([view_loader.as_write(view) for view in views])
159
+ view_write = ViewApplyDict([view_loader.as_write(view) for view in views])
155
160
 
156
- container_write = containers.as_write()
161
+ container_write = ContainerApplyDict(containers.as_write())
157
162
  user_space = data_model.space
158
163
  if reference_model:
159
164
  user_model_view_ids = set(data_model_write.views)
160
165
  ref_model_write = reference_model.as_write()
161
166
  ref_model_write.views = [view.as_id() for view in reference_model.views]
162
167
 
163
- ref_views = dm.ViewApplyList(
164
- [view for view in view_write if (view.space != user_space) or (view.as_id() not in user_model_view_ids)]
168
+ ref_views = ViewApplyDict(
169
+ [
170
+ view
171
+ for view_id, view in view_write.items()
172
+ if (view.space != user_space) or (view_id not in user_model_view_ids)
173
+ ]
165
174
  )
166
- view_write = dm.ViewApplyList(
167
- [view for view in view_write if view.space == user_space or view.as_id() in user_model_view_ids]
175
+ view_write = ViewApplyDict(
176
+ [
177
+ view
178
+ for view_id, view in view_write.items()
179
+ if view.space == user_space or view_id in user_model_view_ids
180
+ ]
168
181
  )
169
182
 
170
- ref_containers = dm.ContainerApplyList(
171
- [container for container in container_write if container.space != user_space]
183
+ ref_containers = ContainerApplyDict(
184
+ [container for container in container_write.values() if container.space != user_space]
172
185
  )
173
- container_write = dm.ContainerApplyList(
174
- [container for container in container_write if container.space == user_space]
186
+ container_write = ContainerApplyDict(
187
+ [container for container in container_write.values() if container.space == user_space]
175
188
  )
176
189
 
177
190
  ref_schema: DMSSchema | None = cls(
178
- spaces=dm.SpaceApplyList([s for s in space_write if s.space != user_space]),
191
+ spaces=SpaceApplyDict([s for s in space_write if s.space != user_space]),
179
192
  data_model=ref_model_write,
180
193
  views=ref_views,
181
194
  containers=ref_containers,
@@ -183,7 +196,7 @@ class DMSSchema:
183
196
  else:
184
197
  ref_schema = None
185
198
  return cls(
186
- spaces=dm.SpaceApplyList([s for s in space_write if s.space == user_space]),
199
+ spaces=SpaceApplyDict([s for s in space_write if s.space == user_space]),
187
200
  data_model=data_model_write,
188
201
  views=view_write,
189
202
  containers=container_write,
@@ -245,7 +258,7 @@ class DMSSchema:
245
258
  data_models = path_dir / "data_models"
246
259
  data_models.mkdir(parents=True, exist_ok=True)
247
260
  if "spaces" not in exclude_set:
248
- for space in self.spaces:
261
+ for space in self.spaces.values():
249
262
  (data_models / f"{space.space}.space.yaml").write_text(
250
263
  space.dump_yaml(), newline=new_line, encoding=encoding
251
264
  )
@@ -256,21 +269,21 @@ class DMSSchema:
256
269
  if "views" not in exclude_set and self.views:
257
270
  view_dir = data_models / "views"
258
271
  view_dir.mkdir(parents=True, exist_ok=True)
259
- for view in self.views:
272
+ for view in self.views.values():
260
273
  (view_dir / f"{view.external_id}.view.yaml").write_text(
261
274
  view.dump_yaml(), newline=new_line, encoding=encoding
262
275
  )
263
276
  if "containers" not in exclude_set and self.containers:
264
277
  container_dir = data_models / "containers"
265
278
  container_dir.mkdir(parents=True, exist_ok=True)
266
- for container in self.containers:
279
+ for container in self.containers.values():
267
280
  (container_dir / f"{container.external_id}.container.yaml").write_text(
268
281
  container.dump_yaml(), newline=new_line, encoding=encoding
269
282
  )
270
283
  if "node_types" not in exclude_set and self.node_types:
271
284
  node_dir = data_models / "nodes"
272
285
  node_dir.mkdir(parents=True, exist_ok=True)
273
- for node in self.node_types:
286
+ for node in self.node_types.values():
274
287
  (node_dir / f"{node.external_id}.node.yaml").write_text(
275
288
  node.dump_yaml(), newline=new_line, encoding=encoding
276
289
  )
@@ -324,22 +337,22 @@ class DMSSchema:
324
337
  exclude_set = exclude or set()
325
338
  with zipfile.ZipFile(zip_file, "w") as zip_ref:
326
339
  if "spaces" not in exclude_set:
327
- for space in self.spaces:
340
+ for space in self.spaces.values():
328
341
  zip_ref.writestr(f"data_models/{space.space}.space.yaml", space.dump_yaml())
329
342
  if "data_models" not in exclude_set and self.data_model:
330
343
  zip_ref.writestr(
331
344
  f"data_models/{self.data_model.external_id}.datamodel.yaml", self.data_model.dump_yaml()
332
345
  )
333
346
  if "views" not in exclude_set:
334
- for view in self.views:
347
+ for view in self.views.values():
335
348
  zip_ref.writestr(f"data_models/views/{view.external_id}.view.yaml", view.dump_yaml())
336
349
  if "containers" not in exclude_set:
337
- for container in self.containers:
350
+ for container in self.containers.values():
338
351
  zip_ref.writestr(
339
352
  f"data_models/containers{container.external_id}.container.yaml", container.dump_yaml()
340
353
  )
341
354
  if "node_types" not in exclude_set:
342
- for node in self.node_types:
355
+ for node in self.node_types.values():
343
356
  zip_ref.writestr(f"data_models/nodes/{node.external_id}.node.yaml", node.dump_yaml())
344
357
 
345
358
  @classmethod
@@ -436,9 +449,13 @@ class DMSSchema:
436
449
  for attr in cls_fields:
437
450
  if items := getattr(self, attr.name):
438
451
  key = to_camel(attr.name) if camel_case else attr.name
439
- if isinstance(items, Sequence):
440
- items = sorted(items, key=self._to_sortable_identifier) if sort else items
441
- output[key] = [item.dump(camel_case=camel_case) for item in items]
452
+ if isinstance(items, CogniteResourceDict):
453
+ if sort:
454
+ output[key] = [
455
+ item.dump(camel_case) for item in sorted(items.values(), key=self._to_sortable_identifier)
456
+ ]
457
+ else:
458
+ output[key] = items.dump(camel_case)
442
459
  else:
443
460
  output[key] = items.dump(camel_case=camel_case)
444
461
  return output
@@ -461,19 +478,19 @@ class DMSSchema:
461
478
 
462
479
  def validate(self) -> list[DMSSchemaError]:
463
480
  errors: set[DMSSchemaError] = set()
464
- defined_spaces = {space.space for space in self.spaces}
465
- defined_containers = {container.as_id(): container for container in self.containers}
466
- defined_views = {view.as_id() for view in self.views}
481
+ defined_spaces = self.spaces.copy()
482
+ defined_containers = self.containers.copy()
483
+ defined_views = self.views.copy()
467
484
  if self.reference:
468
- defined_spaces |= {space.space for space in self.reference.spaces}
469
- defined_containers |= {container.as_id(): container for container in self.reference.containers}
470
- defined_views |= {view.as_id() for view in self.reference.views}
485
+ defined_spaces |= self.reference.spaces
486
+ defined_containers |= self.reference.containers
487
+ defined_views |= self.reference.views
471
488
 
472
- for container in self.containers:
489
+ for container in self.containers.values():
473
490
  if container.space not in defined_spaces:
474
491
  errors.add(MissingSpaceError(space=container.space, referred_by=container.as_id()))
475
492
 
476
- for view in self.views:
493
+ for view in self.views.values():
477
494
  view_id = view.as_id()
478
495
  if view.space not in defined_spaces:
479
496
  errors.add(MissingSpaceError(space=view.space, referred_by=view_id))
@@ -601,16 +618,18 @@ class DMSSchema:
601
618
  Returns:
602
619
  set[str]: The spaces referenced by the schema.
603
620
  """
604
- referenced_spaces = {view.space for view in self.views}
605
- referenced_spaces |= {container.space for container in self.containers}
621
+ referenced_spaces = {view.space for view in self.views.values()}
622
+ referenced_spaces |= {container.space for container in self.containers.values()}
606
623
  if include_indirect_references:
607
- referenced_spaces |= {container.space for view in self.views for container in view.referenced_containers()}
608
- referenced_spaces |= {parent.space for view in self.views for parent in view.implements or []}
609
- referenced_spaces |= {node.space for node in self.node_types}
624
+ referenced_spaces |= {
625
+ container.space for view in self.views.values() for container in view.referenced_containers()
626
+ }
627
+ referenced_spaces |= {parent.space for view in self.views.values() for parent in view.implements or []}
628
+ referenced_spaces |= {node.space for node in self.node_types.values()}
610
629
  if self.data_model:
611
630
  referenced_spaces |= {self.data_model.space}
612
631
  referenced_spaces |= {view.space for view in self.data_model.views or []}
613
- referenced_spaces |= {s.space for s in self.spaces}
632
+ referenced_spaces |= {s.space for s in self.spaces.values()}
614
633
  return referenced_spaces
615
634
 
616
635
 
@@ -727,12 +746,12 @@ class PipelineSchema(DMSSchema):
727
746
  database_name = first_data_model.external_id[:32]
728
747
  instance_space = instance_space or first_data_model.space
729
748
  database = DatabaseWrite(name=database_name)
730
- parent_views = {parent for view in schema.views for parent in view.implements or []}
731
- container_by_id = {container.as_id(): container for container in schema.containers}
749
+ parent_views = {parent for view in schema.views.values() for parent in view.implements or []}
750
+ container_by_id = schema.containers.copy()
732
751
 
733
752
  transformations = TransformationWriteList([])
734
753
  raw_tables = RawTableWriteList([])
735
- for view in schema.views:
754
+ for view in schema.views.values():
736
755
  if view.as_id() in parent_views:
737
756
  # Skipping parents as they do not have their own data
738
757
  continue
@@ -8,6 +8,7 @@ from cognite.neat.rules.issues import IssueList
8
8
  from cognite.neat.rules.models._base import ExtensionCategory, SchemaCompleteness
9
9
  from cognite.neat.rules.models.data_types import DataType
10
10
  from cognite.neat.rules.models.entities import ContainerEntity
11
+ from cognite.neat.rules.models.wrapped_entities import RawFilter
11
12
 
12
13
  from ._rules import DMSProperty, DMSRules
13
14
 
@@ -25,6 +26,7 @@ class DMSPostValidation:
25
26
  self.issue_list = IssueList()
26
27
 
27
28
  def validate(self) -> IssueList:
29
+ self._validate_best_practices()
28
30
  self._consistent_container_properties()
29
31
  self._referenced_views_and_containers_are_existing()
30
32
  self._validate_extension()
@@ -166,8 +168,8 @@ class DMSPostValidation:
166
168
  # Is an extension of an existing model.
167
169
  user_schema = self.rules.as_schema()
168
170
  ref_schema = self.rules.reference.as_schema()
169
- new_containers = {container.as_id(): container for container in user_schema.containers}
170
- existing_containers = {container.as_id(): container for container in ref_schema.containers}
171
+ new_containers = user_schema.containers.copy()
172
+ existing_containers = ref_schema.containers.copy()
171
173
 
172
174
  for container_id, container in new_containers.items():
173
175
  existing_container = existing_containers.get(container_id)
@@ -193,8 +195,8 @@ class DMSPostValidation:
193
195
  # Reshape allows changes to views
194
196
  return None
195
197
 
196
- new_views = {view.as_id(): view for view in user_schema.views}
197
- existing_views = {view.as_id(): view for view in ref_schema.views}
198
+ new_views = user_schema.views.copy()
199
+ existing_views = ref_schema.views.copy()
198
200
  for view_id, view in new_views.items():
199
201
  existing_view = existing_views.get(view_id)
200
202
  if not existing_view or existing_view == view:
@@ -219,13 +221,13 @@ class DMSPostValidation:
219
221
 
220
222
  dms_schema = self.rules.as_schema()
221
223
 
222
- for view in dms_schema.views:
223
- mapped_containers = dms_schema._get_mapped_container_from_view(view.as_id())
224
+ for view_id, view in dms_schema.views.items():
225
+ mapped_containers = dms_schema._get_mapped_container_from_view(view_id)
224
226
 
225
227
  if mapped_containers and len(mapped_containers) > 10:
226
228
  self.issue_list.append(
227
229
  issues.dms.ViewMapsToTooManyContainersWarning(
228
- view_id=view.as_id(),
230
+ view_id=view_id,
229
231
  container_ids=mapped_containers,
230
232
  )
231
233
  )
@@ -236,11 +238,20 @@ class DMSPostValidation:
236
238
  ):
237
239
  self.issue_list.append(
238
240
  issues.dms.HasDataFilterAppliedToTooManyContainersWarning(
239
- view_id=view.as_id(),
241
+ view_id=view_id,
240
242
  container_ids=mapped_containers,
241
243
  )
242
244
  )
243
245
 
246
+ def _validate_best_practices(self) -> None:
247
+ for view in self.views:
248
+ if view.filter_ and isinstance(view.filter_, RawFilter):
249
+ self.issue_list.append(
250
+ issues.dms.RawFilterAppliedToViewWarning(
251
+ view_id=view.view.as_id(),
252
+ )
253
+ )
254
+
244
255
  @staticmethod
245
256
  def _changed_attributes_and_properties(
246
257
  new_dumped: dict[str, Any], existing_dumped: dict[str, Any]
@@ -1,3 +1,5 @@
1
+ import json
2
+ import re
1
3
  from abc import ABC, abstractmethod
2
4
  from collections.abc import Collection
3
5
  from functools import total_ordering
@@ -37,8 +39,19 @@ class WrappedEntity(BaseModel, ABC):
37
39
  def _parse(cls, data: str) -> dict:
38
40
  if data.casefold() == cls.name.casefold():
39
41
  return {"inner": None}
40
- inner = data[len(cls.name) :].removeprefix("(").removesuffix(")")
41
- return {"inner": [cls._inner_cls.load(entry.strip()) for entry in inner.split(",")]}
42
+
43
+ # raw filter case:
44
+ if cls.__name__ == "RawFilter":
45
+ if match := re.search(r"rawFilter\(([\s\S]*?)\)", data):
46
+ return {"filter": match.group(1), "inner": None}
47
+ else:
48
+ raise ValueError(f"Cannot parse {cls.name} from {data}. Ill formatted raw filter.")
49
+
50
+ # nodeType and hasData case:
51
+ elif inner := data[len(cls.name) :].removeprefix("(").removesuffix(")"):
52
+ return {"inner": [cls._inner_cls.load(entry.strip()) for entry in inner.split(",")]}
53
+ else:
54
+ raise ValueError(f"Cannot parse {cls.name} from {data}")
42
55
 
43
56
  @model_serializer(when_used="unless-none", return_type=str)
44
57
  def as_str(self) -> str:
@@ -164,3 +177,22 @@ class HasDataFilter(DMSFilter):
164
177
  # Sorting to ensure deterministic order
165
178
  containers=sorted(containers, key=lambda container: container.as_tuple()) # type: ignore[union-attr]
166
179
  )
180
+
181
+
182
+ class RawFilter(DMSFilter):
183
+ name: ClassVar[str] = "rawFilter"
184
+ filter: str
185
+ inner: None = None # type: ignore[assignment]
186
+
187
+ def as_dms_filter(self) -> dm.Filter: # type: ignore[override]
188
+ try:
189
+ return dm.Filter.load(json.loads(self.filter))
190
+ except json.JSONDecodeError as e:
191
+ raise ValueError(f"Error loading raw filter: {e}") from e
192
+
193
+ @property
194
+ def is_empty(self) -> bool:
195
+ return self.filter is None
196
+
197
+ def __repr__(self) -> str:
198
+ return self.filter
@@ -0,0 +1,181 @@
1
+ from abc import ABC, abstractmethod
2
+ from collections.abc import (
3
+ ItemsView,
4
+ Iterable,
5
+ Iterator,
6
+ KeysView,
7
+ Mapping,
8
+ MutableMapping,
9
+ ValuesView,
10
+ )
11
+ from typing import Any, TypeVar, cast, final
12
+
13
+ import pandas as pd
14
+ import yaml
15
+ from cognite.client.data_classes._base import T_CogniteResource
16
+ from cognite.client.data_classes.data_modeling import (
17
+ ContainerApply,
18
+ ContainerId,
19
+ DataModelApply,
20
+ DataModelId,
21
+ NodeApply,
22
+ NodeId,
23
+ SpaceApply,
24
+ ViewApply,
25
+ ViewId,
26
+ )
27
+ from cognite.client.utils._auxiliary import load_yaml_or_json
28
+ from cognite.client.utils._pandas_helpers import (
29
+ convert_nullable_int_cols,
30
+ )
31
+
32
+ T_ID = TypeVar("T_ID")
33
+
34
+
35
+ # Inheriting from dict as we are extending it,
36
+ # ref https://stackoverflow.com/questions/7148419/subclass-dict-userdict-dict-or-abc
37
+ class CogniteResourceDict(dict, MutableMapping[T_ID, T_CogniteResource], ABC):
38
+ """CogniteResource stored in a mapping structure.
39
+
40
+ The serialization format of the CognitiveResourceDict is a list of dicts, where each dict
41
+ represents a CognitiveResource.
42
+
43
+ This means that the serialization methods .dump() and .load() return a list of dicts and
44
+ expects a list of dicts respectively.
45
+
46
+ In addition, the init method is slightly abused compared to a regular dict by allowing the input to be a
47
+ list of CognitiveResources.
48
+ """
49
+
50
+ _RESOURCE: type[T_CogniteResource]
51
+
52
+ def __init__(
53
+ self,
54
+ items: Iterable[T_CogniteResource]
55
+ | Iterable[tuple[T_ID, T_CogniteResource]]
56
+ | Mapping[T_ID, T_CogniteResource]
57
+ | None = None,
58
+ ) -> None:
59
+ if isinstance(items, Mapping):
60
+ super().__init__(items)
61
+ elif isinstance(items, Iterable):
62
+ super().__init__(item if isinstance(item, tuple) else (self._as_id(item), item) for item in items) # type: ignore[arg-type]
63
+ else:
64
+ super().__init__()
65
+
66
+ @classmethod
67
+ @abstractmethod
68
+ def _as_id(cls, resource: T_CogniteResource) -> T_ID:
69
+ raise NotImplementedError
70
+
71
+ def dump(self, camel_case: bool = True) -> list[dict[str, Any]]:
72
+ return [value.dump(camel_case) for value in self.values()]
73
+
74
+ def dump_yaml(self) -> str:
75
+ return yaml.dump(self.dump(camel_case=True), sort_keys=False)
76
+
77
+ def to_pandas(self, camel_case: bool = False) -> pd.DataFrame:
78
+ df = pd.DataFrame(self.dump(camel_case=camel_case))
79
+ df = convert_nullable_int_cols(df)
80
+ return df
81
+
82
+ def _repr_html_(self) -> str:
83
+ # Pretty print the dataframe in Jupyter
84
+ return self.to_pandas()._repr_html_() # type: ignore[operator]
85
+
86
+ @classmethod
87
+ @final
88
+ def load(cls: "type[T_CogniteResourceDict]", resource: Iterable[dict[str, Any]] | str) -> "T_CogniteResourceDict":
89
+ """Load a resource from a YAML/JSON string or iterable of dict."""
90
+ if isinstance(resource, str):
91
+ resource = load_yaml_or_json(resource)
92
+
93
+ if isinstance(resource, Iterable):
94
+ return cls._load(cast(Iterable, resource))
95
+
96
+ raise TypeError(f"Resource must be json or yaml str, or iterable of dicts, not {type(resource)}")
97
+
98
+ @classmethod
99
+ def _load(
100
+ cls: "type[T_CogniteResourceDict]",
101
+ resource_list: Iterable[dict[str, Any]],
102
+ ) -> "T_CogniteResourceDict":
103
+ resources = (cls._RESOURCE._load(resource) for resource in resource_list)
104
+ return cls({cls._as_id(resource): resource for resource in resources}) # type: ignore[abstract]
105
+
106
+ # The below methods are included to make better type hints in the IDE
107
+ def __getitem__(self, k: T_ID) -> T_CogniteResource:
108
+ return super().__getitem__(k)
109
+
110
+ def __setitem__(self, k: T_ID, v: T_CogniteResource) -> None:
111
+ super().__setitem__(k, v)
112
+
113
+ def __delitem__(self, k: T_ID) -> None:
114
+ super().__delitem__(k)
115
+
116
+ def __iter__(self) -> Iterator[T_ID]:
117
+ return super().__iter__()
118
+
119
+ def keys(self) -> KeysView[T_ID]: # type: ignore[override]
120
+ return super().keys()
121
+
122
+ def values(self) -> ValuesView[T_CogniteResource]: # type: ignore[override]
123
+ return super().values()
124
+
125
+ def items(self) -> ItemsView[T_ID, T_CogniteResource]: # type: ignore[override]
126
+ return super().items()
127
+
128
+ def get(self, __key: T_ID, __default: Any = ...) -> T_CogniteResource:
129
+ return super().get(__key, __default)
130
+
131
+ def pop(self, __key: T_ID, __default: Any = ...) -> T_CogniteResource:
132
+ return super().pop(__key, __default)
133
+
134
+ def popitem(self) -> tuple[T_ID, T_CogniteResource]:
135
+ return super().popitem()
136
+
137
+ def copy(self) -> "CogniteResourceDict[T_ID, T_CogniteResource]":
138
+ return cast(CogniteResourceDict[T_ID, T_CogniteResource], super().copy())
139
+
140
+
141
+ T_CogniteResourceDict = TypeVar("T_CogniteResourceDict", bound=CogniteResourceDict)
142
+
143
+
144
+ class ViewApplyDict(CogniteResourceDict[ViewId, ViewApply]):
145
+ _RESOURCE = ViewApply
146
+
147
+ @classmethod
148
+ def _as_id(cls, resource: ViewApply) -> ViewId:
149
+ return resource.as_id()
150
+
151
+
152
+ class SpaceApplyDict(CogniteResourceDict[str, SpaceApply]):
153
+ _RESOURCE = SpaceApply
154
+
155
+ @classmethod
156
+ def _as_id(cls, resource: SpaceApply) -> str:
157
+ return resource.space
158
+
159
+
160
+ class ContainerApplyDict(CogniteResourceDict[ContainerId, ContainerApply]):
161
+ _RESOURCE = ContainerApply
162
+
163
+ @classmethod
164
+ def _as_id(cls, resource: ContainerApply) -> ContainerId:
165
+ return resource.as_id()
166
+
167
+
168
+ class DataModelApplyDict(CogniteResourceDict[DataModelId, DataModelApply]):
169
+ _RESOURCE = DataModelApply
170
+
171
+ @classmethod
172
+ def _as_id(cls, resource: DataModelApply) -> DataModelId:
173
+ return resource.as_id()
174
+
175
+
176
+ class NodeApplyDict(CogniteResourceDict[NodeId, NodeApply]):
177
+ _RESOURCE = NodeApply
178
+
179
+ @classmethod
180
+ def _as_id(cls, resource: NodeApply) -> NodeId:
181
+ return resource.as_id()
@@ -78,9 +78,9 @@ class ValidateRulesAgainstCDF(Step):
78
78
  f"and {len(retrieved_views)} views from CDF."
79
79
  )
80
80
 
81
- schema.spaces.extend(retrieved_spaces)
82
- schema.containers.extend(retrieved_containers)
83
- schema.views.extend(retrieved_views)
81
+ schema.spaces.update({space.space: space for space in retrieved_spaces})
82
+ schema.containers.update({container.as_id(): container for container in retrieved_containers})
83
+ schema.views.update({view.as_id(): view for view in retrieved_views})
84
84
 
85
85
  errors = schema.validate()
86
86
  if errors:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cognite-neat
3
- Version: 0.77.0
3
+ Version: 0.77.2
4
4
  Summary: Knowledge graph transformation
5
5
  Home-page: https://cognite-neat.readthedocs-hosted.com/
6
6
  License: Apache-2.0
@@ -1,5 +1,5 @@
1
1
  cognite/neat/__init__.py,sha256=v-rRiDOgZ3sQSMQKq0vgUQZvpeOkoHFXissAx6Ktg84,61
2
- cognite/neat/_version.py,sha256=FsVkDXIxQgpS6bGWK5nz3Q12DD7jjMcehD-qkWurVzM,23
2
+ cognite/neat/_version.py,sha256=kh8YirXq1n0W6XtV5vM5A8L0p7-1zfBuOABzfVzGjbs,23
3
3
  cognite/neat/app/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  cognite/neat/app/api/asgi/metrics.py,sha256=nxFy7L5cChTI0a-zkCiJ59Aq8yLuIJp5c9Dg0wRXtV0,152
5
5
  cognite/neat/app/api/configuration.py,sha256=2U5M6M252swvQPQyooA1EBzFUZNtcTmuSaywfJDgckM,4232
@@ -165,14 +165,14 @@ cognite/neat/rules/exceptions.py,sha256=YLnsbXXJdDSr_szQoioEtOdqDV8PR7RdQjpMP2SW
165
165
  cognite/neat/rules/exporters/__init__.py,sha256=Gn3CjkVKHJF9Po1ZPH4wAJ-sRW9up7b2CpXm-eReV3Q,413
166
166
  cognite/neat/rules/exporters/_base.py,sha256=m63iw8xjlZbZAxGL8mn7pjGf1pW3rVv8C20_RSiu4t0,1511
167
167
  cognite/neat/rules/exporters/_models.py,sha256=vRd0P_YsrZ1eaAGGHfdTeFunaqHdaa0ZtnWiVZBR1nc,1976
168
- cognite/neat/rules/exporters/_rules2dms.py,sha256=_-RLw-SfmopQILKMvXwMkVCMHgNkyto5Z4xHzisniUQ,13530
168
+ cognite/neat/rules/exporters/_rules2dms.py,sha256=US2IO4YTJSF_CDzau1dTpXyeHntJWVSPkMCQoUoKeC0,13688
169
169
  cognite/neat/rules/exporters/_rules2excel.py,sha256=K3D_AC6UZ-cG9ZFkqFvuDiMTdBC9ZUW9_IkkY9KsYW0,14934
170
170
  cognite/neat/rules/exporters/_rules2ontology.py,sha256=NWS3cn2927LQqW_PdQ-92OLIlmIKGNk7xh5yOMAyj94,20120
171
171
  cognite/neat/rules/exporters/_rules2yaml.py,sha256=sOSdnTJ5mXuyAJECdNnNsX6oLvgETptkpgPUQbK0n2w,3026
172
172
  cognite/neat/rules/exporters/_validation.py,sha256=OlKIyf4nhSDehJwFHDQ8Zdf6HpNfW7dSe2s67eywHu4,4078
173
173
  cognite/neat/rules/importers/__init__.py,sha256=zqNbGpvdVhYkLjWx1i9dJ3FXzYGtuQyTydUYsj-BndQ,408
174
174
  cognite/neat/rules/importers/_base.py,sha256=GUiJrYwJ25thI71iS9hCeP_iSZ0Vv8ou3z6MfD07FAk,4274
175
- cognite/neat/rules/importers/_dms2rules.py,sha256=nh9x1j5ZleviuTTRYuOoVK2XgJtpqfh93PUamt8CJxM,18317
175
+ cognite/neat/rules/importers/_dms2rules.py,sha256=UxAatq8WL0rYz4wcopY0wHcBE4JTf--FzflhMxymypY,18274
176
176
  cognite/neat/rules/importers/_dtdl2rules/__init__.py,sha256=CNR-sUihs2mnR1bPMKs3j3L4ds3vFTsrl6YycExZTfU,68
177
177
  cognite/neat/rules/importers/_dtdl2rules/_unit_lookup.py,sha256=wW4saKva61Q_i17guY0dc4OseJDQfqHy_QZBtm0OD6g,12134
178
178
  cognite/neat/rules/importers/_dtdl2rules/dtdl_converter.py,sha256=ysmWUxZ0npwrTB0uiH5jA0v37sfCwowGaYk17IyxPUU,12663
@@ -187,7 +187,7 @@ cognite/neat/rules/importers/_spreadsheet2rules.py,sha256=dKTue97yZlPQagegfdyOWt
187
187
  cognite/neat/rules/importers/_yaml2rules.py,sha256=F0uksSz1A3po5OlRM2152_w5j8D9oYTLB9NFTkSMlWI,4275
188
188
  cognite/neat/rules/issues/__init__.py,sha256=Ms6jgCxCezc5IgTOwCFtXQPtoVFfOvdcXj84_rs917I,563
189
189
  cognite/neat/rules/issues/base.py,sha256=i2aTC-wq3UVW2bj_7wKeuhYxCpMD06Bd9-m00bWcTBs,6438
190
- cognite/neat/rules/issues/dms.py,sha256=7UyVCqLfky6-KR9-pGNDhJhhMpAxuvOXj2FG-OR5kSA,22035
190
+ cognite/neat/rules/issues/dms.py,sha256=LP6RREMg_CNKBwqYZLR7IBozKWzR607HH4JuUD7X9Fk,22893
191
191
  cognite/neat/rules/issues/fileread.py,sha256=ao199mtvhPSW0IA8ZQZ0RzuLIIipYtL0jp6fLqxb4_c,5748
192
192
  cognite/neat/rules/issues/formatters.py,sha256=_ag2bJ9hncOj8pAGJvTTEPs9kTtxbD7vkqvS9Zcnizc,3385
193
193
  cognite/neat/rules/issues/importing.py,sha256=p90847g_TbUAXMyxalcEaWXaPygJoSE5E85dQO4syoo,12288
@@ -202,21 +202,22 @@ cognite/neat/rules/models/_types/_field.py,sha256=74WfCSVbTubpK4n4VsysQqCch6VI8I
202
202
  cognite/neat/rules/models/data_types.py,sha256=lanwkhwG8iHKfjYfia4v2SBTJrMeXOsqaVkVEP2QMXs,6078
203
203
  cognite/neat/rules/models/dms/__init__.py,sha256=Wzyqzz2ZIjpUbDg04CMuuIAw-f2A02DayNeqO9R-2Hw,491
204
204
  cognite/neat/rules/models/dms/_converter.py,sha256=x3u3jLnkknozoXXoAXXOWFHCsppqUwSvWv9wMOJ2F1Y,5706
205
- cognite/neat/rules/models/dms/_exporter.py,sha256=bmU3jh4WfusHszQPtLardfc7F1_0oyntvnbfXcVPbtQ,18809
206
- cognite/neat/rules/models/dms/_rules.py,sha256=DNzl-wiZzGmsa8RFO9fwdjJGfZb9Akj3lEtyS54-t7U,15545
207
- cognite/neat/rules/models/dms/_rules_input.py,sha256=qfInh3JYf7XGEghxPOtIj7GY0f5_aVvnYeUBmfGV9mk,13620
208
- cognite/neat/rules/models/dms/_schema.py,sha256=e8UhfPK3xfBGHfxwgpHlRnh8nfl3Lt2TqPMOvLuryYc,41719
205
+ cognite/neat/rules/models/dms/_exporter.py,sha256=WTokr7gyjrpxW212kZpFfvd7zw09RRVPjAsxe_aizFo,18903
206
+ cognite/neat/rules/models/dms/_rules.py,sha256=ZLdJLdAJGX1l5t1hChEic9TOHdculbWRhiLbUluZRRQ,15568
207
+ cognite/neat/rules/models/dms/_rules_input.py,sha256=2ZGE3nsQyJ7RgdR5o9Wf8XbpSD57ZPbhvMz6H92aJ9g,13633
208
+ cognite/neat/rules/models/dms/_schema.py,sha256=6lJSLPoZAjFnbfFl6dmAJR0xlAsQKi_Obcxp8Lp_t-0,41973
209
209
  cognite/neat/rules/models/dms/_serializer.py,sha256=Zulj__rnaVNtrbGJPkn4dYMfMXWYyRmtNPR2Yb5zYW0,6668
210
- cognite/neat/rules/models/dms/_validation.py,sha256=7rIBBGjQTP4UYJDz1zK32b12SaTz_YeA6iVvX5XAWAo,14273
210
+ cognite/neat/rules/models/dms/_validation.py,sha256=-7bpj1vQybB7P7nqvSc1XjKJhbpIRCXBzm3pdx6pqPQ,14589
211
211
  cognite/neat/rules/models/domain.py,sha256=13OhG-XavE5ipU2ICaYaUhz60volkuVfbJrsp0PhaUU,2993
212
212
  cognite/neat/rules/models/entities.py,sha256=iBG84Jr1qQ7PvkMJUJzJ1oWApeONb1IACixdJSztUhk,16395
213
213
  cognite/neat/rules/models/information/__init__.py,sha256=KvbYxVk38qReGbGTrU_Y3P3Gz6Bfghk5lHSKs8DlTOI,195
214
214
  cognite/neat/rules/models/information/_converter.py,sha256=jzaIk7Q2CeU3TIGULEINwUNNyhWu-VdOW646EjH_FrI,7964
215
215
  cognite/neat/rules/models/information/_rules.py,sha256=YE7X8MsPQv-AVtl4vYtQW99moT45sYk2dI2DDS1YRO0,15546
216
- cognite/neat/rules/models/wrapped_entities.py,sha256=c5GkzOrYrE6SSRzIS2r8OAjhwxXpOoAO1WGc8kwiPPo,6154
216
+ cognite/neat/rules/models/wrapped_entities.py,sha256=ThhjnNNrpgz0HeORIQ8Q894trxP73P7T_TuZj6qH2CU,7157
217
217
  cognite/neat/utils/__init__.py,sha256=l5Nyqhqo25bcQXCOb_lk01cr-UXsG8cczz_y_I0u6bg,68
218
218
  cognite/neat/utils/auxiliary.py,sha256=E2-YtddzScvN7l7j0kNYIMlfqIUT9NWMqLpcJYPK4rY,309
219
219
  cognite/neat/utils/cdf.py,sha256=dTg8wnm2916yhWT_2Jg9_PlauHCbmnuNgmpqrGU8eO0,711
220
+ cognite/neat/utils/cdf_classes.py,sha256=NEmz5UprBlqfqZnqJkRk5xjSpzazwHbhcWsMH_GNxP8,5831
220
221
  cognite/neat/utils/cdf_loaders/__init__.py,sha256=s2aPR5XLo6WZ0ybstAJlcGFYkA7CyHW1XO-NYpL0V6o,483
221
222
  cognite/neat/utils/cdf_loaders/_base.py,sha256=j85HINIx4poGD-0dN3JPHTqjOS1XhCxv7G9s1gC1GBo,2057
222
223
  cognite/neat/utils/cdf_loaders/_data_modeling.py,sha256=RoIj2cL_j3vP6e4BlCExZU8d96p3dLitU9nsIIyesLc,11336
@@ -255,7 +256,7 @@ cognite/neat/workflows/steps/lib/current/graph_loader.py,sha256=HfGg1HRZhbV58TFu
255
256
  cognite/neat/workflows/steps/lib/current/graph_store.py,sha256=r7VTxdaz8jJQU7FJbnRDMxvEYbSAZFNMABhPyfNwiFk,6295
256
257
  cognite/neat/workflows/steps/lib/current/rules_exporter.py,sha256=wUQAZXWBCqWXe0241QSREtnNTii_tSmOkeiSPwNQRjk,22898
257
258
  cognite/neat/workflows/steps/lib/current/rules_importer.py,sha256=yDq06cvxLvEpSnTXTjwhxDie_MzHa3wO1A4cbKnrH6c,10338
258
- cognite/neat/workflows/steps/lib/current/rules_validator.py,sha256=fDRQiRHN9Cuph38-WruK0T1UG5H448S_GsbzdOpi0h4,4729
259
+ cognite/neat/workflows/steps/lib/current/rules_validator.py,sha256=LwF9lXlnuPOxDSsOMMTHBi2BHc5rk08IF5zahS9yQuw,4844
259
260
  cognite/neat/workflows/steps/lib/io/__init__.py,sha256=k7IPbIq3ey19oRc5sA_15F99-O6dxzqbm1LihGRRo5A,32
260
261
  cognite/neat/workflows/steps/lib/io/io_steps.py,sha256=QAGypoi1vP32BRiIgBZ0B4qsbFMcwhzpRiVUUnWysLA,16874
261
262
  cognite/neat/workflows/steps/lib/legacy/__init__.py,sha256=725aFzVqhE0tbVOAW70zWXTGKFiYImVupRZ4C5_IkUo,274
@@ -271,8 +272,8 @@ cognite/neat/workflows/steps_registry.py,sha256=fkTX14ZA7_gkUYfWIlx7A1XbCidvqR23
271
272
  cognite/neat/workflows/tasks.py,sha256=dqlJwKAb0jlkl7abbY8RRz3m7MT4SK8-7cntMWkOYjw,788
272
273
  cognite/neat/workflows/triggers.py,sha256=_BLNplzoz0iic367u1mhHMHiUrCwP-SLK6_CZzfODX0,7071
273
274
  cognite/neat/workflows/utils.py,sha256=gKdy3RLG7ctRhbCRwaDIWpL9Mi98zm56-d4jfHDqP1E,453
274
- cognite_neat-0.77.0.dist-info/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
275
- cognite_neat-0.77.0.dist-info/METADATA,sha256=aydcanjya23Af6cnUR8ZTbMURCUXiMSTGMjxvJgydfw,9316
276
- cognite_neat-0.77.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
277
- cognite_neat-0.77.0.dist-info/entry_points.txt,sha256=61FPqiWb25vbqB0KI7znG8nsg_ibLHBvTjYnkPvNFso,50
278
- cognite_neat-0.77.0.dist-info/RECORD,,
275
+ cognite_neat-0.77.2.dist-info/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
276
+ cognite_neat-0.77.2.dist-info/METADATA,sha256=3XmTaOBYr0Q856UUs19-zkc2BAeUTudgKn2LoMgHW6Q,9316
277
+ cognite_neat-0.77.2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
278
+ cognite_neat-0.77.2.dist-info/entry_points.txt,sha256=61FPqiWb25vbqB0KI7znG8nsg_ibLHBvTjYnkPvNFso,50
279
+ cognite_neat-0.77.2.dist-info/RECORD,,