cognite-neat 0.75.6__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/_models.py +6 -1
- cognite/neat/rules/exporters/_rules2dms.py +67 -14
- 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 +282 -0
- cognite/neat/rules/models/entities.py +442 -0
- 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/utils/cdf_loaders/_data_modeling.py +4 -2
- cognite/neat/workflows/steps/lib/rules_exporter.py +97 -0
- cognite/neat/workflows/steps/lib/rules_importer.py +3 -3
- {cognite_neat-0.75.6.dist-info → cognite_neat-0.75.8.dist-info}/METADATA +1 -1
- {cognite_neat-0.75.6.dist-info → cognite_neat-0.75.8.dist-info}/RECORD +35 -34
- cognite/neat/rules/models/_entity.py +0 -142
- cognite/neat/rules/models/rules/_types/_value.py +0 -159
- {cognite_neat-0.75.6.dist-info → cognite_neat-0.75.8.dist-info}/LICENSE +0 -0
- {cognite_neat-0.75.6.dist-info → cognite_neat-0.75.8.dist-info}/WHEEL +0 -0
- {cognite_neat-0.75.6.dist-info → cognite_neat-0.75.8.dist-info}/entry_points.txt +0 -0
|
@@ -13,6 +13,25 @@ from rdflib import Namespace
|
|
|
13
13
|
import cognite.neat.rules.issues.spreadsheet
|
|
14
14
|
from cognite.neat.constants import PREFIXES
|
|
15
15
|
from cognite.neat.rules import exceptions
|
|
16
|
+
from cognite.neat.rules.models.data_types import DataType
|
|
17
|
+
from cognite.neat.rules.models.entities import (
|
|
18
|
+
ClassEntity,
|
|
19
|
+
ContainerEntity,
|
|
20
|
+
DMSUnknownEntity,
|
|
21
|
+
Entity,
|
|
22
|
+
EntityTypes,
|
|
23
|
+
ParentClassEntity,
|
|
24
|
+
ParentEntityList,
|
|
25
|
+
ReferenceEntity,
|
|
26
|
+
Undefined,
|
|
27
|
+
Unknown,
|
|
28
|
+
UnknownEntity,
|
|
29
|
+
URLEntity,
|
|
30
|
+
ViewEntity,
|
|
31
|
+
ViewPropertyEntity,
|
|
32
|
+
_UndefinedType,
|
|
33
|
+
_UnknownType,
|
|
34
|
+
)
|
|
16
35
|
from cognite.neat.rules.models.rdfpath import (
|
|
17
36
|
AllReferences,
|
|
18
37
|
Hop,
|
|
@@ -37,26 +56,12 @@ from ._base import (
|
|
|
37
56
|
)
|
|
38
57
|
from ._domain_rules import DomainRules
|
|
39
58
|
from ._types import (
|
|
40
|
-
ClassEntity,
|
|
41
|
-
ContainerEntity,
|
|
42
|
-
Entity,
|
|
43
|
-
EntityTypes,
|
|
44
59
|
NamespaceType,
|
|
45
|
-
ParentClassEntity,
|
|
46
|
-
ParentClassType,
|
|
47
60
|
PrefixType,
|
|
48
61
|
PropertyType,
|
|
49
|
-
ReferenceEntity,
|
|
50
|
-
ReferenceType,
|
|
51
|
-
SemanticValueType,
|
|
52
62
|
StrListType,
|
|
53
|
-
Undefined,
|
|
54
63
|
VersionType,
|
|
55
|
-
ViewEntity,
|
|
56
|
-
ViewPropEntity,
|
|
57
|
-
XSDValueType,
|
|
58
64
|
)
|
|
59
|
-
from ._types._base import Unknown
|
|
60
65
|
|
|
61
66
|
if TYPE_CHECKING:
|
|
62
67
|
from ._dms_architect_rules import DMSProperty, DMSRules
|
|
@@ -118,8 +123,8 @@ class InformationClass(SheetEntity):
|
|
|
118
123
|
match_type: The match type of the resource being described and the source entity.
|
|
119
124
|
"""
|
|
120
125
|
|
|
121
|
-
parent:
|
|
122
|
-
reference:
|
|
126
|
+
parent: ParentEntityList | None = Field(alias="Parent Class", default=None)
|
|
127
|
+
reference: URLEntity | ReferenceEntity | None = Field(alias="Reference", default=None, union_mode="left_to_right")
|
|
123
128
|
match_type: MatchType | None = Field(alias="Match Type", default=None)
|
|
124
129
|
comment: str | None = Field(alias="Comment", default=None)
|
|
125
130
|
|
|
@@ -146,11 +151,11 @@ class InformationProperty(SheetEntity):
|
|
|
146
151
|
"""
|
|
147
152
|
|
|
148
153
|
property_: PropertyType = Field(alias="Property")
|
|
149
|
-
value_type:
|
|
154
|
+
value_type: DataType | ClassEntity | UnknownEntity = Field(alias="Value Type", union_mode="left_to_right")
|
|
150
155
|
min_count: int | None = Field(alias="Min Count", default=None)
|
|
151
156
|
max_count: int | float | None = Field(alias="Max Count", default=None)
|
|
152
157
|
default: Any | None = Field(alias="Default", default=None)
|
|
153
|
-
reference:
|
|
158
|
+
reference: URLEntity | ReferenceEntity | None = Field(alias="Reference", default=None, union_mode="left_to_right")
|
|
154
159
|
match_type: MatchType | None = Field(alias="Match Type", default=None)
|
|
155
160
|
rule_type: str | TransformationRuleType | None = Field(alias="Rule Type", default=None)
|
|
156
161
|
rule: str | AllReferences | SingleProperty | Hop | RawLookup | SPARQLQuery | Traversal | None = Field(
|
|
@@ -223,9 +228,9 @@ class InformationProperty(SheetEntity):
|
|
|
223
228
|
@property
|
|
224
229
|
def type_(self) -> EntityTypes:
|
|
225
230
|
"""Type of property based on value type. Either data (attribute) or object (edge) property."""
|
|
226
|
-
if self.value_type
|
|
231
|
+
if isinstance(self.value_type, DataType):
|
|
227
232
|
return EntityTypes.data_property
|
|
228
|
-
elif self.value_type
|
|
233
|
+
elif isinstance(self.value_type, ClassEntity):
|
|
229
234
|
return EntityTypes.object_property
|
|
230
235
|
else:
|
|
231
236
|
return EntityTypes.undefined
|
|
@@ -258,7 +263,7 @@ class InformationRules(RuleModel):
|
|
|
258
263
|
def update_entities_prefix(self) -> Self:
|
|
259
264
|
# update expected_value_types
|
|
260
265
|
for property_ in self.properties:
|
|
261
|
-
if property_.value_type
|
|
266
|
+
if isinstance(property_.value_type, ClassEntity) and property_.value_type.prefix is Undefined:
|
|
262
267
|
property_.value_type.prefix = self.metadata.prefix
|
|
263
268
|
if property_.class_.prefix is Undefined:
|
|
264
269
|
property_.class_.prefix = self.metadata.prefix
|
|
@@ -267,7 +272,7 @@ class InformationRules(RuleModel):
|
|
|
267
272
|
for class_ in self.classes:
|
|
268
273
|
if class_.parent:
|
|
269
274
|
for parent in cast(list[ParentClassEntity], class_.parent):
|
|
270
|
-
if parent.prefix
|
|
275
|
+
if not isinstance(parent.prefix, str):
|
|
271
276
|
parent.prefix = self.metadata.prefix
|
|
272
277
|
if class_.class_.prefix is Undefined:
|
|
273
278
|
class_.class_.prefix = self.metadata.prefix
|
|
@@ -279,15 +284,15 @@ class InformationRules(RuleModel):
|
|
|
279
284
|
# update expected_value_types
|
|
280
285
|
|
|
281
286
|
if self.metadata.schema_ == SchemaCompleteness.complete:
|
|
282
|
-
defined_classes = {class_.class_
|
|
283
|
-
referred_classes = {property_.class_
|
|
284
|
-
parent
|
|
287
|
+
defined_classes = {str(class_.class_) for class_ in self.classes}
|
|
288
|
+
referred_classes = {str(property_.class_) for property_ in self.properties} | {
|
|
289
|
+
str(parent) for class_ in self.classes for parent in class_.parent or []
|
|
285
290
|
}
|
|
286
291
|
referred_types = {
|
|
287
|
-
property_.value_type
|
|
292
|
+
str(property_.value_type)
|
|
288
293
|
for property_ in self.properties
|
|
289
|
-
if property_.
|
|
290
|
-
and not
|
|
294
|
+
if isinstance(property_.value_type, Entity)
|
|
295
|
+
and not isinstance(property_.value_type.suffix, _UnknownType)
|
|
291
296
|
}
|
|
292
297
|
if not referred_classes.issubset(defined_classes) or not referred_types.issubset(defined_classes):
|
|
293
298
|
missing_classes = referred_classes.difference(defined_classes).union(
|
|
@@ -300,7 +305,7 @@ class InformationRules(RuleModel):
|
|
|
300
305
|
@model_validator(mode="after")
|
|
301
306
|
def validate_class_has_properties_or_parent(self) -> Self:
|
|
302
307
|
defined_classes = {class_.class_ for class_ in self.classes if class_.reference is None}
|
|
303
|
-
referred_classes = {property_.class_ for property_ in self.properties}
|
|
308
|
+
referred_classes = {property_.class_ for property_ in self.properties if property_.class_.suffix is not Unknown}
|
|
304
309
|
has_parent_classes = {class_.class_ for class_ in self.classes if class_.parent}
|
|
305
310
|
missing_classes = defined_classes.difference(referred_classes) - has_parent_classes
|
|
306
311
|
if missing_classes:
|
|
@@ -357,15 +362,21 @@ class InformationRules(RuleModel):
|
|
|
357
362
|
new_self = self.model_copy(deep=True)
|
|
358
363
|
for prop in new_self.properties:
|
|
359
364
|
prop.reference = ReferenceEntity(
|
|
360
|
-
prefix=prop.class_.prefix
|
|
365
|
+
prefix=prop.class_.prefix
|
|
366
|
+
if not isinstance(prop.class_.prefix, _UndefinedType)
|
|
367
|
+
else self.metadata.prefix,
|
|
361
368
|
suffix=prop.class_.suffix,
|
|
362
369
|
version=prop.class_.version,
|
|
363
|
-
|
|
370
|
+
property=prop.property_,
|
|
364
371
|
)
|
|
365
372
|
|
|
366
373
|
for cls_ in new_self.classes:
|
|
367
374
|
cls_.reference = ReferenceEntity(
|
|
368
|
-
prefix=cls_.class_.prefix
|
|
375
|
+
prefix=cls_.class_.prefix
|
|
376
|
+
if not isinstance(cls_.class_.prefix, _UndefinedType)
|
|
377
|
+
else self.metadata.prefix,
|
|
378
|
+
suffix=cls_.class_.suffix,
|
|
379
|
+
version=cls_.class_.version,
|
|
369
380
|
)
|
|
370
381
|
|
|
371
382
|
return new_self
|
|
@@ -382,7 +393,8 @@ class _InformationRulesConverter:
|
|
|
382
393
|
from ._dms_architect_rules import DMSContainer, DMSMetadata, DMSProperty, DMSRules, DMSView
|
|
383
394
|
|
|
384
395
|
info_metadata = self.information.metadata
|
|
385
|
-
|
|
396
|
+
default_version = info_metadata.version
|
|
397
|
+
default_space = self._to_space(info_metadata.prefix)
|
|
386
398
|
space = self._to_space(info_metadata.prefix)
|
|
387
399
|
|
|
388
400
|
metadata = DMSMetadata(
|
|
@@ -398,13 +410,15 @@ class _InformationRulesConverter:
|
|
|
398
410
|
|
|
399
411
|
properties_by_class: dict[str, list[DMSProperty]] = defaultdict(list)
|
|
400
412
|
for prop in self.information.properties:
|
|
401
|
-
properties_by_class[prop.class_.versioned_id].append(
|
|
413
|
+
properties_by_class[prop.class_.versioned_id].append(
|
|
414
|
+
self._as_dms_property(prop, default_space, default_version)
|
|
415
|
+
)
|
|
402
416
|
|
|
403
417
|
views: list[DMSView] = [
|
|
404
418
|
DMSView(
|
|
405
419
|
class_=cls_.class_,
|
|
406
420
|
name=cls_.name,
|
|
407
|
-
view=
|
|
421
|
+
view=cls_.class_.as_view_entity(default_space, default_version),
|
|
408
422
|
description=cls_.description,
|
|
409
423
|
reference=cls_.reference,
|
|
410
424
|
implements=self._get_view_implements(cls_, info_metadata),
|
|
@@ -416,7 +430,7 @@ class _InformationRulesConverter:
|
|
|
416
430
|
for class_ in self.information.classes:
|
|
417
431
|
properties: list[DMSProperty] = properties_by_class.get(class_.class_.versioned_id, [])
|
|
418
432
|
if not properties or all(
|
|
419
|
-
isinstance(prop.value_type,
|
|
433
|
+
isinstance(prop.value_type, ViewPropertyEntity) and prop.relation != "direct" for prop in properties
|
|
420
434
|
):
|
|
421
435
|
classes_without_properties.add(class_.class_.versioned_id)
|
|
422
436
|
|
|
@@ -428,13 +442,10 @@ class _InformationRulesConverter:
|
|
|
428
442
|
DMSContainer(
|
|
429
443
|
class_=class_.class_,
|
|
430
444
|
name=class_.name,
|
|
431
|
-
container=
|
|
445
|
+
container=class_.class_.as_container_entity(default_space),
|
|
432
446
|
description=class_.description,
|
|
433
447
|
constraint=[
|
|
434
|
-
|
|
435
|
-
prefix=parent.prefix,
|
|
436
|
-
suffix=parent.suffix,
|
|
437
|
-
)
|
|
448
|
+
parent.as_container_entity(default_space)
|
|
438
449
|
for parent in class_.parent or []
|
|
439
450
|
if parent.versioned_id not in classes_without_properties
|
|
440
451
|
]
|
|
@@ -453,23 +464,24 @@ class _InformationRulesConverter:
|
|
|
453
464
|
)
|
|
454
465
|
|
|
455
466
|
@classmethod
|
|
456
|
-
def _as_dms_property(cls, prop: InformationProperty) -> "DMSProperty":
|
|
467
|
+
def _as_dms_property(cls, prop: InformationProperty, default_space: str, default_version: str) -> "DMSProperty":
|
|
457
468
|
"""This creates the first"""
|
|
458
469
|
|
|
459
470
|
from ._dms_architect_rules import DMSProperty
|
|
460
471
|
|
|
461
472
|
# returns property type, which can be ObjectProperty or DatatypeProperty
|
|
462
|
-
|
|
463
|
-
|
|
473
|
+
value_type: DataType | ViewEntity | ViewPropertyEntity | DMSUnknownEntity
|
|
474
|
+
if isinstance(prop.value_type, DataType):
|
|
475
|
+
value_type = prop.value_type
|
|
476
|
+
elif isinstance(prop.value_type, UnknownEntity):
|
|
477
|
+
value_type = DMSUnknownEntity()
|
|
464
478
|
elif isinstance(prop.value_type, ClassEntity):
|
|
465
|
-
value_type =
|
|
466
|
-
prefix=prop.value_type.prefix, suffix=prop.value_type.suffix, version=prop.value_type.version
|
|
467
|
-
)
|
|
479
|
+
value_type = prop.value_type.as_view_entity(default_space, default_version)
|
|
468
480
|
else:
|
|
469
481
|
raise ValueError(f"Unsupported value type: {prop.value_type.type_}")
|
|
470
482
|
|
|
471
483
|
relation: Literal["direct", "multiedge"] | None = None
|
|
472
|
-
if isinstance(value_type,
|
|
484
|
+
if isinstance(value_type, ViewEntity | ViewPropertyEntity):
|
|
473
485
|
relation = "multiedge" if prop.is_list else "direct"
|
|
474
486
|
|
|
475
487
|
container: ContainerEntity | None = None
|
|
@@ -481,9 +493,9 @@ class _InformationRulesConverter:
|
|
|
481
493
|
nullable = None
|
|
482
494
|
elif relation == "direct":
|
|
483
495
|
nullable = True
|
|
484
|
-
container, container_property = cls._get_container(prop)
|
|
496
|
+
container, container_property = cls._get_container(prop, default_space)
|
|
485
497
|
else:
|
|
486
|
-
container, container_property = cls._get_container(prop)
|
|
498
|
+
container, container_property = cls._get_container(prop, default_space)
|
|
487
499
|
|
|
488
500
|
return DMSProperty(
|
|
489
501
|
class_=prop.class_,
|
|
@@ -497,7 +509,7 @@ class _InformationRulesConverter:
|
|
|
497
509
|
reference=prop.reference,
|
|
498
510
|
container=container,
|
|
499
511
|
container_property=container_property,
|
|
500
|
-
view=
|
|
512
|
+
view=prop.class_.as_view_entity(default_space, default_version),
|
|
501
513
|
view_property=prop.property_,
|
|
502
514
|
)
|
|
503
515
|
|
|
@@ -513,29 +525,24 @@ class _InformationRulesConverter:
|
|
|
513
525
|
return prefix
|
|
514
526
|
|
|
515
527
|
@classmethod
|
|
516
|
-
def _get_container(cls, prop: InformationProperty) -> tuple[ContainerEntity, str]:
|
|
528
|
+
def _get_container(cls, prop: InformationProperty, default_space: str) -> tuple[ContainerEntity, str]:
|
|
517
529
|
if isinstance(prop.reference, ReferenceEntity):
|
|
518
530
|
return (
|
|
519
|
-
|
|
531
|
+
prop.reference.as_container_entity(default_space),
|
|
520
532
|
prop.reference.property_ or prop.property_,
|
|
521
533
|
)
|
|
522
534
|
else:
|
|
523
|
-
return
|
|
535
|
+
return prop.class_.as_container_entity(default_space), prop.property_
|
|
524
536
|
|
|
525
537
|
@classmethod
|
|
526
538
|
def _get_view_implements(cls, cls_: InformationClass, metadata: InformationMetadata) -> list[ViewEntity]:
|
|
527
539
|
if isinstance(cls_.reference, ReferenceEntity) and cls_.reference.prefix != metadata.prefix:
|
|
528
540
|
# We use the reference for implements if it is in a different namespace
|
|
529
541
|
implements = [
|
|
530
|
-
|
|
542
|
+
cls_.reference.as_view_entity(metadata.prefix, metadata.version),
|
|
531
543
|
]
|
|
532
544
|
else:
|
|
533
545
|
implements = []
|
|
534
546
|
|
|
535
|
-
implements.extend(
|
|
536
|
-
[
|
|
537
|
-
ViewEntity(prefix=parent.prefix, suffix=parent.suffix, version=parent.version)
|
|
538
|
-
for parent in cls_.parent or []
|
|
539
|
-
]
|
|
540
|
-
)
|
|
547
|
+
implements.extend([parent.as_view_entity(metadata.prefix, metadata.version) for parent in cls_.parent or []])
|
|
541
548
|
return implements
|
|
@@ -1,66 +1,19 @@
|
|
|
1
|
-
from ._base import (
|
|
2
|
-
ClassEntity,
|
|
3
|
-
ContainerEntity,
|
|
4
|
-
DataModelEntity,
|
|
5
|
-
Entity,
|
|
6
|
-
EntityTypes,
|
|
7
|
-
ParentClassEntity,
|
|
8
|
-
ReferenceEntity,
|
|
9
|
-
Undefined,
|
|
10
|
-
Unknown,
|
|
11
|
-
ViewEntity,
|
|
12
|
-
ViewPropEntity,
|
|
13
|
-
)
|
|
14
1
|
from ._field import (
|
|
15
|
-
CdfValueType,
|
|
16
|
-
ClassType,
|
|
17
|
-
ContainerListType,
|
|
18
|
-
ContainerType,
|
|
19
2
|
ExternalIdType,
|
|
20
3
|
NamespaceType,
|
|
21
|
-
ParentClassType,
|
|
22
4
|
PrefixType,
|
|
23
5
|
PropertyType,
|
|
24
|
-
ReferenceType,
|
|
25
|
-
SemanticValueType,
|
|
26
6
|
StrListType,
|
|
27
7
|
StrOrListType,
|
|
28
8
|
VersionType,
|
|
29
|
-
ViewListType,
|
|
30
|
-
ViewType,
|
|
31
9
|
)
|
|
32
|
-
from ._value import DMS_VALUE_TYPE_MAPPINGS, XSD_VALUE_TYPE_MAPPINGS, DMSValueType, XSDValueType
|
|
33
10
|
|
|
34
11
|
__all__ = [
|
|
35
|
-
"Undefined",
|
|
36
|
-
"Unknown",
|
|
37
|
-
"Entity",
|
|
38
|
-
"EntityTypes",
|
|
39
|
-
"ClassEntity",
|
|
40
|
-
"ParentClassEntity",
|
|
41
|
-
"ContainerEntity",
|
|
42
|
-
"ViewEntity",
|
|
43
|
-
"ViewPropEntity",
|
|
44
|
-
"ReferenceEntity",
|
|
45
|
-
"DataModelEntity",
|
|
46
|
-
"XSDValueType",
|
|
47
|
-
"DMSValueType",
|
|
48
|
-
"XSD_VALUE_TYPE_MAPPINGS",
|
|
49
|
-
"DMS_VALUE_TYPE_MAPPINGS",
|
|
50
12
|
"StrOrListType",
|
|
51
13
|
"StrListType",
|
|
52
14
|
"NamespaceType",
|
|
53
15
|
"PrefixType",
|
|
54
16
|
"ExternalIdType",
|
|
55
17
|
"VersionType",
|
|
56
|
-
"ParentClassType",
|
|
57
|
-
"ClassType",
|
|
58
18
|
"PropertyType",
|
|
59
|
-
"SemanticValueType",
|
|
60
|
-
"CdfValueType",
|
|
61
|
-
"ReferenceType",
|
|
62
|
-
"ContainerType",
|
|
63
|
-
"ViewType",
|
|
64
|
-
"ContainerListType",
|
|
65
|
-
"ViewListType",
|
|
66
19
|
]
|
|
@@ -1,51 +1,6 @@
|
|
|
1
|
-
import re
|
|
2
|
-
import sys
|
|
3
|
-
from typing import Any, ClassVar, Literal, cast, overload
|
|
4
|
-
|
|
5
|
-
from cognite.client.data_classes.data_modeling import ContainerId, DataModelId, PropertyId, ViewId
|
|
6
|
-
|
|
7
|
-
from cognite.neat.rules.models._entity import (
|
|
8
|
-
ENTITY_ID_REGEX_COMPILED,
|
|
9
|
-
PREFIX_REGEX,
|
|
10
|
-
PROPERTY_REGEX,
|
|
11
|
-
SUFFIX_REGEX,
|
|
12
|
-
VERSION_REGEX,
|
|
13
|
-
VERSIONED_ENTITY_REGEX_COMPILED,
|
|
14
|
-
Entity,
|
|
15
|
-
EntityTypes,
|
|
16
|
-
Undefined,
|
|
17
|
-
Unknown,
|
|
18
|
-
)
|
|
19
|
-
from cognite.neat.rules.models.rdfpath import (
|
|
20
|
-
SINGLE_PROPERTY_REGEX_COMPILED,
|
|
21
|
-
AllReferences,
|
|
22
|
-
RDFPath,
|
|
23
|
-
SingleProperty,
|
|
24
|
-
TransformationRuleType,
|
|
25
|
-
parse_rule,
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
if sys.version_info >= (3, 11):
|
|
29
|
-
from typing import Self
|
|
30
|
-
else:
|
|
31
|
-
from typing_extensions import Self
|
|
32
|
-
|
|
33
|
-
# mypy: ignore-errors
|
|
34
|
-
VERSION_ID_REGEX = rf"\(version=(?P<version>{VERSION_REGEX})\)"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
PROPERTY_ENTITY_REGEX_COMPILED = re.compile(
|
|
38
|
-
rf"^((?P<prefix>{PREFIX_REGEX}):)?(?P<suffix>{SUFFIX_REGEX})"
|
|
39
|
-
rf"\((version=(?P<version>{VERSION_REGEX}), )?property=(?P<property>{PROPERTY_REGEX})\)$"
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
|
|
43
1
|
MORE_THAN_ONE_NONE_ALPHANUMERIC_REGEX = r"([_-]{2,})"
|
|
44
2
|
PREFIX_COMPLIANCE_REGEX = r"^([a-zA-Z]+)([a-zA-Z0-9]*[_-]{0,1}[a-zA-Z0-9_-]*)([a-zA-Z0-9]*)$"
|
|
45
|
-
|
|
46
|
-
CDF_SPACE_COMPLIANCE_REGEX = (
|
|
47
|
-
r"(?!^(space|cdf|dms|pg3|shared|system|node|edge)$)(^[a-zA-Z][a-zA-Z0-9_-]{0,41}[a-zA-Z0-9]?$)"
|
|
48
|
-
)
|
|
3
|
+
|
|
49
4
|
VIEW_ID_COMPLIANCE_REGEX = (
|
|
50
5
|
r"(?!^(Query|Mutation|Subscription|String|Int32|Int64|Int|Float32|Float64|Float|"
|
|
51
6
|
r"Timestamp|JSONObject|Date|Numeric|Boolean|PageInfo|File|Sequence|TimeSeries)$)"
|
|
@@ -59,266 +14,3 @@ DMS_PROPERTY_ID_COMPLIANCE_REGEX = (
|
|
|
59
14
|
CLASS_ID_COMPLIANCE_REGEX = r"(?!^(Class|class)$)(^[a-zA-Z][a-zA-Z0-9._-]{0,253}[a-zA-Z0-9]?$)"
|
|
60
15
|
PROPERTY_ID_COMPLIANCE_REGEX = r"^(\*)|(?!^(Property|property)$)(^[a-zA-Z][a-zA-Z0-9._-]{0,253}[a-zA-Z0-9]?$)"
|
|
61
16
|
VERSION_COMPLIANCE_REGEX = r"^[a-zA-Z0-9]([.a-zA-Z0-9_-]{0,41}[a-zA-Z0-9])?$"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
class ContainerEntity(Entity):
|
|
65
|
-
type_: ClassVar[EntityTypes] = EntityTypes.container
|
|
66
|
-
|
|
67
|
-
@classmethod
|
|
68
|
-
def from_raw(cls, value: Any) -> "ContainerEntity":
|
|
69
|
-
if not value:
|
|
70
|
-
return ContainerEntity(prefix=Undefined, suffix=value)
|
|
71
|
-
elif isinstance(value, ContainerEntity):
|
|
72
|
-
return value
|
|
73
|
-
|
|
74
|
-
if ENTITY_ID_REGEX_COMPILED.match(value):
|
|
75
|
-
return ContainerEntity.from_string(entity_string=value)
|
|
76
|
-
else:
|
|
77
|
-
return ContainerEntity(prefix=Undefined, suffix=value)
|
|
78
|
-
|
|
79
|
-
@classmethod
|
|
80
|
-
def from_id(cls, container_id: ContainerId) -> "ContainerEntity":
|
|
81
|
-
return ContainerEntity(prefix=container_id.space, suffix=container_id.external_id)
|
|
82
|
-
|
|
83
|
-
def as_id(self, default_space: str | None) -> ContainerId:
|
|
84
|
-
if self.space is Undefined and default_space is None:
|
|
85
|
-
raise ValueError("Space is Undefined! Set default_space!")
|
|
86
|
-
|
|
87
|
-
if self.space is Undefined:
|
|
88
|
-
return ContainerId(space=cast(str, default_space), external_id=self.external_id)
|
|
89
|
-
else:
|
|
90
|
-
return ContainerId(space=self.space, external_id=self.external_id)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
class ViewEntity(Entity):
|
|
94
|
-
type_: ClassVar[EntityTypes] = EntityTypes.view
|
|
95
|
-
|
|
96
|
-
@classmethod
|
|
97
|
-
def from_raw(cls, value: Any) -> "ViewEntity":
|
|
98
|
-
if not value:
|
|
99
|
-
return ViewEntity(prefix=Undefined, suffix=value)
|
|
100
|
-
elif isinstance(value, ViewEntity):
|
|
101
|
-
return value
|
|
102
|
-
|
|
103
|
-
if ENTITY_ID_REGEX_COMPILED.match(value) or VERSIONED_ENTITY_REGEX_COMPILED.match(value):
|
|
104
|
-
return cls.from_string(entity_string=value)
|
|
105
|
-
else:
|
|
106
|
-
return cls(prefix=Undefined, suffix=value)
|
|
107
|
-
|
|
108
|
-
@classmethod
|
|
109
|
-
def from_id(cls, view_id: ViewId) -> Self:
|
|
110
|
-
return cls(prefix=view_id.space, suffix=view_id.external_id, version=view_id.version)
|
|
111
|
-
|
|
112
|
-
@overload
|
|
113
|
-
def as_id(
|
|
114
|
-
self,
|
|
115
|
-
allow_none: Literal[False] = False,
|
|
116
|
-
default_space: str | None = None,
|
|
117
|
-
default_version: str | None = None,
|
|
118
|
-
) -> ViewId:
|
|
119
|
-
...
|
|
120
|
-
|
|
121
|
-
@overload
|
|
122
|
-
def as_id(
|
|
123
|
-
self,
|
|
124
|
-
allow_none: Literal[True],
|
|
125
|
-
default_space: str | None = None,
|
|
126
|
-
default_version: str | None = None,
|
|
127
|
-
) -> ViewId | None:
|
|
128
|
-
...
|
|
129
|
-
|
|
130
|
-
def as_id(
|
|
131
|
-
self,
|
|
132
|
-
allow_none: bool = False,
|
|
133
|
-
default_space: str | None = None,
|
|
134
|
-
default_version: str | None = None,
|
|
135
|
-
) -> ViewId | None:
|
|
136
|
-
if self.suffix is Unknown and allow_none:
|
|
137
|
-
return None
|
|
138
|
-
elif self.suffix is Unknown:
|
|
139
|
-
raise ValueError("suffix is Unknown and cannot be converted to ViewId")
|
|
140
|
-
space = default_space if self.space is Undefined else self.space
|
|
141
|
-
version = self.version or default_version
|
|
142
|
-
|
|
143
|
-
if space is None or space is Undefined:
|
|
144
|
-
raise ValueError("space is required")
|
|
145
|
-
if version is None:
|
|
146
|
-
raise ValueError("version is required")
|
|
147
|
-
return ViewId(space=space, external_id=self.external_id, version=version)
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
class ViewPropEntity(ViewEntity):
|
|
151
|
-
type_: ClassVar[EntityTypes] = EntityTypes.view_prop
|
|
152
|
-
property_: str | None = None
|
|
153
|
-
|
|
154
|
-
@classmethod
|
|
155
|
-
def from_raw(cls, value: Any) -> "ViewPropEntity":
|
|
156
|
-
if not value:
|
|
157
|
-
return ViewPropEntity(prefix=Undefined, suffix=value)
|
|
158
|
-
elif isinstance(value, ViewPropEntity):
|
|
159
|
-
return value
|
|
160
|
-
elif isinstance(value, ViewEntity):
|
|
161
|
-
return cls(prefix=value.prefix, suffix=value.suffix, version=value.version)
|
|
162
|
-
|
|
163
|
-
if result := PROPERTY_ENTITY_REGEX_COMPILED.match(value):
|
|
164
|
-
return cls(
|
|
165
|
-
prefix=result.group("prefix") or Undefined,
|
|
166
|
-
suffix=result.group("suffix"),
|
|
167
|
-
version=result.group("version"),
|
|
168
|
-
property_=result.group("property"),
|
|
169
|
-
)
|
|
170
|
-
elif ENTITY_ID_REGEX_COMPILED.match(value) or VERSIONED_ENTITY_REGEX_COMPILED.match(value):
|
|
171
|
-
return cls.from_string(entity_string=value)
|
|
172
|
-
else:
|
|
173
|
-
return cls(prefix=Undefined, suffix=value)
|
|
174
|
-
|
|
175
|
-
@classmethod
|
|
176
|
-
def from_prop_id(cls, prop_id: PropertyId) -> "ViewPropEntity":
|
|
177
|
-
return ViewPropEntity(
|
|
178
|
-
prefix=prop_id.source.space,
|
|
179
|
-
suffix=prop_id.source.external_id,
|
|
180
|
-
version=cast(ViewId, prop_id.source).version,
|
|
181
|
-
property_=prop_id.property,
|
|
182
|
-
)
|
|
183
|
-
|
|
184
|
-
def as_prop_id(self, default_space: str | None = None, default_version: str | None = None) -> PropertyId:
|
|
185
|
-
if self.property_ is None:
|
|
186
|
-
raise ValueError("property is required to create PropertyId")
|
|
187
|
-
return PropertyId(source=self.as_id(False, default_space, default_version), property=self.property_)
|
|
188
|
-
|
|
189
|
-
@property
|
|
190
|
-
def versioned_id(self) -> str:
|
|
191
|
-
if self.version is None and self.property_ is None:
|
|
192
|
-
output = self.id
|
|
193
|
-
elif self.version is None:
|
|
194
|
-
output = f"{self.id}(property={self.property_})"
|
|
195
|
-
elif self.property_ is None:
|
|
196
|
-
output = f"{self.id}(version={self.version})"
|
|
197
|
-
else:
|
|
198
|
-
output = f"{self.id}(version={self.version}, property={self.property_})"
|
|
199
|
-
return output
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
class DataModelEntity(Entity):
|
|
203
|
-
type_: ClassVar[EntityTypes] = EntityTypes.datamodel
|
|
204
|
-
|
|
205
|
-
@classmethod
|
|
206
|
-
def from_raw(cls, value: Any) -> "DataModelEntity":
|
|
207
|
-
if not value:
|
|
208
|
-
return DataModelEntity(prefix=Undefined, suffix=value)
|
|
209
|
-
elif isinstance(value, DataModelEntity):
|
|
210
|
-
return value
|
|
211
|
-
|
|
212
|
-
if ENTITY_ID_REGEX_COMPILED.match(value) or VERSIONED_ENTITY_REGEX_COMPILED.match(value):
|
|
213
|
-
return DataModelEntity.from_string(entity_string=value)
|
|
214
|
-
else:
|
|
215
|
-
return DataModelEntity(prefix=Undefined, suffix=value)
|
|
216
|
-
|
|
217
|
-
@classmethod
|
|
218
|
-
def from_id(cls, data_model_id: DataModelId) -> "DataModelEntity":
|
|
219
|
-
return DataModelEntity(
|
|
220
|
-
prefix=data_model_id.space, suffix=data_model_id.external_id, version=data_model_id.version
|
|
221
|
-
)
|
|
222
|
-
|
|
223
|
-
def as_id(self, default_space: str | None = None, default_version: str | None = None) -> DataModelId:
|
|
224
|
-
space = default_space if self.space is Undefined else self.space
|
|
225
|
-
version = self.version or default_version
|
|
226
|
-
|
|
227
|
-
if space is None or space is Undefined:
|
|
228
|
-
raise ValueError("space is required")
|
|
229
|
-
|
|
230
|
-
return DataModelId(space=space, external_id=self.external_id, version=version)
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
class ClassEntity(Entity):
|
|
234
|
-
type_: ClassVar[EntityTypes] = EntityTypes.class_
|
|
235
|
-
|
|
236
|
-
@classmethod
|
|
237
|
-
def from_raw(cls, value: Any) -> Self:
|
|
238
|
-
if not value:
|
|
239
|
-
return cls(prefix=Undefined, suffix=value)
|
|
240
|
-
elif isinstance(value, cls):
|
|
241
|
-
return value
|
|
242
|
-
|
|
243
|
-
if ENTITY_ID_REGEX_COMPILED.match(value) or VERSIONED_ENTITY_REGEX_COMPILED.match(value):
|
|
244
|
-
return cls.from_string(entity_string=value)
|
|
245
|
-
else:
|
|
246
|
-
return cls(prefix=Undefined, suffix=value)
|
|
247
|
-
|
|
248
|
-
@classmethod
|
|
249
|
-
def from_view_id(cls, view_id: ViewId) -> Self:
|
|
250
|
-
return cls(prefix=view_id.space, suffix=view_id.external_id, version=view_id.version)
|
|
251
|
-
|
|
252
|
-
@property
|
|
253
|
-
def view_id(self) -> ViewId:
|
|
254
|
-
return ViewId(space=self.space, external_id=self.external_id, version=self.version)
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
class ParentClassEntity(ClassEntity):
|
|
258
|
-
type_: ClassVar[EntityTypes] = EntityTypes.parent_class
|
|
259
|
-
|
|
260
|
-
@classmethod
|
|
261
|
-
def from_raw(cls, value: Any) -> Self:
|
|
262
|
-
if isinstance(value, ClassEntity):
|
|
263
|
-
return cls(prefix=value.prefix, suffix=value.suffix, version=value.version)
|
|
264
|
-
return super().from_raw(value)
|
|
265
|
-
|
|
266
|
-
def as_class_entity(self) -> ClassEntity:
|
|
267
|
-
return ClassEntity(prefix=self.prefix, suffix=self.suffix, version=self.version)
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
class ReferenceEntity(ViewPropEntity):
|
|
271
|
-
type_: ClassVar[EntityTypes] = EntityTypes.reference_entity
|
|
272
|
-
|
|
273
|
-
@classmethod
|
|
274
|
-
def from_raw(cls, value: Any) -> "ReferenceEntity":
|
|
275
|
-
if not value:
|
|
276
|
-
return ReferenceEntity(prefix=Undefined, suffix=value)
|
|
277
|
-
elif isinstance(value, ReferenceEntity):
|
|
278
|
-
return value
|
|
279
|
-
elif isinstance(value, ViewEntity):
|
|
280
|
-
return cls(prefix=value.prefix, suffix=value.suffix, version=value.version)
|
|
281
|
-
|
|
282
|
-
if result := PROPERTY_ENTITY_REGEX_COMPILED.match(value):
|
|
283
|
-
return cls(
|
|
284
|
-
prefix=result.group("prefix") or Undefined,
|
|
285
|
-
suffix=result.group("suffix"),
|
|
286
|
-
version=result.group("version"),
|
|
287
|
-
property_=result.group("property"),
|
|
288
|
-
)
|
|
289
|
-
elif ENTITY_ID_REGEX_COMPILED.match(value) or VERSIONED_ENTITY_REGEX_COMPILED.match(value):
|
|
290
|
-
return cls.from_string(entity_string=value)
|
|
291
|
-
elif result := SINGLE_PROPERTY_REGEX_COMPILED.match(value):
|
|
292
|
-
return cls.from_rdfpath(value)
|
|
293
|
-
else:
|
|
294
|
-
return cls(prefix=Undefined, suffix=value)
|
|
295
|
-
|
|
296
|
-
@classmethod
|
|
297
|
-
def from_rdfpath(cls, rdfpath: RDFPath | str) -> "ReferenceEntity":
|
|
298
|
-
if isinstance(rdfpath, str):
|
|
299
|
-
rdfpath = parse_rule(rdfpath, TransformationRuleType.rdfpath)
|
|
300
|
-
|
|
301
|
-
if isinstance(rdfpath.traversal, AllReferences):
|
|
302
|
-
return cls(prefix=rdfpath.traversal.class_.prefix, suffix=rdfpath.traversal.class_.suffix)
|
|
303
|
-
elif isinstance(rdfpath.traversal, SingleProperty):
|
|
304
|
-
return cls(
|
|
305
|
-
prefix=rdfpath.traversal.class_.prefix,
|
|
306
|
-
suffix=rdfpath.traversal.class_.suffix,
|
|
307
|
-
property_=rdfpath.traversal.property.suffix,
|
|
308
|
-
)
|
|
309
|
-
else:
|
|
310
|
-
raise ValueError(f"Invalid RDFPath traversal type: {rdfpath.traversal}")
|
|
311
|
-
|
|
312
|
-
def as_rdfpath(self, default_prefix: str | None = None) -> RDFPath:
|
|
313
|
-
prefix = self.prefix if self.prefix is not Undefined else default_prefix
|
|
314
|
-
|
|
315
|
-
if prefix is None:
|
|
316
|
-
raise ValueError("prefix is required")
|
|
317
|
-
|
|
318
|
-
if self.property_:
|
|
319
|
-
return parse_rule(f"{prefix}:{self.suffix}({self.prefix}:{self.property_})", TransformationRuleType.rdfpath)
|
|
320
|
-
else:
|
|
321
|
-
return parse_rule(f"{self.prefix}:{self.suffix}", TransformationRuleType.rdfpath)
|
|
322
|
-
|
|
323
|
-
def as_class_entity(self) -> ClassEntity:
|
|
324
|
-
return ClassEntity(prefix=self.prefix, suffix=self.suffix, version=self.version)
|