cognite-neat 0.70.0__py3-none-any.whl → 0.70.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.

cognite/neat/_version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.70.0"
1
+ __version__ = "0.70.1"
@@ -1,7 +1,7 @@
1
1
  import warnings
2
2
  from collections.abc import Collection, Iterable
3
3
  from pathlib import Path
4
- from typing import Literal, TypeAlias
4
+ from typing import Literal, TypeAlias, cast
5
5
 
6
6
  from cognite.client import CogniteClient
7
7
  from cognite.client.data_classes._base import CogniteResourceList
@@ -9,7 +9,8 @@ from cognite.client.exceptions import CogniteAPIError
9
9
 
10
10
  from cognite.neat.rules._shared import Rules
11
11
  from cognite.neat.rules.models._rules import InformationRules
12
- from cognite.neat.rules.models._rules.dms_architect_rules import DMSRules
12
+ from cognite.neat.rules.models._rules.base import ExtensionCategory, SheetList
13
+ from cognite.neat.rules.models._rules.dms_architect_rules import DMSContainer, DMSRules
13
14
  from cognite.neat.rules.models._rules.dms_schema import DMSSchema, PipelineSchema
14
15
  from cognite.neat.utils.cdf_loaders import (
15
16
  ContainerLoader,
@@ -107,14 +108,53 @@ class DMSExporter(CDFExporter[DMSSchema]):
107
108
 
108
109
  def export(self, rules: Rules) -> DMSSchema:
109
110
  if isinstance(rules, DMSRules):
110
- return rules.as_schema(self.standardize_casing, self.export_pipeline, self.instance_space)
111
+ dms_rules = rules
111
112
  elif isinstance(rules, InformationRules):
112
- return rules.as_dms_architect_rules().as_schema(
113
- self.standardize_casing, self.export_pipeline, self.instance_space
114
- )
113
+ dms_rules = rules.as_dms_architect_rules()
115
114
  else:
116
115
  raise ValueError(f"{type(rules).__name__} cannot be exported to DMS")
117
116
 
117
+ is_solution_model = (
118
+ dms_rules.reference and dms_rules.metadata.external_id != dms_rules.reference.metadata.external_id
119
+ )
120
+ is_new_model = dms_rules.reference is None
121
+ if is_new_model or is_solution_model:
122
+ return dms_rules.as_schema(self.standardize_casing, self.export_pipeline, self.instance_space)
123
+
124
+ # This is an extension of an existing model.
125
+ reference_rules = cast(DMSRules, dms_rules.reference).copy(deep=True)
126
+ reference_schema = reference_rules.as_schema(self.standardize_casing, self.export_pipeline)
127
+
128
+ # Todo Move this to an appropriate location
129
+ # Merging Reference with User Rules
130
+ combined_rules = dms_rules.copy(deep=True)
131
+ existing_containers = {container.class_ for container in combined_rules.containers or []}
132
+ if combined_rules.containers is None:
133
+ combined_rules.containers = SheetList[DMSContainer](data=[])
134
+ for container in reference_rules.containers or []:
135
+ if container.class_ not in existing_containers:
136
+ container.reference = None
137
+ combined_rules.containers.append(container)
138
+ existing_views = {view.class_ for view in combined_rules.views}
139
+ for view in reference_rules.views:
140
+ if view.class_ not in existing_views:
141
+ view.reference = None
142
+ combined_rules.views.append(view)
143
+ existing_properties = {(property_.class_, property_.property_) for property_ in combined_rules.properties}
144
+ for property_ in reference_rules.properties:
145
+ if (property_.class_, property_.property_) not in existing_properties:
146
+ property_.reference = None
147
+ combined_rules.properties.append(property_)
148
+
149
+ schema = combined_rules.as_schema(self.standardize_casing, self.export_pipeline, self.instance_space)
150
+
151
+ if dms_rules.metadata.extension in (ExtensionCategory.addition, ExtensionCategory.reshape):
152
+ # We do not freeze views as they might be changed, even for addition,
153
+ # in case, for example, new properties are added. The validation will catch this.
154
+ schema.frozen_ids.update(set(reference_schema.containers.as_ids()))
155
+ schema.frozen_ids.update(set(reference_schema.node_types.as_ids()))
156
+ return schema
157
+
118
158
  def export_to_cdf(self, rules: Rules, client: CogniteClient, dry_run: bool = False) -> Iterable[UploadResult]:
119
159
  schema = self.export(rules)
120
160
  to_export: list[tuple[CogniteResourceList, ResourceLoader]] = []
@@ -136,7 +176,9 @@ class DMSExporter(CDFExporter[DMSSchema]):
136
176
  redeploy_data_model = False
137
177
 
138
178
  for items, loader in to_export:
139
- item_ids = loader.get_ids(items)
179
+ all_item_ids = loader.get_ids(items)
180
+ skipped = sum(1 for item_id in all_item_ids if item_id in schema.frozen_ids)
181
+ item_ids = [item_id for item_id in all_item_ids if item_id not in schema.frozen_ids]
140
182
  cdf_items = loader.retrieve(item_ids)
141
183
  cdf_item_by_id = {loader.get_id(item): item for item in cdf_items}
142
184
  to_create, to_update, unchanged, to_delete = [], [], [], []
@@ -163,7 +205,6 @@ class DMSExporter(CDFExporter[DMSSchema]):
163
205
  created = len(to_create)
164
206
  failed_created = 0
165
207
 
166
- skipped = 0
167
208
  if self.existing_handling in ["update", "force"]:
168
209
  changed = len(to_update)
169
210
  failed_changed = 0
@@ -211,7 +211,7 @@ class DMSContainer(SheetEntity):
211
211
  container_id = self.container.as_id(default_space, standardize_casing)
212
212
  constraints: dict[str, dm.Constraint] = {}
213
213
  for constraint in self.constraint or []:
214
- requires = dm.RequiresConstraint(constraint.as_id(default_space))
214
+ requires = dm.RequiresConstraint(constraint.as_id(default_space, standardize_casing))
215
215
  constraints[f"{constraint.space}_{constraint.external_id}"] = requires
216
216
 
217
217
  return dm.ContainerApply(
@@ -796,7 +796,7 @@ class _DMSExporter:
796
796
  parent_views = {parent for view in views for parent in view.implements or []}
797
797
  node_type_flag = False
798
798
  for view in views:
799
- ref_containers = view.referenced_containers()
799
+ ref_containers = sorted(view.referenced_containers(), key=lambda c: c.as_tuple())
800
800
  has_data = dm.filters.HasData(containers=list(ref_containers)) if ref_containers else None
801
801
  node_type = dm.filters.Equals(["node", "type"], {"space": view.space, "externalId": view.external_id})
802
802
  if view.as_id() in parent_views:
@@ -45,6 +45,9 @@ class DMSSchema:
45
45
  views: dm.ViewApplyList = field(default_factory=lambda: dm.ViewApplyList([]))
46
46
  containers: dm.ContainerApplyList = field(default_factory=lambda: dm.ContainerApplyList([]))
47
47
  node_types: dm.NodeApplyList = field(default_factory=lambda: dm.NodeApplyList([]))
48
+ # The frozen ids are parts of the schema that should not be modified or deleted.
49
+ # This is used the exporting the schema.
50
+ frozen_ids: set[dm.ViewId | dm.ContainerId | dm.NodeId] = field(default_factory=set)
48
51
 
49
52
  _FIELD_NAME_BY_RESOURCE_TYPE: ClassVar[dict[str, str]] = {
50
53
  "container": "containers",
@@ -304,7 +304,7 @@ class InformationRules(RuleModel):
304
304
  kwargs = vars(info)
305
305
  default_prefix = f"{self.metadata.prefix}:" if self.metadata.prefix else ""
306
306
 
307
- field_names = ["Class"] if info.by_alias else ["class_"]
307
+ field_names = ["Class", "Value Type"] if info.by_alias else ["class_", "value_type"]
308
308
  properties = []
309
309
  for prop in self.properties:
310
310
  dumped = prop.model_dump(**kwargs)
@@ -392,7 +392,7 @@ class _InformationRulesConverter:
392
392
  class_=cls_.class_,
393
393
  view=ViewPropEntity(prefix=cls_.class_.prefix, suffix=cls_.class_.suffix, version=cls_.class_.version),
394
394
  description=cls_.description,
395
- implements=self._get_view_implements(cls_),
395
+ implements=self._get_view_implements(cls_, info_metadata),
396
396
  )
397
397
  for cls_ in self.information.classes
398
398
  ]
@@ -507,15 +507,19 @@ class _InformationRulesConverter:
507
507
  return ContainerEntity(prefix=prop.class_.prefix, suffix=prop.class_.suffix), prop.property_
508
508
 
509
509
  @classmethod
510
- def _get_view_implements(cls, cls_: InformationClass) -> list[ViewEntity]:
511
- if isinstance(cls_.reference, ReferenceEntity):
512
- return [
513
- ViewPropEntity(
514
- prefix=cls_.reference.prefix, suffix=cls_.reference.suffix, version=cls_.reference.version
515
- )
510
+ def _get_view_implements(cls, cls_: InformationClass, metadata: InformationMetadata) -> list[ViewEntity]:
511
+ if isinstance(cls_.reference, ReferenceEntity) and cls_.reference.prefix != metadata.prefix:
512
+ # We use the reference for implements if it is in a different namespace
513
+ implements = [
514
+ ViewEntity(prefix=cls_.reference.prefix, suffix=cls_.reference.suffix, version=cls_.reference.version)
516
515
  ]
517
516
  else:
518
- return [
517
+ implements = []
518
+
519
+ implements.extend(
520
+ [
519
521
  ViewEntity(prefix=parent.prefix, suffix=parent.suffix, version=parent.version)
520
522
  for parent in cls_.parent or []
521
523
  ]
524
+ )
525
+ return implements
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cognite-neat
3
- Version: 0.70.0
3
+ Version: 0.70.1
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=3IhgUqYnqMysoIwxT7jN8hqTm0UVFXntZR74E9Nb9vI,23
2
+ cognite/neat/_version.py,sha256=WVjSRSd2zgGQFanscfNpVjo_q_ShT12r7ukn4JBk-AU,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=xnKdBE_dtq1nRvKa79YGA_wimI5UhoSRuBQz4LkLzQw,4606
@@ -113,7 +113,7 @@ cognite/neat/rules/exporter/_validation.py,sha256=CnEer181-EdnWl3yOuZJKOJ80W7H7q
113
113
  cognite/neat/rules/exporters/__init__.py,sha256=Gn3CjkVKHJF9Po1ZPH4wAJ-sRW9up7b2CpXm-eReV3Q,413
114
114
  cognite/neat/rules/exporters/_base.py,sha256=aRCzRjGDoXILkGvASev2UjVvLXrVCRTFiKgYwzJZqAo,1518
115
115
  cognite/neat/rules/exporters/_models.py,sha256=f_RbFhoyD27z6Dsk4upYMHp7JHZRCfIvZsEzH5JSvtc,1645
116
- cognite/neat/rules/exporters/_rules2dms.py,sha256=R39FpCNx7l5-A2yheR-IPT5fHDviq-6OxyqF9UC2yt4,9688
116
+ cognite/neat/rules/exporters/_rules2dms.py,sha256=5KUVBYyGr4Q4YVqBs6taTeh8nDVM1L-ABGFTpcaph4c,12129
117
117
  cognite/neat/rules/exporters/_rules2excel.py,sha256=uK-aS9sBwXUCFQLIO1jciBQrB4w7ySF6MafDqG23hrQ,9080
118
118
  cognite/neat/rules/exporters/_rules2ontology.py,sha256=70T28d1tcT179kt5yOZQlLgAQ67uydz3XbhbA10IRuI,19768
119
119
  cognite/neat/rules/exporters/_rules2yaml.py,sha256=HKgFlpgD7U2vWLQC_VdSvkDk19QgeVAd_J8wQ9ZgrN8,3038
@@ -163,10 +163,10 @@ cognite/neat/rules/models/_rules/_types/_base.py,sha256=EsTqjXUP0zpuQ-Z_BMP-00rJ
163
163
  cognite/neat/rules/models/_rules/_types/_field.py,sha256=dOVAU1jWCupFVnrYYwLfI-nNUC4rv4vXHMzpiObtWiw,10295
164
164
  cognite/neat/rules/models/_rules/_types/_value.py,sha256=I7Ke388M2NOi0U5F9kAzOjE0O4ZXbIxefupgDAjnISM,6079
165
165
  cognite/neat/rules/models/_rules/base.py,sha256=9DgtdCmpz84sMFxZB_stWkalVbjA4HQKsTMpSjjOVLU,10635
166
- cognite/neat/rules/models/_rules/dms_architect_rules.py,sha256=K0A8iJN8FRfiZQO-jhCBii1EGcALtgth9VZbo56PSWQ,49323
167
- cognite/neat/rules/models/_rules/dms_schema.py,sha256=KmxMTa9Iircc_3sUGMg2zQkSHjxLmtAwaXxzssjfAWQ,30010
166
+ cognite/neat/rules/models/_rules/dms_architect_rules.py,sha256=aevTRWHscgYBih4DqdMzKPAHpj5NVOrCpld0sTp-5Qk,49379
167
+ cognite/neat/rules/models/_rules/dms_schema.py,sha256=-ru40beGY2WJvf9_sd5eO2Wh8x2qLQ2UmgzExloBWac,30229
168
168
  cognite/neat/rules/models/_rules/domain_rules.py,sha256=mOE4M6wOurmnAehxbnxvP9vIVXsFuKSiyMmD1shXKpA,2051
169
- cognite/neat/rules/models/_rules/information_rules.py,sha256=9Wjhpq5itp1CblRMFYKckFzeQDUp8kkArFzbEEK_lUA,20732
169
+ cognite/neat/rules/models/_rules/information_rules.py,sha256=e_SesgvMbzgC9WMFx0b_6qrpOIQvoQ_kXUiXrSYC9RI,20984
170
170
  cognite/neat/rules/models/raw_rules.py,sha256=Y7ZVKyvLhX0s6WdwztbFiYFj4EijGEfjtBmv0ibRmmg,12368
171
171
  cognite/neat/rules/models/rdfpath.py,sha256=kk1dqxl3n2W_vSQtpSJri2O4nCXnCDZB2lhLsLV1PN0,7344
172
172
  cognite/neat/rules/models/rules.py,sha256=ECKrQEtoiQqtR8W-rKMAWmODpHeHhI8Qzf3TwCa3dy8,51063
@@ -227,8 +227,8 @@ cognite/neat/workflows/steps_registry.py,sha256=PZVoHX4d6Vmjz6XzUFnFFWMCnrVnqkUC
227
227
  cognite/neat/workflows/tasks.py,sha256=dqlJwKAb0jlkl7abbY8RRz3m7MT4SK8-7cntMWkOYjw,788
228
228
  cognite/neat/workflows/triggers.py,sha256=_BLNplzoz0iic367u1mhHMHiUrCwP-SLK6_CZzfODX0,7071
229
229
  cognite/neat/workflows/utils.py,sha256=gKdy3RLG7ctRhbCRwaDIWpL9Mi98zm56-d4jfHDqP1E,453
230
- cognite_neat-0.70.0.dist-info/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
231
- cognite_neat-0.70.0.dist-info/METADATA,sha256=3SfpZKbevbpJ1NnjVPu_CA3rlMNF_fPMoRKj1JFGRMs,9321
232
- cognite_neat-0.70.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
233
- cognite_neat-0.70.0.dist-info/entry_points.txt,sha256=61FPqiWb25vbqB0KI7znG8nsg_ibLHBvTjYnkPvNFso,50
234
- cognite_neat-0.70.0.dist-info/RECORD,,
230
+ cognite_neat-0.70.1.dist-info/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
231
+ cognite_neat-0.70.1.dist-info/METADATA,sha256=olXq5x4vGn839BRr4LQBKuE8gsBpqDuiUW57iH9he1k,9321
232
+ cognite_neat-0.70.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
233
+ cognite_neat-0.70.1.dist-info/entry_points.txt,sha256=61FPqiWb25vbqB0KI7znG8nsg_ibLHBvTjYnkPvNFso,50
234
+ cognite_neat-0.70.1.dist-info/RECORD,,