cognite-neat 0.98.0__py3-none-any.whl → 0.99.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of cognite-neat might be problematic. Click here for more details.

Files changed (103) hide show
  1. cognite/neat/_client/__init__.py +4 -0
  2. cognite/neat/_client/_api/data_modeling_loaders.py +585 -0
  3. cognite/neat/_client/_api/schema.py +111 -0
  4. cognite/neat/_client/_api_client.py +17 -0
  5. cognite/neat/_client/data_classes/__init__.py +0 -0
  6. cognite/neat/{_utils/cdf/data_classes.py → _client/data_classes/data_modeling.py} +8 -135
  7. cognite/neat/_client/data_classes/schema.py +495 -0
  8. cognite/neat/_constants.py +27 -4
  9. cognite/neat/_graph/_shared.py +14 -15
  10. cognite/neat/_graph/extractors/_classic_cdf/_assets.py +14 -154
  11. cognite/neat/_graph/extractors/_classic_cdf/_base.py +154 -7
  12. cognite/neat/_graph/extractors/_classic_cdf/_classic.py +25 -14
  13. cognite/neat/_graph/extractors/_classic_cdf/_data_sets.py +17 -92
  14. cognite/neat/_graph/extractors/_classic_cdf/_events.py +13 -162
  15. cognite/neat/_graph/extractors/_classic_cdf/_files.py +15 -179
  16. cognite/neat/_graph/extractors/_classic_cdf/_labels.py +32 -100
  17. cognite/neat/_graph/extractors/_classic_cdf/_relationships.py +27 -178
  18. cognite/neat/_graph/extractors/_classic_cdf/_sequences.py +14 -139
  19. cognite/neat/_graph/extractors/_classic_cdf/_timeseries.py +15 -173
  20. cognite/neat/_graph/extractors/_rdf_file.py +6 -7
  21. cognite/neat/_graph/loaders/_rdf2dms.py +2 -2
  22. cognite/neat/_graph/queries/_base.py +17 -1
  23. cognite/neat/_graph/transformers/_classic_cdf.py +74 -147
  24. cognite/neat/_graph/transformers/_prune_graph.py +1 -1
  25. cognite/neat/_graph/transformers/_rdfpath.py +1 -1
  26. cognite/neat/_issues/_base.py +26 -17
  27. cognite/neat/_issues/errors/__init__.py +4 -2
  28. cognite/neat/_issues/errors/_external.py +7 -0
  29. cognite/neat/_issues/errors/_properties.py +2 -7
  30. cognite/neat/_issues/errors/_resources.py +1 -1
  31. cognite/neat/_issues/warnings/__init__.py +8 -0
  32. cognite/neat/_issues/warnings/_external.py +16 -0
  33. cognite/neat/_issues/warnings/_properties.py +16 -0
  34. cognite/neat/_issues/warnings/_resources.py +26 -2
  35. cognite/neat/_issues/warnings/user_modeling.py +4 -4
  36. cognite/neat/_rules/_constants.py +8 -11
  37. cognite/neat/_rules/analysis/_base.py +8 -4
  38. cognite/neat/_rules/exporters/_base.py +3 -4
  39. cognite/neat/_rules/exporters/_rules2dms.py +33 -46
  40. cognite/neat/_rules/importers/__init__.py +1 -3
  41. cognite/neat/_rules/importers/_base.py +1 -1
  42. cognite/neat/_rules/importers/_dms2rules.py +6 -29
  43. cognite/neat/_rules/importers/_rdf/__init__.py +5 -0
  44. cognite/neat/_rules/importers/_rdf/_base.py +34 -11
  45. cognite/neat/_rules/importers/_rdf/_imf2rules.py +91 -0
  46. cognite/neat/_rules/importers/_rdf/_inference2rules.py +43 -35
  47. cognite/neat/_rules/importers/_rdf/_owl2rules.py +80 -0
  48. cognite/neat/_rules/importers/_rdf/_shared.py +138 -441
  49. cognite/neat/_rules/models/__init__.py +1 -1
  50. cognite/neat/_rules/models/_base_rules.py +22 -12
  51. cognite/neat/_rules/models/dms/__init__.py +4 -2
  52. cognite/neat/_rules/models/dms/_exporter.py +45 -48
  53. cognite/neat/_rules/models/dms/_rules.py +20 -17
  54. cognite/neat/_rules/models/dms/_rules_input.py +52 -8
  55. cognite/neat/_rules/models/dms/_validation.py +391 -119
  56. cognite/neat/_rules/models/entities/_single_value.py +32 -4
  57. cognite/neat/_rules/models/information/__init__.py +2 -0
  58. cognite/neat/_rules/models/information/_rules.py +0 -67
  59. cognite/neat/_rules/models/information/_validation.py +9 -9
  60. cognite/neat/_rules/models/mapping/__init__.py +2 -3
  61. cognite/neat/_rules/models/mapping/_classic2core.py +36 -146
  62. cognite/neat/_rules/models/mapping/_classic2core.yaml +343 -0
  63. cognite/neat/_rules/transformers/__init__.py +2 -2
  64. cognite/neat/_rules/transformers/_converters.py +110 -11
  65. cognite/neat/_rules/transformers/_mapping.py +105 -30
  66. cognite/neat/_rules/transformers/_pipelines.py +1 -1
  67. cognite/neat/_rules/transformers/_verification.py +31 -3
  68. cognite/neat/_session/_base.py +24 -8
  69. cognite/neat/_session/_drop.py +35 -0
  70. cognite/neat/_session/_inspect.py +17 -5
  71. cognite/neat/_session/_mapping.py +39 -0
  72. cognite/neat/_session/_prepare.py +219 -23
  73. cognite/neat/_session/_read.py +49 -12
  74. cognite/neat/_session/_to.py +8 -5
  75. cognite/neat/_session/exceptions.py +4 -0
  76. cognite/neat/_store/_base.py +27 -24
  77. cognite/neat/_utils/rdf_.py +34 -5
  78. cognite/neat/_version.py +1 -1
  79. cognite/neat/_workflows/steps/lib/current/rules_exporter.py +5 -88
  80. cognite/neat/_workflows/steps/lib/current/rules_importer.py +3 -14
  81. cognite/neat/_workflows/steps/lib/current/rules_validator.py +6 -7
  82. {cognite_neat-0.98.0.dist-info → cognite_neat-0.99.1.dist-info}/METADATA +3 -3
  83. {cognite_neat-0.98.0.dist-info → cognite_neat-0.99.1.dist-info}/RECORD +87 -92
  84. cognite/neat/_rules/importers/_rdf/_imf2rules/__init__.py +0 -3
  85. cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2classes.py +0 -86
  86. cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2metadata.py +0 -29
  87. cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2properties.py +0 -130
  88. cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2rules.py +0 -154
  89. cognite/neat/_rules/importers/_rdf/_owl2rules/__init__.py +0 -3
  90. cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2classes.py +0 -58
  91. cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2metadata.py +0 -65
  92. cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2properties.py +0 -59
  93. cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2rules.py +0 -39
  94. cognite/neat/_rules/models/dms/_schema.py +0 -1101
  95. cognite/neat/_rules/models/mapping/_base.py +0 -131
  96. cognite/neat/_utils/cdf/loaders/__init__.py +0 -25
  97. cognite/neat/_utils/cdf/loaders/_base.py +0 -54
  98. cognite/neat/_utils/cdf/loaders/_data_modeling.py +0 -339
  99. cognite/neat/_utils/cdf/loaders/_ingestion.py +0 -167
  100. /cognite/neat/{_utils/cdf → _client/_api}/__init__.py +0 -0
  101. {cognite_neat-0.98.0.dist-info → cognite_neat-0.99.1.dist-info}/LICENSE +0 -0
  102. {cognite_neat-0.98.0.dist-info → cognite_neat-0.99.1.dist-info}/WHEEL +0 -0
  103. {cognite_neat-0.98.0.dist-info → cognite_neat-0.99.1.dist-info}/entry_points.txt +0 -0
@@ -2,8 +2,6 @@
2
2
  its sub-models and validators.
3
3
  """
4
4
 
5
- from __future__ import annotations
6
-
7
5
  import math
8
6
  import sys
9
7
  import types
@@ -39,13 +37,16 @@ from rdflib import Namespace, URIRef
39
37
 
40
38
  from cognite.neat._constants import DEFAULT_NAMESPACE
41
39
  from cognite.neat._rules.models._types import (
42
- ClassEntityType,
40
+ ContainerEntityType,
43
41
  DataModelExternalIdType,
44
- InformationPropertyType,
42
+ DmsPropertyType,
45
43
  SpaceType,
46
44
  StrListType,
47
45
  VersionType,
46
+ ViewEntityType,
48
47
  )
48
+ from cognite.neat._rules.models.data_types import DataType
49
+ from cognite.neat._rules.models.entities import EdgeEntity, ReverseConnectionEntity, ViewEntity
49
50
 
50
51
  if sys.version_info >= (3, 11):
51
52
  from enum import StrEnum
@@ -249,7 +250,7 @@ class BaseRules(SchemaModel, ABC):
249
250
  """Returns a list of headers for the model, typically used by ExcelExporter"""
250
251
  headers_by_sheet: dict[str, list[str]] = {}
251
252
  for field_name, field in cls.model_fields.items():
252
- if field_name == "validators_to_skip":
253
+ if field_name in ["validators_to_skip", "post_validate"]:
253
254
  continue
254
255
  sheet_name = (field.alias or field_name) if by_alias else field_name
255
256
  annotation = field.annotation
@@ -379,9 +380,9 @@ class SheetList(list, MutableSequence[T_SheetRow]):
379
380
  def __getitem__(self, index: SupportsIndex) -> T_SheetRow: ...
380
381
 
381
382
  @overload
382
- def __getitem__(self, index: slice) -> SheetList[T_SheetRow]: ...
383
+ def __getitem__(self, index: slice) -> "SheetList[T_SheetRow]": ...
383
384
 
384
- def __getitem__(self, index: SupportsIndex | slice, /) -> T_SheetRow | SheetList[T_SheetRow]:
385
+ def __getitem__(self, index: SupportsIndex | slice, /) -> "T_SheetRow | SheetList[T_SheetRow]":
385
386
  if isinstance(index, slice):
386
387
  return SheetList[T_SheetRow](super().__getitem__(index))
387
388
  return super().__getitem__(index)
@@ -399,10 +400,19 @@ ExtensionCategoryType = Annotated[
399
400
 
400
401
 
401
402
  # Immutable such that this can be used as a key in a dictionary
402
- class PropertyRef(BaseModel, frozen=True):
403
- class_: ClassEntityType = Field(alias="Class")
404
- property_: InformationPropertyType = Field(alias="Property")
403
+ class ContainerProperty(BaseModel, frozen=True):
404
+ container: ContainerEntityType
405
+ property_: DmsPropertyType
406
+
407
+
408
+ class ContainerDestinationProperty(ContainerProperty, frozen=True):
409
+ value_type: DataType | ViewEntity
410
+ connection: Literal["direct"] | ReverseConnectionEntity | EdgeEntity | None = None
411
+
412
+
413
+ class ViewRef(BaseModel, frozen=True):
414
+ view: ViewEntityType
405
415
 
406
416
 
407
- class ClassRef(BaseModel, frozen=True):
408
- class_: ClassEntityType = Field(alias="Class")
417
+ class ViewProperty(ViewRef, frozen=True):
418
+ property_: DmsPropertyType
@@ -1,3 +1,5 @@
1
+ from cognite.neat._client.data_classes.schema import DMSSchema
2
+
1
3
  from ._rules import DMSContainer, DMSEnum, DMSMetadata, DMSNode, DMSProperty, DMSRules, DMSView
2
4
  from ._rules_input import (
3
5
  DMSInputContainer,
@@ -8,7 +10,7 @@ from ._rules_input import (
8
10
  DMSInputRules,
9
11
  DMSInputView,
10
12
  )
11
- from ._schema import DMSSchema, PipelineSchema
13
+ from ._validation import DMSValidation
12
14
 
13
15
  __all__ = [
14
16
  "DMSRules",
@@ -19,7 +21,6 @@ __all__ = [
19
21
  "DMSContainer",
20
22
  "DMSNode",
21
23
  "DMSEnum",
22
- "PipelineSchema",
23
24
  "DMSInputRules",
24
25
  "DMSInputMetadata",
25
26
  "DMSInputView",
@@ -27,4 +28,5 @@ __all__ = [
27
28
  "DMSInputContainer",
28
29
  "DMSInputNode",
29
30
  "DMSInputEnum",
31
+ "DMSValidation",
30
32
  ]
@@ -13,6 +13,14 @@ from cognite.client.data_classes.data_modeling.views import (
13
13
  ViewPropertyApply,
14
14
  )
15
15
 
16
+ from cognite.neat._client.data_classes.data_modeling import (
17
+ ContainerApplyDict,
18
+ NodeApplyDict,
19
+ SpaceApplyDict,
20
+ ViewApplyDict,
21
+ )
22
+ from cognite.neat._client.data_classes.schema import DMSSchema
23
+ from cognite.neat._constants import COGNITE_SPACES
16
24
  from cognite.neat._issues.errors import NeatTypeError, ResourceNotFoundError
17
25
  from cognite.neat._issues.warnings import NotSupportedWarning, PropertyNotFoundWarning
18
26
  from cognite.neat._issues.warnings.user_modeling import (
@@ -33,10 +41,8 @@ from cognite.neat._rules.models.entities import (
33
41
  UnitEntity,
34
42
  ViewEntity,
35
43
  )
36
- from cognite.neat._utils.cdf.data_classes import ContainerApplyDict, NodeApplyDict, SpaceApplyDict, ViewApplyDict
37
44
 
38
45
  from ._rules import DMSEnum, DMSMetadata, DMSProperty, DMSRules, DMSView
39
- from ._schema import DMSSchema, PipelineSchema
40
46
 
41
47
 
42
48
  class _DMSExporter:
@@ -49,25 +55,13 @@ class _DMSExporter:
49
55
  include_pipeline (bool): If True, the pipeline will be included with the schema. Pipeline means the
50
56
  raw tables and transformations necessary to populate the data model.
51
57
  instance_space (str): The space to use for the instance. Defaults to None,`Rules.metadata.space` will be used
58
+ remove_cdf_spaces(bool): The
52
59
  """
53
60
 
54
- def __init__(
55
- self,
56
- rules: DMSRules,
57
- include_pipeline: bool = False,
58
- instance_space: str | None = None,
59
- ):
60
- self.include_pipeline = include_pipeline
61
+ def __init__(self, rules: DMSRules, instance_space: str | None = None, remove_cdf_spaces: bool = False):
61
62
  self.instance_space = instance_space
62
63
  self.rules = rules
63
- self._ref_schema = None
64
- if self._ref_schema:
65
- # We skip version as that will always be missing in the reference
66
- self._ref_views_by_id = {
67
- dm.ViewId(view.space, view.external_id): view for view in self._ref_schema.views.values()
68
- }
69
- else:
70
- self._ref_views_by_id = {} # type: ignore
64
+ self.remove_cdf_spaces = remove_cdf_spaces
71
65
 
72
66
  def to_schema(self) -> DMSSchema:
73
67
  rules = self.rules
@@ -79,44 +73,39 @@ class _DMSExporter:
79
73
  view_properties_by_id, rules.views
80
74
  )
81
75
 
82
- views, view_node_type_filters = self._create_views_with_node_types(
83
- view_properties_by_id, view_properties_with_ancestors_by_id
84
- )
76
+ views = self._create_views(view_properties_by_id, view_properties_with_ancestors_by_id)
77
+ view_node_type_filters: set[dm.NodeId] = set()
78
+ for dms_view in rules.views:
79
+ if isinstance(dms_view.filter_, NodeTypeFilter):
80
+ view_node_type_filters.update(node.as_id() for node in dms_view.filter_.inner or [])
85
81
  if rules.nodes:
86
82
  node_types = NodeApplyDict(
87
83
  [node.as_node() for node in rules.nodes]
88
84
  + [dm.NodeApply(node.space, node.external_id) for node in view_node_type_filters]
89
85
  )
90
86
  else:
91
- node_types = NodeApplyDict([dm.NodeApply(node.space, node.external_id) for node in view_node_type_filters])
92
-
93
- last_schema: DMSSchema | None = None
87
+ node_types = NodeApplyDict(
88
+ [
89
+ dm.NodeApply(node.space, node.external_id)
90
+ for node in view_node_type_filters
91
+ if not (self.remove_cdf_spaces and node.space in COGNITE_SPACES)
92
+ ]
93
+ )
94
94
 
95
- views_not_in_model = {view.view.as_id() for view in rules.views if not view.in_model}
96
95
  data_model = rules.metadata.as_data_model()
97
-
98
- data_model_views = [view_id for view_id in views if view_id not in views_not_in_model]
99
-
100
96
  # Sorting to ensure deterministic order
101
- data_model.views = sorted(data_model_views, key=lambda v: v.as_tuple()) # type: ignore[union-attr]
102
-
97
+ data_model.views = sorted(
98
+ [dms_view.view.as_id() for dms_view in rules.views if dms_view.in_model],
99
+ key=lambda x: x.as_tuple(), # type: ignore[union-attr]
100
+ )
103
101
  spaces = self._create_spaces(rules.metadata, containers, views, data_model)
104
-
105
- output = DMSSchema(
102
+ return DMSSchema(
106
103
  spaces=spaces,
107
104
  data_model=data_model,
108
105
  views=views,
109
106
  containers=containers,
110
107
  node_types=node_types,
111
108
  )
112
- if self.include_pipeline:
113
- return PipelineSchema.from_dms(output, self.instance_space)
114
-
115
- if self._ref_schema:
116
- output.reference = self._ref_schema
117
- if last_schema:
118
- output.last = last_schema
119
- return output
120
109
 
121
110
  def _create_spaces(
122
111
  self,
@@ -137,14 +126,20 @@ class _DMSExporter:
137
126
  spaces[self.instance_space] = dm.SpaceApply(space=self.instance_space, name=self.instance_space)
138
127
  return spaces
139
128
 
140
- def _create_views_with_node_types(
129
+ def _create_views(
141
130
  self,
142
131
  view_properties_by_id: dict[dm.ViewId, list[DMSProperty]],
143
132
  view_properties_with_ancestors_by_id: dict[dm.ViewId, list[DMSProperty]],
144
- ) -> tuple[ViewApplyDict, set[dm.NodeId]]:
133
+ ) -> ViewApplyDict:
145
134
  input_views = list(self.rules.views)
146
135
 
147
- views = ViewApplyDict([dms_view.as_view() for dms_view in input_views])
136
+ views = ViewApplyDict(
137
+ [
138
+ dms_view.as_view()
139
+ for dms_view in input_views
140
+ if not (self.remove_cdf_spaces and dms_view.view.space in COGNITE_SPACES)
141
+ ]
142
+ )
148
143
 
149
144
  for view_id, view in views.items():
150
145
  view.properties = {}
@@ -155,11 +150,7 @@ class _DMSExporter:
155
150
  if view_property is not None:
156
151
  view.properties[prop.view_property] = view_property
157
152
 
158
- unique_node_types: set[dm.NodeId] = set()
159
- for view in views.values():
160
- unique_node_types.add(dm.NodeId(space=view.space, external_id=view.external_id))
161
-
162
- return views, unique_node_types
153
+ return views
163
154
 
164
155
  @classmethod
165
156
  def _create_edge_type_from_prop(cls, prop: DMSProperty) -> dm.DirectRelationReference:
@@ -189,7 +180,13 @@ class _DMSExporter:
189
180
 
190
181
  containers = list(self.rules.containers or [])
191
182
 
192
- containers = dm.ContainerApplyList([dms_container.as_container() for dms_container in containers])
183
+ containers = dm.ContainerApplyList(
184
+ [
185
+ dms_container.as_container()
186
+ for dms_container in containers
187
+ if not (self.remove_cdf_spaces and dms_container.container.space in COGNITE_SPACES)
188
+ ]
189
+ )
193
190
  container_to_drop = set()
194
191
  for container in containers:
195
192
  container_id = container.as_id()
@@ -4,22 +4,26 @@ from typing import Any, ClassVar, Literal
4
4
 
5
5
  import pandas as pd
6
6
  from cognite.client import data_modeling as dm
7
- from pydantic import Field, field_serializer, field_validator, model_validator
7
+ from pydantic import Field, field_serializer, field_validator
8
8
  from pydantic_core.core_schema import SerializationInfo, ValidationInfo
9
9
  from rdflib import URIRef
10
10
 
11
+ from cognite.neat._client.data_classes.schema import DMSSchema
11
12
  from cognite.neat._constants import COGNITE_SPACES
12
- from cognite.neat._issues import MultiValueError
13
+ from cognite.neat._issues.errors import NeatValueError
13
14
  from cognite.neat._issues.warnings import (
14
15
  PrincipleMatchingSpaceAndVersionWarning,
15
16
  )
16
17
  from cognite.neat._rules.models._base_rules import (
17
18
  BaseMetadata,
18
19
  BaseRules,
20
+ ContainerProperty,
19
21
  DataModelAspect,
20
22
  RoleTypes,
21
23
  SheetList,
22
24
  SheetRow,
25
+ ViewProperty,
26
+ ViewRef,
23
27
  )
24
28
  from cognite.neat._rules.models._types import (
25
29
  ClassEntityType,
@@ -44,8 +48,6 @@ from cognite.neat._rules.models.entities import (
44
48
  ViewEntityList,
45
49
  )
46
50
 
47
- from ._schema import DMSSchema
48
-
49
51
  _DEFAULT_VERSION = "1"
50
52
 
51
53
 
@@ -180,6 +182,14 @@ class DMSProperty(SheetRow):
180
182
  return value.dump(space=metadata.space, version=metadata.version, type=default_type)
181
183
  return str(value)
182
184
 
185
+ def as_container_reference(self) -> ContainerProperty:
186
+ if self.container is None or self.container_property is None:
187
+ raise NeatValueError("Accessing container reference without container and container property set")
188
+ return ContainerProperty(container=self.container, property_=self.container_property)
189
+
190
+ def as_view_reference(self) -> ViewProperty:
191
+ return ViewProperty(view=self.view, property_=self.view_property)
192
+
183
193
 
184
194
  class DMSContainer(SheetRow):
185
195
  container: ContainerEntityType = Field(alias="Container")
@@ -272,10 +282,14 @@ class DMSView(SheetRow):
272
282
  version=view_id.version or _DEFAULT_VERSION,
273
283
  name=self.name or None,
274
284
  description=self.description,
285
+ filter=None if self.filter_ is None else self.filter_.as_dms_filter(),
275
286
  implements=implements,
276
287
  properties={},
277
288
  )
278
289
 
290
+ def as_view_reference(self) -> ViewRef:
291
+ return ViewRef(view=self.view)
292
+
279
293
 
280
294
  class DMSNode(SheetRow):
281
295
  node: DMSNodeEntity = Field(alias="Node")
@@ -356,21 +370,10 @@ class DMSRules(BaseRules):
356
370
  )
357
371
  return value
358
372
 
359
- @model_validator(mode="after")
360
- def post_validation(self) -> "DMSRules":
361
- from ._validation import DMSPostValidation
362
-
363
- issue_list = DMSPostValidation(self).validate()
364
- if issue_list.warnings:
365
- issue_list.trigger_warnings()
366
- if issue_list.has_errors:
367
- raise MultiValueError(issue_list.errors)
368
- return self
369
-
370
- def as_schema(self, include_pipeline: bool = False, instance_space: str | None = None) -> DMSSchema:
373
+ def as_schema(self, instance_space: str | None = None, remove_cdf_spaces: bool = False) -> DMSSchema:
371
374
  from ._exporter import _DMSExporter
372
375
 
373
- return _DMSExporter(self, include_pipeline, instance_space).to_schema()
376
+ return _DMSExporter(self, instance_space, remove_cdf_spaces=remove_cdf_spaces).to_schema()
374
377
 
375
378
  def _repr_html_(self) -> str:
376
379
  summary = {
@@ -5,6 +5,7 @@ from typing import Any, Literal
5
5
 
6
6
  import pandas as pd
7
7
  from cognite.client import data_modeling as dm
8
+ from cognite.client.data_classes.data_modeling import ContainerId, ViewId
8
9
  from rdflib import Namespace, URIRef
9
10
 
10
11
  from cognite.neat._constants import DEFAULT_NAMESPACE
@@ -125,6 +126,12 @@ class DMSInputProperty(InputComponent[DMSProperty]):
125
126
  )
126
127
  return output
127
128
 
129
+ def referenced_view(self, default_space: str, default_version: str) -> ViewEntity:
130
+ return ViewEntity.load(self.view, strict=True, space=default_space, version=default_version)
131
+
132
+ def referenced_container(self, default_space: str) -> ContainerEntity | None:
133
+ return ContainerEntity.load(self.container, strict=True, space=default_space) if self.container else None
134
+
128
135
 
129
136
  @dataclass
130
137
  class DMSInputContainer(InputComponent[DMSContainer]):
@@ -140,8 +147,7 @@ class DMSInputContainer(InputComponent[DMSContainer]):
140
147
 
141
148
  def dump(self, default_space: str) -> dict[str, Any]: # type: ignore[override]
142
149
  output = super().dump()
143
- container = ContainerEntity.load(self.container, space=default_space)
144
- output["Container"] = container
150
+ output["Container"] = self.as_entity_id(default_space)
145
151
  output["Constraint"] = (
146
152
  [ContainerEntity.load(constraint.strip(), space=default_space) for constraint in self.constraint.split(",")]
147
153
  if self.constraint
@@ -149,6 +155,9 @@ class DMSInputContainer(InputComponent[DMSContainer]):
149
155
  )
150
156
  return output
151
157
 
158
+ def as_entity_id(self, default_space: str) -> ContainerEntity:
159
+ return ContainerEntity.load(self.container, strict=True, space=default_space)
160
+
152
161
  @classmethod
153
162
  def from_container(cls, container: dm.ContainerApply) -> "DMSInputContainer":
154
163
  constraints: list[str] = []
@@ -172,7 +181,7 @@ class DMSInputView(InputComponent[DMSView]):
172
181
  name: str | None = None
173
182
  description: str | None = None
174
183
  implements: str | None = None
175
- filter_: Literal["hasData", "nodeType", "rawFilter"] | None = None
184
+ filter_: Literal["hasData", "nodeType", "rawFilter"] | str | None = None
176
185
  in_model: bool = True
177
186
  logical: str | None = None
178
187
 
@@ -182,17 +191,25 @@ class DMSInputView(InputComponent[DMSView]):
182
191
 
183
192
  def dump(self, default_space: str, default_version: str) -> dict[str, Any]: # type: ignore[override]
184
193
  output = super().dump()
185
- view = ViewEntity.load(self.view, space=default_space, version=default_version)
186
- output["View"] = view
187
- output["Implements"] = (
194
+ output["View"] = self.as_entity_id(default_space, default_version)
195
+ output["Implements"] = self._load_implements(default_space, default_version)
196
+ return output
197
+
198
+ def as_entity_id(self, default_space: str, default_version: str) -> ViewEntity:
199
+ return ViewEntity.load(self.view, strict=True, space=default_space, version=default_version)
200
+
201
+ def _load_implements(self, default_space: str, default_version: str) -> list[ViewEntity] | None:
202
+ return (
188
203
  [
189
- ViewEntity.load(implement, space=default_space, version=default_version)
204
+ ViewEntity.load(implement, strict=True, space=default_space, version=default_version)
190
205
  for implement in self.implements.split(",")
191
206
  ]
192
207
  if self.implements
193
208
  else None
194
209
  )
195
- return output
210
+
211
+ def referenced_views(self, default_space: str, default_version: str) -> list[ViewEntity]:
212
+ return self._load_implements(default_space, default_version) or []
196
213
 
197
214
  @classmethod
198
215
  def from_view(cls, view: dm.ViewApply, in_model: bool) -> "DMSInputView":
@@ -287,3 +304,30 @@ class DMSInputRules(InputRules[DMSRules]):
287
304
  return DEFAULT_NAMESPACE[
288
305
  f"data-model/unverified/dms/{self.metadata.space}/{self.metadata.external_id}/{self.metadata.version}"
289
306
  ]
307
+
308
+ def referenced_views_and_containers(self) -> tuple[set[ViewEntity], set[ContainerEntity]]:
309
+ default_space = self.metadata.space
310
+ default_version = self.metadata.version
311
+
312
+ containers: set[ContainerEntity] = set()
313
+ views = {parent for view in self.views for parent in view.referenced_views(default_space, default_version)}
314
+ for prop in self.properties:
315
+ views.add(prop.referenced_view(default_space, default_version))
316
+ if ref_container := prop.referenced_container(default_space):
317
+ containers.add(ref_container)
318
+
319
+ return views, containers
320
+
321
+ def as_view_entities(self) -> list[ViewEntity]:
322
+ return [view.as_entity_id(self.metadata.space, self.metadata.version) for view in self.views]
323
+
324
+ def as_container_entities(self) -> list[ContainerEntity]:
325
+ return [container.as_entity_id(self.metadata.space) for container in self.containers or []]
326
+
327
+ def imported_views_and_containers(self) -> tuple[set[ViewEntity], set[ContainerEntity]]:
328
+ views, containers = self.referenced_views_and_containers()
329
+ return views - set(self.as_view_entities()), containers - set(self.as_container_entities())
330
+
331
+ def imported_views_and_containers_ids(self) -> tuple[set[ViewId], set[ContainerId]]:
332
+ views, containers = self.imported_views_and_containers()
333
+ return {view.as_id() for view in views}, {container.as_id() for container in containers}