cognite-neat 0.88.2__py3-none-any.whl → 0.89.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 (129) hide show
  1. cognite/neat/_version.py +1 -1
  2. cognite/neat/constants.py +3 -0
  3. cognite/neat/graph/__init__.py +0 -3
  4. cognite/neat/graph/extractors/_mock_graph_generator.py +2 -1
  5. cognite/neat/graph/loaders/_base.py +3 -3
  6. cognite/neat/graph/loaders/_rdf2asset.py +24 -25
  7. cognite/neat/graph/loaders/_rdf2dms.py +20 -15
  8. cognite/neat/issues/__init__.py +1 -3
  9. cognite/neat/issues/_base.py +261 -71
  10. cognite/neat/issues/errors/__init__.py +73 -0
  11. cognite/neat/issues/errors/_external.py +67 -0
  12. cognite/neat/issues/errors/_general.py +35 -0
  13. cognite/neat/issues/errors/_properties.py +62 -0
  14. cognite/neat/issues/errors/_resources.py +111 -0
  15. cognite/neat/issues/errors/_workflow.py +36 -0
  16. cognite/neat/issues/formatters.py +1 -1
  17. cognite/neat/issues/warnings/__init__.py +66 -0
  18. cognite/neat/issues/warnings/_external.py +40 -0
  19. cognite/neat/issues/warnings/_general.py +29 -0
  20. cognite/neat/issues/warnings/_models.py +92 -0
  21. cognite/neat/issues/warnings/_properties.py +44 -0
  22. cognite/neat/issues/warnings/_resources.py +55 -0
  23. cognite/neat/issues/warnings/user_modeling.py +113 -0
  24. cognite/neat/rules/_shared.py +53 -2
  25. cognite/neat/rules/analysis/_base.py +1 -1
  26. cognite/neat/rules/exporters/_base.py +7 -18
  27. cognite/neat/rules/exporters/_rules2dms.py +17 -20
  28. cognite/neat/rules/exporters/_rules2excel.py +9 -16
  29. cognite/neat/rules/exporters/_rules2ontology.py +77 -64
  30. cognite/neat/rules/exporters/_rules2yaml.py +6 -9
  31. cognite/neat/rules/exporters/_validation.py +11 -96
  32. cognite/neat/rules/importers/_base.py +9 -58
  33. cognite/neat/rules/importers/_dms2rules.py +188 -135
  34. cognite/neat/rules/importers/_dtdl2rules/dtdl_converter.py +48 -35
  35. cognite/neat/rules/importers/_dtdl2rules/dtdl_importer.py +36 -45
  36. cognite/neat/rules/importers/_dtdl2rules/spec.py +7 -0
  37. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2classes.py +8 -4
  38. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2metadata.py +3 -3
  39. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2properties.py +18 -11
  40. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2rules.py +12 -19
  41. cognite/neat/rules/importers/_rdf/_inference2rules.py +14 -37
  42. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2classes.py +1 -0
  43. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2properties.py +1 -0
  44. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2rules.py +9 -20
  45. cognite/neat/rules/importers/_rdf/_shared.py +4 -4
  46. cognite/neat/rules/importers/_spreadsheet2rules.py +46 -97
  47. cognite/neat/rules/importers/_yaml2rules.py +32 -58
  48. cognite/neat/rules/models/__init__.py +21 -5
  49. cognite/neat/rules/models/_base_input.py +162 -0
  50. cognite/neat/rules/models/{_base.py → _base_rules.py} +1 -12
  51. cognite/neat/rules/models/_rdfpath.py +4 -4
  52. cognite/neat/rules/models/{_types/_field.py → _types.py} +5 -10
  53. cognite/neat/rules/models/asset/__init__.py +5 -2
  54. cognite/neat/rules/models/asset/_rules.py +3 -23
  55. cognite/neat/rules/models/asset/_rules_input.py +40 -115
  56. cognite/neat/rules/models/asset/_validation.py +14 -10
  57. cognite/neat/rules/models/data_types.py +150 -44
  58. cognite/neat/rules/models/dms/__init__.py +19 -7
  59. cognite/neat/rules/models/dms/_exporter.py +102 -34
  60. cognite/neat/rules/models/dms/_rules.py +65 -162
  61. cognite/neat/rules/models/dms/_rules_input.py +186 -254
  62. cognite/neat/rules/models/dms/_schema.py +87 -78
  63. cognite/neat/rules/models/dms/_serializer.py +44 -3
  64. cognite/neat/rules/models/dms/_validation.py +106 -68
  65. cognite/neat/rules/models/domain.py +52 -1
  66. cognite/neat/rules/models/entities/__init__.py +63 -0
  67. cognite/neat/rules/models/entities/_constants.py +73 -0
  68. cognite/neat/rules/models/entities/_loaders.py +76 -0
  69. cognite/neat/rules/models/entities/_multi_value.py +67 -0
  70. cognite/neat/rules/models/{entities.py → entities/_single_value.py} +74 -232
  71. cognite/neat/rules/models/entities/_types.py +86 -0
  72. cognite/neat/rules/models/{wrapped_entities.py → entities/_wrapped.py} +1 -1
  73. cognite/neat/rules/models/information/__init__.py +10 -2
  74. cognite/neat/rules/models/information/_rules.py +10 -22
  75. cognite/neat/rules/models/information/_rules_input.py +57 -204
  76. cognite/neat/rules/models/information/_validation.py +48 -25
  77. cognite/neat/rules/transformers/__init__.py +21 -0
  78. cognite/neat/rules/transformers/_base.py +81 -0
  79. cognite/neat/rules/{models/information/_converter.py → transformers/_converters.py} +217 -21
  80. cognite/neat/rules/transformers/_map_onto.py +97 -0
  81. cognite/neat/rules/transformers/_pipelines.py +61 -0
  82. cognite/neat/rules/transformers/_verification.py +136 -0
  83. cognite/neat/{graph/stores → store}/_provenance.py +10 -1
  84. cognite/neat/utils/auxiliary.py +2 -35
  85. cognite/neat/utils/cdf/data_classes.py +20 -0
  86. cognite/neat/utils/regex_patterns.py +6 -0
  87. cognite/neat/utils/text.py +17 -0
  88. cognite/neat/workflows/base.py +4 -4
  89. cognite/neat/workflows/cdf_store.py +3 -3
  90. cognite/neat/workflows/steps/data_contracts.py +1 -1
  91. cognite/neat/workflows/steps/lib/current/graph_extractor.py +3 -3
  92. cognite/neat/workflows/steps/lib/current/graph_loader.py +2 -2
  93. cognite/neat/workflows/steps/lib/current/graph_store.py +1 -1
  94. cognite/neat/workflows/steps/lib/current/rules_exporter.py +116 -47
  95. cognite/neat/workflows/steps/lib/current/rules_importer.py +30 -28
  96. cognite/neat/workflows/steps/lib/current/rules_validator.py +5 -6
  97. cognite/neat/workflows/steps/lib/io/io_steps.py +5 -5
  98. cognite/neat/workflows/steps_registry.py +4 -5
  99. {cognite_neat-0.88.2.dist-info → cognite_neat-0.89.0.dist-info}/METADATA +1 -1
  100. {cognite_neat-0.88.2.dist-info → cognite_neat-0.89.0.dist-info}/RECORD +105 -106
  101. cognite/neat/exceptions.py +0 -145
  102. cognite/neat/graph/exceptions.py +0 -90
  103. cognite/neat/issues/errors/external.py +0 -21
  104. cognite/neat/issues/errors/properties.py +0 -75
  105. cognite/neat/issues/errors/resources.py +0 -123
  106. cognite/neat/issues/errors/schema.py +0 -0
  107. cognite/neat/issues/neat_warnings/__init__.py +0 -2
  108. cognite/neat/issues/neat_warnings/identifier.py +0 -27
  109. cognite/neat/issues/neat_warnings/models.py +0 -22
  110. cognite/neat/issues/neat_warnings/properties.py +0 -77
  111. cognite/neat/issues/neat_warnings/resources.py +0 -125
  112. cognite/neat/rules/issues/__init__.py +0 -22
  113. cognite/neat/rules/issues/base.py +0 -63
  114. cognite/neat/rules/issues/dms.py +0 -549
  115. cognite/neat/rules/issues/fileread.py +0 -197
  116. cognite/neat/rules/issues/ontology.py +0 -298
  117. cognite/neat/rules/issues/spreadsheet.py +0 -563
  118. cognite/neat/rules/issues/spreadsheet_file.py +0 -151
  119. cognite/neat/rules/issues/tables.py +0 -72
  120. cognite/neat/rules/models/_constants.py +0 -1
  121. cognite/neat/rules/models/_types/__init__.py +0 -19
  122. cognite/neat/rules/models/asset/_converter.py +0 -4
  123. cognite/neat/rules/models/dms/_converter.py +0 -145
  124. cognite/neat/workflows/_exceptions.py +0 -41
  125. /cognite/neat/{graph/stores → store}/__init__.py +0 -0
  126. /cognite/neat/{graph/stores → store}/_base.py +0 -0
  127. {cognite_neat-0.88.2.dist-info → cognite_neat-0.89.0.dist-info}/LICENSE +0 -0
  128. {cognite_neat-0.88.2.dist-info → cognite_neat-0.89.0.dist-info}/WHEEL +0 -0
  129. {cognite_neat-0.88.2.dist-info → cognite_neat-0.89.0.dist-info}/entry_points.txt +0 -0
@@ -1,9 +1,12 @@
1
- import re
1
+ import inspect
2
2
  import sys
3
3
  from abc import ABC, abstractmethod
4
4
  from functools import total_ordering
5
- from typing import Annotated, Any, ClassVar, Generic, TypeVar, cast
5
+ from types import UnionType
6
+ from typing import Any, ClassVar, Generic, Literal, TypeVar, Union, cast, get_args, get_origin
6
7
 
8
+ from cognite.client.data_classes.data_modeling import DirectRelationReference
9
+ from cognite.client.data_classes.data_modeling.data_types import UnitReference
7
10
  from cognite.client.data_classes.data_modeling.ids import (
8
11
  ContainerId,
9
12
  DataModelId,
@@ -12,16 +15,12 @@ from cognite.client.data_classes.data_modeling.ids import (
12
15
  ViewId,
13
16
  )
14
17
  from pydantic import (
15
- AnyHttpUrl,
16
18
  BaseModel,
17
- BeforeValidator,
18
19
  Field,
19
- PlainSerializer,
20
20
  model_serializer,
21
21
  model_validator,
22
22
  )
23
23
 
24
- from cognite.neat.rules.models.data_types import DataType
25
24
  from cognite.neat.utils.text import replace_non_alphanumeric_with_underscore
26
25
 
27
26
  if sys.version_info >= (3, 11):
@@ -31,66 +30,17 @@ else:
31
30
  from backports.strenum import StrEnum
32
31
  from typing_extensions import Self
33
32
 
33
+ from cognite.neat.utils.regex_patterns import SPLIT_ON_COMMA_PATTERN, SPLIT_ON_EQUAL_PATTERN
34
34
 
35
- class EntityTypes(StrEnum):
36
- view_non_versioned = "view_non_versioned"
37
- subject = "subject"
38
- predicate = "predicate"
39
- object = "object"
40
- class_ = "class"
41
- parent_class = "parent_class"
42
- property_ = "property"
43
- object_property = "ObjectProperty"
44
- data_property = "DatatypeProperty"
45
- annotation_property = "AnnotationProperty"
46
- object_value_type = "object_value_type"
47
- data_value_type = "data_value_type" # these are strings, floats, ...
48
- xsd_value_type = "xsd_value_type"
49
- dms_value_type = "dms_value_type"
50
- dms_node = "dms_node"
51
- view = "view"
52
- reference_entity = "reference_entity"
53
- container = "container"
54
- datamodel = "datamodel"
55
- undefined = "undefined"
56
- multi_value_type = "multi_value_type"
57
- asset = "asset"
58
- relationship = "relationship"
59
-
60
-
61
- # ALLOWED
62
- _ALLOWED_PATTERN = r"[^a-zA-Z0-9-_.]"
63
-
64
- # FOR PARSING STRINGS:
65
- _PREFIX_REGEX = r"[a-zA-Z]+[a-zA-Z0-9-_.]*[a-zA-Z0-9]+"
66
- _SUFFIX_REGEX = r"[a-zA-Z0-9-_.]+[a-zA-Z0-9]|[-_.]*[a-zA-Z0-9]+"
67
- _VERSION_REGEX = r"[a-zA-Z0-9]([.a-zA-Z0-9_-]{0,41}[a-zA-Z0-9])?"
68
- _PROPERTY_REGEX = r"[a-zA-Z0-9][a-zA-Z0-9_-]*[a-zA-Z0-9]?"
69
- _ENTITY_ID_REGEX = rf"{_PREFIX_REGEX}:({_SUFFIX_REGEX})"
70
- _ENTITY_ID_REGEX_COMPILED = re.compile(rf"^(?P<prefix>{_PREFIX_REGEX}):(?P<suffix>{_SUFFIX_REGEX})$")
71
- _VERSIONED_ENTITY_REGEX_COMPILED = re.compile(
72
- rf"^(?P<prefix>{_PREFIX_REGEX}):(?P<suffix>{_SUFFIX_REGEX})\(version=(?P<version>{_VERSION_REGEX})\)$"
35
+ from ._constants import (
36
+ _PARSE,
37
+ ENTITY_PATTERN,
38
+ EntityTypes,
39
+ Undefined,
40
+ Unknown,
41
+ _UndefinedType,
42
+ _UnknownType,
73
43
  )
74
- _CLASS_ID_REGEX = rf"(?P<{EntityTypes.class_}>{_ENTITY_ID_REGEX})"
75
- _CLASS_ID_REGEX_COMPILED = re.compile(rf"^{_CLASS_ID_REGEX}$")
76
- _PROPERTY_ID_REGEX = rf"\((?P<{EntityTypes.property_}>{_ENTITY_ID_REGEX})\)"
77
-
78
- _ENTITY_PATTERN = re.compile(r"^(?P<prefix>.*?):?(?P<suffix>[^(:]*)(\((?P<content>[^)]+)\))?$")
79
- _MULTI_VALUE_TYPE_PATTERN = re.compile(r"^(?P<types>.*?)(\((?P<content>[^)]+)\))?$")
80
-
81
-
82
- class _UndefinedType(BaseModel): ...
83
-
84
-
85
- class _UnknownType(BaseModel):
86
- def __str__(self) -> str:
87
- return "#N/A"
88
-
89
-
90
- # This is a trick to make Undefined and Unknown singletons
91
- Undefined = _UndefinedType()
92
- Unknown = _UnknownType()
93
- _PARSE = object()
94
44
 
95
45
 
96
46
  @total_ordering
@@ -108,7 +58,7 @@ class Entity(BaseModel, extra="ignore"):
108
58
  elif isinstance(data, str) and data == str(Unknown):
109
59
  return UnknownEntity(prefix=Undefined, suffix=Unknown)
110
60
  if defaults and isinstance(defaults, dict):
111
- # This is trick to pass in default values
61
+ # This is is a trick to pass in default values
112
62
  return cls.model_validate({_PARSE: data, "defaults": defaults})
113
63
  else:
114
64
  return cls.model_validate(data)
@@ -132,7 +82,7 @@ class Entity(BaseModel, extra="ignore"):
132
82
  elif data == str(Unknown):
133
83
  raise ValueError(f"Unknown is not allowed for {cls.type_} entity")
134
84
 
135
- result = cls._parse(data)
85
+ result = cls._parse(data, defaults)
136
86
  output = defaults.copy()
137
87
  # Populate by alias
138
88
  for field_name, field_ in cls.model_fields.items():
@@ -148,20 +98,29 @@ class Entity(BaseModel, extra="ignore"):
148
98
  return str(self)
149
99
 
150
100
  @classmethod
151
- def _parse(cls, raw: str) -> dict:
152
- if not (result := _ENTITY_PATTERN.match(raw)):
101
+ def _parse(cls, raw: str, defaults: dict) -> dict:
102
+ if not (result := ENTITY_PATTERN.match(raw)):
153
103
  return dict(prefix=Undefined, suffix=Unknown)
154
104
  prefix = result.group("prefix") or Undefined
155
105
  suffix = result.group("suffix")
156
106
  content = result.group("content")
157
107
  if content is None:
158
108
  return dict(prefix=prefix, suffix=suffix)
159
- extra_args = dict(pair.strip().split("=") for pair in content.split(","))
160
- expected_args = {field_.alias or field_name for field_name, field_ in cls.model_fields.items()}
109
+ extra_args = dict(SPLIT_ON_EQUAL_PATTERN.split(pair.strip()) for pair in SPLIT_ON_COMMA_PATTERN.split(content))
110
+ expected_args = {
111
+ field_.alias or field_name: field_.annotation for field_name, field_ in cls.model_fields.items()
112
+ }
161
113
  for key in list(extra_args):
162
114
  if key not in expected_args:
163
115
  # Todo Warning about unknown key
164
116
  del extra_args[key]
117
+ continue
118
+ annotation = expected_args[key]
119
+ if isinstance(annotation, UnionType) or get_origin(annotation) is Union:
120
+ annotation = get_args(annotation)[0]
121
+
122
+ if inspect.isclass(annotation) and issubclass(annotation, Entity): # type: ignore[arg-type]
123
+ extra_args[key] = annotation.load(extra_args[key], **defaults) # type: ignore[union-attr, assignment]
165
124
  return dict(prefix=prefix, suffix=suffix, **extra_args)
166
125
 
167
126
  def dump(self) -> str:
@@ -206,12 +165,15 @@ class Entity(BaseModel, extra="ignore"):
206
165
  @property
207
166
  def id(self) -> str:
208
167
  # We have overwritten the serialization to str, so we need to do it manually
209
- model_dump = (
168
+ model_dump = [
210
169
  (field.alias or field_name, v)
211
170
  for field_name, field in self.model_fields.items()
212
171
  if (v := getattr(self, field_name)) is not None and field_name not in {"prefix", "suffix"}
213
- )
214
- args = ",".join([f"{k}={v}" for k, v in model_dump])
172
+ ]
173
+ if len(model_dump) == 1:
174
+ args = f"{model_dump[0][0]}={model_dump[0][1]}"
175
+ else:
176
+ args = ",".join([f"{k}={v}" for k, v in model_dump])
215
177
  if self.prefix == Undefined:
216
178
  base_id = str(self.suffix)
217
179
  else:
@@ -268,6 +230,15 @@ class UnknownEntity(ClassEntity):
268
230
  return str(Unknown)
269
231
 
270
232
 
233
+ class UnitEntity(Entity):
234
+ type_: ClassVar[EntityTypes] = EntityTypes.unit
235
+ prefix: str
236
+ suffix: str
237
+
238
+ def as_reference(self) -> UnitReference:
239
+ return UnitReference(external_id=f"{self.prefix}:{self.suffix}")
240
+
241
+
271
242
  class AssetFields(StrEnum):
272
243
  externalId = "externalId"
273
244
  name = "name"
@@ -293,61 +264,6 @@ class RelationshipEntity(Entity):
293
264
  T_ID = TypeVar("T_ID", bound=ContainerId | ViewId | DataModelId | PropertyId | NodeId | None)
294
265
 
295
266
 
296
- class MultiValueTypeInfo(BaseModel):
297
- type_: ClassVar[EntityTypes] = EntityTypes.multi_value_type
298
- types: list[DataType | ClassEntity]
299
-
300
- def __str__(self) -> str:
301
- return " | ".join([str(t) for t in self.types])
302
-
303
- @model_serializer(when_used="unless-none", return_type=str)
304
- def as_str(self) -> str:
305
- return str(self)
306
-
307
- @classmethod
308
- def load(cls, data: Any) -> "MultiValueTypeInfo":
309
- # already instance of MultiValueTypeInfo
310
- if isinstance(data, cls):
311
- return data
312
-
313
- # it is a raw string that needs to be parsed
314
- elif isinstance(data, str):
315
- return cls.model_validate({_PARSE: data})
316
-
317
- # it is dict that needs to be parsed
318
- else:
319
- return cls.model_validate(data)
320
-
321
- @model_validator(mode="before")
322
- def _load(cls, data: Any) -> "dict | MultiValueTypeInfo":
323
- if isinstance(data, dict) and _PARSE in data:
324
- data = data[_PARSE]
325
- elif isinstance(data, dict):
326
- return data
327
- else:
328
- raise ValueError(f"Cannot load {cls.__name__} from {data}")
329
-
330
- result = cls._parse(data)
331
- return result
332
-
333
- @classmethod
334
- def _parse(cls, raw: str) -> dict:
335
- if not (types := [type_.strip() for type_ in raw.split("|")]):
336
- return {"types": [UnknownEntity()]}
337
- else:
338
- return {
339
- "types": [
340
- (DataType.load(type_) if DataType.is_data_type(type_) else ClassEntity.load(type_))
341
- for type_ in types
342
- ]
343
- }
344
-
345
- def set_default_prefix(self, prefix: str):
346
- for type_ in self.types:
347
- if isinstance(type_, ClassEntity) and type_.prefix is Undefined:
348
- type_.prefix = prefix
349
-
350
-
351
267
  class DMSEntity(Entity, Generic[T_ID], ABC):
352
268
  type_: ClassVar[EntityTypes] = EntityTypes.undefined
353
269
  prefix: str = Field(alias="space")
@@ -452,33 +368,6 @@ class DMSUnknownEntity(DMSEntity[None]):
452
368
  return str(Unknown)
453
369
 
454
370
 
455
- class ViewPropertyEntity(DMSVersionedEntity[PropertyId]):
456
- type_: ClassVar[EntityTypes] = EntityTypes.property_
457
- property_: str = Field(alias="property")
458
-
459
- def as_id(self) -> PropertyId:
460
- return PropertyId(
461
- source=ViewId(self.space, self.external_id, self.version),
462
- property=self.property_,
463
- )
464
-
465
- def as_view_id(self) -> ViewId:
466
- return ViewId(space=self.space, external_id=self.external_id, version=self.version)
467
-
468
- @classmethod
469
- def from_id(cls, id: PropertyId) -> "ViewPropertyEntity":
470
- if isinstance(id.source, ContainerId):
471
- raise ValueError("Only view source are supported")
472
- if id.source.version is None:
473
- raise ValueError("Version must be specified")
474
- return cls(
475
- space=id.source.space,
476
- externalId=id.source.external_id,
477
- version=id.source.version,
478
- property=id.property,
479
- )
480
-
481
-
482
371
  class DataModelEntity(DMSVersionedEntity[DataModelId]):
483
372
  type_: ClassVar[EntityTypes] = EntityTypes.datamodel
484
373
 
@@ -498,10 +387,40 @@ class DMSNodeEntity(DMSEntity[NodeId]):
498
387
  def as_id(self) -> NodeId:
499
388
  return NodeId(space=self.space, external_id=self.external_id)
500
389
 
390
+ def as_reference(self) -> DirectRelationReference:
391
+ return DirectRelationReference(space=self.space, external_id=self.external_id)
392
+
501
393
  @classmethod
502
394
  def from_id(cls, id: NodeId) -> "DMSNodeEntity":
503
395
  return cls(space=id.space, externalId=id.external_id)
504
396
 
397
+ @classmethod
398
+ def from_reference(cls, ref: DirectRelationReference) -> "DMSNodeEntity":
399
+ return cls(space=ref.space, externalId=ref.external_id)
400
+
401
+
402
+ class EdgeEntity(DMSEntity[None]):
403
+ type_: ClassVar[EntityTypes] = EntityTypes.edge
404
+ prefix: _UndefinedType = Undefined # type: ignore[assignment]
405
+ suffix: Literal["edge"] = "edge"
406
+ edge_type: DMSNodeEntity | None = Field(None, alias="type")
407
+ properties: ViewEntity | None = None
408
+ direction: Literal["outwards", "inwards"] = "outwards"
409
+
410
+ def as_id(self) -> None:
411
+ return None
412
+
413
+ @classmethod
414
+ def from_id(cls, id: None) -> Self:
415
+ return cls()
416
+
417
+
418
+ class ReverseConnectionEntity(Entity):
419
+ type_: ClassVar[EntityTypes] = EntityTypes.reverse
420
+ prefix: _UndefinedType = Undefined
421
+ suffix: Literal["reverse"] = "reverse"
422
+ property_: str = Field(alias="property")
423
+
505
424
 
506
425
  class ReferenceEntity(ClassEntity):
507
426
  type_: ClassVar[EntityTypes] = EntityTypes.reference_entity
@@ -538,80 +457,3 @@ class ReferenceEntity(ClassEntity):
538
457
 
539
458
  def as_class_entity(self) -> ClassEntity:
540
459
  return ClassEntity(prefix=self.prefix, suffix=self.suffix, version=self.version)
541
-
542
-
543
- def _split_str(v: Any) -> list[str]:
544
- if isinstance(v, str):
545
- return v.replace(", ", ",").split(",")
546
- return v
547
-
548
-
549
- def _join_str(v: list[ClassEntity]) -> str | None:
550
- return ",".join([entry.id for entry in v]) if v else None
551
-
552
-
553
- def _generate_cdf_resource_list(v: Any) -> list[AssetEntity | RelationshipEntity]:
554
- results = []
555
- for item in _split_str(v):
556
- if isinstance(item, str):
557
- if "relationship" in item.lower():
558
- results.append(RelationshipEntity.load(item))
559
- elif "asset" in item.lower():
560
- results.append(AssetEntity.load(item)) # type: ignore
561
- else:
562
- raise ValueError(f"Unsupported implementation definition: {item}")
563
-
564
- elif isinstance(item, AssetEntity | RelationshipEntity):
565
- results.append(item)
566
- else:
567
- raise ValueError(f"Unsupported implementation definition: {item}")
568
-
569
- return results # type: ignore
570
-
571
-
572
- ClassEntityList = Annotated[
573
- list[ClassEntity],
574
- BeforeValidator(_split_str),
575
- PlainSerializer(
576
- _join_str,
577
- return_type=str,
578
- when_used="unless-none",
579
- ),
580
- ]
581
-
582
-
583
- CdfResourceEntityList = Annotated[
584
- list[AssetEntity | RelationshipEntity],
585
- BeforeValidator(_generate_cdf_resource_list),
586
- PlainSerializer(
587
- _join_str,
588
- return_type=str,
589
- when_used="unless-none",
590
- ),
591
- ]
592
-
593
-
594
- ContainerEntityList = Annotated[
595
- list[ContainerEntity],
596
- BeforeValidator(_split_str),
597
- PlainSerializer(
598
- _join_str,
599
- return_type=str,
600
- when_used="unless-none",
601
- ),
602
- ]
603
-
604
- ViewEntityList = Annotated[
605
- list[ViewEntity],
606
- BeforeValidator(_split_str),
607
- PlainSerializer(
608
- _join_str,
609
- return_type=str,
610
- when_used="unless-none",
611
- ),
612
- ]
613
-
614
- URLEntity = Annotated[
615
- AnyHttpUrl,
616
- PlainSerializer(lambda v: str(v), return_type=str, when_used="unless-none"),
617
- ]
@@ -0,0 +1,86 @@
1
+ from typing import Annotated, Any
2
+
3
+ from pydantic import (
4
+ AnyHttpUrl,
5
+ BeforeValidator,
6
+ PlainSerializer,
7
+ )
8
+
9
+ from ._single_value import AssetEntity, ClassEntity, ContainerEntity, RelationshipEntity, ViewEntity
10
+
11
+
12
+ def _split_str(v: Any) -> list[str]:
13
+ if isinstance(v, str):
14
+ return v.replace(", ", ",").split(",")
15
+ return v
16
+
17
+
18
+ def _join_str(v: list[ClassEntity]) -> str | None:
19
+ return ",".join([entry.id for entry in v]) if v else None
20
+
21
+
22
+ def _generate_cdf_resource_list(v: Any) -> list[AssetEntity | RelationshipEntity]:
23
+ results = []
24
+ for item in _split_str(v):
25
+ if isinstance(item, str):
26
+ if "relationship" in item.lower():
27
+ results.append(RelationshipEntity.load(item))
28
+ elif "asset" in item.lower():
29
+ results.append(AssetEntity.load(item)) # type: ignore
30
+ else:
31
+ raise ValueError(f"Unsupported implementation definition: {item}")
32
+
33
+ elif isinstance(item, AssetEntity | RelationshipEntity):
34
+ results.append(item)
35
+ else:
36
+ raise ValueError(f"Unsupported implementation definition: {item}")
37
+
38
+ return results # type: ignore
39
+
40
+
41
+ ClassEntityList = Annotated[
42
+ list[ClassEntity],
43
+ BeforeValidator(_split_str),
44
+ PlainSerializer(
45
+ _join_str,
46
+ return_type=str,
47
+ when_used="unless-none",
48
+ ),
49
+ ]
50
+
51
+
52
+ CdfResourceEntityList = Annotated[
53
+ list[AssetEntity | RelationshipEntity],
54
+ BeforeValidator(_generate_cdf_resource_list),
55
+ PlainSerializer(
56
+ _join_str,
57
+ return_type=str,
58
+ when_used="unless-none",
59
+ ),
60
+ ]
61
+
62
+
63
+ ContainerEntityList = Annotated[
64
+ list[ContainerEntity],
65
+ BeforeValidator(_split_str),
66
+ PlainSerializer(
67
+ _join_str,
68
+ return_type=str,
69
+ when_used="unless-none",
70
+ ),
71
+ ]
72
+
73
+ ViewEntityList = Annotated[
74
+ list[ViewEntity],
75
+ BeforeValidator(_split_str),
76
+ PlainSerializer(
77
+ _join_str,
78
+ return_type=str,
79
+ when_used="unless-none",
80
+ ),
81
+ ]
82
+
83
+ URLEntity = Annotated[
84
+ AnyHttpUrl,
85
+ PlainSerializer(lambda v: str(v), return_type=str, when_used="unless-none"),
86
+ ]
@@ -9,7 +9,7 @@ from cognite.client import data_modeling as dm
9
9
  from cognite.client.data_classes.data_modeling import ContainerId, NodeId
10
10
  from pydantic import BaseModel, model_serializer, model_validator
11
11
 
12
- from cognite.neat.rules.models.entities import ContainerEntity, DMSNodeEntity, Entity
12
+ from ._single_value import ContainerEntity, DMSNodeEntity, Entity
13
13
 
14
14
 
15
15
  @total_ordering
@@ -1,10 +1,18 @@
1
1
  from ._rules import InformationClass, InformationMetadata, InformationProperty, InformationRules
2
- from ._rules_input import InformationRulesInput
2
+ from ._rules_input import (
3
+ InformationInputClass,
4
+ InformationInputMetadata,
5
+ InformationInputProperty,
6
+ InformationInputRules,
7
+ )
3
8
 
4
9
  __all__ = [
5
10
  "InformationRules",
6
11
  "InformationMetadata",
7
12
  "InformationClass",
8
13
  "InformationProperty",
9
- "InformationRulesInput",
14
+ "InformationInputRules",
15
+ "InformationInputMetadata",
16
+ "InformationInputClass",
17
+ "InformationInputProperty",
10
18
  ]
@@ -8,10 +8,8 @@ from pydantic.main import IncEx
8
8
  from rdflib import Namespace
9
9
 
10
10
  from cognite.neat.constants import get_default_prefixes
11
- from cognite.neat.issues import MultiValueError
12
- from cognite.neat.rules import issues
13
- from cognite.neat.rules.issues.spreadsheet import DefaultValueTypeNotProperError
14
- from cognite.neat.rules.models._base import (
11
+ from cognite.neat.issues.errors import PropertyDefinitionError
12
+ from cognite.neat.rules.models._base_rules import (
15
13
  BaseMetadata,
16
14
  BaseRules,
17
15
  DataModelType,
@@ -36,7 +34,6 @@ from cognite.neat.rules.models._types import (
36
34
  VersionType,
37
35
  )
38
36
  from cognite.neat.rules.models.data_types import DataType
39
- from cognite.neat.rules.models.domain import DomainRules
40
37
  from cognite.neat.rules.models.entities import (
41
38
  ClassEntity,
42
39
  ClassEntityList,
@@ -49,7 +46,7 @@ from cognite.neat.rules.models.entities import (
49
46
  )
50
47
 
51
48
  if TYPE_CHECKING:
52
- from cognite.neat.rules.models import AssetRules, DMSRules
49
+ from cognite.neat.rules.models import DMSRules
53
50
 
54
51
 
55
52
  if sys.version_info >= (3, 11):
@@ -228,11 +225,12 @@ class InformationProperty(SheetEntity):
228
225
  self.default = self.value_type.python(self.default)
229
226
 
230
227
  except Exception:
231
- raise DefaultValueTypeNotProperError(
228
+ raise PropertyDefinitionError(
229
+ self.class_,
230
+ "Class",
232
231
  self.property_,
233
- type(self.default),
234
- str(self.value_type.python),
235
- ).as_exception() from None
232
+ f"Default value {self.default} is not of type {self.value_type.python}",
233
+ ) from None
236
234
  return self
237
235
 
238
236
  @property
@@ -306,7 +304,7 @@ class InformationRules(BaseRules):
306
304
  if issue_list.warnings:
307
305
  issue_list.trigger_warnings()
308
306
  if issue_list.has_errors:
309
- raise MultiValueError([error for error in issue_list if isinstance(error, issues.NeatValidationError)])
307
+ raise issue_list.as_exception()
310
308
  return self
311
309
 
312
310
  def dump(
@@ -341,17 +339,7 @@ class InformationRules(BaseRules):
341
339
  cleaned[reference] = _InformationRulesSerializer(by_alias, prefix).clean(ref_dump, True)
342
340
  return cleaned
343
341
 
344
- def as_domain_rules(self) -> DomainRules:
345
- from ._converter import _InformationRulesConverter
346
-
347
- return _InformationRulesConverter(self).as_domain_rules()
348
-
349
- def as_asset_architect_rules(self) -> "AssetRules":
350
- from ._converter import _InformationRulesConverter
351
-
352
- return _InformationRulesConverter(self).as_asset_architect_rules()
353
-
354
342
  def as_dms_rules(self) -> "DMSRules":
355
- from ._converter import _InformationRulesConverter
343
+ from cognite.neat.rules.transformers._converters import _InformationRulesConverter
356
344
 
357
345
  return _InformationRulesConverter(self).as_dms_rules()