cognite-neat 0.88.3__py3-none-any.whl → 0.90.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 (84) hide show
  1. cognite/neat/_version.py +1 -1
  2. cognite/neat/constants.py +6 -3
  3. cognite/neat/graph/extractors/__init__.py +2 -0
  4. cognite/neat/graph/extractors/_classic_cdf/_base.py +2 -2
  5. cognite/neat/graph/extractors/_dms.py +158 -0
  6. cognite/neat/graph/extractors/_mock_graph_generator.py +50 -9
  7. cognite/neat/graph/loaders/_rdf2dms.py +16 -13
  8. cognite/neat/graph/models.py +1 -0
  9. cognite/neat/graph/queries/_base.py +4 -2
  10. cognite/neat/issues/_base.py +3 -1
  11. cognite/neat/issues/errors/__init__.py +2 -1
  12. cognite/neat/issues/errors/_general.py +7 -0
  13. cognite/neat/issues/warnings/__init__.py +2 -0
  14. cognite/neat/issues/warnings/_models.py +1 -1
  15. cognite/neat/issues/warnings/_properties.py +12 -0
  16. cognite/neat/issues/warnings/user_modeling.py +1 -1
  17. cognite/neat/rules/_shared.py +49 -6
  18. cognite/neat/rules/analysis/_base.py +1 -1
  19. cognite/neat/rules/exporters/_base.py +7 -18
  20. cognite/neat/rules/exporters/_rules2dms.py +8 -18
  21. cognite/neat/rules/exporters/_rules2excel.py +5 -12
  22. cognite/neat/rules/exporters/_rules2ontology.py +9 -19
  23. cognite/neat/rules/exporters/_rules2yaml.py +3 -6
  24. cognite/neat/rules/importers/_base.py +7 -52
  25. cognite/neat/rules/importers/_dms2rules.py +172 -116
  26. cognite/neat/rules/importers/_dtdl2rules/dtdl_converter.py +26 -18
  27. cognite/neat/rules/importers/_dtdl2rules/dtdl_importer.py +14 -30
  28. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2classes.py +7 -3
  29. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2metadata.py +3 -3
  30. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2properties.py +18 -11
  31. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2rules.py +9 -18
  32. cognite/neat/rules/importers/_rdf/_inference2rules.py +37 -65
  33. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2rules.py +9 -20
  34. cognite/neat/rules/importers/_rdf/_shared.py +1 -1
  35. cognite/neat/rules/importers/_spreadsheet2rules.py +22 -86
  36. cognite/neat/rules/importers/_yaml2rules.py +14 -41
  37. cognite/neat/rules/models/__init__.py +21 -5
  38. cognite/neat/rules/models/_base_input.py +162 -0
  39. cognite/neat/rules/models/{_base.py → _base_rules.py} +1 -12
  40. cognite/neat/rules/models/asset/__init__.py +5 -2
  41. cognite/neat/rules/models/asset/_rules.py +2 -20
  42. cognite/neat/rules/models/asset/_rules_input.py +40 -115
  43. cognite/neat/rules/models/asset/_validation.py +1 -1
  44. cognite/neat/rules/models/data_types.py +150 -44
  45. cognite/neat/rules/models/dms/__init__.py +19 -7
  46. cognite/neat/rules/models/dms/_exporter.py +82 -39
  47. cognite/neat/rules/models/dms/_rules.py +42 -155
  48. cognite/neat/rules/models/dms/_rules_input.py +186 -254
  49. cognite/neat/rules/models/dms/_serializer.py +44 -3
  50. cognite/neat/rules/models/dms/_validation.py +3 -4
  51. cognite/neat/rules/models/domain.py +52 -1
  52. cognite/neat/rules/models/entities/__init__.py +63 -0
  53. cognite/neat/rules/models/entities/_constants.py +73 -0
  54. cognite/neat/rules/models/entities/_loaders.py +76 -0
  55. cognite/neat/rules/models/entities/_multi_value.py +67 -0
  56. cognite/neat/rules/models/{entities.py → entities/_single_value.py} +74 -232
  57. cognite/neat/rules/models/entities/_types.py +86 -0
  58. cognite/neat/rules/models/{wrapped_entities.py → entities/_wrapped.py} +1 -1
  59. cognite/neat/rules/models/information/__init__.py +10 -2
  60. cognite/neat/rules/models/information/_rules.py +3 -14
  61. cognite/neat/rules/models/information/_rules_input.py +57 -204
  62. cognite/neat/rules/models/information/_validation.py +1 -1
  63. cognite/neat/rules/transformers/__init__.py +21 -0
  64. cognite/neat/rules/transformers/_base.py +69 -3
  65. cognite/neat/rules/{models/information/_converter.py → transformers/_converters.py} +226 -21
  66. cognite/neat/rules/transformers/_map_onto.py +97 -0
  67. cognite/neat/rules/transformers/_pipelines.py +61 -0
  68. cognite/neat/rules/transformers/_verification.py +136 -0
  69. cognite/neat/store/_base.py +2 -2
  70. cognite/neat/store/_provenance.py +10 -1
  71. cognite/neat/utils/cdf/data_classes.py +20 -0
  72. cognite/neat/utils/regex_patterns.py +6 -0
  73. cognite/neat/workflows/steps/lib/current/rules_exporter.py +106 -37
  74. cognite/neat/workflows/steps/lib/current/rules_importer.py +24 -22
  75. {cognite_neat-0.88.3.dist-info → cognite_neat-0.90.0.dist-info}/METADATA +1 -1
  76. {cognite_neat-0.88.3.dist-info → cognite_neat-0.90.0.dist-info}/RECORD +80 -74
  77. cognite/neat/rules/models/_constants.py +0 -2
  78. cognite/neat/rules/models/_types/__init__.py +0 -19
  79. cognite/neat/rules/models/asset/_converter.py +0 -4
  80. cognite/neat/rules/models/dms/_converter.py +0 -143
  81. /cognite/neat/rules/models/{_types/_field.py → _types.py} +0 -0
  82. {cognite_neat-0.88.3.dist-info → cognite_neat-0.90.0.dist-info}/LICENSE +0 -0
  83. {cognite_neat-0.88.3.dist-info → cognite_neat-0.90.0.dist-info}/WHEEL +0 -0
  84. {cognite_neat-0.88.3.dist-info → cognite_neat-0.90.0.dist-info}/entry_points.txt +0 -0
@@ -1,4 +1,5 @@
1
1
  import math
2
+ from dataclasses import dataclass, field
2
3
  from typing import Any, ClassVar
3
4
 
4
5
  from pydantic import Field, field_serializer, field_validator, model_serializer
@@ -7,7 +8,8 @@ from pydantic_core.core_schema import SerializationInfo
7
8
  from cognite.neat.rules.models.data_types import DataType
8
9
  from cognite.neat.rules.models.entities import ClassEntity, ClassEntityList
9
10
 
10
- from ._base import (
11
+ from ._base_input import InputComponent, InputRules
12
+ from ._base_rules import (
11
13
  BaseMetadata,
12
14
  BaseRules,
13
15
  RoleTypes,
@@ -76,3 +78,52 @@ class DomainRules(BaseRules):
76
78
  cls.model_dump(**kwargs) for cls in self.classes or []
77
79
  ] or None
78
80
  return output
81
+
82
+
83
+ @dataclass
84
+ class DomainInputMetadata(InputComponent[DomainMetadata]):
85
+ creator: str
86
+
87
+ @classmethod
88
+ def _get_verified_cls(cls) -> type[DomainMetadata]:
89
+ return DomainMetadata
90
+
91
+
92
+ @dataclass
93
+ class DomainInputProperty(InputComponent[DomainProperty]):
94
+ class_: str
95
+ property_: str
96
+ value_type: str
97
+ name: str | None = None
98
+ description: str | None = None
99
+ min_count: int | None = None
100
+ max_count: int | float | None = None
101
+
102
+ @classmethod
103
+ def _get_verified_cls(cls) -> type[DomainProperty]:
104
+ return DomainProperty
105
+
106
+
107
+ @dataclass
108
+ class DomainInputClass(InputComponent[DomainClass]):
109
+ class_: str
110
+ name: str | None = None
111
+ description: str | None = None
112
+ parent: list[str] | None = None
113
+
114
+ @classmethod
115
+ def _get_verified_cls(cls) -> type[DomainClass]:
116
+ return DomainClass
117
+
118
+
119
+ @dataclass
120
+ class DomainInputRules(InputRules[DomainRules]):
121
+ metadata: DomainInputMetadata
122
+ properties: list[DomainInputProperty] = field(default_factory=list)
123
+ classes: list[DomainInputClass] = field(default_factory=list)
124
+ last: "DomainInputRules | None" = None
125
+ reference: "DomainInputRules | None" = None
126
+
127
+ @classmethod
128
+ def _get_verified_cls(cls) -> type[DomainRules]:
129
+ return DomainRules
@@ -0,0 +1,63 @@
1
+ from ._constants import EntityTypes, Undefined, Unknown
2
+ from ._loaders import load_connection, load_dms_value_type, load_value_type
3
+ from ._multi_value import MultiValueTypeInfo
4
+ from ._single_value import (
5
+ AssetEntity,
6
+ AssetFields,
7
+ ClassEntity,
8
+ ContainerEntity,
9
+ DataModelEntity,
10
+ DMSEntity,
11
+ DMSNodeEntity,
12
+ DMSUnknownEntity,
13
+ DMSVersionedEntity,
14
+ EdgeEntity,
15
+ Entity,
16
+ ReferenceEntity,
17
+ RelationshipEntity,
18
+ ReverseConnectionEntity,
19
+ T_Entity,
20
+ UnitEntity,
21
+ UnknownEntity,
22
+ ViewEntity,
23
+ )
24
+ from ._types import CdfResourceEntityList, ClassEntityList, ContainerEntityList, URLEntity, ViewEntityList
25
+ from ._wrapped import DMSFilter, HasDataFilter, NodeTypeFilter, RawFilter, WrappedEntity
26
+
27
+ __all__ = [
28
+ "Entity",
29
+ "UnitEntity",
30
+ "DMSVersionedEntity",
31
+ "RelationshipEntity",
32
+ "EdgeEntity",
33
+ "ViewEntity",
34
+ "ClassEntity",
35
+ "ViewEntityList",
36
+ "UnknownEntity",
37
+ "EntityTypes",
38
+ "Unknown",
39
+ "Undefined",
40
+ "T_Entity",
41
+ "AssetEntity",
42
+ "AssetFields",
43
+ "ReverseConnectionEntity",
44
+ "MultiValueTypeInfo",
45
+ "DMSNodeEntity",
46
+ "DMSEntity",
47
+ "ContainerEntity",
48
+ "DMSUnknownEntity",
49
+ "DataModelEntity",
50
+ "ReferenceEntity",
51
+ "ClassEntityList",
52
+ "CdfResourceEntityList",
53
+ "ContainerEntityList",
54
+ "URLEntity",
55
+ "load_value_type",
56
+ "load_dms_value_type",
57
+ "load_connection",
58
+ "WrappedEntity",
59
+ "NodeTypeFilter",
60
+ "DMSFilter",
61
+ "HasDataFilter",
62
+ "RawFilter",
63
+ ]
@@ -0,0 +1,73 @@
1
+ import re
2
+ import sys
3
+
4
+ from pydantic import BaseModel
5
+
6
+ if sys.version_info >= (3, 11):
7
+ from enum import StrEnum
8
+ else:
9
+ from backports.strenum import StrEnum
10
+
11
+
12
+ class EntityTypes(StrEnum):
13
+ view_non_versioned = "view_non_versioned"
14
+ subject = "subject"
15
+ predicate = "predicate"
16
+ object = "object"
17
+ class_ = "class"
18
+ parent_class = "parent_class"
19
+ property_ = "property"
20
+ object_property = "ObjectProperty"
21
+ data_property = "DatatypeProperty"
22
+ annotation_property = "AnnotationProperty"
23
+ object_value_type = "object_value_type"
24
+ data_value_type = "data_value_type" # these are strings, floats, ...
25
+ xsd_value_type = "xsd_value_type"
26
+ dms_value_type = "dms_value_type"
27
+ dms_node = "dms_node"
28
+ view = "view"
29
+ reference_entity = "reference_entity"
30
+ container = "container"
31
+ datamodel = "datamodel"
32
+ undefined = "undefined"
33
+ multi_value_type = "multi_value_type"
34
+ asset = "asset"
35
+ relationship = "relationship"
36
+ edge = "edge"
37
+ reverse = "reverse"
38
+ unit = "unit"
39
+
40
+
41
+ # ALLOWED
42
+ _ALLOWED_PATTERN = r"[^a-zA-Z0-9-_.]"
43
+
44
+ # FOR PARSING STRINGS:
45
+ _PREFIX_REGEX = r"[a-zA-Z]+[a-zA-Z0-9-_.]*[a-zA-Z0-9]+"
46
+ _SUFFIX_REGEX = r"[a-zA-Z0-9-_.]+[a-zA-Z0-9]|[-_.]*[a-zA-Z0-9]+"
47
+ _VERSION_REGEX = r"[a-zA-Z0-9]([.a-zA-Z0-9_-]{0,41}[a-zA-Z0-9])?"
48
+ _PROPERTY_REGEX = r"[a-zA-Z0-9][a-zA-Z0-9_-]*[a-zA-Z0-9]?"
49
+ _ENTITY_ID_REGEX = rf"{_PREFIX_REGEX}:({_SUFFIX_REGEX})"
50
+ _ENTITY_ID_REGEX_COMPILED = re.compile(rf"^(?P<prefix>{_PREFIX_REGEX}):(?P<suffix>{_SUFFIX_REGEX})$")
51
+ _VERSIONED_ENTITY_REGEX_COMPILED = re.compile(
52
+ rf"^(?P<prefix>{_PREFIX_REGEX}):(?P<suffix>{_SUFFIX_REGEX})\(version=(?P<version>{_VERSION_REGEX})\)$"
53
+ )
54
+ _CLASS_ID_REGEX = rf"(?P<{EntityTypes.class_}>{_ENTITY_ID_REGEX})"
55
+ _CLASS_ID_REGEX_COMPILED = re.compile(rf"^{_CLASS_ID_REGEX}$")
56
+ _PROPERTY_ID_REGEX = rf"\((?P<{EntityTypes.property_}>{_ENTITY_ID_REGEX})\)"
57
+
58
+ ENTITY_PATTERN = re.compile(r"^(?P<prefix>.*?):?(?P<suffix>[^(:]*)(\((?P<content>.+)\))?$")
59
+ MULTI_VALUE_TYPE_PATTERN = re.compile(r"^(?P<types>.*?)(\((?P<content>[^)]+)\))?$")
60
+
61
+
62
+ class _UndefinedType(BaseModel): ...
63
+
64
+
65
+ class _UnknownType(BaseModel):
66
+ def __str__(self) -> str:
67
+ return "#N/A"
68
+
69
+
70
+ # This is a trick to make Undefined and Unknown singletons
71
+ Undefined = _UndefinedType()
72
+ Unknown = _UnknownType()
73
+ _PARSE = object()
@@ -0,0 +1,76 @@
1
+ from typing import Literal
2
+
3
+ from cognite.neat.issues.errors import NeatTypeError
4
+ from cognite.neat.rules.models.data_types import DataType
5
+
6
+ from ._multi_value import MultiValueTypeInfo
7
+ from ._single_value import (
8
+ ClassEntity,
9
+ DMSUnknownEntity,
10
+ EdgeEntity,
11
+ ReverseConnectionEntity,
12
+ Unknown,
13
+ UnknownEntity,
14
+ ViewEntity,
15
+ )
16
+
17
+
18
+ def load_value_type(
19
+ raw: str | MultiValueTypeInfo | DataType | ClassEntity | UnknownEntity, default_prefix: str
20
+ ) -> MultiValueTypeInfo | DataType | ClassEntity | UnknownEntity:
21
+ if isinstance(raw, MultiValueTypeInfo | DataType | ClassEntity | UnknownEntity):
22
+ return raw
23
+ elif isinstance(raw, str):
24
+ # property holding xsd data type
25
+ # check if it is multi value type
26
+ if "|" in raw:
27
+ value_type = MultiValueTypeInfo.load(raw)
28
+ value_type.set_default_prefix(default_prefix)
29
+ return value_type
30
+ elif DataType.is_data_type(raw):
31
+ return DataType.load(raw)
32
+
33
+ # unknown value type
34
+ elif raw == str(Unknown):
35
+ return UnknownEntity()
36
+
37
+ # property holding link to class
38
+ else:
39
+ return ClassEntity.load(raw, prefix=default_prefix)
40
+ else:
41
+ raise NeatTypeError(f"Invalid value type: {type(raw)}")
42
+
43
+
44
+ def load_dms_value_type(
45
+ raw: str | DataType | ViewEntity | DMSUnknownEntity,
46
+ default_space: str,
47
+ default_version: str,
48
+ ) -> DataType | ViewEntity | DMSUnknownEntity:
49
+ if isinstance(raw, DataType | ViewEntity | DMSUnknownEntity):
50
+ return raw
51
+ elif isinstance(raw, str):
52
+ if DataType.is_data_type(raw):
53
+ return DataType.load(raw)
54
+ elif raw == str(Unknown):
55
+ return DMSUnknownEntity()
56
+ else:
57
+ return ViewEntity.load(raw, space=default_space, version=default_version)
58
+ raise NeatTypeError(f"Invalid value type: {type(raw)}")
59
+
60
+
61
+ def load_connection(
62
+ raw: Literal["direct"] | ReverseConnectionEntity | EdgeEntity | str | None,
63
+ default_space: str,
64
+ default_version: str,
65
+ ) -> Literal["direct"] | ReverseConnectionEntity | EdgeEntity | None:
66
+ if (
67
+ isinstance(raw, EdgeEntity | ReverseConnectionEntity)
68
+ or raw is None
69
+ or (isinstance(raw, str) and raw == "direct")
70
+ ):
71
+ return raw # type: ignore[return-value]
72
+ elif isinstance(raw, str) and raw.startswith("edge"):
73
+ return EdgeEntity.load(raw, space=default_space, version=default_version) # type: ignore[return-value]
74
+ elif isinstance(raw, str) and raw.startswith("reverse"):
75
+ return ReverseConnectionEntity.load(raw) # type: ignore[return-value]
76
+ raise NeatTypeError(f"Invalid connection: {type(raw)}")
@@ -0,0 +1,67 @@
1
+ from typing import Any, ClassVar
2
+
3
+ from pydantic import (
4
+ BaseModel,
5
+ model_serializer,
6
+ model_validator,
7
+ )
8
+
9
+ from cognite.neat.rules.models.data_types import DataType
10
+
11
+ from ._constants import _PARSE, EntityTypes, Undefined
12
+ from ._single_value import ClassEntity, UnknownEntity
13
+
14
+
15
+ class MultiValueTypeInfo(BaseModel):
16
+ type_: ClassVar[EntityTypes] = EntityTypes.multi_value_type
17
+ types: list[DataType | ClassEntity]
18
+
19
+ def __str__(self) -> str:
20
+ return " | ".join([str(t) for t in self.types])
21
+
22
+ @model_serializer(when_used="unless-none", return_type=str)
23
+ def as_str(self) -> str:
24
+ return str(self)
25
+
26
+ @classmethod
27
+ def load(cls, data: Any) -> "MultiValueTypeInfo":
28
+ # already instance of MultiValueTypeInfo
29
+ if isinstance(data, cls):
30
+ return data
31
+
32
+ # it is a raw string that needs to be parsed
33
+ elif isinstance(data, str):
34
+ return cls.model_validate({_PARSE: data})
35
+
36
+ # it is dict that needs to be parsed
37
+ else:
38
+ return cls.model_validate(data)
39
+
40
+ @model_validator(mode="before")
41
+ def _load(cls, data: Any) -> "dict | MultiValueTypeInfo":
42
+ if isinstance(data, dict) and _PARSE in data:
43
+ data = data[_PARSE]
44
+ elif isinstance(data, dict):
45
+ return data
46
+ else:
47
+ raise ValueError(f"Cannot load {cls.__name__} from {data}")
48
+
49
+ result = cls._parse(data)
50
+ return result
51
+
52
+ @classmethod
53
+ def _parse(cls, raw: str) -> dict:
54
+ if not (types := [type_.strip() for type_ in raw.split("|")]):
55
+ return {"types": [UnknownEntity()]}
56
+ else:
57
+ return {
58
+ "types": [
59
+ (DataType.load(type_) if DataType.is_data_type(type_) else ClassEntity.load(type_))
60
+ for type_ in types
61
+ ]
62
+ }
63
+
64
+ def set_default_prefix(self, prefix: str):
65
+ for type_ in self.types:
66
+ if isinstance(type_, ClassEntity) and type_.prefix is Undefined:
67
+ type_.prefix = prefix