cognite-neat 0.75.7__py3-none-any.whl → 0.75.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cognite-neat might be problematic. Click here for more details.
- cognite/neat/_version.py +1 -1
- cognite/neat/graph/extractors/_mock_graph_generator.py +6 -5
- cognite/neat/rules/analysis/_base.py +1 -1
- cognite/neat/rules/analysis/_information_rules.py +4 -4
- cognite/neat/rules/exporters/_rules2ontology.py +20 -17
- cognite/neat/rules/exporters/_validation.py +2 -2
- cognite/neat/rules/importers/_dms2rules.py +14 -15
- cognite/neat/rules/importers/_dtdl2rules/dtdl_converter.py +21 -19
- cognite/neat/rules/importers/_dtdl2rules/spec.py +1 -1
- cognite/neat/rules/importers/_owl2rules/_owl2rules.py +2 -2
- cognite/neat/rules/importers/_spreadsheet2rules.py +6 -1
- cognite/neat/rules/importers/_yaml2rules.py +8 -2
- cognite/neat/rules/issues/dms.py +1 -1
- cognite/neat/rules/models/data_types.py +54 -31
- cognite/neat/rules/models/entities.py +184 -41
- cognite/neat/rules/models/rdfpath.py +111 -11
- cognite/neat/rules/models/rules/_base.py +2 -2
- cognite/neat/rules/models/rules/_dms_architect_rules.py +117 -188
- cognite/neat/rules/models/rules/_dms_rules_write.py +355 -0
- cognite/neat/rules/models/rules/_dms_schema.py +3 -3
- cognite/neat/rules/models/rules/_domain_rules.py +6 -3
- cognite/neat/rules/models/rules/_information_rules.py +68 -61
- cognite/neat/rules/models/rules/_types/__init__.py +0 -47
- cognite/neat/rules/models/rules/_types/_base.py +1 -309
- cognite/neat/rules/models/rules/_types/_field.py +0 -225
- cognite/neat/workflows/steps/lib/rules_importer.py +3 -3
- {cognite_neat-0.75.7.dist-info → cognite_neat-0.75.8.dist-info}/METADATA +1 -1
- {cognite_neat-0.75.7.dist-info → cognite_neat-0.75.8.dist-info}/RECORD +31 -32
- cognite/neat/rules/models/_entity.py +0 -142
- cognite/neat/rules/models/rules/_types/_value.py +0 -159
- {cognite_neat-0.75.7.dist-info → cognite_neat-0.75.8.dist-info}/LICENSE +0 -0
- {cognite_neat-0.75.7.dist-info → cognite_neat-0.75.8.dist-info}/WHEEL +0 -0
- {cognite_neat-0.75.7.dist-info → cognite_neat-0.75.8.dist-info}/entry_points.txt +0 -0
|
@@ -11,36 +11,35 @@ from cognite.client import data_modeling as dm
|
|
|
11
11
|
from cognite.client.data_classes.data_modeling import PropertyType as CognitePropertyType
|
|
12
12
|
from cognite.client.data_classes.data_modeling.containers import BTreeIndex
|
|
13
13
|
from cognite.client.data_classes.data_modeling.views import SingleReverseDirectRelationApply, ViewPropertyApply
|
|
14
|
-
from pydantic import Field, field_validator, model_serializer, model_validator
|
|
14
|
+
from pydantic import Field, field_serializer, field_validator, model_serializer, model_validator
|
|
15
15
|
from pydantic_core.core_schema import SerializationInfo, ValidationInfo
|
|
16
16
|
from rdflib import Namespace
|
|
17
17
|
|
|
18
18
|
import cognite.neat.rules.issues.spreadsheet
|
|
19
19
|
from cognite.neat.rules import issues
|
|
20
|
+
from cognite.neat.rules.models.data_types import DataType
|
|
21
|
+
from cognite.neat.rules.models.entities import (
|
|
22
|
+
ClassEntity,
|
|
23
|
+
ContainerEntity,
|
|
24
|
+
ContainerEntityList,
|
|
25
|
+
DMSUnknownEntity,
|
|
26
|
+
ParentClassEntity,
|
|
27
|
+
ReferenceEntity,
|
|
28
|
+
UnknownEntity,
|
|
29
|
+
URLEntity,
|
|
30
|
+
ViewEntity,
|
|
31
|
+
ViewEntityList,
|
|
32
|
+
ViewPropertyEntity,
|
|
33
|
+
)
|
|
20
34
|
from cognite.neat.rules.models.rules._domain_rules import DomainRules
|
|
21
35
|
|
|
22
36
|
from ._base import BaseMetadata, BaseRules, ExtensionCategory, RoleTypes, SchemaCompleteness, SheetEntity, SheetList
|
|
23
37
|
from ._dms_schema import DMSSchema, PipelineSchema
|
|
24
38
|
from ._types import (
|
|
25
|
-
CdfValueType,
|
|
26
|
-
ClassEntity,
|
|
27
|
-
ContainerEntity,
|
|
28
|
-
ContainerListType,
|
|
29
|
-
ContainerType,
|
|
30
|
-
DMSValueType,
|
|
31
39
|
ExternalIdType,
|
|
32
|
-
ParentClassEntity,
|
|
33
40
|
PropertyType,
|
|
34
|
-
ReferenceEntity,
|
|
35
|
-
ReferenceType,
|
|
36
41
|
StrListType,
|
|
37
|
-
Undefined,
|
|
38
42
|
VersionType,
|
|
39
|
-
ViewEntity,
|
|
40
|
-
ViewListType,
|
|
41
|
-
ViewPropEntity,
|
|
42
|
-
ViewType,
|
|
43
|
-
XSDValueType,
|
|
44
43
|
)
|
|
45
44
|
|
|
46
45
|
if TYPE_CHECKING:
|
|
@@ -51,6 +50,7 @@ if sys.version_info >= (3, 11):
|
|
|
51
50
|
else:
|
|
52
51
|
from typing_extensions import Self
|
|
53
52
|
|
|
53
|
+
_DEFAULT_VERSION = "1"
|
|
54
54
|
|
|
55
55
|
subclasses = list(CognitePropertyType.__subclasses__())
|
|
56
56
|
_PropertyType_by_name: dict[str, type[CognitePropertyType]] = {}
|
|
@@ -164,14 +164,14 @@ class DMSMetadata(BaseMetadata):
|
|
|
164
164
|
class DMSProperty(SheetEntity):
|
|
165
165
|
property_: PropertyType = Field(alias="Property")
|
|
166
166
|
relation: Literal["direct", "reversedirect", "multiedge"] | None = Field(None, alias="Relation")
|
|
167
|
-
value_type:
|
|
167
|
+
value_type: DataType | ViewPropertyEntity | ViewEntity | DMSUnknownEntity = Field(alias="Value Type")
|
|
168
168
|
nullable: bool | None = Field(default=None, alias="Nullable")
|
|
169
169
|
is_list: bool | None = Field(default=None, alias="IsList")
|
|
170
170
|
default: str | int | dict | None = Field(None, alias="Default")
|
|
171
|
-
reference:
|
|
172
|
-
container:
|
|
171
|
+
reference: URLEntity | ReferenceEntity | None = Field(default=None, alias="Reference", union_mode="left_to_right")
|
|
172
|
+
container: ContainerEntity | None = Field(None, alias="Container")
|
|
173
173
|
container_property: str | None = Field(None, alias="ContainerProperty")
|
|
174
|
-
view:
|
|
174
|
+
view: ViewEntity = Field(alias="View")
|
|
175
175
|
view_property: str = Field(alias="ViewProperty")
|
|
176
176
|
index: StrListType | None = Field(None, alias="Index")
|
|
177
177
|
constraint: StrListType | None = Field(None, alias="Constraint")
|
|
@@ -189,12 +189,13 @@ class DMSProperty(SheetEntity):
|
|
|
189
189
|
return value
|
|
190
190
|
|
|
191
191
|
@field_validator("value_type", mode="after")
|
|
192
|
-
def relations_value_type(cls, value:
|
|
192
|
+
def relations_value_type(cls, value: DataType | ClassEntity, info: ValidationInfo) -> DataType | ClassEntity:
|
|
193
193
|
if (relation := info.data["relation"]) is None:
|
|
194
194
|
return value
|
|
195
|
-
if not isinstance(value,
|
|
195
|
+
if not isinstance(value, ViewEntity | ViewPropertyEntity | DMSUnknownEntity):
|
|
196
196
|
raise ValueError(f"Relations must have a value type that points to another view, got {value}")
|
|
197
197
|
if relation == "reversedirect" and value.property_ is None:
|
|
198
|
+
# Todo fix this error message. It have the wrong syntax for how to have a property
|
|
198
199
|
raise ValueError(
|
|
199
200
|
"Reverse direct relation must set what it is the reverse property of. "
|
|
200
201
|
f"Which property in {value.versioned_id} is this the reverse of? Expecting"
|
|
@@ -202,17 +203,25 @@ class DMSProperty(SheetEntity):
|
|
|
202
203
|
)
|
|
203
204
|
return value
|
|
204
205
|
|
|
206
|
+
@field_serializer("value_type", when_used="always")
|
|
207
|
+
@staticmethod
|
|
208
|
+
def as_dms_type(value_type: DataType | ViewPropertyEntity | ViewEntity) -> str:
|
|
209
|
+
if isinstance(value_type, DataType):
|
|
210
|
+
return value_type.dms._type
|
|
211
|
+
else:
|
|
212
|
+
return str(value_type)
|
|
213
|
+
|
|
205
214
|
|
|
206
215
|
class DMSContainer(SheetEntity):
|
|
207
|
-
container:
|
|
208
|
-
reference:
|
|
209
|
-
constraint:
|
|
216
|
+
container: ContainerEntity = Field(alias="Container")
|
|
217
|
+
reference: URLEntity | ReferenceEntity | None = Field(alias="Reference", default=None, union_mode="left_to_right")
|
|
218
|
+
constraint: ContainerEntityList | None = Field(None, alias="Constraint")
|
|
210
219
|
|
|
211
|
-
def as_container(self
|
|
212
|
-
container_id = self.container.as_id(
|
|
220
|
+
def as_container(self) -> dm.ContainerApply:
|
|
221
|
+
container_id = self.container.as_id()
|
|
213
222
|
constraints: dict[str, dm.Constraint] = {}
|
|
214
223
|
for constraint in self.constraint or []:
|
|
215
|
-
requires = dm.RequiresConstraint(constraint.as_id(
|
|
224
|
+
requires = dm.RequiresConstraint(constraint.as_id())
|
|
216
225
|
constraints[f"{constraint.space}_{constraint.external_id}"] = requires
|
|
217
226
|
|
|
218
227
|
return dm.ContainerApply(
|
|
@@ -233,7 +242,7 @@ class DMSContainer(SheetEntity):
|
|
|
233
242
|
# UniquenessConstraint it handled in the properties
|
|
234
243
|
return cls(
|
|
235
244
|
class_=ClassEntity(prefix=container.space, suffix=container.external_id),
|
|
236
|
-
container=
|
|
245
|
+
container=ContainerEntity(space=container.space, externalId=container.external_id),
|
|
237
246
|
name=container.name or None,
|
|
238
247
|
description=container.description,
|
|
239
248
|
constraint=constraints or None,
|
|
@@ -241,22 +250,21 @@ class DMSContainer(SheetEntity):
|
|
|
241
250
|
|
|
242
251
|
|
|
243
252
|
class DMSView(SheetEntity):
|
|
244
|
-
view:
|
|
245
|
-
implements:
|
|
246
|
-
reference:
|
|
253
|
+
view: ViewEntity = Field(alias="View")
|
|
254
|
+
implements: ViewEntityList | None = Field(None, alias="Implements")
|
|
255
|
+
reference: URLEntity | ReferenceEntity | None = Field(alias="Reference", default=None, union_mode="left_to_right")
|
|
247
256
|
filter_: Literal["hasData", "nodeType"] | None = Field(None, alias="Filter")
|
|
248
257
|
in_model: bool = Field(True, alias="InModel")
|
|
249
258
|
|
|
250
|
-
def as_view(self
|
|
251
|
-
view_id = self.view.as_id(
|
|
259
|
+
def as_view(self) -> dm.ViewApply:
|
|
260
|
+
view_id = self.view.as_id()
|
|
252
261
|
return dm.ViewApply(
|
|
253
262
|
space=view_id.space,
|
|
254
263
|
external_id=view_id.external_id,
|
|
255
|
-
version=view_id.version or
|
|
264
|
+
version=view_id.version or _DEFAULT_VERSION,
|
|
256
265
|
name=self.name or None,
|
|
257
266
|
description=self.description,
|
|
258
|
-
implements=[parent.as_id(
|
|
259
|
-
or None,
|
|
267
|
+
implements=[parent.as_id() for parent in self.implements or []] or None,
|
|
260
268
|
properties={},
|
|
261
269
|
)
|
|
262
270
|
|
|
@@ -264,11 +272,13 @@ class DMSView(SheetEntity):
|
|
|
264
272
|
def from_view(cls, view: dm.ViewApply, data_model_view_ids: set[dm.ViewId]) -> "DMSView":
|
|
265
273
|
return cls(
|
|
266
274
|
class_=ClassEntity(prefix=view.space, suffix=view.external_id),
|
|
267
|
-
view=
|
|
275
|
+
view=ViewEntity(space=view.space, externalId=view.external_id, version=view.version),
|
|
268
276
|
description=view.description,
|
|
269
277
|
name=view.name,
|
|
270
278
|
implements=[
|
|
271
|
-
|
|
279
|
+
ViewEntity(
|
|
280
|
+
space=parent.space, externalId=parent.external_id, version=parent.version or _DEFAULT_VERSION
|
|
281
|
+
)
|
|
272
282
|
for parent in view.implements
|
|
273
283
|
]
|
|
274
284
|
or None,
|
|
@@ -283,79 +293,6 @@ class DMSRules(BaseRules):
|
|
|
283
293
|
containers: SheetList[DMSContainer] | None = Field(None, alias="Containers")
|
|
284
294
|
reference: "DMSRules | None" = Field(None, alias="Reference")
|
|
285
295
|
|
|
286
|
-
@model_validator(mode="after")
|
|
287
|
-
def set_default_space_and_version(self) -> "DMSRules":
|
|
288
|
-
default_space = self.metadata.space
|
|
289
|
-
default_view_version = self.metadata.default_view_version
|
|
290
|
-
for entity in self.properties:
|
|
291
|
-
if entity.class_.prefix is Undefined or entity.class_.version is None:
|
|
292
|
-
entity.class_ = ClassEntity(
|
|
293
|
-
prefix=default_space if entity.class_.prefix is Undefined else entity.class_.prefix,
|
|
294
|
-
suffix=entity.class_.suffix,
|
|
295
|
-
version=default_view_version if entity.class_.version is None else entity.class_.version,
|
|
296
|
-
)
|
|
297
|
-
if entity.container and entity.container.space is Undefined:
|
|
298
|
-
entity.container = ContainerEntity(prefix=default_space, suffix=entity.container.external_id)
|
|
299
|
-
|
|
300
|
-
if entity.view and (entity.view.space is Undefined or entity.view.version is None):
|
|
301
|
-
entity.view = ViewEntity(
|
|
302
|
-
prefix=default_space if entity.view.space is Undefined else entity.view.space,
|
|
303
|
-
suffix=entity.view.external_id,
|
|
304
|
-
version=default_view_version if entity.view.version is None else entity.view.version,
|
|
305
|
-
)
|
|
306
|
-
if isinstance(entity.value_type, ViewPropEntity) and (
|
|
307
|
-
entity.value_type.space is Undefined or entity.value_type.version is None
|
|
308
|
-
):
|
|
309
|
-
entity.value_type = ViewPropEntity(
|
|
310
|
-
prefix=default_space if entity.value_type.space is Undefined else entity.value_type.space,
|
|
311
|
-
suffix=entity.value_type.suffix,
|
|
312
|
-
version=default_view_version if entity.value_type.version is None else entity.value_type.version,
|
|
313
|
-
property_=entity.value_type.property_,
|
|
314
|
-
)
|
|
315
|
-
|
|
316
|
-
for container in self.containers or []:
|
|
317
|
-
if container.class_.prefix is Undefined:
|
|
318
|
-
container.class_ = ClassEntity(prefix=default_space, suffix=container.class_.suffix)
|
|
319
|
-
if container.container.space is Undefined:
|
|
320
|
-
container.container = ContainerEntity(prefix=default_space, suffix=container.container.external_id)
|
|
321
|
-
container.constraint = [
|
|
322
|
-
(
|
|
323
|
-
ContainerEntity(prefix=default_space, suffix=constraint.external_id)
|
|
324
|
-
if constraint.space is Undefined
|
|
325
|
-
else constraint
|
|
326
|
-
)
|
|
327
|
-
for constraint in container.constraint or []
|
|
328
|
-
] or None
|
|
329
|
-
|
|
330
|
-
for view in self.views or []:
|
|
331
|
-
if view.class_.prefix is Undefined or view.class_.version is None:
|
|
332
|
-
view.class_ = ClassEntity(
|
|
333
|
-
prefix=default_space if view.class_.prefix is Undefined else view.class_.prefix,
|
|
334
|
-
suffix=view.class_.suffix,
|
|
335
|
-
version=default_view_version if view.class_.version is None else view.class_.version,
|
|
336
|
-
)
|
|
337
|
-
|
|
338
|
-
if view.view.space is Undefined or view.view.version is None:
|
|
339
|
-
view.view = ViewEntity(
|
|
340
|
-
prefix=default_space if view.view.space is Undefined else view.view.space,
|
|
341
|
-
suffix=view.view.external_id,
|
|
342
|
-
version=default_view_version if view.view.version is None else view.view.version,
|
|
343
|
-
)
|
|
344
|
-
view.implements = [
|
|
345
|
-
(
|
|
346
|
-
ViewEntity(
|
|
347
|
-
prefix=default_space if parent.space is Undefined else parent.space,
|
|
348
|
-
suffix=parent.external_id,
|
|
349
|
-
version=default_view_version if parent.version is None else parent.version,
|
|
350
|
-
)
|
|
351
|
-
if parent.space is Undefined or parent.version is None
|
|
352
|
-
else parent
|
|
353
|
-
)
|
|
354
|
-
for parent in view.implements or []
|
|
355
|
-
] or None
|
|
356
|
-
|
|
357
|
-
return self
|
|
358
|
-
|
|
359
296
|
@model_validator(mode="after")
|
|
360
297
|
def consistent_container_properties(self) -> "DMSRules":
|
|
361
298
|
container_properties_by_id: dict[tuple[ContainerEntity, str], list[tuple[int, DMSProperty]]] = defaultdict(list)
|
|
@@ -367,13 +304,16 @@ class DMSRules(BaseRules):
|
|
|
367
304
|
for (container, prop_name), properties in container_properties_by_id.items():
|
|
368
305
|
if len(properties) == 1:
|
|
369
306
|
continue
|
|
370
|
-
container_id = container.as_id(
|
|
307
|
+
container_id = container.as_id()
|
|
371
308
|
row_numbers = {prop_no for prop_no, _ in properties}
|
|
372
309
|
value_types = {prop.value_type for _, prop in properties if prop.value_type}
|
|
373
310
|
if len(value_types) > 1:
|
|
374
311
|
errors.append(
|
|
375
312
|
cognite.neat.rules.issues.spreadsheet.MultiValueTypeError(
|
|
376
|
-
container_id,
|
|
313
|
+
container_id,
|
|
314
|
+
prop_name,
|
|
315
|
+
row_numbers,
|
|
316
|
+
{v.dms._type if isinstance(v, DataType) else str(v) for v in value_types},
|
|
377
317
|
)
|
|
378
318
|
)
|
|
379
319
|
list_definitions = {prop.is_list for _, prop in properties if prop.is_list is not None}
|
|
@@ -437,14 +377,11 @@ class DMSRules(BaseRules):
|
|
|
437
377
|
@model_validator(mode="after")
|
|
438
378
|
def referenced_views_and_containers_are_existing(self) -> "DMSRules":
|
|
439
379
|
# There two checks are done in the same method to raise all the errors at once.
|
|
440
|
-
defined_views = {view.view.as_id(
|
|
380
|
+
defined_views = {view.view.as_id() for view in self.views}
|
|
441
381
|
|
|
442
382
|
errors: list[issues.NeatValidationError] = []
|
|
443
383
|
for prop_no, prop in enumerate(self.properties):
|
|
444
|
-
if (
|
|
445
|
-
prop.view
|
|
446
|
-
and (view_id := prop.view.as_id(False, self.metadata.space, self.metadata.version)) not in defined_views
|
|
447
|
-
):
|
|
384
|
+
if prop.view and (view_id := prop.view.as_id()) not in defined_views:
|
|
448
385
|
errors.append(
|
|
449
386
|
cognite.neat.rules.issues.spreadsheet.NonExistingViewError(
|
|
450
387
|
column="View",
|
|
@@ -457,12 +394,9 @@ class DMSRules(BaseRules):
|
|
|
457
394
|
)
|
|
458
395
|
)
|
|
459
396
|
if self.metadata.schema_ is SchemaCompleteness.complete:
|
|
460
|
-
defined_containers = {container.container.as_id(
|
|
397
|
+
defined_containers = {container.container.as_id() for container in self.containers or []}
|
|
461
398
|
for prop_no, prop in enumerate(self.properties):
|
|
462
|
-
if (
|
|
463
|
-
prop.container
|
|
464
|
-
and (container_id := prop.container.as_id(self.metadata.space)) not in defined_containers
|
|
465
|
-
):
|
|
399
|
+
if prop.container and (container_id := prop.container.as_id()) not in defined_containers:
|
|
466
400
|
errors.append(
|
|
467
401
|
cognite.neat.rules.issues.spreadsheet.NonExistingContainerError(
|
|
468
402
|
column="Container",
|
|
@@ -476,13 +410,13 @@ class DMSRules(BaseRules):
|
|
|
476
410
|
)
|
|
477
411
|
for _container_no, container in enumerate(self.containers or []):
|
|
478
412
|
for constraint_no, constraint in enumerate(container.constraint or []):
|
|
479
|
-
if constraint.as_id(
|
|
413
|
+
if constraint.as_id() not in defined_containers:
|
|
480
414
|
errors.append(
|
|
481
415
|
cognite.neat.rules.issues.spreadsheet.NonExistingContainerError(
|
|
482
416
|
column="Constraint",
|
|
483
417
|
row=constraint_no,
|
|
484
418
|
type="value_error.missing",
|
|
485
|
-
container_id=constraint.as_id(
|
|
419
|
+
container_id=constraint.as_id(),
|
|
486
420
|
msg="",
|
|
487
421
|
input=None,
|
|
488
422
|
url=None,
|
|
@@ -584,17 +518,15 @@ class DMSRules(BaseRules):
|
|
|
584
518
|
# This is an extension of the reference rules, we need to merge the two
|
|
585
519
|
rules = self.model_copy(deep=True)
|
|
586
520
|
rules.properties.extend(self.reference.properties.data)
|
|
587
|
-
existing_views = {view.view.as_id(
|
|
588
|
-
rules.views.extend([view for view in self.reference.views if view.view.as_id(
|
|
521
|
+
existing_views = {view.view.as_id() for view in rules.views}
|
|
522
|
+
rules.views.extend([view for view in self.reference.views if view.view.as_id() not in existing_views])
|
|
589
523
|
if rules.containers and self.reference.containers:
|
|
590
|
-
existing_containers = {
|
|
591
|
-
container.container.as_id(self.metadata.space) for container in rules.containers.data
|
|
592
|
-
}
|
|
524
|
+
existing_containers = {container.container.as_id() for container in rules.containers.data}
|
|
593
525
|
rules.containers.extend(
|
|
594
526
|
[
|
|
595
527
|
container
|
|
596
528
|
for container in self.reference.containers
|
|
597
|
-
if container.container.as_id(
|
|
529
|
+
if container.container.as_id() not in existing_containers
|
|
598
530
|
]
|
|
599
531
|
)
|
|
600
532
|
elif not rules.containers and self.reference.containers:
|
|
@@ -683,7 +615,7 @@ class DMSRules(BaseRules):
|
|
|
683
615
|
new_rules = self.model_copy(deep=True)
|
|
684
616
|
for prop in new_rules.properties:
|
|
685
617
|
prop.reference = ReferenceEntity(
|
|
686
|
-
prefix=prop.view.prefix, suffix=prop.view.suffix, version=prop.view.version,
|
|
618
|
+
prefix=prop.view.prefix, suffix=prop.view.suffix, version=prop.view.version, property=prop.property_
|
|
687
619
|
)
|
|
688
620
|
view: DMSView
|
|
689
621
|
for view in new_rules.views:
|
|
@@ -713,22 +645,13 @@ class _DMSExporter:
|
|
|
713
645
|
self.instance_space = instance_space
|
|
714
646
|
|
|
715
647
|
def to_schema(self, rules: DMSRules) -> DMSSchema:
|
|
716
|
-
|
|
717
|
-
default_space = rules.metadata.space
|
|
718
|
-
|
|
719
|
-
container_properties_by_id, view_properties_by_id = self._gather_properties(
|
|
720
|
-
rules, default_space, default_version
|
|
721
|
-
)
|
|
648
|
+
container_properties_by_id, view_properties_by_id = self._gather_properties(rules)
|
|
722
649
|
|
|
723
|
-
containers = self._create_containers(rules.containers, container_properties_by_id
|
|
650
|
+
containers = self._create_containers(rules.containers, container_properties_by_id)
|
|
724
651
|
|
|
725
|
-
views, node_types = self._create_views_with_node_types(
|
|
726
|
-
rules.views, view_properties_by_id, default_space, default_version
|
|
727
|
-
)
|
|
652
|
+
views, node_types = self._create_views_with_node_types(rules.views, view_properties_by_id)
|
|
728
653
|
|
|
729
|
-
views_not_in_model = {
|
|
730
|
-
view.view.as_id(False, default_space, default_version) for view in rules.views if not view.in_model
|
|
731
|
-
}
|
|
654
|
+
views_not_in_model = {view.view.as_id() for view in rules.views if not view.in_model}
|
|
732
655
|
data_model = rules.metadata.as_data_model()
|
|
733
656
|
data_model.views = sorted(
|
|
734
657
|
[view_id for view_id in views.as_ids() if view_id not in views_not_in_model], key=lambda v: v.as_tuple() # type: ignore[union-attr]
|
|
@@ -770,13 +693,9 @@ class _DMSExporter:
|
|
|
770
693
|
self,
|
|
771
694
|
dms_views: SheetList[DMSView],
|
|
772
695
|
view_properties_by_id: dict[dm.ViewId, list[DMSProperty]],
|
|
773
|
-
default_space: str,
|
|
774
|
-
default_version: str,
|
|
775
696
|
) -> tuple[dm.ViewApplyList, dm.NodeApplyList]:
|
|
776
|
-
views = dm.ViewApplyList([dms_view.as_view(
|
|
777
|
-
dms_view_by_id = {
|
|
778
|
-
dms_view.view.as_id(False, default_space, default_version): dms_view for dms_view in dms_views
|
|
779
|
-
}
|
|
697
|
+
views = dm.ViewApplyList([dms_view.as_view() for dms_view in dms_views])
|
|
698
|
+
dms_view_by_id = {dms_view.view.as_id(): dms_view for dms_view in dms_views}
|
|
780
699
|
|
|
781
700
|
for view in views:
|
|
782
701
|
view_id = view.as_id()
|
|
@@ -789,7 +708,9 @@ class _DMSExporter:
|
|
|
789
708
|
# This is not yet supported in the CDF API, a warning has already been issued, here we convert it to
|
|
790
709
|
# a multi-edge connection.
|
|
791
710
|
if isinstance(prop.value_type, ViewEntity):
|
|
792
|
-
|
|
711
|
+
source_view_id = prop.value_type.as_id()
|
|
712
|
+
elif isinstance(prop.value_type, ViewPropertyEntity):
|
|
713
|
+
source_view_id = prop.value_type.as_view_id()
|
|
793
714
|
else:
|
|
794
715
|
raise ValueError(
|
|
795
716
|
"Direct relation must have a view as value type. "
|
|
@@ -797,10 +718,10 @@ class _DMSExporter:
|
|
|
797
718
|
)
|
|
798
719
|
view_property = dm.MultiEdgeConnectionApply(
|
|
799
720
|
type=dm.DirectRelationReference(
|
|
800
|
-
space=
|
|
721
|
+
space=source_view_id.space,
|
|
801
722
|
external_id=f"{prop.view.external_id}.{prop.view_property}",
|
|
802
723
|
),
|
|
803
|
-
source=
|
|
724
|
+
source=source_view_id,
|
|
804
725
|
direction="outwards",
|
|
805
726
|
name=prop.name,
|
|
806
727
|
description=prop.description,
|
|
@@ -809,14 +730,16 @@ class _DMSExporter:
|
|
|
809
730
|
container_prop_identifier = prop.container_property
|
|
810
731
|
extra_args: dict[str, Any] = {}
|
|
811
732
|
if prop.relation == "direct" and isinstance(prop.value_type, ViewEntity):
|
|
812
|
-
extra_args["source"] = prop.value_type.as_id(
|
|
733
|
+
extra_args["source"] = prop.value_type.as_id()
|
|
734
|
+
elif isinstance(prop.value_type, DMSUnknownEntity):
|
|
735
|
+
extra_args["source"] = None
|
|
813
736
|
elif prop.relation == "direct" and not isinstance(prop.value_type, ViewEntity):
|
|
814
737
|
raise ValueError(
|
|
815
738
|
"Direct relation must have a view as value type. "
|
|
816
739
|
"This should have been validated in the rules"
|
|
817
740
|
)
|
|
818
741
|
view_property = dm.MappedPropertyApply(
|
|
819
|
-
container=prop.container.as_id(
|
|
742
|
+
container=prop.container.as_id(),
|
|
820
743
|
container_property_identifier=container_prop_identifier,
|
|
821
744
|
name=prop.name,
|
|
822
745
|
description=prop.description,
|
|
@@ -824,34 +747,35 @@ class _DMSExporter:
|
|
|
824
747
|
)
|
|
825
748
|
elif prop.view and prop.view_property and prop.relation == "multiedge":
|
|
826
749
|
if isinstance(prop.value_type, ViewEntity):
|
|
827
|
-
|
|
750
|
+
source_view_id = prop.value_type.as_id()
|
|
828
751
|
else:
|
|
829
752
|
raise ValueError(
|
|
830
753
|
"Multiedge relation must have a view as value type. "
|
|
831
754
|
"This should have been validated in the rules"
|
|
832
755
|
)
|
|
833
756
|
if isinstance(prop.reference, ReferenceEntity):
|
|
834
|
-
ref_view_prop = prop.reference.
|
|
757
|
+
ref_view_prop = prop.reference.as_view_property_id()
|
|
835
758
|
edge_type = dm.DirectRelationReference(
|
|
836
759
|
space=ref_view_prop.source.space,
|
|
837
760
|
external_id=f"{ref_view_prop.source.external_id}.{ref_view_prop.property}",
|
|
838
761
|
)
|
|
839
762
|
else:
|
|
840
763
|
edge_type = dm.DirectRelationReference(
|
|
841
|
-
space=
|
|
764
|
+
space=source_view_id.space,
|
|
842
765
|
external_id=f"{prop.view.external_id}.{prop.view_property}",
|
|
843
766
|
)
|
|
844
767
|
|
|
845
768
|
view_property = dm.MultiEdgeConnectionApply(
|
|
846
769
|
type=edge_type,
|
|
847
|
-
source=
|
|
770
|
+
source=source_view_id,
|
|
848
771
|
direction="outwards",
|
|
849
772
|
name=prop.name,
|
|
850
773
|
description=prop.description,
|
|
851
774
|
)
|
|
852
775
|
elif prop.view and prop.view_property and prop.relation == "reversedirect":
|
|
853
|
-
if isinstance(prop.value_type,
|
|
854
|
-
|
|
776
|
+
if isinstance(prop.value_type, ViewPropertyEntity):
|
|
777
|
+
source_prop_id = prop.value_type.as_id()
|
|
778
|
+
source_view_id = cast(dm.ViewId, source_prop_id.source)
|
|
855
779
|
else:
|
|
856
780
|
raise ValueError(
|
|
857
781
|
"Reverse direct relation must have a view as value type. "
|
|
@@ -865,34 +789,39 @@ class _DMSExporter:
|
|
|
865
789
|
f"{prop.value_type.versioned_id}:<property>"
|
|
866
790
|
)
|
|
867
791
|
reverse_prop = next(
|
|
868
|
-
(
|
|
792
|
+
(
|
|
793
|
+
prop
|
|
794
|
+
for prop in view_properties_by_id.get(source_view_id, [])
|
|
795
|
+
if prop.property_ == source_prop
|
|
796
|
+
),
|
|
797
|
+
None,
|
|
869
798
|
)
|
|
870
799
|
if reverse_prop and reverse_prop.relation == "direct" and reverse_prop.is_list:
|
|
871
800
|
warnings.warn(
|
|
872
801
|
issues.dms.ReverseOfDirectRelationListWarning(view_id, prop.property_), stacklevel=2
|
|
873
802
|
)
|
|
874
803
|
if isinstance(reverse_prop.reference, ReferenceEntity):
|
|
875
|
-
ref_view_prop = reverse_prop.reference.
|
|
804
|
+
ref_view_prop = reverse_prop.reference.as_view_property_id()
|
|
876
805
|
edge_type = dm.DirectRelationReference(
|
|
877
806
|
space=ref_view_prop.source.space,
|
|
878
807
|
external_id=f"{ref_view_prop.source.external_id}.{ref_view_prop.property}",
|
|
879
808
|
)
|
|
880
809
|
else:
|
|
881
810
|
edge_type = dm.DirectRelationReference(
|
|
882
|
-
space=source.space,
|
|
811
|
+
space=source_prop_id.source.space,
|
|
883
812
|
external_id=f"{reverse_prop.view.external_id}.{reverse_prop.view_property}",
|
|
884
813
|
)
|
|
885
814
|
view_property = dm.MultiEdgeConnectionApply(
|
|
886
815
|
type=edge_type,
|
|
887
|
-
source=source,
|
|
816
|
+
source=source_prop_id.source, # type: ignore[arg-type]
|
|
888
817
|
direction="inwards",
|
|
889
818
|
name=prop.name,
|
|
890
819
|
description=prop.description,
|
|
891
820
|
)
|
|
892
821
|
else:
|
|
893
822
|
args: dict[str, Any] = dict(
|
|
894
|
-
source=
|
|
895
|
-
through=dm.PropertyId(source, source_prop),
|
|
823
|
+
source=source_view_id,
|
|
824
|
+
through=dm.PropertyId(source_prop_id.source, source_prop),
|
|
896
825
|
description=prop.description,
|
|
897
826
|
name=prop.name,
|
|
898
827
|
)
|
|
@@ -925,7 +854,7 @@ class _DMSExporter:
|
|
|
925
854
|
if dms_view and isinstance(dms_view.reference, ReferenceEntity):
|
|
926
855
|
# If the view is a reference, we implement the reference view,
|
|
927
856
|
# and need the filter to match the reference
|
|
928
|
-
ref_view = dms_view.reference.
|
|
857
|
+
ref_view = dms_view.reference.as_view_id()
|
|
929
858
|
node_type = dm.filters.Equals(
|
|
930
859
|
["node", "type"], {"space": ref_view.space, "externalId": ref_view.external_id}
|
|
931
860
|
)
|
|
@@ -959,11 +888,8 @@ class _DMSExporter:
|
|
|
959
888
|
self,
|
|
960
889
|
dms_container: SheetList[DMSContainer] | None,
|
|
961
890
|
container_properties_by_id: dict[dm.ContainerId, list[DMSProperty]],
|
|
962
|
-
default_space: str,
|
|
963
891
|
) -> dm.ContainerApplyList:
|
|
964
|
-
containers = dm.ContainerApplyList(
|
|
965
|
-
[dms_container.as_container(default_space) for dms_container in dms_container or []]
|
|
966
|
-
)
|
|
892
|
+
containers = dm.ContainerApplyList([dms_container.as_container() for dms_container in dms_container or []])
|
|
967
893
|
container_to_drop = set()
|
|
968
894
|
for container in containers:
|
|
969
895
|
container_id = container.as_id()
|
|
@@ -974,7 +900,7 @@ class _DMSExporter:
|
|
|
974
900
|
for prop in container_properties:
|
|
975
901
|
if prop.container_property is None:
|
|
976
902
|
continue
|
|
977
|
-
if isinstance(prop.value_type,
|
|
903
|
+
if isinstance(prop.value_type, DataType):
|
|
978
904
|
type_cls = prop.value_type.dms
|
|
979
905
|
else:
|
|
980
906
|
type_cls = dm.DirectRelation
|
|
@@ -1032,26 +958,26 @@ class _DMSExporter:
|
|
|
1032
958
|
)
|
|
1033
959
|
|
|
1034
960
|
def _gather_properties(
|
|
1035
|
-
self, rules: DMSRules
|
|
961
|
+
self, rules: DMSRules
|
|
1036
962
|
) -> tuple[dict[dm.ContainerId, list[DMSProperty]], dict[dm.ViewId, list[DMSProperty]]]:
|
|
1037
963
|
container_properties_by_id: dict[dm.ContainerId, list[DMSProperty]] = defaultdict(list)
|
|
1038
964
|
view_properties_by_id: dict[dm.ViewId, list[DMSProperty]] = defaultdict(list)
|
|
1039
965
|
for prop in rules.properties:
|
|
1040
|
-
view_id = prop.view.as_id(
|
|
966
|
+
view_id = prop.view.as_id()
|
|
1041
967
|
view_properties_by_id[view_id].append(prop)
|
|
1042
968
|
|
|
1043
969
|
if prop.container and prop.container_property:
|
|
1044
970
|
if prop.relation == "direct" and prop.is_list:
|
|
1045
971
|
warnings.warn(
|
|
1046
972
|
issues.dms.DirectRelationListWarning(
|
|
1047
|
-
container_id=prop.container.as_id(
|
|
1048
|
-
view_id=prop.view.as_id(
|
|
973
|
+
container_id=prop.container.as_id(),
|
|
974
|
+
view_id=prop.view.as_id(),
|
|
1049
975
|
property=prop.container_property,
|
|
1050
976
|
),
|
|
1051
977
|
stacklevel=2,
|
|
1052
978
|
)
|
|
1053
979
|
continue
|
|
1054
|
-
container_id = prop.container.as_id(
|
|
980
|
+
container_id = prop.container.as_id()
|
|
1055
981
|
container_properties_by_id[container_id].append(prop)
|
|
1056
982
|
|
|
1057
983
|
return container_properties_by_id, view_properties_by_id
|
|
@@ -1090,7 +1016,7 @@ class _DMSRulesConverter:
|
|
|
1090
1016
|
classes = [
|
|
1091
1017
|
InformationClass(
|
|
1092
1018
|
# we do not want a version in class as we use URI for the class
|
|
1093
|
-
class_=view.class_.
|
|
1019
|
+
class_=ClassEntity(prefix=view.class_.prefix, suffix=view.class_.suffix),
|
|
1094
1020
|
description=view.description,
|
|
1095
1021
|
parent=[
|
|
1096
1022
|
# we do not want a version in class as we use URI for the class
|
|
@@ -1105,23 +1031,26 @@ class _DMSRulesConverter:
|
|
|
1105
1031
|
]
|
|
1106
1032
|
|
|
1107
1033
|
properties: list[InformationProperty] = []
|
|
1108
|
-
value_type:
|
|
1034
|
+
value_type: DataType | ClassEntity | str
|
|
1109
1035
|
for property_ in self.dms.properties:
|
|
1110
|
-
if isinstance(property_.value_type,
|
|
1111
|
-
value_type =
|
|
1112
|
-
elif isinstance(property_.value_type, ViewEntity):
|
|
1036
|
+
if isinstance(property_.value_type, DataType):
|
|
1037
|
+
value_type = property_.value_type
|
|
1038
|
+
elif isinstance(property_.value_type, ViewEntity | ViewPropertyEntity):
|
|
1113
1039
|
value_type = ClassEntity(
|
|
1114
1040
|
prefix=property_.value_type.prefix,
|
|
1115
1041
|
suffix=property_.value_type.suffix,
|
|
1116
1042
|
)
|
|
1043
|
+
elif isinstance(property_.value_type, DMSUnknownEntity):
|
|
1044
|
+
value_type = UnknownEntity()
|
|
1117
1045
|
else:
|
|
1118
1046
|
raise ValueError(f"Unsupported value type: {property_.value_type.type_}")
|
|
1119
1047
|
|
|
1120
1048
|
properties.append(
|
|
1121
1049
|
InformationProperty(
|
|
1122
|
-
|
|
1050
|
+
# Removing version
|
|
1051
|
+
class_=ClassEntity(suffix=property_.class_.suffix, prefix=property_.class_.prefix),
|
|
1123
1052
|
property_=property_.view_property,
|
|
1124
|
-
value_type=
|
|
1053
|
+
value_type=value_type,
|
|
1125
1054
|
description=property_.description,
|
|
1126
1055
|
min_count=0 if property_.nullable or property_.nullable is None else 1,
|
|
1127
1056
|
max_count=float("inf") if property_.is_list or property_.nullable is None else 1,
|
|
@@ -1161,5 +1090,5 @@ class _DMSRulesConverter:
|
|
|
1161
1090
|
return ReferenceEntity(
|
|
1162
1091
|
prefix=container.prefix,
|
|
1163
1092
|
suffix=container.suffix,
|
|
1164
|
-
|
|
1093
|
+
property=property_.container_property,
|
|
1165
1094
|
)
|