cognite-neat 0.103.1__py3-none-any.whl → 0.105.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 (175) hide show
  1. cognite/neat/_client/_api/data_modeling_loaders.py +83 -23
  2. cognite/neat/_client/_api/schema.py +2 -1
  3. cognite/neat/_client/data_classes/neat_sequence.py +261 -0
  4. cognite/neat/_client/data_classes/schema.py +5 -1
  5. cognite/neat/_client/testing.py +33 -0
  6. cognite/neat/_constants.py +56 -0
  7. cognite/neat/_graph/extractors/_classic_cdf/_base.py +6 -5
  8. cognite/neat/_graph/extractors/_classic_cdf/_sequences.py +225 -11
  9. cognite/neat/_graph/extractors/_mock_graph_generator.py +2 -2
  10. cognite/neat/_graph/loaders/_rdf2dms.py +13 -2
  11. cognite/neat/_graph/transformers/__init__.py +3 -1
  12. cognite/neat/_graph/transformers/_base.py +109 -1
  13. cognite/neat/_graph/transformers/_classic_cdf.py +6 -1
  14. cognite/neat/_graph/transformers/_prune_graph.py +103 -47
  15. cognite/neat/_graph/transformers/_rdfpath.py +41 -17
  16. cognite/neat/_graph/transformers/_value_type.py +188 -151
  17. cognite/neat/_issues/__init__.py +0 -2
  18. cognite/neat/_issues/_base.py +54 -43
  19. cognite/neat/_issues/warnings/__init__.py +4 -1
  20. cognite/neat/_issues/warnings/_general.py +7 -0
  21. cognite/neat/_issues/warnings/_resources.py +12 -1
  22. cognite/neat/_rules/_shared.py +18 -34
  23. cognite/neat/_rules/exporters/_base.py +28 -2
  24. cognite/neat/_rules/exporters/_rules2dms.py +39 -1
  25. cognite/neat/_rules/exporters/_rules2excel.py +13 -2
  26. cognite/neat/_rules/exporters/_rules2instance_template.py +4 -0
  27. cognite/neat/_rules/exporters/_rules2ontology.py +13 -1
  28. cognite/neat/_rules/exporters/_rules2yaml.py +4 -0
  29. cognite/neat/_rules/importers/_base.py +9 -0
  30. cognite/neat/_rules/importers/_dms2rules.py +80 -57
  31. cognite/neat/_rules/importers/_dtdl2rules/dtdl_importer.py +5 -2
  32. cognite/neat/_rules/importers/_rdf/_base.py +10 -8
  33. cognite/neat/_rules/importers/_rdf/_imf2rules.py +4 -0
  34. cognite/neat/_rules/importers/_rdf/_inference2rules.py +7 -0
  35. cognite/neat/_rules/importers/_rdf/_owl2rules.py +4 -0
  36. cognite/neat/_rules/importers/_spreadsheet2rules.py +17 -8
  37. cognite/neat/_rules/importers/_yaml2rules.py +21 -7
  38. cognite/neat/_rules/models/_base_input.py +1 -1
  39. cognite/neat/_rules/models/_base_rules.py +9 -1
  40. cognite/neat/_rules/models/dms/_rules.py +4 -0
  41. cognite/neat/_rules/models/dms/_rules_input.py +9 -0
  42. cognite/neat/_rules/models/entities/_wrapped.py +10 -5
  43. cognite/neat/_rules/models/information/_rules.py +4 -0
  44. cognite/neat/_rules/models/information/_rules_input.py +9 -0
  45. cognite/neat/_rules/models/mapping/_classic2core.py +2 -5
  46. cognite/neat/_rules/models/mapping/_classic2core.yaml +239 -38
  47. cognite/neat/_rules/transformers/__init__.py +13 -6
  48. cognite/neat/_rules/transformers/_base.py +41 -65
  49. cognite/neat/_rules/transformers/_converters.py +404 -234
  50. cognite/neat/_rules/transformers/_mapping.py +93 -72
  51. cognite/neat/_rules/transformers/_verification.py +50 -38
  52. cognite/neat/_session/_base.py +32 -121
  53. cognite/neat/_session/_inspect.py +5 -3
  54. cognite/neat/_session/_mapping.py +17 -105
  55. cognite/neat/_session/_prepare.py +138 -268
  56. cognite/neat/_session/_read.py +39 -195
  57. cognite/neat/_session/_set.py +6 -30
  58. cognite/neat/_session/_show.py +40 -21
  59. cognite/neat/_session/_state.py +49 -107
  60. cognite/neat/_session/_to.py +44 -33
  61. cognite/neat/_shared.py +23 -2
  62. cognite/neat/_store/_provenance.py +3 -82
  63. cognite/neat/_store/_rules_store.py +368 -10
  64. cognite/neat/_store/exceptions.py +23 -0
  65. cognite/neat/_utils/graph_transformations_report.py +36 -0
  66. cognite/neat/_utils/rdf_.py +8 -0
  67. cognite/neat/_utils/reader/_base.py +27 -0
  68. cognite/neat/_utils/spreadsheet.py +5 -4
  69. cognite/neat/_version.py +1 -1
  70. {cognite_neat-0.103.1.dist-info → cognite_neat-0.105.0.dist-info}/METADATA +3 -2
  71. cognite_neat-0.105.0.dist-info/RECORD +179 -0
  72. {cognite_neat-0.103.1.dist-info → cognite_neat-0.105.0.dist-info}/WHEEL +1 -1
  73. cognite/neat/_app/api/__init__.py +0 -0
  74. cognite/neat/_app/api/asgi/metrics.py +0 -4
  75. cognite/neat/_app/api/configuration.py +0 -98
  76. cognite/neat/_app/api/context_manager/__init__.py +0 -3
  77. cognite/neat/_app/api/context_manager/manager.py +0 -16
  78. cognite/neat/_app/api/data_classes/__init__.py +0 -0
  79. cognite/neat/_app/api/data_classes/rest.py +0 -59
  80. cognite/neat/_app/api/explorer.py +0 -66
  81. cognite/neat/_app/api/routers/configuration.py +0 -25
  82. cognite/neat/_app/api/routers/crud.py +0 -102
  83. cognite/neat/_app/api/routers/metrics.py +0 -10
  84. cognite/neat/_app/api/routers/workflows.py +0 -224
  85. cognite/neat/_app/api/utils/__init__.py +0 -0
  86. cognite/neat/_app/api/utils/data_mapping.py +0 -17
  87. cognite/neat/_app/api/utils/logging.py +0 -26
  88. cognite/neat/_app/api/utils/query_templates.py +0 -92
  89. cognite/neat/_app/main.py +0 -17
  90. cognite/neat/_app/monitoring/__init__.py +0 -0
  91. cognite/neat/_app/monitoring/metrics.py +0 -69
  92. cognite/neat/_app/ui/index.html +0 -1
  93. cognite/neat/_app/ui/neat-app/.gitignore +0 -23
  94. cognite/neat/_app/ui/neat-app/README.md +0 -70
  95. cognite/neat/_app/ui/neat-app/build/asset-manifest.json +0 -14
  96. cognite/neat/_app/ui/neat-app/build/favicon.ico +0 -0
  97. cognite/neat/_app/ui/neat-app/build/img/architect-icon.svg +0 -116
  98. cognite/neat/_app/ui/neat-app/build/img/developer-icon.svg +0 -112
  99. cognite/neat/_app/ui/neat-app/build/img/sme-icon.svg +0 -34
  100. cognite/neat/_app/ui/neat-app/build/index.html +0 -1
  101. cognite/neat/_app/ui/neat-app/build/logo192.png +0 -0
  102. cognite/neat/_app/ui/neat-app/build/manifest.json +0 -25
  103. cognite/neat/_app/ui/neat-app/build/robots.txt +0 -3
  104. cognite/neat/_app/ui/neat-app/build/static/css/main.72e3d92e.css +0 -2
  105. cognite/neat/_app/ui/neat-app/build/static/css/main.72e3d92e.css.map +0 -1
  106. cognite/neat/_app/ui/neat-app/build/static/js/main.5a52cf09.js +0 -3
  107. cognite/neat/_app/ui/neat-app/build/static/js/main.5a52cf09.js.LICENSE.txt +0 -88
  108. cognite/neat/_app/ui/neat-app/build/static/js/main.5a52cf09.js.map +0 -1
  109. cognite/neat/_app/ui/neat-app/build/static/media/logo.8093b84df9ed36a174c629d6fe0b730d.svg +0 -1
  110. cognite/neat/_app/ui/neat-app/package-lock.json +0 -18306
  111. cognite/neat/_app/ui/neat-app/package.json +0 -62
  112. cognite/neat/_app/ui/neat-app/public/favicon.ico +0 -0
  113. cognite/neat/_app/ui/neat-app/public/img/architect-icon.svg +0 -116
  114. cognite/neat/_app/ui/neat-app/public/img/developer-icon.svg +0 -112
  115. cognite/neat/_app/ui/neat-app/public/img/sme-icon.svg +0 -34
  116. cognite/neat/_app/ui/neat-app/public/index.html +0 -43
  117. cognite/neat/_app/ui/neat-app/public/logo192.png +0 -0
  118. cognite/neat/_app/ui/neat-app/public/manifest.json +0 -25
  119. cognite/neat/_app/ui/neat-app/public/robots.txt +0 -3
  120. cognite/neat/_app/ui/neat-app/src/App.css +0 -38
  121. cognite/neat/_app/ui/neat-app/src/App.js +0 -17
  122. cognite/neat/_app/ui/neat-app/src/App.test.js +0 -8
  123. cognite/neat/_app/ui/neat-app/src/MainContainer.tsx +0 -70
  124. cognite/neat/_app/ui/neat-app/src/components/JsonViewer.tsx +0 -43
  125. cognite/neat/_app/ui/neat-app/src/components/LocalUploader.tsx +0 -124
  126. cognite/neat/_app/ui/neat-app/src/components/OverviewComponentEditorDialog.tsx +0 -63
  127. cognite/neat/_app/ui/neat-app/src/components/StepEditorDialog.tsx +0 -511
  128. cognite/neat/_app/ui/neat-app/src/components/TabPanel.tsx +0 -36
  129. cognite/neat/_app/ui/neat-app/src/components/Utils.tsx +0 -56
  130. cognite/neat/_app/ui/neat-app/src/components/WorkflowDeleteDialog.tsx +0 -60
  131. cognite/neat/_app/ui/neat-app/src/components/WorkflowExecutionReport.tsx +0 -112
  132. cognite/neat/_app/ui/neat-app/src/components/WorkflowImportExportDialog.tsx +0 -67
  133. cognite/neat/_app/ui/neat-app/src/components/WorkflowMetadataDialog.tsx +0 -79
  134. cognite/neat/_app/ui/neat-app/src/index.css +0 -13
  135. cognite/neat/_app/ui/neat-app/src/index.js +0 -13
  136. cognite/neat/_app/ui/neat-app/src/logo.svg +0 -1
  137. cognite/neat/_app/ui/neat-app/src/reportWebVitals.js +0 -13
  138. cognite/neat/_app/ui/neat-app/src/setupTests.js +0 -5
  139. cognite/neat/_app/ui/neat-app/src/types/WorkflowTypes.ts +0 -388
  140. cognite/neat/_app/ui/neat-app/src/views/AboutView.tsx +0 -61
  141. cognite/neat/_app/ui/neat-app/src/views/ConfigView.tsx +0 -184
  142. cognite/neat/_app/ui/neat-app/src/views/GlobalConfigView.tsx +0 -180
  143. cognite/neat/_app/ui/neat-app/src/views/WorkflowView.tsx +0 -570
  144. cognite/neat/_app/ui/neat-app/tsconfig.json +0 -27
  145. cognite/neat/_rules/transformers/_pipelines.py +0 -70
  146. cognite/neat/_workflows/__init__.py +0 -17
  147. cognite/neat/_workflows/base.py +0 -590
  148. cognite/neat/_workflows/cdf_store.py +0 -393
  149. cognite/neat/_workflows/examples/Export_DMS/workflow.yaml +0 -89
  150. cognite/neat/_workflows/examples/Export_Semantic_Data_Model/workflow.yaml +0 -66
  151. cognite/neat/_workflows/examples/Import_DMS/workflow.yaml +0 -65
  152. cognite/neat/_workflows/examples/Validate_Rules/workflow.yaml +0 -67
  153. cognite/neat/_workflows/examples/Validate_Solution_Model/workflow.yaml +0 -64
  154. cognite/neat/_workflows/manager.py +0 -292
  155. cognite/neat/_workflows/model.py +0 -203
  156. cognite/neat/_workflows/steps/__init__.py +0 -0
  157. cognite/neat/_workflows/steps/data_contracts.py +0 -109
  158. cognite/neat/_workflows/steps/lib/__init__.py +0 -0
  159. cognite/neat/_workflows/steps/lib/current/__init__.py +0 -6
  160. cognite/neat/_workflows/steps/lib/current/graph_extractor.py +0 -100
  161. cognite/neat/_workflows/steps/lib/current/graph_loader.py +0 -51
  162. cognite/neat/_workflows/steps/lib/current/graph_store.py +0 -48
  163. cognite/neat/_workflows/steps/lib/current/rules_exporter.py +0 -537
  164. cognite/neat/_workflows/steps/lib/current/rules_importer.py +0 -398
  165. cognite/neat/_workflows/steps/lib/current/rules_validator.py +0 -106
  166. cognite/neat/_workflows/steps/lib/io/__init__.py +0 -1
  167. cognite/neat/_workflows/steps/lib/io/io_steps.py +0 -393
  168. cognite/neat/_workflows/steps/step_model.py +0 -79
  169. cognite/neat/_workflows/steps_registry.py +0 -218
  170. cognite/neat/_workflows/tasks.py +0 -18
  171. cognite/neat/_workflows/triggers.py +0 -169
  172. cognite/neat/_workflows/utils.py +0 -19
  173. cognite_neat-0.103.1.dist-info/RECORD +0 -275
  174. {cognite_neat-0.103.1.dist-info → cognite_neat-0.105.0.dist-info}/LICENSE +0 -0
  175. {cognite_neat-0.103.1.dist-info → cognite_neat-0.105.0.dist-info}/entry_points.txt +0 -0
@@ -1,6 +1,4 @@
1
- import copy
2
1
  from collections.abc import Callable, Collection
3
- from datetime import datetime, timezone
4
2
  from typing import Any, Literal, cast
5
3
 
6
4
  from cognite.client.data_classes.data_modeling import DataModelIdentifier
@@ -8,11 +6,12 @@ from rdflib import URIRef
8
6
 
9
7
  from cognite.neat._client import NeatClient
10
8
  from cognite.neat._constants import (
11
- DEFAULT_NAMESPACE,
12
9
  get_default_prefixes_and_namespaces,
13
10
  )
11
+ from cognite.neat._graph import extractors
14
12
  from cognite.neat._graph.transformers import (
15
13
  AttachPropertyFromTargetToSource,
14
+ ConnectionToLiteral,
16
15
  ConvertLiteral,
17
16
  LiteralToEntity,
18
17
  PruneDeadEndEdges,
@@ -22,30 +21,25 @@ from cognite.neat._graph.transformers import (
22
21
  Transformers,
23
22
  )
24
23
  from cognite.neat._graph.transformers._rdfpath import MakeConnectionOnExactMatch
25
- from cognite.neat._rules._shared import InputRules, ReadRules
26
- from cognite.neat._rules.importers import DMSImporter
27
- from cognite.neat._rules.models import DMSRules
24
+ from cognite.neat._issues import IssueList
25
+ from cognite.neat._issues.errors import NeatValueError
28
26
  from cognite.neat._rules.models.dms import DMSValidation
29
- from cognite.neat._rules.models.entities import ClassEntity
30
- from cognite.neat._rules.models.information._rules_input import InformationInputRules
31
27
  from cognite.neat._rules.transformers import (
28
+ AddClassImplements,
29
+ IncludeReferenced,
32
30
  PrefixEntities,
33
31
  ReduceCogniteModel,
32
+ RulesTransformer,
34
33
  ToCompliantEntities,
35
- ToExtension,
36
- VerifyDMSRules,
34
+ ToDataProductModel,
35
+ ToEnterpriseModel,
36
+ ToSolutionModel,
37
37
  )
38
- from cognite.neat._store._provenance import Agent as ProvenanceAgent
39
- from cognite.neat._store._provenance import Change
38
+ from cognite.neat._utils.text import humanize_collection
40
39
 
41
40
  from ._state import SessionState
42
41
  from .exceptions import NeatSessionError, session_class_wrapper
43
42
 
44
- try:
45
- from rich import print
46
- except ImportError:
47
- ...
48
-
49
43
 
50
44
  @session_class_wrapper
51
45
  class PrepareAPI:
@@ -209,9 +203,11 @@ class InstancePrepareAPI:
209
203
  neat.prepare.instances.make_connection_on_exact_match(source, target, connection)
210
204
  ```
211
205
  """
212
-
213
- subject_type, subject_predicate = self._get_type_and_property_uris(*source)
214
- object_type, object_predicate = self._get_type_and_property_uris(*target)
206
+ try:
207
+ subject_type, subject_predicate = self._get_type_and_property_uris(*source)
208
+ object_type, object_predicate = self._get_type_and_property_uris(*target)
209
+ except NeatValueError as e:
210
+ raise NeatSessionError(f"Cannot make connection: {e}") from None
215
211
 
216
212
  transformer = MakeConnectionOnExactMatch(
217
213
  subject_type,
@@ -229,17 +225,19 @@ class InstancePrepareAPI:
229
225
  property_uri = self._state.instances.store.queries.property_uri(property_)
230
226
 
231
227
  if not type_uri:
232
- raise NeatSessionError(f"Type {type_} does not exist in the graph.")
228
+ raise NeatValueError(f"Type {type_} does not exist in the graph.")
233
229
  elif len(type_uri) > 1:
234
- raise NeatSessionError(f"{type_} has multiple ids found in the graph: {','.join(type_uri)}.")
230
+ raise NeatValueError(f"{type_} has multiple ids found in the graph: {humanize_collection(type_uri)}.")
235
231
 
236
232
  if not property_uri:
237
- raise NeatSessionError(f"Property {property_} does not exist in the graph.")
233
+ raise NeatValueError(f"Property {property_} does not exist in the graph.")
238
234
  elif len(type_uri) > 1:
239
- raise NeatSessionError(f"{property_} has multiple ids found in the graph: {','.join(property_uri)}.")
235
+ raise NeatValueError(
236
+ f"{property_} has multiple ids found in the graph: {humanize_collection(property_uri)}."
237
+ )
240
238
 
241
239
  if not self._state.instances.store.queries.type_with_property(type_uri[0], property_uri[0]):
242
- raise NeatSessionError(f"Property {property_} is not defined for type {type_}. Cannot make connection")
240
+ raise NeatValueError(f"Property {property_} is not defined for type {type_}.")
243
241
  return type_uri[0], property_uri[0]
244
242
 
245
243
  def relationships_as_edges(self, min_relationship_types: int = 1, limit_per_type: int | None = None) -> None:
@@ -283,7 +281,10 @@ class InstancePrepareAPI:
283
281
  ```
284
282
 
285
283
  """
286
- subject_type, subject_predicate = self._get_type_and_property_uris(*source)
284
+ try:
285
+ subject_type, subject_predicate = self._get_type_and_property_uris(*source)
286
+ except NeatValueError as e:
287
+ raise NeatSessionError(f"Cannot convert data type: {e}") from None
287
288
 
288
289
  transformer = ConvertLiteral(subject_type, subject_predicate, convert)
289
290
  self._state.instances.store.transform(transformer)
@@ -308,13 +309,81 @@ class InstancePrepareAPI:
308
309
  """
309
310
  subject_type: URIRef | None = None
310
311
  if source[0] is not None:
311
- subject_type, subject_predicate = self._get_type_and_property_uris(*source) # type: ignore[arg-type, assignment]
312
+ try:
313
+ subject_type, subject_predicate = self._get_type_and_property_uris(*source) # type: ignore[arg-type, assignment]
314
+ except NeatValueError as e:
315
+ raise NeatSessionError(f"Cannot convert to type: {e}") from None
312
316
  else:
313
317
  subject_predicate = self._state.instances.store.queries.property_uri(source[1])[0]
314
318
 
315
319
  transformer = LiteralToEntity(subject_type, subject_predicate, type, new_property)
316
320
  self._state.instances.store.transform(transformer)
317
321
 
322
+ def connection_to_data_type(self, source: tuple[str | None, str]) -> None:
323
+ """Converts a connection to a data type.
324
+
325
+ Args:
326
+ source: The source of the conversion. A tuple of (type, property)
327
+ where property is the property that should be converted.
328
+ You can pass (None, property) to covert all properties with the given name.
329
+
330
+ Example:
331
+
332
+ Convert all properties 'labels' from a connection to a string:
333
+
334
+ ```python
335
+ neat.prepare.instances.connection_to_data_type(
336
+ (None, "labels")
337
+ )
338
+ ```
339
+
340
+ """
341
+ subject_type: URIRef | None = None
342
+ if source[0] is not None:
343
+ try:
344
+ subject_type, subject_predicate = self._get_type_and_property_uris(*source) # type: ignore[arg-type, assignment]
345
+ except NeatValueError as e:
346
+ raise NeatSessionError(f"Cannot convert to data type: {e}") from None
347
+ else:
348
+ subject_predicate = self._state.instances.store.queries.property_uri(source[1])[0]
349
+ transformer = ConnectionToLiteral(subject_type, subject_predicate)
350
+ self._state.instances.store.transform(transformer)
351
+
352
+ def classic_to_core(self) -> None:
353
+ """Prepares extracted CDF classic graph for the Core Data model.
354
+
355
+ !!! note "This method bundles several graph transformers which"
356
+ - Convert relationships to edges
357
+ - Convert TimeSeries.type from bool to enum
358
+ - Convert all properties 'source' to a connection to SourceSystem
359
+ - Convert all properties 'labels' from a connection to a string
360
+
361
+ Example:
362
+ Apply classic to core transformations:
363
+ ```python
364
+ neat.prepare.instances.classic_to_core()
365
+ ```
366
+ """
367
+ self.relationships_as_edges()
368
+ self.convert_data_type(
369
+ ("TimeSeries", "isString"), convert=lambda is_string: "string" if is_string else "numeric"
370
+ )
371
+ self.property_to_type((None, "source"), "SourceSystem", "name")
372
+ for type_ in [
373
+ extractors.EventsExtractor._default_rdf_type,
374
+ extractors.AssetsExtractor._default_rdf_type,
375
+ extractors.FilesExtractor._default_rdf_type,
376
+ ]:
377
+ try:
378
+ subject_type, subject_predicate = self._get_type_and_property_uris(type_, "labels")
379
+ except NeatValueError:
380
+ # If the type_.labels does not exist, continue. This is not an error, it just means that the
381
+ # Labels is not used in the graph for that type.
382
+ continue
383
+ else:
384
+ transformer = ConnectionToLiteral(subject_type, subject_predicate)
385
+ self._state.instances.store.transform(transformer)
386
+
318
387
 
319
388
  @session_class_wrapper
320
389
  class DataModelPrepareAPI:
@@ -327,53 +396,18 @@ class DataModelPrepareAPI:
327
396
  self._state = state
328
397
  self._verbose = verbose
329
398
 
330
- def cdf_compliant_external_ids(self) -> None:
399
+ def cdf_compliant_external_ids(self) -> IssueList:
331
400
  """Convert data model component external ids to CDF compliant entities."""
332
- source_id, rules = self._state.data_model.last_info_unverified_rule
333
-
334
- start = datetime.now(timezone.utc)
335
- transformer = ToCompliantEntities()
336
- output: ReadRules[InformationInputRules] = transformer.transform(rules)
337
- end = datetime.now(timezone.utc)
338
-
339
- change = Change.from_rules_activity(
340
- output,
341
- transformer.agent,
342
- start,
343
- end,
344
- "Converted external ids to CDF compliant entities",
345
- self._state.data_model.provenance.source_entity(source_id)
346
- or self._state.data_model.provenance.target_entity(source_id),
347
- )
348
-
349
- self._state.data_model.write(output, change)
401
+ return self._state.rule_transform(ToCompliantEntities())
350
402
 
351
- def prefix(self, prefix: str) -> None:
403
+ def prefix(self, prefix: str) -> IssueList:
352
404
  """Prefix all views in the data model with the given prefix.
353
405
 
354
406
  Args:
355
407
  prefix: The prefix to add to the views in the data model.
356
408
 
357
409
  """
358
- source_id, rules = self._state.data_model.last_unverified_rule
359
-
360
- start = datetime.now(timezone.utc)
361
- transformer = PrefixEntities(prefix)
362
- new_rules = cast(InputRules, copy.deepcopy(rules.get_rules()))
363
- output = transformer.transform(new_rules)
364
- end = datetime.now(timezone.utc)
365
-
366
- change = Change.from_rules_activity(
367
- output,
368
- transformer.agent,
369
- start,
370
- end,
371
- "Added prefix to the data model views",
372
- self._state.data_model.provenance.source_entity(source_id)
373
- or self._state.data_model.provenance.target_entity(source_id),
374
- )
375
-
376
- self._state.data_model.write(output, change)
410
+ return self._state.rule_transform(PrefixEntities(prefix))
377
411
 
378
412
  def to_enterprise(
379
413
  self,
@@ -381,7 +415,7 @@ class DataModelPrepareAPI:
381
415
  org_name: str = "My",
382
416
  dummy_property: str = "GUID",
383
417
  move_connections: bool = False,
384
- ) -> None:
418
+ ) -> IssueList:
385
419
  """Uses the current data model as a basis to create enterprise data model
386
420
 
387
421
  Args:
@@ -405,34 +439,14 @@ class DataModelPrepareAPI:
405
439
  views as the source and target views.
406
440
 
407
441
  """
408
- if input := self._state.data_model.last_verified_dms_rules:
409
- source_id, rules = input
410
-
411
- start = datetime.now(timezone.utc)
412
- transformer = ToExtension(
442
+ return self._state.rule_transform(
443
+ ToEnterpriseModel(
413
444
  new_model_id=data_model_id,
414
445
  org_name=org_name,
415
- type_="enterprise",
416
446
  dummy_property=dummy_property,
417
447
  move_connections=move_connections,
418
448
  )
419
- output = transformer.transform(rules)
420
- end = datetime.now(timezone.utc)
421
-
422
- change = Change.from_rules_activity(
423
- output,
424
- transformer.agent,
425
- start,
426
- end,
427
- (
428
- f"Prepared data model {data_model_id} to be enterprise data "
429
- f"model on top of {rules.metadata.as_data_model_id()}"
430
- ),
431
- self._state.data_model.provenance.source_entity(source_id)
432
- or self._state.data_model.provenance.target_entity(source_id),
433
- )
434
-
435
- self._state.data_model.write(output.rules, change)
449
+ )
436
450
 
437
451
  def to_solution(
438
452
  self,
@@ -440,7 +454,7 @@ class DataModelPrepareAPI:
440
454
  org_name: str = "My",
441
455
  mode: Literal["read", "write"] = "read",
442
456
  dummy_property: str = "GUID",
443
- ) -> None:
457
+ ) -> IssueList:
444
458
  """Uses the current data model as a basis to create solution data model
445
459
 
446
460
  Args:
@@ -461,34 +475,14 @@ class DataModelPrepareAPI:
461
475
  the containers in the solution data model space.
462
476
 
463
477
  """
464
- if input := self._state.data_model.last_verified_dms_rules:
465
- source_id, rules = input
466
-
467
- start = datetime.now(timezone.utc)
468
- transformer = ToExtension(
478
+ return self._state.rule_transform(
479
+ ToSolutionModel(
469
480
  new_model_id=data_model_id,
470
481
  org_name=org_name,
471
- type_="solution",
472
482
  mode=mode,
473
483
  dummy_property=dummy_property,
474
484
  )
475
- output = transformer.transform(rules)
476
- end = datetime.now(timezone.utc)
477
-
478
- change = Change.from_rules_activity(
479
- output,
480
- transformer.agent,
481
- start,
482
- end,
483
- (
484
- f"Prepared data model {data_model_id} to be solution data model "
485
- f"on top of {rules.metadata.as_data_model_id()}"
486
- ),
487
- self._state.data_model.provenance.source_entity(source_id)
488
- or self._state.data_model.provenance.target_entity(source_id),
489
- )
490
-
491
- self._state.data_model.write(output.rules, change)
485
+ )
492
486
 
493
487
  def to_data_product(
494
488
  self,
@@ -503,69 +497,36 @@ class DataModelPrepareAPI:
503
497
 
504
498
  Args:
505
499
  data_model_id: The data product data model id that is being created.
506
- org_name: Organization name to use for the views in the new data model.
500
+ org_name: Organization name used as prefix if the model is building on top of a Cognite Data Model.
507
501
  include: The views to include in the data product data model. Can be either "same-space" or "all".
508
- If you set same-space, only the views in the same space as the data model will be included.
502
+ If you set same-space, only the properties of the views in the same space as the data model
503
+ will be included.
509
504
  """
510
- source_id, rules = self._state.data_model.last_verified_dms_rules
511
-
512
- dms_ref: DMSRules | None = None
513
- view_ids, container_ids = DMSValidation(rules, self._client).imported_views_and_containers_ids()
514
- if view_ids or container_ids:
515
- if self._client is None:
516
- raise NeatSessionError(
517
- "No client provided. You are referencing unknown views and containers in your data model, "
518
- "NEAT needs a client to lookup the definitions. "
519
- "Please set the client in the session, NeatSession(client=client)."
520
- )
521
- schema = self._client.schema.retrieve([v.as_id() for v in view_ids], [c.as_id() for c in container_ids])
522
-
523
- importer = DMSImporter(schema)
524
- reference_rules = importer.to_rules().rules
525
- if reference_rules is not None:
526
- imported = VerifyDMSRules("continue").transform(reference_rules)
527
- if dms_ref := imported.rules:
528
- rules = rules.model_copy(deep=True)
529
- if rules.containers is None:
530
- rules.containers = dms_ref.containers
531
- else:
532
- existing_containers = {c.container for c in rules.containers}
533
- rules.containers.extend(
534
- [c for c in dms_ref.containers or [] if c.container not in existing_containers]
535
- )
536
- existing_views = {v.view for v in rules.views}
537
- rules.views.extend([v for v in dms_ref.views if v.view not in existing_views])
538
- existing_properties = {(p.view, p.view_property) for p in rules.properties}
539
- rules.properties.extend(
540
- [p for p in dms_ref.properties if (p.view, p.view_property) not in existing_properties]
541
- )
542
-
543
- start = datetime.now(timezone.utc)
544
- transformer = ToExtension(
545
- new_model_id=data_model_id,
546
- org_name=org_name,
547
- type_="data_product",
548
- include=include,
549
- )
550
- output = transformer.transform(rules)
551
- end = datetime.now(timezone.utc)
552
-
553
- change = Change.from_rules_activity(
554
- output,
555
- transformer.agent,
556
- start,
557
- end,
558
- (
559
- f"Prepared data model {data_model_id} to be data product model "
560
- f"on top of {rules.metadata.as_data_model_id()}"
561
- ),
562
- self._state.data_model.provenance.source_entity(source_id)
563
- or self._state.data_model.provenance.target_entity(source_id),
505
+
506
+ view_ids, container_ids = DMSValidation(
507
+ self._state.rule_store.last_verified_dms_rules
508
+ ).imported_views_and_containers_ids()
509
+ transformers: list[RulesTransformer] = []
510
+ if (view_ids or container_ids) and self._client is None:
511
+ raise NeatSessionError(
512
+ "No client provided. You are referencing unknown views and containers in your data model, "
513
+ "NEAT needs a client to lookup the definitions. "
514
+ "Please set the client in the session, NeatSession(client=client)."
515
+ )
516
+ elif (view_ids or container_ids) and self._client:
517
+ transformers.append(IncludeReferenced(self._client, include_properties=True))
518
+
519
+ transformers.append(
520
+ ToDataProductModel(
521
+ new_model_id=data_model_id,
522
+ org_name=org_name,
523
+ include=include,
524
+ )
564
525
  )
565
526
 
566
- self._state.data_model.write(output.rules, change)
527
+ self._state.rule_transform(*transformers)
567
528
 
568
- def reduce(self, drop: Collection[Literal["3D", "Annotation", "BaseViews"] | str]) -> None:
529
+ def reduce(self, drop: Collection[Literal["3D", "Annotation", "BaseViews"] | str]) -> IssueList:
569
530
  """This is a special method that allow you to drop parts of the data model.
570
531
  This only applies to Cognite Data Models.
571
532
 
@@ -574,90 +535,19 @@ class DataModelPrepareAPI:
574
535
  drops multiple views at once. You can also pass externalIds of views to drop individual views.
575
536
 
576
537
  """
577
- if input := self._state.data_model.last_verified_dms_rules:
578
- source_id, rules = input
579
- start = datetime.now(timezone.utc)
580
-
581
- transformer = ReduceCogniteModel(drop)
582
- output = transformer.transform(rules)
583
- output.rules.metadata.version = f"{rules.metadata.version}.reduced"
584
-
585
- end = datetime.now(timezone.utc)
586
-
587
- change = Change.from_rules_activity(
588
- output,
589
- transformer.agent,
590
- start,
591
- end,
592
- (
593
- f"Reduced data model {rules.metadata.as_data_model_id()}"
594
- f"on top of {rules.metadata.as_data_model_id()}"
595
- ),
596
- self._state.data_model.provenance.source_entity(source_id),
597
- )
598
-
599
- self._state.data_model.write(output.rules, change)
538
+ return self._state.rule_transform(ReduceCogniteModel(drop))
600
539
 
601
- def include_referenced(self) -> None:
540
+ def include_referenced(self) -> IssueList:
602
541
  """Include referenced views and containers in the data model."""
603
- start = datetime.now(timezone.utc)
604
-
605
- source_id, rules = self._state.data_model.last_verified_dms_rules
606
- view_ids, container_ids = DMSValidation(rules, self._client).imported_views_and_containers_ids()
607
- if not (view_ids or container_ids):
608
- print(
609
- f"Data model {rules.metadata.as_data_model_id()} does not have any referenced views or containers."
610
- f"that is not already included in the data model."
611
- )
612
- return
613
542
  if self._client is None:
614
543
  raise NeatSessionError(
615
544
  "No client provided. You are referencing unknown views and containers in your data model, "
616
545
  "NEAT needs a client to lookup the definitions. "
617
546
  "Please set the client in the session, NeatSession(client=client)."
618
547
  )
619
- schema = self._client.schema.retrieve([v.as_id() for v in view_ids], [c.as_id() for c in container_ids])
620
- copy_ = rules.model_copy(deep=True)
621
- copy_.metadata.version = f"{rules.metadata.version}_completed"
622
- importer = DMSImporter(schema)
623
- imported = importer.to_rules()
624
- if imported.rules is None:
625
- self._state.data_model.issue_lists.append(imported.issues)
626
- raise NeatSessionError(
627
- "Could not import the referenced views and containers. "
628
- "See `neat.inspect.issues()` for more information."
629
- )
630
- verified = VerifyDMSRules("continue", validate=False).transform(imported.rules)
631
- if verified.rules is None:
632
- self._state.data_model.issue_lists.append(verified.issues)
633
- raise NeatSessionError(
634
- "Could not verify the referenced views and containers. "
635
- "See `neat.inspect.issues()` for more information."
636
- )
637
- if copy_.containers is None:
638
- copy_.containers = verified.rules.containers
639
- else:
640
- existing_containers = {c.container for c in copy_.containers}
641
- copy_.containers.extend(
642
- [c for c in verified.rules.containers or [] if c.container not in existing_containers]
643
- )
644
- existing_views = {v.view for v in copy_.views}
645
- copy_.views.extend([v for v in verified.rules.views if v.view not in existing_views])
646
- end = datetime.now(timezone.utc)
647
-
648
- change = Change.from_rules_activity(
649
- copy_,
650
- ProvenanceAgent(id_=DEFAULT_NAMESPACE["agent/"]),
651
- start,
652
- end,
653
- (f"Included referenced views and containers in the data model {rules.metadata.as_data_model_id()}"),
654
- self._state.data_model.provenance.source_entity(source_id)
655
- or self._state.data_model.provenance.target_entity(source_id),
656
- )
657
-
658
- self._state.data_model.write(copy_, change)
548
+ return self._state.rule_transform(IncludeReferenced(self._client))
659
549
 
660
- def add_implements_to_classes(self, suffix: Literal["Edge"], implements: str = "Edge") -> None:
550
+ def add_implements_to_classes(self, suffix: Literal["Edge"], implements: str = "Edge") -> IssueList:
661
551
  """All classes with the suffix will have the implements property set to the given value.
662
552
 
663
553
  Args:
@@ -665,24 +555,4 @@ class DataModelPrepareAPI:
665
555
  implements: The value of the implements property to set.
666
556
 
667
557
  """
668
- source_id, rules = self._state.data_model.last_verified_information_rules
669
- start = datetime.now(timezone.utc)
670
-
671
- output = rules.model_copy(deep=True)
672
- for class_ in output.classes:
673
- if class_.class_.suffix.endswith(suffix):
674
- class_.implements = [ClassEntity(prefix=class_.class_.prefix, suffix=implements)]
675
- output.metadata.version = f"{rules.metadata.version}.implements_{implements}"
676
- end = datetime.now(timezone.utc)
677
-
678
- change = Change.from_rules_activity(
679
- output,
680
- ProvenanceAgent(id_=DEFAULT_NAMESPACE["agent/"]),
681
- start,
682
- end,
683
- (f"Added implements property to classes with suffix {suffix}"),
684
- self._state.data_model.provenance.source_entity(source_id)
685
- or self._state.data_model.provenance.target_entity(source_id),
686
- )
687
-
688
- self._state.data_model.write(output, change)
558
+ return self._state.rule_transform(AddClassImplements(implements, suffix))