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
@@ -0,0 +1,355 @@
1
+ from collections.abc import Sequence
2
+ from dataclasses import dataclass
3
+ from datetime import datetime
4
+ from typing import Any, Literal, cast, overload
5
+
6
+ from pydantic import BaseModel
7
+
8
+ from cognite.neat.rules.models.data_types import DataType
9
+ from cognite.neat.rules.models.entities import (
10
+ ClassEntity,
11
+ ContainerEntity,
12
+ DMSUnknownEntity,
13
+ Unknown,
14
+ ViewEntity,
15
+ ViewPropertyEntity,
16
+ )
17
+
18
+ from ._base import ExtensionCategory, SchemaCompleteness
19
+ from ._dms_architect_rules import DMSContainer, DMSMetadata, DMSProperty, DMSRules, DMSView
20
+
21
+
22
+ @dataclass
23
+ class DMSMetadataWrite:
24
+ schema_: Literal["complete", "partial", "extended"]
25
+ space: str
26
+ external_id: str
27
+ creator: str
28
+ version: str
29
+ extension: Literal["addition", "reshape", "rebuild"] = "addition"
30
+ name: str | None = None
31
+ description: str | None = None
32
+ created: datetime | str | None = None
33
+ updated: datetime | str | None = None
34
+ default_view_version: str | None = None
35
+
36
+ @classmethod
37
+ def load(cls, data: dict[str, Any] | None) -> "DMSMetadataWrite | None":
38
+ if data is None:
39
+ return None
40
+ _add_alias(data, DMSMetadata)
41
+ return cls(
42
+ schema_=data.get("schema_"), # type: ignore[arg-type]
43
+ space=data.get("space"), # type: ignore[arg-type]
44
+ external_id=data.get("external_id"), # type: ignore[arg-type]
45
+ creator=data.get("creator"), # type: ignore[arg-type]
46
+ version=data.get("version"), # type: ignore[arg-type]
47
+ extension=data.get("extension", "addition"),
48
+ name=data.get("name"),
49
+ description=data.get("description"),
50
+ created=data.get("created"),
51
+ updated=data.get("updated"),
52
+ default_view_version=data.get("default_view_version"),
53
+ )
54
+
55
+ def dump(self) -> dict[str, Any]:
56
+ return dict(
57
+ schema=SchemaCompleteness(self.schema_),
58
+ extension=ExtensionCategory(self.extension),
59
+ space=self.space,
60
+ externalId=self.external_id,
61
+ creator=self.creator,
62
+ version=self.version,
63
+ name=self.name,
64
+ description=self.description,
65
+ created=self.created or datetime.now(),
66
+ updated=self.updated or datetime.now(),
67
+ default_view_version=self.default_view_version or self.version,
68
+ )
69
+
70
+
71
+ @dataclass
72
+ class DMSPropertyWrite:
73
+ view: str
74
+ view_property: str | None
75
+ value_type: str
76
+ property_: str | None
77
+ class_: str | None = None
78
+ name: str | None = None
79
+ description: str | None = None
80
+ relation: Literal["direct", "reversedirect", "multiedge"] | None = None
81
+ nullable: bool | None = None
82
+ is_list: bool | None = None
83
+ default: str | int | dict | None = None
84
+ reference: str | None = None
85
+ container: str | None = None
86
+ container_property: str | None = None
87
+ index: str | list[str] | None = None
88
+ constraint: str | list[str] | None = None
89
+
90
+ @classmethod
91
+ @overload
92
+ def load(cls, data: None) -> None:
93
+ ...
94
+
95
+ @classmethod
96
+ @overload
97
+ def load(cls, data: dict[str, Any]) -> "DMSPropertyWrite":
98
+ ...
99
+
100
+ @classmethod
101
+ @overload
102
+ def load(cls, data: list[dict[str, Any]]) -> list["DMSPropertyWrite"]:
103
+ ...
104
+
105
+ @classmethod
106
+ def load(
107
+ cls, data: dict[str, Any] | list[dict[str, Any]] | None
108
+ ) -> "DMSPropertyWrite | list[DMSPropertyWrite] | None":
109
+ if data is None:
110
+ return None
111
+ if isinstance(data, list) or (isinstance(data, dict) and isinstance(data.get("data"), list)):
112
+ items = cast(list[dict[str, Any]], data.get("data") if isinstance(data, dict) else data)
113
+ return [loaded for item in items if (loaded := cls.load(item)) is not None]
114
+
115
+ _add_alias(data, DMSProperty)
116
+ return cls(
117
+ view=data.get("view"), # type: ignore[arg-type]
118
+ view_property=data.get("view_property"), # type: ignore[arg-type]
119
+ value_type=data.get("value_type"), # type: ignore[arg-type]
120
+ property_=data.get("property_"),
121
+ class_=data.get("class_"),
122
+ name=data.get("name"),
123
+ description=data.get("description"),
124
+ relation=data.get("relation"),
125
+ nullable=data.get("nullable"),
126
+ is_list=data.get("is_list"),
127
+ default=data.get("default"),
128
+ reference=data.get("reference"),
129
+ container=data.get("container"),
130
+ container_property=data.get("container_property"),
131
+ index=data.get("index"),
132
+ constraint=data.get("constraint"),
133
+ )
134
+
135
+ def dump(self, default_space: str, default_version: str) -> dict[str, Any]:
136
+ value_type: DataType | ViewPropertyEntity | ViewEntity | DMSUnknownEntity
137
+ if DataType.is_data_type(self.value_type):
138
+ value_type = DataType.load(self.value_type)
139
+ elif self.value_type == str(Unknown):
140
+ value_type = DMSUnknownEntity()
141
+ else:
142
+ try:
143
+ value_type = ViewPropertyEntity.load(self.value_type, space=default_space, version=default_version)
144
+ except ValueError:
145
+ value_type = ViewEntity.load(self.value_type, space=default_space, version=default_version)
146
+
147
+ return {
148
+ "View": ViewEntity.load(self.view, space=default_space, version=default_version),
149
+ "ViewProperty": self.view_property,
150
+ "Value Type": value_type,
151
+ "Property": self.property_ or self.view_property,
152
+ "Class": ClassEntity.load(self.class_, prefix=default_space, version=default_version)
153
+ if self.class_
154
+ else None,
155
+ "Name": self.name,
156
+ "Description": self.description,
157
+ "Relation": self.relation,
158
+ "Nullable": self.nullable,
159
+ "IsList": self.is_list,
160
+ "Default": self.default,
161
+ "Reference": self.reference,
162
+ "Container": ContainerEntity.load(self.container, space=default_space, version=default_version)
163
+ if self.container
164
+ else None,
165
+ "ContainerProperty": self.container_property,
166
+ "Index": self.index,
167
+ "Constraint": self.constraint,
168
+ }
169
+
170
+
171
+ @dataclass
172
+ class DMSContainerWrite:
173
+ container: str
174
+ class_: str | None = None
175
+ name: str | None = None
176
+ description: str | None = None
177
+ reference: str | None = None
178
+ constraint: str | None = None
179
+
180
+ @classmethod
181
+ @overload
182
+ def load(cls, data: None) -> None:
183
+ ...
184
+
185
+ @classmethod
186
+ @overload
187
+ def load(cls, data: dict[str, Any]) -> "DMSContainerWrite":
188
+ ...
189
+
190
+ @classmethod
191
+ @overload
192
+ def load(cls, data: list[dict[str, Any]]) -> list["DMSContainerWrite"]:
193
+ ...
194
+
195
+ @classmethod
196
+ def load(
197
+ cls, data: dict[str, Any] | list[dict[str, Any]] | None
198
+ ) -> "DMSContainerWrite | list[DMSContainerWrite] | None":
199
+ if data is None:
200
+ return None
201
+ if isinstance(data, list) or (isinstance(data, dict) and isinstance(data.get("data"), list)):
202
+ items = cast(list[dict[str, Any]], data.get("data") if isinstance(data, dict) else data)
203
+ return [loaded for item in items if (loaded := cls.load(item)) is not None]
204
+
205
+ _add_alias(data, DMSContainer)
206
+ return cls(
207
+ container=data.get("container"), # type: ignore[arg-type]
208
+ class_=data.get("class_"),
209
+ name=data.get("name"),
210
+ description=data.get("description"),
211
+ reference=data.get("reference"),
212
+ constraint=data.get("constraint"),
213
+ )
214
+
215
+ def dump(self, default_space: str) -> dict[str, Any]:
216
+ container = ContainerEntity.load(self.container, space=default_space)
217
+ return dict(
218
+ Container=container,
219
+ Class=ClassEntity.load(self.class_, prefix=default_space) if self.class_ else container.as_class(),
220
+ Name=self.name,
221
+ Description=self.description,
222
+ Reference=self.reference,
223
+ Constraint=[
224
+ ContainerEntity.load(constraint.strip(), space=default_space)
225
+ for constraint in self.constraint.split(",")
226
+ ]
227
+ if self.constraint
228
+ else None,
229
+ )
230
+
231
+
232
+ @dataclass
233
+ class DMSViewWrite:
234
+ view: str
235
+ class_: str | None = None
236
+ name: str | None = None
237
+ description: str | None = None
238
+ implements: str | None = None
239
+ reference: str | None = None
240
+ filter_: Literal["hasData", "nodeType"] | None = None
241
+ in_model: bool = True
242
+
243
+ @classmethod
244
+ @overload
245
+ def load(cls, data: None) -> None:
246
+ ...
247
+
248
+ @classmethod
249
+ @overload
250
+ def load(cls, data: dict[str, Any]) -> "DMSViewWrite":
251
+ ...
252
+
253
+ @classmethod
254
+ @overload
255
+ def load(cls, data: list[dict[str, Any]]) -> list["DMSViewWrite"]:
256
+ ...
257
+
258
+ @classmethod
259
+ def load(cls, data: dict[str, Any] | list[dict[str, Any]] | None) -> "DMSViewWrite | list[DMSViewWrite] | None":
260
+ if data is None:
261
+ return None
262
+ if isinstance(data, list) or (isinstance(data, dict) and isinstance(data.get("data"), list)):
263
+ items = cast(list[dict[str, Any]], data.get("data") if isinstance(data, dict) else data)
264
+ return [loaded for item in items if (loaded := cls.load(item)) is not None]
265
+ _add_alias(data, DMSView)
266
+
267
+ return cls(
268
+ view=data.get("view"), # type: ignore[arg-type]
269
+ class_=data.get("class"),
270
+ name=data.get("name"),
271
+ description=data.get("description"),
272
+ implements=data.get("implements"),
273
+ reference=data.get("reference"),
274
+ filter_=data.get("filter_"),
275
+ in_model=data.get("in_model", True),
276
+ )
277
+
278
+ def dump(self, default_space: str, default_version: str) -> dict[str, Any]:
279
+ view = ViewEntity.load(self.view, space=default_space, version=default_version)
280
+ return dict(
281
+ View=view,
282
+ Class=ClassEntity.load(self.class_, prefix=default_space, version=default_version)
283
+ if self.class_
284
+ else view.as_class(),
285
+ Name=self.name,
286
+ Description=self.description,
287
+ Implements=[
288
+ ViewEntity.load(implement, space=default_space, version=default_version)
289
+ for implement in self.implements.split(",")
290
+ ]
291
+ if self.implements
292
+ else None,
293
+ Reference=self.reference,
294
+ Filter=self.filter_,
295
+ InModel=self.in_model,
296
+ )
297
+
298
+
299
+ @dataclass
300
+ class DMSRulesWrite:
301
+ metadata: DMSMetadataWrite
302
+ properties: Sequence[DMSPropertyWrite]
303
+ views: Sequence[DMSViewWrite]
304
+ containers: Sequence[DMSContainerWrite] | None = None
305
+ reference: "DMSRulesWrite | DMSRules | None" = None
306
+
307
+ @classmethod
308
+ @overload
309
+ def load(cls, data: dict[str, Any]) -> "DMSRulesWrite":
310
+ ...
311
+
312
+ @classmethod
313
+ @overload
314
+ def load(cls, data: None) -> None:
315
+ ...
316
+
317
+ @classmethod
318
+ def load(cls, data: dict | None) -> "DMSRulesWrite | None":
319
+ if data is None:
320
+ return None
321
+ _add_alias(data, DMSRules)
322
+ return cls(
323
+ metadata=DMSMetadataWrite.load(data.get("metadata")), # type: ignore[arg-type]
324
+ properties=DMSPropertyWrite.load(data.get("properties")), # type: ignore[arg-type]
325
+ views=DMSViewWrite.load(data.get("views")), # type: ignore[arg-type]
326
+ containers=DMSContainerWrite.load(data.get("containers")) or [],
327
+ reference=DMSRulesWrite.load(data.get("reference")),
328
+ )
329
+
330
+ def as_read(self) -> DMSRules:
331
+ return DMSRules.model_validate(self.dump())
332
+
333
+ def dump(self) -> dict[str, Any]:
334
+ default_space = self.metadata.space
335
+ default_version = self.metadata.version
336
+ reference: dict[str, Any] | None = None
337
+ if isinstance(self.reference, DMSRulesWrite):
338
+ reference = self.reference.dump()
339
+ elif isinstance(self.reference, DMSRules):
340
+ # We need to load through the DMSRulesWrite to set the correct default space and version
341
+ reference = DMSRulesWrite.load(self.reference.model_dump()).dump()
342
+
343
+ return dict(
344
+ Metadata=self.metadata.dump(),
345
+ Properties=[prop.dump(default_space, default_version) for prop in self.properties],
346
+ Views=[view.dump(default_space, default_version) for view in self.views],
347
+ Containers=[container.dump(default_space) for container in self.containers or []] or None,
348
+ Reference=reference,
349
+ )
350
+
351
+
352
+ def _add_alias(data: dict[str, Any], base_model: type[BaseModel]) -> None:
353
+ for field_name, field_ in base_model.model_fields.items():
354
+ if field_name not in data and field_.alias in data:
355
+ data[field_name] = data[field_.alias]
@@ -27,7 +27,7 @@ from cognite.neat.rules.issues.dms import (
27
27
  MissingSpaceError,
28
28
  MissingViewError,
29
29
  )
30
- from cognite.neat.rules.models.rules._types._value import DMS_VALUE_TYPE_MAPPINGS
30
+ from cognite.neat.rules.models.data_types import _DATA_TYPE_BY_DMS_TYPE
31
31
  from cognite.neat.utils.cdf_loaders import ViewLoader
32
32
  from cognite.neat.utils.cdf_loaders.data_classes import RawTableWrite, RawTableWriteList
33
33
  from cognite.neat.utils.text import to_camel
@@ -577,8 +577,8 @@ class PipelineSchema(DMSSchema):
577
577
  container = container_by_id.get(prop.container)
578
578
  if container is not None:
579
579
  dms_type = container.properties[prop.container_property_identifier].type._type
580
- if dms_type in DMS_VALUE_TYPE_MAPPINGS:
581
- sql_type = DMS_VALUE_TYPE_MAPPINGS[dms_type].sql
580
+ if dms_type in _DATA_TYPE_BY_DMS_TYPE:
581
+ sql_type = _DATA_TYPE_BY_DMS_TYPE[dms_type].sql
582
582
  else:
583
583
  warnings.warn(
584
584
  f"Unknown DMS type '{dms_type}' for property '{prop_name}'", RuntimeWarning, stacklevel=2
@@ -4,6 +4,9 @@ from typing import Any, ClassVar
4
4
  from pydantic import Field, field_serializer, field_validator, model_serializer
5
5
  from pydantic_core.core_schema import SerializationInfo
6
6
 
7
+ from cognite.neat.rules.models.data_types import DataType
8
+ from cognite.neat.rules.models.entities import ClassEntity, ParentEntityList
9
+
7
10
  from ._base import (
8
11
  BaseMetadata,
9
12
  RoleTypes,
@@ -11,7 +14,7 @@ from ._base import (
11
14
  SheetEntity,
12
15
  SheetList,
13
16
  )
14
- from ._types import ParentClassType, PropertyType, SemanticValueType, StrOrListType
17
+ from ._types import PropertyType, StrOrListType
15
18
 
16
19
 
17
20
  class DomainMetadata(BaseMetadata):
@@ -21,7 +24,7 @@ class DomainMetadata(BaseMetadata):
21
24
 
22
25
  class DomainProperty(SheetEntity):
23
26
  property_: PropertyType = Field(alias="Property")
24
- value_type: SemanticValueType = Field(alias="Value Type")
27
+ value_type: DataType | ClassEntity = Field(alias="Value Type")
25
28
  min_count: int | None = Field(alias="Min Count", default=None)
26
29
  max_count: int | float | None = Field(alias="Max Count", default=None)
27
30
 
@@ -40,7 +43,7 @@ class DomainProperty(SheetEntity):
40
43
 
41
44
  class DomainClass(SheetEntity):
42
45
  description: str | None = Field(None, alias="Description")
43
- parent: ParentClassType = Field(alias="Parent Class")
46
+ parent: ParentEntityList | None = Field(alias="Parent Class")
44
47
 
45
48
 
46
49
  class DomainRules(RuleModel):