cognite-neat 0.104.0__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 (141) 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 +1 -1
  10. cognite/neat/_graph/loaders/_rdf2dms.py +13 -2
  11. cognite/neat/_graph/transformers/__init__.py +3 -1
  12. cognite/neat/_graph/transformers/_classic_cdf.py +2 -1
  13. cognite/neat/_graph/transformers/_value_type.py +72 -0
  14. cognite/neat/_issues/__init__.py +0 -2
  15. cognite/neat/_issues/_base.py +19 -35
  16. cognite/neat/_issues/warnings/__init__.py +4 -1
  17. cognite/neat/_issues/warnings/_general.py +7 -0
  18. cognite/neat/_issues/warnings/_resources.py +11 -0
  19. cognite/neat/_rules/exporters/_rules2dms.py +35 -1
  20. cognite/neat/_rules/exporters/_rules2excel.py +2 -2
  21. cognite/neat/_rules/importers/_dms2rules.py +66 -55
  22. cognite/neat/_rules/models/_base_rules.py +4 -1
  23. cognite/neat/_rules/models/entities/_wrapped.py +10 -5
  24. cognite/neat/_rules/models/mapping/_classic2core.yaml +239 -38
  25. cognite/neat/_rules/transformers/__init__.py +8 -2
  26. cognite/neat/_rules/transformers/_converters.py +271 -188
  27. cognite/neat/_rules/transformers/_mapping.py +75 -59
  28. cognite/neat/_rules/transformers/_verification.py +2 -3
  29. cognite/neat/_session/_inspect.py +3 -1
  30. cognite/neat/_session/_prepare.py +112 -24
  31. cognite/neat/_session/_read.py +33 -70
  32. cognite/neat/_session/_state.py +2 -2
  33. cognite/neat/_session/_to.py +2 -2
  34. cognite/neat/_store/_rules_store.py +4 -8
  35. cognite/neat/_utils/reader/_base.py +27 -0
  36. cognite/neat/_version.py +1 -1
  37. {cognite_neat-0.104.0.dist-info → cognite_neat-0.105.0.dist-info}/METADATA +3 -2
  38. cognite_neat-0.105.0.dist-info/RECORD +179 -0
  39. {cognite_neat-0.104.0.dist-info → cognite_neat-0.105.0.dist-info}/WHEEL +1 -1
  40. cognite/neat/_app/api/__init__.py +0 -0
  41. cognite/neat/_app/api/asgi/metrics.py +0 -4
  42. cognite/neat/_app/api/configuration.py +0 -98
  43. cognite/neat/_app/api/context_manager/__init__.py +0 -3
  44. cognite/neat/_app/api/context_manager/manager.py +0 -16
  45. cognite/neat/_app/api/data_classes/__init__.py +0 -0
  46. cognite/neat/_app/api/data_classes/rest.py +0 -59
  47. cognite/neat/_app/api/explorer.py +0 -66
  48. cognite/neat/_app/api/routers/configuration.py +0 -25
  49. cognite/neat/_app/api/routers/crud.py +0 -102
  50. cognite/neat/_app/api/routers/metrics.py +0 -10
  51. cognite/neat/_app/api/routers/workflows.py +0 -224
  52. cognite/neat/_app/api/utils/__init__.py +0 -0
  53. cognite/neat/_app/api/utils/data_mapping.py +0 -17
  54. cognite/neat/_app/api/utils/logging.py +0 -26
  55. cognite/neat/_app/api/utils/query_templates.py +0 -92
  56. cognite/neat/_app/main.py +0 -17
  57. cognite/neat/_app/monitoring/__init__.py +0 -0
  58. cognite/neat/_app/monitoring/metrics.py +0 -69
  59. cognite/neat/_app/ui/index.html +0 -1
  60. cognite/neat/_app/ui/neat-app/.gitignore +0 -23
  61. cognite/neat/_app/ui/neat-app/README.md +0 -70
  62. cognite/neat/_app/ui/neat-app/build/asset-manifest.json +0 -14
  63. cognite/neat/_app/ui/neat-app/build/favicon.ico +0 -0
  64. cognite/neat/_app/ui/neat-app/build/img/architect-icon.svg +0 -116
  65. cognite/neat/_app/ui/neat-app/build/img/developer-icon.svg +0 -112
  66. cognite/neat/_app/ui/neat-app/build/img/sme-icon.svg +0 -34
  67. cognite/neat/_app/ui/neat-app/build/index.html +0 -1
  68. cognite/neat/_app/ui/neat-app/build/logo192.png +0 -0
  69. cognite/neat/_app/ui/neat-app/build/manifest.json +0 -25
  70. cognite/neat/_app/ui/neat-app/build/robots.txt +0 -3
  71. cognite/neat/_app/ui/neat-app/build/static/css/main.72e3d92e.css +0 -2
  72. cognite/neat/_app/ui/neat-app/build/static/css/main.72e3d92e.css.map +0 -1
  73. cognite/neat/_app/ui/neat-app/build/static/js/main.5a52cf09.js +0 -3
  74. cognite/neat/_app/ui/neat-app/build/static/js/main.5a52cf09.js.LICENSE.txt +0 -88
  75. cognite/neat/_app/ui/neat-app/build/static/js/main.5a52cf09.js.map +0 -1
  76. cognite/neat/_app/ui/neat-app/build/static/media/logo.8093b84df9ed36a174c629d6fe0b730d.svg +0 -1
  77. cognite/neat/_app/ui/neat-app/package-lock.json +0 -18306
  78. cognite/neat/_app/ui/neat-app/package.json +0 -62
  79. cognite/neat/_app/ui/neat-app/public/favicon.ico +0 -0
  80. cognite/neat/_app/ui/neat-app/public/img/architect-icon.svg +0 -116
  81. cognite/neat/_app/ui/neat-app/public/img/developer-icon.svg +0 -112
  82. cognite/neat/_app/ui/neat-app/public/img/sme-icon.svg +0 -34
  83. cognite/neat/_app/ui/neat-app/public/index.html +0 -43
  84. cognite/neat/_app/ui/neat-app/public/logo192.png +0 -0
  85. cognite/neat/_app/ui/neat-app/public/manifest.json +0 -25
  86. cognite/neat/_app/ui/neat-app/public/robots.txt +0 -3
  87. cognite/neat/_app/ui/neat-app/src/App.css +0 -38
  88. cognite/neat/_app/ui/neat-app/src/App.js +0 -17
  89. cognite/neat/_app/ui/neat-app/src/App.test.js +0 -8
  90. cognite/neat/_app/ui/neat-app/src/MainContainer.tsx +0 -70
  91. cognite/neat/_app/ui/neat-app/src/components/JsonViewer.tsx +0 -43
  92. cognite/neat/_app/ui/neat-app/src/components/LocalUploader.tsx +0 -124
  93. cognite/neat/_app/ui/neat-app/src/components/OverviewComponentEditorDialog.tsx +0 -63
  94. cognite/neat/_app/ui/neat-app/src/components/StepEditorDialog.tsx +0 -511
  95. cognite/neat/_app/ui/neat-app/src/components/TabPanel.tsx +0 -36
  96. cognite/neat/_app/ui/neat-app/src/components/Utils.tsx +0 -56
  97. cognite/neat/_app/ui/neat-app/src/components/WorkflowDeleteDialog.tsx +0 -60
  98. cognite/neat/_app/ui/neat-app/src/components/WorkflowExecutionReport.tsx +0 -112
  99. cognite/neat/_app/ui/neat-app/src/components/WorkflowImportExportDialog.tsx +0 -67
  100. cognite/neat/_app/ui/neat-app/src/components/WorkflowMetadataDialog.tsx +0 -79
  101. cognite/neat/_app/ui/neat-app/src/index.css +0 -13
  102. cognite/neat/_app/ui/neat-app/src/index.js +0 -13
  103. cognite/neat/_app/ui/neat-app/src/logo.svg +0 -1
  104. cognite/neat/_app/ui/neat-app/src/reportWebVitals.js +0 -13
  105. cognite/neat/_app/ui/neat-app/src/setupTests.js +0 -5
  106. cognite/neat/_app/ui/neat-app/src/types/WorkflowTypes.ts +0 -388
  107. cognite/neat/_app/ui/neat-app/src/views/AboutView.tsx +0 -61
  108. cognite/neat/_app/ui/neat-app/src/views/ConfigView.tsx +0 -184
  109. cognite/neat/_app/ui/neat-app/src/views/GlobalConfigView.tsx +0 -180
  110. cognite/neat/_app/ui/neat-app/src/views/WorkflowView.tsx +0 -570
  111. cognite/neat/_app/ui/neat-app/tsconfig.json +0 -27
  112. cognite/neat/_workflows/__init__.py +0 -17
  113. cognite/neat/_workflows/base.py +0 -590
  114. cognite/neat/_workflows/cdf_store.py +0 -393
  115. cognite/neat/_workflows/examples/Export_DMS/workflow.yaml +0 -89
  116. cognite/neat/_workflows/examples/Export_Semantic_Data_Model/workflow.yaml +0 -66
  117. cognite/neat/_workflows/examples/Import_DMS/workflow.yaml +0 -65
  118. cognite/neat/_workflows/examples/Validate_Rules/workflow.yaml +0 -67
  119. cognite/neat/_workflows/examples/Validate_Solution_Model/workflow.yaml +0 -64
  120. cognite/neat/_workflows/manager.py +0 -292
  121. cognite/neat/_workflows/model.py +0 -203
  122. cognite/neat/_workflows/steps/__init__.py +0 -0
  123. cognite/neat/_workflows/steps/data_contracts.py +0 -109
  124. cognite/neat/_workflows/steps/lib/__init__.py +0 -0
  125. cognite/neat/_workflows/steps/lib/current/__init__.py +0 -6
  126. cognite/neat/_workflows/steps/lib/current/graph_extractor.py +0 -100
  127. cognite/neat/_workflows/steps/lib/current/graph_loader.py +0 -51
  128. cognite/neat/_workflows/steps/lib/current/graph_store.py +0 -48
  129. cognite/neat/_workflows/steps/lib/current/rules_exporter.py +0 -537
  130. cognite/neat/_workflows/steps/lib/current/rules_importer.py +0 -323
  131. cognite/neat/_workflows/steps/lib/current/rules_validator.py +0 -106
  132. cognite/neat/_workflows/steps/lib/io/__init__.py +0 -1
  133. cognite/neat/_workflows/steps/lib/io/io_steps.py +0 -393
  134. cognite/neat/_workflows/steps/step_model.py +0 -79
  135. cognite/neat/_workflows/steps_registry.py +0 -218
  136. cognite/neat/_workflows/tasks.py +0 -18
  137. cognite/neat/_workflows/triggers.py +0 -169
  138. cognite/neat/_workflows/utils.py +0 -19
  139. cognite_neat-0.104.0.dist-info/RECORD +0 -276
  140. {cognite_neat-0.104.0.dist-info → cognite_neat-0.105.0.dist-info}/LICENSE +0 -0
  141. {cognite_neat-0.104.0.dist-info → cognite_neat-0.105.0.dist-info}/entry_points.txt +0 -0
@@ -1,6 +1,6 @@
1
- from collections import Counter, defaultdict
1
+ from collections import defaultdict
2
2
  from collections.abc import Collection, Iterable, Sequence
3
- from datetime import datetime, timezone
3
+ from datetime import datetime
4
4
  from pathlib import Path
5
5
  from typing import Literal, cast
6
6
 
@@ -20,12 +20,19 @@ from cognite.client.utils import ms_to_datetime
20
20
 
21
21
  from cognite.neat._client import NeatClient
22
22
  from cognite.neat._issues import IssueList, MultiValueError, NeatIssue
23
- from cognite.neat._issues.errors import FileTypeUnexpectedError, ResourceMissingIdentifierError, ResourceRetrievalError
23
+ from cognite.neat._issues.errors import (
24
+ FileTypeUnexpectedError,
25
+ NeatValueError,
26
+ ResourceMissingIdentifierError,
27
+ ResourceRetrievalError,
28
+ )
24
29
  from cognite.neat._issues.warnings import (
30
+ MissingCogniteClientWarning,
25
31
  PropertyNotFoundWarning,
26
32
  PropertyTypeNotSupportedWarning,
27
33
  ResourceNotFoundWarning,
28
34
  ResourcesDuplicatedWarning,
35
+ ResourceUnknownWarning,
29
36
  )
30
37
  from cognite.neat._rules._shared import ReadRules
31
38
  from cognite.neat._rules.importers._base import BaseImporter, _handle_issues
@@ -60,7 +67,6 @@ class DMSImporter(BaseImporter[DMSInputRules]):
60
67
  schema: The schema containing the data model.
61
68
  read_issues: A list of issues that occurred during the import.
62
69
  metadata: Metadata for the data model.
63
- ref_metadata: Metadata for the reference data model.
64
70
 
65
71
  """
66
72
 
@@ -69,30 +75,23 @@ class DMSImporter(BaseImporter[DMSInputRules]):
69
75
  schema: DMSSchema,
70
76
  read_issues: Sequence[NeatIssue] | None = None,
71
77
  metadata: DMSInputMetadata | None = None,
72
- ref_metadata: DMSInputMetadata | None = None,
78
+ referenced_containers: Iterable[dm.ContainerApply] | None = None,
73
79
  ):
74
- # Calling this root schema to distinguish it from
75
- # * User Schema
76
- # * Reference Schema
77
- self.root_schema = schema
80
+ self.schema = schema
78
81
  self.metadata = metadata
79
- self.ref_metadata = ref_metadata
80
82
  self.issue_list = IssueList(read_issues)
81
83
  self._all_containers_by_id = schema.containers.copy()
82
84
  self._all_views_by_id = schema.views.copy()
83
-
84
- def update_referenced_containers(self, containers: Iterable[dm.ContainerApply]) -> None:
85
- """Update the referenced containers. This is useful to add Cognite containers identified after the root schema
86
- is read"""
87
- for container in containers:
88
- if container.as_id() in self._all_containers_by_id:
89
- continue
90
- self._all_containers_by_id[container.as_id()] = container
85
+ if referenced_containers is not None:
86
+ for container in referenced_containers:
87
+ if container.as_id() in self._all_containers_by_id:
88
+ continue
89
+ self._all_containers_by_id[container.as_id()] = container
91
90
 
92
91
  @property
93
92
  def description(self) -> str:
94
- if self.root_schema.data_model is not None:
95
- identifier = f"{self.root_schema.data_model.as_id().as_tuple()!s}"
93
+ if self.schema.data_model is not None:
94
+ identifier = f"{self.schema.data_model.as_id().as_tuple()!s}"
96
95
  else:
97
96
  identifier = "Unknown"
98
97
  return f"DMS Data model {identifier} read as unverified data model"
@@ -107,8 +106,6 @@ class DMSImporter(BaseImporter[DMSInputRules]):
107
106
 
108
107
  Args:
109
108
  client: Instantiated CogniteClient to retrieve data model.
110
- reference_model_id: The reference data model to retrieve. This is the data model that
111
- the given data model is built on top of, typically, an enterprise data model.
112
109
  data_model_id: Data Model to retrieve.
113
110
 
114
111
  Returns:
@@ -141,7 +138,12 @@ class DMSImporter(BaseImporter[DMSInputRules]):
141
138
 
142
139
  metadata = cls._create_metadata_from_model(user_model)
143
140
 
144
- return cls(schema, issue_list, metadata, None)
141
+ return cls(
142
+ schema,
143
+ issue_list,
144
+ metadata,
145
+ referenced_containers=cls._lookup_referenced_containers(schema, issue_list, client),
146
+ )
145
147
 
146
148
  @classmethod
147
149
  def _find_model_in_list(
@@ -182,15 +184,17 @@ class DMSImporter(BaseImporter[DMSInputRules]):
182
184
  )
183
185
 
184
186
  @classmethod
185
- def from_directory(cls, directory: str | Path) -> "DMSImporter":
187
+ def from_directory(cls, directory: str | Path, client: NeatClient | None = None) -> "DMSImporter":
186
188
  issue_list = IssueList()
187
189
  with _handle_issues(issue_list) as _:
188
190
  schema = DMSSchema.from_directory(directory)
189
191
  # If there were errors during the import, the to_rules
190
- return cls(schema, issue_list)
192
+ return cls(
193
+ schema, issue_list, referenced_containers=cls._lookup_referenced_containers(schema, issue_list, client)
194
+ )
191
195
 
192
196
  @classmethod
193
- def from_zip_file(cls, zip_file: str | Path) -> "DMSImporter":
197
+ def from_zip_file(cls, zip_file: str | Path, client: NeatClient | None = None) -> "DMSImporter":
194
198
  if Path(zip_file).suffix != ".zip":
195
199
  return cls(
196
200
  DMSSchema(),
@@ -199,30 +203,49 @@ class DMSImporter(BaseImporter[DMSInputRules]):
199
203
  issue_list = IssueList()
200
204
  with _handle_issues(issue_list) as _:
201
205
  schema = DMSSchema.from_zip(zip_file)
202
- return cls(schema, issue_list)
206
+ return cls(
207
+ schema, issue_list, referenced_containers=cls._lookup_referenced_containers(schema, issue_list, client)
208
+ )
209
+
210
+ @classmethod
211
+ def _lookup_referenced_containers(
212
+ cls, schema: DMSSchema, issue_list: IssueList, client: NeatClient | None = None
213
+ ) -> Iterable[dm.ContainerApply]:
214
+ ref_containers = schema.externally_referenced_containers()
215
+ if not ref_containers:
216
+ return []
217
+ elif client is None:
218
+ id_ = ""
219
+ if schema.data_model:
220
+ id_ = f" {schema.data_model.as_id()!r}"
221
+ issue_list.append(MissingCogniteClientWarning(f"importing full DMS model{id_}"))
222
+ return []
223
+ return client.loaders.containers.retrieve(list(ref_containers), format="write")
224
+
225
+ @classmethod
226
+ def from_path(cls, path: Path, client: NeatClient | None = None) -> "DMSImporter":
227
+ if path.is_file():
228
+ return cls.from_zip_file(path, client)
229
+ elif path.is_dir():
230
+ return cls.from_directory(path, client)
231
+ else:
232
+ raise NeatValueError(f"Unsupported YAML format: {format}")
203
233
 
204
234
  def to_rules(self) -> ReadRules[DMSInputRules]:
205
235
  if self.issue_list.has_errors:
206
236
  # In case there were errors during the import, the to_rules method will return None
207
- self._end = datetime.now(timezone.utc)
208
237
  self.issue_list.trigger_warnings()
209
238
  raise MultiValueError(self.issue_list.errors)
210
239
 
211
- if not self.root_schema.data_model:
212
- self.issue_list.append(ResourceMissingIdentifierError("data model", type(self.root_schema).__name__))
213
- self._end = datetime.now(timezone.utc)
240
+ if not self.schema.data_model:
241
+ self.issue_list.append(ResourceMissingIdentifierError("data model", type(self.schema).__name__))
214
242
  self.issue_list.trigger_warnings()
215
243
  raise MultiValueError(self.issue_list.errors)
216
244
 
217
- model = self.root_schema.data_model
245
+ model = self.schema.data_model
218
246
 
219
- user_rules = self._create_rule_components(
220
- model,
221
- self.root_schema,
222
- self.metadata,
223
- )
247
+ user_rules = self._create_rule_components(model, self.schema, self.metadata)
224
248
 
225
- self._end = datetime.now(timezone.utc)
226
249
  self.issue_list.trigger_warnings()
227
250
  if self.issue_list.has_errors:
228
251
  raise MultiValueError(self.issue_list.errors)
@@ -234,7 +257,7 @@ class DMSImporter(BaseImporter[DMSInputRules]):
234
257
  schema: DMSSchema,
235
258
  metadata: DMSInputMetadata | None = None,
236
259
  ) -> DMSInputRules:
237
- enum_by_container_property = self._create_enum_collections(schema.containers.values())
260
+ enum_by_container_property = self._create_enum_collections(self._all_containers_by_id.values())
238
261
  enum_collection_by_container_property = {
239
262
  key: enum_list[0].collection for key, enum_list in enum_by_container_property.items() if enum_list
240
263
  }
@@ -267,21 +290,6 @@ class DMSImporter(BaseImporter[DMSInputRules]):
267
290
  enum=[enum for enum_list in enum_by_container_property.values() for enum in enum_list] or None,
268
291
  )
269
292
 
270
- @classmethod
271
- def _create_default_metadata(
272
- cls, views: Sequence[dm.View | dm.ViewApply], is_ref: bool = False
273
- ) -> DMSInputMetadata:
274
- now = datetime.now().replace(microsecond=0)
275
- space = Counter(view.space for view in views).most_common(1)[0][0]
276
- return DMSInputMetadata(
277
- space=space,
278
- external_id="Unknown",
279
- version="0.1.0",
280
- creator="Unknown",
281
- created=now,
282
- updated=now,
283
- )
284
-
285
293
  def _create_dms_property(
286
294
  self,
287
295
  prop_id: str,
@@ -384,8 +392,11 @@ class DMSImporter(BaseImporter[DMSInputRules]):
384
392
  elif isinstance(prop, dm.MappedPropertyApply):
385
393
  container_prop = self._container_prop_unsafe(cast(dm.MappedPropertyApply, prop))
386
394
  if isinstance(container_prop.type, dm.DirectRelation):
387
- if prop.source is None or prop.source not in self._all_views_by_id:
395
+ if prop.source is None:
388
396
  return DMSUnknownEntity()
397
+ elif prop.source not in self._all_views_by_id:
398
+ self.issue_list.append(ResourceUnknownWarning(prop.source, "view", view_entity.as_id(), "view"))
399
+ return ViewEntity.from_id(prop.source)
389
400
  else:
390
401
  return ViewEntity.from_id(prop.source)
391
402
  elif isinstance(container_prop.type, PropertyTypeWithUnit) and container_prop.type.unit:
@@ -398,7 +398,10 @@ class SheetList(list, MutableSequence[T_SheetRow]):
398
398
 
399
399
  def _repr_html_(self) -> str:
400
400
  """Returns HTML representation of ResourceDict."""
401
- return self.to_pandas(drop_na_columns=True)._repr_html_() # type: ignore[operator]
401
+ df = self.to_pandas(drop_na_columns=True)
402
+ if "neatId" in df.columns:
403
+ df = df.drop(columns=["neatId"])
404
+ return df._repr_html_() # type: ignore[operator]
402
405
 
403
406
  # Implemented to get correct type hints
404
407
  def __iter__(self) -> Iterator[T_SheetRow]:
@@ -9,7 +9,7 @@ from cognite.client import data_modeling as dm
9
9
  from cognite.client.data_classes.data_modeling import ContainerId, NodeId
10
10
  from pydantic import BaseModel, model_serializer, model_validator
11
11
 
12
- from ._single_value import ContainerEntity, DMSNodeEntity, Entity
12
+ from ._single_value import ContainerEntity, DMSNodeEntity, Entity, ViewEntity
13
13
 
14
14
 
15
15
  @total_ordering
@@ -121,6 +121,8 @@ class DMSFilter(WrappedEntity):
121
121
  return HasDataFilter(
122
122
  inner=[
123
123
  ContainerEntity(space=entry["space"], externalId=entry["externalId"])
124
+ if entry["type"] == "container"
125
+ else ViewEntity(space=entry["space"], externalId=entry["externalId"], version=entry["version"])
124
126
  for entry in body
125
127
  if isinstance(entry, dict) and "space" in entry and "externalId" in entry
126
128
  ]
@@ -161,21 +163,24 @@ class NodeTypeFilter(DMSFilter):
161
163
 
162
164
  class HasDataFilter(DMSFilter):
163
165
  name: ClassVar[str] = "hasData"
164
- _inner_cls: ClassVar[type[ContainerEntity]] = ContainerEntity
165
- inner: list[ContainerEntity] | None = None # type: ignore[assignment]
166
+ _inner_cls: ClassVar[type[ContainerEntity | ViewEntity]] = ContainerEntity
167
+ inner: list[ContainerEntity | ViewEntity] | None = None # type: ignore[assignment]
166
168
 
167
169
  def as_dms_filter(self, default: Collection[ContainerId] | None = None) -> dm.Filter:
168
170
  containers: list[ContainerId]
169
171
  if self.inner:
170
- containers = [container.as_id() for container in self.inner]
172
+ containers = [item.as_id() for item in self.inner if isinstance(item, ContainerEntity)]
173
+ views = [item.as_id() for item in self.inner if isinstance(item, ViewEntity)]
171
174
  elif default:
172
175
  containers = list(default)
176
+ views = []
173
177
  else:
174
178
  raise ValueError("Empty hasData filter, please provide a default containers.")
175
179
 
176
180
  return dm.filters.HasData(
177
181
  # Sorting to ensure deterministic order
178
- containers=sorted(containers, key=lambda container: container.as_tuple()) # type: ignore[union-attr]
182
+ containers=sorted(containers, key=lambda container: container.as_tuple()), # type: ignore[union-attr]
183
+ views=sorted(views, key=lambda view: view.as_tuple()), # type: ignore[union-attr]
179
184
  )
180
185
 
181
186