cognite-neat 0.77.5__py3-none-any.whl → 0.77.7__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/rules/issues/importing.py +17 -0
- cognite/neat/rules/models/_types/_field.py +11 -17
- cognite/neat/rules/models/dms/_validation.py +4 -1
- cognite/neat/rules/models/information/_converter.py +45 -44
- {cognite_neat-0.77.5.dist-info → cognite_neat-0.77.7.dist-info}/METADATA +1 -1
- {cognite_neat-0.77.5.dist-info → cognite_neat-0.77.7.dist-info}/RECORD +10 -10
- {cognite_neat-0.77.5.dist-info → cognite_neat-0.77.7.dist-info}/LICENSE +0 -0
- {cognite_neat-0.77.5.dist-info → cognite_neat-0.77.7.dist-info}/WHEEL +0 -0
- {cognite_neat-0.77.5.dist-info → cognite_neat-0.77.7.dist-info}/entry_points.txt +0 -0
cognite/neat/_version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.77.
|
|
1
|
+
__version__ = "0.77.7"
|
|
@@ -16,6 +16,7 @@ __all__ = [
|
|
|
16
16
|
"MultipleDataModelsWarning",
|
|
17
17
|
"UnknownPropertyTypeWarning",
|
|
18
18
|
"FailedToInferValueTypeWarning",
|
|
19
|
+
"MoreThanOneNonAlphanumericCharacterWarning",
|
|
19
20
|
"UnknownContainerConstraintWarning",
|
|
20
21
|
"NoDataModelError",
|
|
21
22
|
"ModelImportError",
|
|
@@ -275,6 +276,22 @@ class FailedImportWarning(ModelImportWarning):
|
|
|
275
276
|
return {"identifier": list(self.identifier)}
|
|
276
277
|
|
|
277
278
|
|
|
279
|
+
@dataclass(frozen=True)
|
|
280
|
+
class MoreThanOneNonAlphanumericCharacterWarning(ModelImportWarning):
|
|
281
|
+
description = """This warning is raised when doing regex validation of strings which either represent class ids,
|
|
282
|
+
property ids, prefix, data model name, that contain more than one non-alphanumeric character,
|
|
283
|
+
such as for example '_' or '-'."""
|
|
284
|
+
|
|
285
|
+
field_name: str
|
|
286
|
+
value: str
|
|
287
|
+
|
|
288
|
+
def message(self) -> str:
|
|
289
|
+
return f"Field {self.field_name} with value {self.value} contains more than one non-alphanumeric character!"
|
|
290
|
+
|
|
291
|
+
def dump(self) -> dict[str, str]:
|
|
292
|
+
return {"field_name": self.field_name, "value": self.value}
|
|
293
|
+
|
|
294
|
+
|
|
278
295
|
@dataclass(frozen=True)
|
|
279
296
|
class ModelImportError(NeatValidationError, ABC):
|
|
280
297
|
description = "An error was raised during importing."
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import re
|
|
2
|
+
import warnings
|
|
2
3
|
from collections.abc import Callable
|
|
3
4
|
from typing import Annotated, Any, cast
|
|
4
5
|
|
|
@@ -17,6 +18,7 @@ from pydantic.functional_serializers import PlainSerializer
|
|
|
17
18
|
from pydantic_core import PydanticCustomError
|
|
18
19
|
|
|
19
20
|
from cognite.neat.rules import exceptions
|
|
21
|
+
from cognite.neat.rules.issues.importing import MoreThanOneNonAlphanumericCharacterWarning
|
|
20
22
|
|
|
21
23
|
from ._base import (
|
|
22
24
|
MORE_THAN_ONE_NONE_ALPHANUMERIC_REGEX,
|
|
@@ -50,7 +52,6 @@ StrOrListType = Annotated[
|
|
|
50
52
|
),
|
|
51
53
|
]
|
|
52
54
|
|
|
53
|
-
|
|
54
55
|
StrListType = Annotated[
|
|
55
56
|
list[str],
|
|
56
57
|
BeforeValidator(lambda value: [entry.strip() for entry in value.split(",")] if isinstance(value, str) else value),
|
|
@@ -96,19 +97,12 @@ VersionType = Annotated[
|
|
|
96
97
|
]
|
|
97
98
|
|
|
98
99
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
else _raise(
|
|
109
|
-
exceptions.PropertyIDRegexViolation(value, PROPERTY_ID_COMPLIANCE_REGEX).to_pydantic_custom_error()
|
|
110
|
-
)
|
|
111
|
-
)
|
|
112
|
-
)
|
|
113
|
-
),
|
|
114
|
-
]
|
|
100
|
+
def _property_validation(value: str) -> str:
|
|
101
|
+
if not re.match(PROPERTY_ID_COMPLIANCE_REGEX, value):
|
|
102
|
+
_raise(exceptions.PropertyIDRegexViolation(value, PROPERTY_ID_COMPLIANCE_REGEX).to_pydantic_custom_error())
|
|
103
|
+
if re.search(MORE_THAN_ONE_NONE_ALPHANUMERIC_REGEX, value):
|
|
104
|
+
warnings.warn(MoreThanOneNonAlphanumericCharacterWarning("property", value), stacklevel=2)
|
|
105
|
+
return value
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
PropertyType = Annotated[str, AfterValidator(_property_validation)]
|
|
@@ -57,7 +57,10 @@ class DMSPostValidation:
|
|
|
57
57
|
container_id = container.as_id()
|
|
58
58
|
row_numbers = {prop_no for prop_no, _ in properties}
|
|
59
59
|
value_types = {prop.value_type for _, prop in properties if prop.value_type}
|
|
60
|
-
|
|
60
|
+
# The container type 'direct' is an exception. On a container the type direct can point to any
|
|
61
|
+
# node. The value type is typically set on the view.
|
|
62
|
+
is_all_direct = all(prop.connection == "direct" for _, prop in properties)
|
|
63
|
+
if len(value_types) > 1 and not is_all_direct:
|
|
61
64
|
errors.append(
|
|
62
65
|
issues.spreadsheet.MultiValueTypeError(
|
|
63
66
|
container_id,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import re
|
|
2
|
-
from collections import defaultdict
|
|
2
|
+
from collections import Counter, defaultdict
|
|
3
|
+
from collections.abc import Collection
|
|
3
4
|
from typing import TYPE_CHECKING, Literal
|
|
4
5
|
|
|
5
6
|
from cognite.neat.rules.models._base import (
|
|
@@ -40,7 +41,6 @@ class _InformationRulesConverter:
|
|
|
40
41
|
self.last_classes = {class_.class_: class_ for class_ in self.rules.last.classes}
|
|
41
42
|
else:
|
|
42
43
|
self.last_classes = {}
|
|
43
|
-
self._created_classes_from: dict[ClassEntity, ClassEntity] = {}
|
|
44
44
|
|
|
45
45
|
def as_domain_rules(self) -> DomainRules:
|
|
46
46
|
raise NotImplementedError("DomainRules not implemented yet")
|
|
@@ -58,11 +58,13 @@ class _InformationRulesConverter:
|
|
|
58
58
|
default_space = self._to_space(info_metadata.prefix)
|
|
59
59
|
metadata = self._convert_metadata_to_dms(info_metadata)
|
|
60
60
|
|
|
61
|
-
properties_by_class: dict[
|
|
61
|
+
properties_by_class: dict[ClassEntity, list[DMSProperty]] = defaultdict(list)
|
|
62
|
+
referenced_containers: dict[ContainerEntity, Counter[ClassEntity]] = defaultdict(Counter)
|
|
62
63
|
for prop in self.rules.properties:
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
dms_property = self._as_dms_property(prop, default_space, default_version)
|
|
65
|
+
properties_by_class[prop.class_].append(dms_property)
|
|
66
|
+
if dms_property.container:
|
|
67
|
+
referenced_containers[dms_property.container][prop.class_] += 1
|
|
66
68
|
|
|
67
69
|
views: list[DMSView] = [
|
|
68
70
|
DMSView(
|
|
@@ -76,41 +78,26 @@ class _InformationRulesConverter:
|
|
|
76
78
|
for cls_ in self.rules.classes
|
|
77
79
|
]
|
|
78
80
|
|
|
79
|
-
classes_without_properties: set[str] = set()
|
|
80
|
-
for class_ in self.rules.classes:
|
|
81
|
-
properties: list[DMSProperty] = properties_by_class.get(class_.class_.versioned_id, [])
|
|
82
|
-
if not properties or all(
|
|
83
|
-
isinstance(prop.value_type, ViewPropertyEntity) and prop.connection != "direct" for prop in properties
|
|
84
|
-
):
|
|
85
|
-
classes_without_properties.add(class_.class_.versioned_id)
|
|
86
|
-
|
|
87
81
|
containers: list[DMSContainer] = []
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
for class_ in classes:
|
|
98
|
-
if class_.class_.versioned_id in classes_without_properties:
|
|
99
|
-
continue
|
|
100
|
-
containers.append(
|
|
101
|
-
DMSContainer(
|
|
102
|
-
class_=class_.class_,
|
|
103
|
-
name=class_.name,
|
|
104
|
-
container=class_.class_.as_container_entity(default_space),
|
|
105
|
-
description=class_.description,
|
|
106
|
-
constraint=[
|
|
107
|
-
parent.as_container_entity(default_space)
|
|
108
|
-
for parent in class_.parent or []
|
|
109
|
-
if parent.versioned_id not in classes_without_properties
|
|
110
|
-
]
|
|
111
|
-
or None,
|
|
112
|
-
)
|
|
82
|
+
class_by_entity = {cls_.class_: cls_ for cls_ in self.rules.classes}
|
|
83
|
+
if self.rules.last:
|
|
84
|
+
for cls_ in self.rules.last.classes:
|
|
85
|
+
if cls_.class_ not in class_by_entity:
|
|
86
|
+
class_by_entity[cls_.class_] = cls_
|
|
87
|
+
for container_entity, class_entities in referenced_containers.items():
|
|
88
|
+
constrains = self._create_container_constraint(
|
|
89
|
+
class_entities, default_space, class_by_entity, referenced_containers
|
|
113
90
|
)
|
|
91
|
+
most_used_class_entity = class_entities.most_common(1)[0][0]
|
|
92
|
+
class_ = class_by_entity[most_used_class_entity]
|
|
93
|
+
container = DMSContainer(
|
|
94
|
+
class_=class_.class_,
|
|
95
|
+
container=container_entity,
|
|
96
|
+
name=class_.name,
|
|
97
|
+
description=class_.description,
|
|
98
|
+
constraint=constrains or None,
|
|
99
|
+
)
|
|
100
|
+
containers.append(container)
|
|
114
101
|
|
|
115
102
|
return DMSRules(
|
|
116
103
|
metadata=metadata,
|
|
@@ -123,6 +110,22 @@ class _InformationRulesConverter:
|
|
|
123
110
|
reference=self.rules.reference.as_dms_architect_rules() if self.rules.reference else None,
|
|
124
111
|
)
|
|
125
112
|
|
|
113
|
+
@staticmethod
|
|
114
|
+
def _create_container_constraint(
|
|
115
|
+
class_entities: Counter[ClassEntity],
|
|
116
|
+
default_space: str,
|
|
117
|
+
class_by_entity: dict[ClassEntity, InformationClass],
|
|
118
|
+
referenced_containers: Collection[ContainerEntity],
|
|
119
|
+
) -> list[ContainerEntity]:
|
|
120
|
+
constrains: list[ContainerEntity] = []
|
|
121
|
+
for entity in class_entities:
|
|
122
|
+
class_ = class_by_entity[entity]
|
|
123
|
+
for parent in class_.parent or []:
|
|
124
|
+
parent_entity = parent.as_container_entity(default_space)
|
|
125
|
+
if parent_entity in referenced_containers:
|
|
126
|
+
constrains.append(parent_entity)
|
|
127
|
+
return constrains
|
|
128
|
+
|
|
126
129
|
@classmethod
|
|
127
130
|
def _convert_metadata_to_dms(cls, metadata: InformationMetadata) -> "DMSMetadata":
|
|
128
131
|
from cognite.neat.rules.models.dms._rules import (
|
|
@@ -211,11 +214,9 @@ class _InformationRulesConverter:
|
|
|
211
214
|
elif (self.is_addition or self.is_reshape) and prop.class_ in self.last_classes:
|
|
212
215
|
# We need to create a new container for the property, as we cannot change
|
|
213
216
|
# the existing container in the last schema
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
self._created_classes_from[class_entity] = prop.class_
|
|
218
|
-
return class_entity.as_container_entity(default_space), prop.property_
|
|
217
|
+
container_entity = prop.class_.as_container_entity(default_space)
|
|
218
|
+
container_entity.suffix = self._bump_suffix(container_entity.suffix)
|
|
219
|
+
return container_entity, prop.property_
|
|
219
220
|
else:
|
|
220
221
|
return prop.class_.as_container_entity(default_space), prop.property_
|
|
221
222
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
cognite/neat/__init__.py,sha256=v-rRiDOgZ3sQSMQKq0vgUQZvpeOkoHFXissAx6Ktg84,61
|
|
2
|
-
cognite/neat/_version.py,sha256=
|
|
2
|
+
cognite/neat/_version.py,sha256=hFsfqx1W0uQf6EjOq0viOjyWKF79pF13oi9ziY65GuY,23
|
|
3
3
|
cognite/neat/app/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
cognite/neat/app/api/asgi/metrics.py,sha256=nxFy7L5cChTI0a-zkCiJ59Aq8yLuIJp5c9Dg0wRXtV0,152
|
|
5
5
|
cognite/neat/app/api/configuration.py,sha256=2U5M6M252swvQPQyooA1EBzFUZNtcTmuSaywfJDgckM,4232
|
|
@@ -190,7 +190,7 @@ cognite/neat/rules/issues/base.py,sha256=i2aTC-wq3UVW2bj_7wKeuhYxCpMD06Bd9-m00bW
|
|
|
190
190
|
cognite/neat/rules/issues/dms.py,sha256=CKztcpNu9E_ygbAmiODOhaYKPX6o9eaXeiod7Ak-kNY,23617
|
|
191
191
|
cognite/neat/rules/issues/fileread.py,sha256=ao199mtvhPSW0IA8ZQZ0RzuLIIipYtL0jp6fLqxb4_c,5748
|
|
192
192
|
cognite/neat/rules/issues/formatters.py,sha256=_ag2bJ9hncOj8pAGJvTTEPs9kTtxbD7vkqvS9Zcnizc,3385
|
|
193
|
-
cognite/neat/rules/issues/importing.py,sha256=
|
|
193
|
+
cognite/neat/rules/issues/importing.py,sha256=uSk4TXo_CO3bglBZkaiWekXLXXd31UWIZE95clVSLz4,13417
|
|
194
194
|
cognite/neat/rules/issues/spreadsheet.py,sha256=1NZQ3a_zCtErAoMKzEt5UMJsukaysoOVmW7WUF6JK1s,15825
|
|
195
195
|
cognite/neat/rules/issues/spreadsheet_file.py,sha256=YCp0Pk_TsiqYuOPdWpjUpre-zvi2c5_MvrC_dxw10YY,4964
|
|
196
196
|
cognite/neat/rules/models/__init__.py,sha256=aqhQUidHYgOk5_iqdi6s72s2g8qyMRFXShYzh-ctNpw,782
|
|
@@ -198,7 +198,7 @@ cognite/neat/rules/models/_base.py,sha256=oQ8f0bvdythJ2m54K1jl2OXEuEZ4N8JqHDXyhC
|
|
|
198
198
|
cognite/neat/rules/models/_rdfpath.py,sha256=RoHnfWufjnDtwJh7UUzWKoJz8luvX7Gb5SDQORfkQTE,11030
|
|
199
199
|
cognite/neat/rules/models/_types/__init__.py,sha256=l1tGxzE7ezNHIL72AoEvNHN2IFuitxOLxiHJG__s6t4,305
|
|
200
200
|
cognite/neat/rules/models/_types/_base.py,sha256=2GhLUE1ukV8X8SGL_JDxpbWGZyAvOnSqAE6JmDh5wbI,929
|
|
201
|
-
cognite/neat/rules/models/_types/_field.py,sha256=
|
|
201
|
+
cognite/neat/rules/models/_types/_field.py,sha256=h2RrhjxdaRbzHG5EyduyHLkCJJmQoyZb9pYCkgMcnVk,3203
|
|
202
202
|
cognite/neat/rules/models/data_types.py,sha256=lanwkhwG8iHKfjYfia4v2SBTJrMeXOsqaVkVEP2QMXs,6078
|
|
203
203
|
cognite/neat/rules/models/dms/__init__.py,sha256=Wzyqzz2ZIjpUbDg04CMuuIAw-f2A02DayNeqO9R-2Hw,491
|
|
204
204
|
cognite/neat/rules/models/dms/_converter.py,sha256=QaJT0z0Yo4gkG9tHPZkU8idF8PK7c-tDahbyIT-WJQU,5959
|
|
@@ -207,11 +207,11 @@ cognite/neat/rules/models/dms/_rules.py,sha256=iqoPilY3tov3GvJ9N3K3go6xy9kiiMt9v
|
|
|
207
207
|
cognite/neat/rules/models/dms/_rules_input.py,sha256=apDDTQll9UAyYL5gS2vDxHsujWrGBilTp7lK2kzJWO8,13467
|
|
208
208
|
cognite/neat/rules/models/dms/_schema.py,sha256=A4z8CINmLQgWzHoScxejRPMRo40ngKlyp1gOdPto8yU,43808
|
|
209
209
|
cognite/neat/rules/models/dms/_serializer.py,sha256=iqp2zyyf8jEcU-R3PERuN8nu248xIqyxiWj4owAn92g,6406
|
|
210
|
-
cognite/neat/rules/models/dms/_validation.py,sha256=
|
|
210
|
+
cognite/neat/rules/models/dms/_validation.py,sha256=nPSyfM1vGZ7d9Uv_2vF2HvMetygtehXW7eNtPD6eW8E,13937
|
|
211
211
|
cognite/neat/rules/models/domain.py,sha256=tkKcHvDXnZ5IkOr1wHiuNBtE1h8OCFmf6GZSqzHzxjI,2814
|
|
212
212
|
cognite/neat/rules/models/entities.py,sha256=iBG84Jr1qQ7PvkMJUJzJ1oWApeONb1IACixdJSztUhk,16395
|
|
213
213
|
cognite/neat/rules/models/information/__init__.py,sha256=HR6g8xgyU53U7Ck8pPdbT70817Q4NC1r1pCRq5SA8iw,291
|
|
214
|
-
cognite/neat/rules/models/information/_converter.py,sha256=
|
|
214
|
+
cognite/neat/rules/models/information/_converter.py,sha256=sH1wJ8TmEfytFPFDfHgDl6QWnSD-1Pqeb74kIgmR8wQ,9963
|
|
215
215
|
cognite/neat/rules/models/information/_rules.py,sha256=tdCjvAtqnFzEo2zcx-BZHmvjSs28gVun2wz8UaT-AOA,13268
|
|
216
216
|
cognite/neat/rules/models/information/_rules_input.py,sha256=IZp_Wnrac0nVaHKth1YttWQOs-kULGKLMtngNQFY40A,10147
|
|
217
217
|
cognite/neat/rules/models/information/_serializer.py,sha256=yti9I_xJruxrib66YIBInhze___Io-oPTQH6uWDumPE,3503
|
|
@@ -275,8 +275,8 @@ cognite/neat/workflows/steps_registry.py,sha256=fkTX14ZA7_gkUYfWIlx7A1XbCidvqR23
|
|
|
275
275
|
cognite/neat/workflows/tasks.py,sha256=dqlJwKAb0jlkl7abbY8RRz3m7MT4SK8-7cntMWkOYjw,788
|
|
276
276
|
cognite/neat/workflows/triggers.py,sha256=_BLNplzoz0iic367u1mhHMHiUrCwP-SLK6_CZzfODX0,7071
|
|
277
277
|
cognite/neat/workflows/utils.py,sha256=gKdy3RLG7ctRhbCRwaDIWpL9Mi98zm56-d4jfHDqP1E,453
|
|
278
|
-
cognite_neat-0.77.
|
|
279
|
-
cognite_neat-0.77.
|
|
280
|
-
cognite_neat-0.77.
|
|
281
|
-
cognite_neat-0.77.
|
|
282
|
-
cognite_neat-0.77.
|
|
278
|
+
cognite_neat-0.77.7.dist-info/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
|
|
279
|
+
cognite_neat-0.77.7.dist-info/METADATA,sha256=3FhpHUDfplCEVHoqUUxkNwF3DoNwC9Ad90mKiQXDLaw,9316
|
|
280
|
+
cognite_neat-0.77.7.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
281
|
+
cognite_neat-0.77.7.dist-info/entry_points.txt,sha256=61FPqiWb25vbqB0KI7znG8nsg_ibLHBvTjYnkPvNFso,50
|
|
282
|
+
cognite_neat-0.77.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|