cognite-neat 0.99.0__py3-none-any.whl → 0.100.0__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 (84) hide show
  1. cognite/neat/_client/_api/data_modeling_loaders.py +390 -116
  2. cognite/neat/_client/_api/schema.py +63 -2
  3. cognite/neat/_client/data_classes/data_modeling.py +4 -0
  4. cognite/neat/_client/data_classes/schema.py +2 -348
  5. cognite/neat/_constants.py +27 -4
  6. cognite/neat/_graph/extractors/_base.py +7 -0
  7. cognite/neat/_graph/extractors/_classic_cdf/_classic.py +28 -18
  8. cognite/neat/_graph/loaders/_rdf2dms.py +52 -13
  9. cognite/neat/_graph/transformers/__init__.py +3 -3
  10. cognite/neat/_graph/transformers/_classic_cdf.py +135 -56
  11. cognite/neat/_issues/_base.py +26 -17
  12. cognite/neat/_issues/errors/__init__.py +4 -2
  13. cognite/neat/_issues/errors/_external.py +7 -0
  14. cognite/neat/_issues/errors/_properties.py +2 -7
  15. cognite/neat/_issues/errors/_resources.py +1 -1
  16. cognite/neat/_issues/warnings/__init__.py +6 -2
  17. cognite/neat/_issues/warnings/_external.py +9 -1
  18. cognite/neat/_issues/warnings/_resources.py +41 -2
  19. cognite/neat/_issues/warnings/user_modeling.py +4 -4
  20. cognite/neat/_rules/_constants.py +2 -6
  21. cognite/neat/_rules/analysis/_base.py +15 -5
  22. cognite/neat/_rules/analysis/_dms.py +20 -0
  23. cognite/neat/_rules/analysis/_information.py +22 -0
  24. cognite/neat/_rules/exporters/_base.py +3 -5
  25. cognite/neat/_rules/exporters/_rules2dms.py +190 -200
  26. cognite/neat/_rules/importers/__init__.py +1 -3
  27. cognite/neat/_rules/importers/_base.py +1 -1
  28. cognite/neat/_rules/importers/_dms2rules.py +3 -25
  29. cognite/neat/_rules/importers/_rdf/__init__.py +5 -0
  30. cognite/neat/_rules/importers/_rdf/_base.py +34 -11
  31. cognite/neat/_rules/importers/_rdf/_imf2rules.py +91 -0
  32. cognite/neat/_rules/importers/_rdf/_inference2rules.py +40 -7
  33. cognite/neat/_rules/importers/_rdf/_owl2rules.py +80 -0
  34. cognite/neat/_rules/importers/_rdf/_shared.py +138 -441
  35. cognite/neat/_rules/models/_base_rules.py +19 -0
  36. cognite/neat/_rules/models/_types.py +5 -0
  37. cognite/neat/_rules/models/dms/__init__.py +2 -0
  38. cognite/neat/_rules/models/dms/_exporter.py +247 -123
  39. cognite/neat/_rules/models/dms/_rules.py +7 -49
  40. cognite/neat/_rules/models/dms/_rules_input.py +8 -3
  41. cognite/neat/_rules/models/dms/_validation.py +421 -123
  42. cognite/neat/_rules/models/entities/_multi_value.py +3 -0
  43. cognite/neat/_rules/models/information/__init__.py +2 -0
  44. cognite/neat/_rules/models/information/_rules.py +17 -61
  45. cognite/neat/_rules/models/information/_rules_input.py +11 -2
  46. cognite/neat/_rules/models/information/_validation.py +107 -11
  47. cognite/neat/_rules/models/mapping/_classic2core.py +1 -1
  48. cognite/neat/_rules/models/mapping/_classic2core.yaml +8 -4
  49. cognite/neat/_rules/transformers/__init__.py +2 -1
  50. cognite/neat/_rules/transformers/_converters.py +163 -61
  51. cognite/neat/_rules/transformers/_mapping.py +132 -2
  52. cognite/neat/_rules/transformers/_pipelines.py +1 -1
  53. cognite/neat/_rules/transformers/_verification.py +29 -4
  54. cognite/neat/_session/_base.py +46 -60
  55. cognite/neat/_session/_mapping.py +105 -5
  56. cognite/neat/_session/_prepare.py +49 -14
  57. cognite/neat/_session/_read.py +50 -4
  58. cognite/neat/_session/_set.py +1 -0
  59. cognite/neat/_session/_to.py +38 -12
  60. cognite/neat/_session/_wizard.py +5 -0
  61. cognite/neat/_session/engine/_interface.py +3 -2
  62. cognite/neat/_session/exceptions.py +4 -0
  63. cognite/neat/_store/_base.py +79 -19
  64. cognite/neat/_utils/collection_.py +22 -0
  65. cognite/neat/_utils/rdf_.py +30 -4
  66. cognite/neat/_version.py +2 -2
  67. cognite/neat/_workflows/steps/lib/current/rules_exporter.py +3 -91
  68. cognite/neat/_workflows/steps/lib/current/rules_importer.py +2 -16
  69. cognite/neat/_workflows/steps/lib/current/rules_validator.py +3 -5
  70. {cognite_neat-0.99.0.dist-info → cognite_neat-0.100.0.dist-info}/METADATA +1 -1
  71. {cognite_neat-0.99.0.dist-info → cognite_neat-0.100.0.dist-info}/RECORD +74 -82
  72. cognite/neat/_rules/importers/_rdf/_imf2rules/__init__.py +0 -3
  73. cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2classes.py +0 -86
  74. cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2metadata.py +0 -29
  75. cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2properties.py +0 -130
  76. cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2rules.py +0 -154
  77. cognite/neat/_rules/importers/_rdf/_owl2rules/__init__.py +0 -3
  78. cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2classes.py +0 -58
  79. cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2metadata.py +0 -65
  80. cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2properties.py +0 -59
  81. cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2rules.py +0 -39
  82. {cognite_neat-0.99.0.dist-info → cognite_neat-0.100.0.dist-info}/LICENSE +0 -0
  83. {cognite_neat-0.99.0.dist-info → cognite_neat-0.100.0.dist-info}/WHEEL +0 -0
  84. {cognite_neat-0.99.0.dist-info → cognite_neat-0.100.0.dist-info}/entry_points.txt +0 -0
@@ -2,6 +2,8 @@ import functools
2
2
  from collections.abc import Callable
3
3
  from typing import Any
4
4
 
5
+ from cognite.neat._issues.errors import CDFMissingClientError
6
+
5
7
  from ._collector import _COLLECTOR
6
8
 
7
9
  try:
@@ -27,6 +29,8 @@ def _session_method_wrapper(func: Callable, cls_name: str):
27
29
  except NeatSessionError as e:
28
30
  action = _get_action()
29
31
  print(f"{_PREFIX} Cannot {action}: {e}")
32
+ except CDFMissingClientError as e:
33
+ print(f"{_PREFIX} {e.as_message()}")
30
34
  except ModuleNotFoundError as e:
31
35
  if e.name == "neatengine":
32
36
  action = _get_action()
@@ -174,34 +174,68 @@ class NeatGraphStore:
174
174
  self._add_triples(extractor.extract())
175
175
 
176
176
  if success:
177
- self.provenance.append(
178
- Change.record(
179
- activity=f"{type(extractor).__name__}",
180
- start=_start,
181
- end=datetime.now(timezone.utc),
182
- description=f"Extracted triples to graph store using {type(extractor).__name__}",
183
- )
177
+ _end = datetime.now(timezone.utc)
178
+ # Need to do the hasattr in case the extractor comes from NeatEngine.
179
+ activities = (
180
+ extractor._get_activity_names()
181
+ if hasattr(extractor, "_get_activity_names")
182
+ else [type(extractor).__name__]
184
183
  )
184
+ for activity in activities:
185
+ self.provenance.append(
186
+ Change.record(
187
+ activity=activity,
188
+ start=_start,
189
+ end=_end,
190
+ description=f"Extracted triples to graph store using {type(extractor).__name__}",
191
+ )
192
+ )
185
193
 
186
- def read(self, class_: str) -> Iterable[tuple[str, dict[str | InstanceType, list[str]]]]:
187
- """Read instances for given view from the graph store."""
188
-
189
- if not self.rules:
194
+ def _read_via_rules_linkage(
195
+ self, class_neat_id: URIRef, property_link_pairs: dict[str, URIRef] | None
196
+ ) -> Iterable[tuple[str, dict[str | InstanceType, list[str]]]]:
197
+ if self.rules is None:
190
198
  warnings.warn("Rules not found in graph store!", stacklevel=2)
191
- return None
199
+ return
200
+
201
+ if cls := InformationAnalysis(self.rules).classes_by_neat_id.get(class_neat_id):
202
+ if property_link_pairs:
203
+ property_renaming_config = {
204
+ prop_uri: prop_name
205
+ for prop_name, prop_neat_id in property_link_pairs.items()
206
+ if (
207
+ prop_uri := InformationAnalysis(self.rules).neat_id_to_transformation_property_uri(prop_neat_id)
208
+ )
209
+ }
210
+
211
+ yield from self._read_via_class_entity(cls.class_, property_renaming_config)
212
+ return
213
+ else:
214
+ warnings.warn("Rules not linked", stacklevel=2)
215
+ return
216
+ else:
217
+ warnings.warn("Class with neat id {class_neat_id} found in rules", stacklevel=2)
218
+ return
192
219
 
193
- class_entity = ClassEntity(prefix=self.rules.metadata.prefix, suffix=class_)
220
+ def _read_via_class_entity(
221
+ self,
222
+ class_entity: ClassEntity,
223
+ property_renaming_config: dict[URIRef, str] | None = None,
224
+ ) -> Iterable[tuple[str, dict[str | InstanceType, list[str]]]]:
225
+ if self.rules is None:
226
+ warnings.warn("Rules not found in graph store!", stacklevel=2)
227
+ return
194
228
 
195
229
  if class_entity not in [definition.class_ for definition in self.rules.classes]:
196
230
  warnings.warn("Desired type not found in graph!", stacklevel=2)
197
- return None
231
+ return
198
232
 
199
233
  if not (class_uri := InformationAnalysis(self.rules).class_uri(class_entity)):
200
234
  warnings.warn(
201
- f"Class {class_} does not have namespace defined for prefix {class_entity.prefix} Rules!",
235
+ f"Class {class_entity.suffix} does not have namespace defined for prefix {class_entity.prefix} Rules!",
202
236
  stacklevel=2,
203
237
  )
204
- return None
238
+ return
205
239
 
206
240
  has_hop_transformations = InformationAnalysis(self.rules).has_hop_transformations()
207
241
  has_self_reference_transformations = InformationAnalysis(
@@ -221,13 +255,15 @@ class NeatGraphStore:
221
255
  msg,
222
256
  stacklevel=2,
223
257
  )
224
- return None
258
+ return
225
259
 
226
260
  # get all the instances for give class_uri
227
261
  instance_ids = self.queries.list_instances_ids_of_class(class_uri)
228
262
 
229
263
  # get potential property renaming config
230
- property_renaming_config = InformationAnalysis(self.rules).define_property_renaming_config(class_entity)
264
+ property_renaming_config = property_renaming_config or InformationAnalysis(
265
+ self.rules
266
+ ).define_property_renaming_config(class_entity)
231
267
 
232
268
  # get property types to guide process of removing or not namespaces from results
233
269
  property_types = InformationAnalysis(self.rules).property_types(class_entity)
@@ -235,12 +271,36 @@ class NeatGraphStore:
235
271
  for instance_id in instance_ids:
236
272
  if res := self.queries.describe(
237
273
  instance_id=instance_id,
238
- instance_type=class_,
274
+ instance_type=class_entity.suffix,
239
275
  property_renaming_config=property_renaming_config,
240
276
  property_types=property_types,
241
277
  ):
242
278
  yield res
243
279
 
280
+ def read(
281
+ self,
282
+ class_: str,
283
+ ) -> Iterable[tuple[str, dict[str | InstanceType, list[str]]]]:
284
+ """Read instances for given class from the graph store.
285
+
286
+ !!! note "Assumption"
287
+ This method assumes that the class_ belongs to the same (name)space as
288
+ the rules which are attached to the graph store.
289
+
290
+ """
291
+
292
+ if not self.rules:
293
+ warnings.warn("Rules not found in graph store!", stacklevel=2)
294
+ return
295
+
296
+ class_entity = ClassEntity(prefix=self.rules.metadata.prefix, suffix=class_)
297
+
298
+ if class_entity not in [definition.class_ for definition in self.rules.classes]:
299
+ warnings.warn("Desired type not found in graph!", stacklevel=2)
300
+ return
301
+
302
+ yield from self._read_via_class_entity(class_entity)
303
+
244
304
  def _parse_file(
245
305
  self,
246
306
  filepath: Path,
@@ -2,6 +2,8 @@ from collections import Counter
2
2
  from collections.abc import Iterable, Sequence
3
3
  from typing import TypeVar
4
4
 
5
+ from cognite.neat._constants import IN_PYODIDE
6
+
5
7
  T_Element = TypeVar("T_Element")
6
8
 
7
9
 
@@ -21,3 +23,23 @@ def chunker(sequence: Sequence[T_Element], chunk_size: int) -> Iterable[Sequence
21
23
 
22
24
  def remove_list_elements(input_list: list, elements_to_remove: list) -> list:
23
25
  return [element for element in input_list if element not in elements_to_remove]
26
+
27
+
28
+ def iterate_progress_bar(iterable: Iterable[T_Element], total: int, description: str) -> Iterable[T_Element]:
29
+ if IN_PYODIDE:
30
+ try:
31
+ from tqdm import tqdm # type: ignore [import]
32
+ except ModuleNotFoundError:
33
+ return iterable
34
+ return tqdm(iterable, total=total, desc=description)
35
+ # Progress bar from rich requires multi-threading, which is not supported in Pyodide
36
+ try:
37
+ from rich.progress import track
38
+ except ModuleNotFoundError:
39
+ return iterable
40
+
41
+ return track(
42
+ iterable,
43
+ total=total,
44
+ description=description,
45
+ )
@@ -115,13 +115,15 @@ def as_neat_compliant_uri(uri: URIRef) -> URIRef:
115
115
  return URIRef(f"{namespace}{compliant_uri}")
116
116
 
117
117
 
118
- def convert_rdflib_content(content: RdfLiteral | URIRef | dict | list) -> Any:
119
- if isinstance(content, RdfLiteral) or isinstance(content, URIRef):
118
+ def convert_rdflib_content(content: RdfLiteral | URIRef | dict | list, remove_namespace: bool = False) -> Any:
119
+ if isinstance(content, RdfLiteral):
120
120
  return content.toPython()
121
+ elif isinstance(content, URIRef):
122
+ return remove_namespace_from_uri(content) if remove_namespace else content.toPython()
121
123
  elif isinstance(content, dict):
122
- return {key: convert_rdflib_content(value) for key, value in content.items()}
124
+ return {key: convert_rdflib_content(value, remove_namespace) for key, value in content.items()}
123
125
  elif isinstance(content, list):
124
- return [convert_rdflib_content(item) for item in content]
126
+ return [convert_rdflib_content(item, remove_namespace) for item in content]
125
127
  else:
126
128
  return content
127
129
 
@@ -206,6 +208,30 @@ def add_triples_in_batch(graph: Graph, triples: Iterable[Triple], batch_size: in
206
208
  check_commit(force_commit=True)
207
209
 
208
210
 
211
+ def remove_triples_in_batch(graph: Graph, triples: Iterable[Triple], batch_size: int = 10_000) -> None:
212
+ """Removes triples from the graph store in batches.
213
+
214
+ Args:
215
+ triples: list of triples to be removed from the graph store
216
+ batch_size: Batch size of triples per commit, by default 10_000
217
+ """
218
+ batch_count = 0
219
+
220
+ def check_commit(force_commit: bool = False):
221
+ """Commit nodes to the graph if batch counter is reached or if force_commit is True"""
222
+ nonlocal batch_count
223
+ batch_count += 1
224
+ if force_commit or batch_count >= batch_size:
225
+ graph.commit()
226
+ batch_count = 0
227
+ return
228
+
229
+ for triple in triples:
230
+ graph.remove(triple)
231
+ check_commit()
232
+ check_commit(force_commit=True)
233
+
234
+
209
235
  def remove_instance_ids_in_batch(graph: Graph, instance_ids: Iterable[URIRef], batch_size: int = 1_000) -> None:
210
236
  """Removes all triples related to the given instances in the graph store in batches.
211
237
 
cognite/neat/_version.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "0.99.0"
2
- __engine__ = "^1.0.3"
1
+ __version__ = "0.100.0"
2
+ __engine__ = "^2.0.1"
@@ -21,7 +21,6 @@ __all__ = [
21
21
  "RulesToOntology",
22
22
  "RulesToSHACL",
23
23
  "RulesToSemanticDataModel",
24
- "RulesToCDFTransformations",
25
24
  "DeleteDataModelFromCDF",
26
25
  ]
27
26
 
@@ -68,7 +67,7 @@ class DeleteDataModelFromCDF(Step):
68
67
  if self.configs is None or self.data_store_path is None:
69
68
  raise WorkflowStepNotInitializedError(type(self).__name__)
70
69
  components_to_delete = {
71
- cast(Literal["all", "spaces", "data_models", "views", "containers"], key)
70
+ cast(Literal["spaces", "data_models", "views", "containers"], key)
72
71
  for key, value in self.complex_configs["Components"].items()
73
72
  if value
74
73
  }
@@ -181,7 +180,7 @@ class RulesToDMS(Step):
181
180
  )
182
181
  multi_space_components_create: bool = self.configs["Multi-space components create"] == "True"
183
182
  components_to_create = {
184
- cast(Literal["all", "spaces", "data_models", "views", "containers"], key)
183
+ cast(Literal["spaces", "data_models", "views", "containers"], key)
185
184
  for key, value in self.complex_configs["Components"].items()
186
185
  if value
187
186
  }
@@ -209,7 +208,7 @@ class RulesToDMS(Step):
209
208
  dms_exporter = exporters.DMSExporter(
210
209
  export_components=frozenset(components_to_create),
211
210
  include_space=(None if multi_space_components_create else {dms_rules.metadata.space}),
212
- existing_handling=existing_components_handling,
211
+ existing=existing_components_handling,
213
212
  )
214
213
 
215
214
  output_dir = self.config.staging_path
@@ -532,93 +531,6 @@ class RulesToSemanticDataModel(Step):
532
531
  return FlowMessage(output_text=output_text)
533
532
 
534
533
 
535
- class RulesToCDFTransformations(Step):
536
- description = "This step exports transformations and RAW tables to populate a data model in CDF"
537
- version = "private-alpha"
538
- category = CATEGORY
539
- configurables: ClassVar[list[Configurable]] = [
540
- Configurable(
541
- name="Dry run",
542
- value="False",
543
- label=("Whether to perform a dry run of the export. "),
544
- options=["True", "False"],
545
- ),
546
- Configurable(
547
- name="Instance space",
548
- value="",
549
- label=(
550
- "The space to use for the transformations instances. If provided, "
551
- "the transformations will be set to populate"
552
- "this space. If not provided, the space from the input rules will be used."
553
- ),
554
- ),
555
- ]
556
-
557
- def run(self, rules: MultiRuleData, cdf_client: CogniteClient) -> FlowMessage: # type: ignore[override]
558
- if self.configs is None or self.data_store_path is None:
559
- raise WorkflowStepNotInitializedError(type(self).__name__)
560
-
561
- input_rules = rules.dms or rules.information
562
- if input_rules is None:
563
- return FlowMessage(
564
- error_text="Missing DMS or Information rules in the input data! "
565
- "Please ensure that a DMS or Information rules is provided!",
566
- step_execution_status=StepExecutionStatus.ABORT_AND_FAIL,
567
- )
568
- if isinstance(input_rules, DMSRules):
569
- dms_rules = input_rules
570
- elif isinstance(input_rules, InformationRules):
571
- dms_rules = InformationToDMS().transform(input_rules).rules
572
- else:
573
- raise NotImplementedError(f"Unsupported rules type {type(input_rules)}")
574
-
575
- instance_space = self.configs.get("Instance space") or dms_rules.metadata.space
576
- dry_run = self.configs.get("Dry run", "False") == "True"
577
- dms_exporter = exporters.DMSExporter(
578
- export_pipeline=True, instance_space=instance_space, export_components=["spaces"]
579
- )
580
- output_dir = self.config.staging_path
581
- output_dir.mkdir(parents=True, exist_ok=True)
582
- file_name = dms_rules.metadata.external_id.replace(":", "_")
583
- schema_zip = f"{file_name}_pipeline.zip"
584
- schema_full_path = output_dir / schema_zip
585
-
586
- dms_exporter.export_to_file(dms_rules, schema_full_path)
587
-
588
- report_lines = ["# DMS Schema Export to CDF\n\n"]
589
- errors = []
590
- for result in dms_exporter.export_to_cdf_iterable(
591
- rules=dms_rules, client=NeatClient(cdf_client), dry_run=dry_run
592
- ):
593
- report_lines.append(str(result))
594
- errors.extend(result.error_messages)
595
-
596
- report_lines.append("\n\n# ERRORS\n\n")
597
- report_lines.extend(errors)
598
-
599
- output_dir = self.config.staging_path
600
- output_dir.mkdir(parents=True, exist_ok=True)
601
- report_file = "pipeline_creation_report.txt"
602
- report_full_path = output_dir / report_file
603
- report_full_path.write_text("\n".join(report_lines))
604
-
605
- output_text = (
606
- "<p></p>"
607
- "Download Pipeline Export "
608
- f'<a href="/data/staging/{report_file}?{time.time()}" '
609
- f'target="_blank">Report</a>'
610
- "<p></p>"
611
- "Download Pipeline exported schema"
612
- f'- <a href="/data/staging/{schema_zip}?{time.time()}" '
613
- f'target="_blank">{schema_zip}</a>'
614
- )
615
-
616
- if errors:
617
- return FlowMessage(error_text=output_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
618
- else:
619
- return FlowMessage(output_text=output_text)
620
-
621
-
622
534
  def _get_default_file_name(rules: MultiRuleData, file_category: str = "ontology", extension: str = "ttl") -> str:
623
535
  name = rules.information.metadata.prefix if rules.information else cast(DMSRules, rules.dms).metadata.space
624
536
  version = rules.information.metadata.version if rules.information else cast(DMSRules, rules.dms).metadata.version
@@ -3,7 +3,6 @@ from pathlib import Path
3
3
  from typing import ClassVar
4
4
 
5
5
  from cognite.client import CogniteClient
6
- from cognite.client.data_classes.data_modeling import DataModelId
7
6
 
8
7
  from cognite.neat._client import NeatClient
9
8
  from cognite.neat._issues.errors import WorkflowStepNotInitializedError
@@ -288,21 +287,8 @@ class DMSToRules(Step):
288
287
  f"or 'my_space:my_data_model', failed to parse space from {datamodel_id_str}"
289
288
  )
290
289
  return FlowMessage(error_text=error_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
291
- ref_datamodel_str = self.configs.get("Reference data model id", "")
292
- ref_model_id: DataModelId | None = None
293
- if ref_datamodel_str:
294
- ref_model = DataModelEntity.load(ref_datamodel_str)
295
- if isinstance(ref_model, DMSUnknownEntity):
296
- error_text = (
297
- f"Reference data model id should be in the format 'my_space:my_data_model(version=1)' "
298
- f"or 'my_space:my_data_model', failed to parse space from {ref_datamodel_str}"
299
- )
300
- return FlowMessage(error_text=error_text, step_execution_status=StepExecutionStatus.ABORT_AND_FAIL)
301
- ref_model_id = ref_model.as_id()
302
-
303
- dms_importer = importers.DMSImporter.from_data_model_id(
304
- NeatClient(cdf_client), datamodel_entity.as_id(), ref_model_id
305
- )
290
+
291
+ dms_importer = importers.DMSImporter.from_data_model_id(NeatClient(cdf_client), datamodel_entity.as_id())
306
292
 
307
293
  # if role is None, it will be inferred from the rules file
308
294
  role = self.configs.get("Role")
@@ -11,6 +11,7 @@ from cognite.neat._issues import NeatIssueList
11
11
  from cognite.neat._issues.errors import ResourceNotFoundError, WorkflowStepNotInitializedError
12
12
  from cognite.neat._issues.formatters import FORMATTER_BY_NAME
13
13
  from cognite.neat._rules.models import DMSRules
14
+ from cognite.neat._rules.models.dms import DMSValidation
14
15
  from cognite.neat._workflows.model import FlowMessage, StepExecutionStatus
15
16
  from cognite.neat._workflows.steps.data_contracts import MultiRuleData
16
17
  from cognite.neat._workflows.steps.step_model import Configurable, Step
@@ -51,10 +52,7 @@ class ValidateRulesAgainstCDF(Step):
51
52
  )
52
53
  dms_rules = rules.dms
53
54
 
54
- schema = dms_rules.as_schema()
55
- errors = schema.validate()
56
- if not errors:
57
- return FlowMessage(output_text="Rules are complete and valid. No need to fetch from CDF.")
55
+ errors = DMSValidation(dms_rules, NeatClient(cdf_client)).validate()
58
56
 
59
57
  missing_spaces = [
60
58
  error.identifier
@@ -85,11 +83,11 @@ class ValidateRulesAgainstCDF(Step):
85
83
  f"and {len(retrieved_views)} views from CDF."
86
84
  )
87
85
 
86
+ schema = dms_rules.as_schema()
88
87
  schema.spaces.update({space.space: space for space in retrieved_spaces})
89
88
  schema.containers.update({container.as_id(): container for container in retrieved_containers})
90
89
  schema.views.update({view.as_id(): view for view in retrieved_views})
91
90
 
92
- errors = schema.validate()
93
91
  if errors:
94
92
  output_dir = self.data_store_path / Path("staging")
95
93
  report_writer = FORMATTER_BY_NAME[self.configs["Report Formatter"]]()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cognite-neat
3
- Version: 0.99.0
3
+ Version: 0.100.0
4
4
  Summary: Knowledge graph transformation
5
5
  Home-page: https://cognite-neat.readthedocs-hosted.com/
6
6
  License: Apache-2.0