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.

Files changed (33) hide show
  1. cognite/neat/_version.py +1 -1
  2. cognite/neat/graph/extractors/_mock_graph_generator.py +6 -5
  3. cognite/neat/rules/analysis/_base.py +1 -1
  4. cognite/neat/rules/analysis/_information_rules.py +4 -4
  5. cognite/neat/rules/exporters/_rules2ontology.py +20 -17
  6. cognite/neat/rules/exporters/_validation.py +2 -2
  7. cognite/neat/rules/importers/_dms2rules.py +14 -15
  8. cognite/neat/rules/importers/_dtdl2rules/dtdl_converter.py +21 -19
  9. cognite/neat/rules/importers/_dtdl2rules/spec.py +1 -1
  10. cognite/neat/rules/importers/_owl2rules/_owl2rules.py +2 -2
  11. cognite/neat/rules/importers/_spreadsheet2rules.py +6 -1
  12. cognite/neat/rules/importers/_yaml2rules.py +8 -2
  13. cognite/neat/rules/issues/dms.py +1 -1
  14. cognite/neat/rules/models/data_types.py +54 -31
  15. cognite/neat/rules/models/entities.py +184 -41
  16. cognite/neat/rules/models/rdfpath.py +111 -11
  17. cognite/neat/rules/models/rules/_base.py +2 -2
  18. cognite/neat/rules/models/rules/_dms_architect_rules.py +117 -188
  19. cognite/neat/rules/models/rules/_dms_rules_write.py +355 -0
  20. cognite/neat/rules/models/rules/_dms_schema.py +3 -3
  21. cognite/neat/rules/models/rules/_domain_rules.py +6 -3
  22. cognite/neat/rules/models/rules/_information_rules.py +68 -61
  23. cognite/neat/rules/models/rules/_types/__init__.py +0 -47
  24. cognite/neat/rules/models/rules/_types/_base.py +1 -309
  25. cognite/neat/rules/models/rules/_types/_field.py +0 -225
  26. cognite/neat/workflows/steps/lib/rules_importer.py +3 -3
  27. {cognite_neat-0.75.7.dist-info → cognite_neat-0.75.8.dist-info}/METADATA +1 -1
  28. {cognite_neat-0.75.7.dist-info → cognite_neat-0.75.8.dist-info}/RECORD +31 -32
  29. cognite/neat/rules/models/_entity.py +0 -142
  30. cognite/neat/rules/models/rules/_types/_value.py +0 -159
  31. {cognite_neat-0.75.7.dist-info → cognite_neat-0.75.8.dist-info}/LICENSE +0 -0
  32. {cognite_neat-0.75.7.dist-info → cognite_neat-0.75.8.dist-info}/WHEEL +0 -0
  33. {cognite_neat-0.75.7.dist-info → cognite_neat-0.75.8.dist-info}/entry_points.txt +0 -0
@@ -4,22 +4,13 @@
4
4
  import re
5
5
  import sys
6
6
  from collections import Counter
7
- from typing import Literal
7
+ from functools import total_ordering
8
+ from typing import ClassVar, Literal
8
9
 
9
10
  from pydantic import BaseModel, field_validator
10
11
 
11
12
  from cognite.neat.rules import exceptions
12
13
 
13
- from ._entity import (
14
- CLASS_ID_REGEX,
15
- CLASS_ID_REGEX_COMPILED,
16
- ENTITY_ID_REGEX,
17
- PROPERTY_ID_REGEX,
18
- SUFFIX_REGEX,
19
- Entity,
20
- EntityTypes,
21
- )
22
-
23
14
  if sys.version_info >= (3, 11):
24
15
  from enum import StrEnum
25
16
  from typing import Self
@@ -40,6 +31,26 @@ class Lookup(StrEnum):
40
31
  value = "value" # type: ignore
41
32
 
42
33
 
34
+ class EntityTypes(StrEnum):
35
+ class_ = "class"
36
+ property_ = "property"
37
+ undefined = "undefined"
38
+
39
+
40
+ # FOR PARSING STRINGS:
41
+ PREFIX_REGEX = r"[a-zA-Z]+[a-zA-Z0-9-_.]*[a-zA-Z0-9]+"
42
+ SUFFIX_REGEX = r"[a-zA-Z0-9-_.]+[a-zA-Z0-9]|[-_.]*[a-zA-Z0-9]+"
43
+ VERSION_REGEX = r"[a-zA-Z0-9]([.a-zA-Z0-9_-]{0,41}[a-zA-Z0-9])?"
44
+
45
+ ENTITY_ID_REGEX = rf"{PREFIX_REGEX}:({SUFFIX_REGEX})"
46
+ ENTITY_ID_REGEX_COMPILED = re.compile(rf"^(?P<prefix>{PREFIX_REGEX}):(?P<suffix>{SUFFIX_REGEX})$")
47
+ VERSIONED_ENTITY_REGEX_COMPILED = re.compile(
48
+ rf"^(?P<prefix>{PREFIX_REGEX}):(?P<suffix>{SUFFIX_REGEX})\(version=(?P<version>{VERSION_REGEX})\)$"
49
+ )
50
+ CLASS_ID_REGEX = rf"(?P<{EntityTypes.class_}>{ENTITY_ID_REGEX})"
51
+ CLASS_ID_REGEX_COMPILED = re.compile(rf"^{CLASS_ID_REGEX}$")
52
+ PROPERTY_ID_REGEX = rf"\((?P<{EntityTypes.property_}>{ENTITY_ID_REGEX})\)"
53
+
43
54
  # traversal direction
44
55
  DIRECTION_REGEX = r"(?P<direction>(->|<-))"
45
56
 
@@ -73,6 +84,95 @@ TABLE_REGEX_COMPILED = re.compile(
73
84
  StepDirection = Literal["source", "target", "origin"]
74
85
  _direction_by_symbol: dict[str, StepDirection] = {"->": "target", "<-": "source"}
75
86
 
87
+ Undefined = type(object())
88
+ Unknown = type(object())
89
+
90
+
91
+ # mypy does not like the sentinel value, and it is not possible to ignore only the line with it below.
92
+ # so we ignore all errors beyond this point.
93
+ # mypy: ignore-errors
94
+ @total_ordering
95
+ class Entity(BaseModel, arbitrary_types_allowed=True):
96
+ """Entity is a class or property in OWL/RDF sense."""
97
+
98
+ type_: ClassVar[EntityTypes] = EntityTypes.undefined
99
+ prefix: str | Undefined = Undefined
100
+ suffix: str | Unknown
101
+ version: str | None = None
102
+ name: str | None = None
103
+ description: str | None = None
104
+
105
+ def __lt__(self, other: object) -> bool:
106
+ if type(self) is not type(other) or not isinstance(other, Entity):
107
+ return NotImplemented
108
+ return self.versioned_id < other.versioned_id
109
+
110
+ def __eq__(self, other: object) -> bool:
111
+ if type(self) is not type(other) or not isinstance(other, Entity):
112
+ return NotImplemented
113
+ return self.versioned_id == other.versioned_id
114
+
115
+ def __hash__(self) -> int:
116
+ return hash(self.versioned_id)
117
+
118
+ def as_non_versioned_entity(self) -> Self:
119
+ return self.from_string(f"{self.prefix}:{self.suffix}")
120
+
121
+ @property
122
+ def id(self) -> str:
123
+ if self.suffix is Unknown:
124
+ return "#N/A"
125
+ elif self.prefix is Undefined:
126
+ return self.suffix
127
+ else:
128
+ return f"{self.prefix}:{self.suffix}"
129
+
130
+ @property
131
+ def versioned_id(self) -> str:
132
+ if self.version is None:
133
+ return self.id
134
+ else:
135
+ return f"{self.id}(version={self.version})"
136
+
137
+ @property
138
+ def space(self) -> str:
139
+ """Returns entity space in CDF."""
140
+ return self.prefix
141
+
142
+ @property
143
+ def external_id(self) -> str:
144
+ """Returns entity external id in CDF."""
145
+ return self.suffix
146
+
147
+ def __repr__(self):
148
+ return self.versioned_id
149
+
150
+ def __str__(self):
151
+ return self.versioned_id
152
+
153
+ @classmethod
154
+ def from_string(cls, entity_string: str, base_prefix: str | None = None) -> Self:
155
+ if entity_string == "#N/A":
156
+ return cls(prefix=Undefined, suffix=Unknown)
157
+ elif result := VERSIONED_ENTITY_REGEX_COMPILED.match(entity_string):
158
+ return cls(
159
+ prefix=result.group("prefix"),
160
+ suffix=result.group("suffix"),
161
+ version=result.group("version"),
162
+ )
163
+ elif result := ENTITY_ID_REGEX_COMPILED.match(entity_string):
164
+ return cls(prefix=result.group("prefix"), suffix=result.group("suffix"))
165
+ elif base_prefix and re.match(SUFFIX_REGEX, entity_string) and re.match(PREFIX_REGEX, base_prefix):
166
+ return cls(prefix=base_prefix, suffix=entity_string)
167
+ else:
168
+ raise ValueError(f"{cls.__name__} is expected to be prefix:suffix, got {entity_string}")
169
+
170
+ @classmethod
171
+ def from_list(cls, entity_strings: list[str], base_prefix: str | None = None) -> list[Self]:
172
+ return [
173
+ cls.from_string(entity_string=entity_string, base_prefix=base_prefix) for entity_string in entity_strings
174
+ ]
175
+
76
176
 
77
177
  class Step(BaseModel):
78
178
  class_: Entity
@@ -27,7 +27,7 @@ from pydantic import (
27
27
  )
28
28
  from pydantic.fields import FieldInfo
29
29
 
30
- from cognite.neat.rules.models.rules._types import ClassType
30
+ from cognite.neat.rules.models.entities import ClassEntity
31
31
 
32
32
  if sys.version_info >= (3, 11):
33
33
  from enum import StrEnum
@@ -274,7 +274,7 @@ class BaseRules(RuleModel):
274
274
 
275
275
  # An sheet entity is either a class or a property.
276
276
  class SheetEntity(RuleModel):
277
- class_: ClassType = Field(alias="Class")
277
+ class_: ClassEntity = Field(alias="Class")
278
278
  name: str | None = Field(alias="Name", default=None)
279
279
  description: str | None = Field(alias="Description", default=None)
280
280