cognite-neat 0.99.0__py3-none-any.whl → 0.100.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/_client/_api/data_modeling_loaders.py +390 -116
  2. cognite/neat/_client/_api/schema.py +63 -2
  3. cognite/neat/_client/data_classes/data_modeling.py +4 -0
  4. cognite/neat/_client/data_classes/schema.py +2 -348
  5. cognite/neat/_constants.py +27 -4
  6. cognite/neat/_graph/extractors/_base.py +7 -0
  7. cognite/neat/_graph/extractors/_classic_cdf/_classic.py +28 -18
  8. cognite/neat/_graph/loaders/_rdf2dms.py +52 -13
  9. cognite/neat/_graph/transformers/__init__.py +3 -3
  10. cognite/neat/_graph/transformers/_classic_cdf.py +135 -56
  11. cognite/neat/_issues/_base.py +26 -17
  12. cognite/neat/_issues/errors/__init__.py +4 -2
  13. cognite/neat/_issues/errors/_external.py +7 -0
  14. cognite/neat/_issues/errors/_properties.py +2 -7
  15. cognite/neat/_issues/errors/_resources.py +1 -1
  16. cognite/neat/_issues/warnings/__init__.py +6 -2
  17. cognite/neat/_issues/warnings/_external.py +9 -1
  18. cognite/neat/_issues/warnings/_resources.py +41 -2
  19. cognite/neat/_issues/warnings/user_modeling.py +4 -4
  20. cognite/neat/_rules/_constants.py +2 -6
  21. cognite/neat/_rules/analysis/_base.py +15 -5
  22. cognite/neat/_rules/analysis/_dms.py +20 -0
  23. cognite/neat/_rules/analysis/_information.py +22 -0
  24. cognite/neat/_rules/exporters/_base.py +3 -5
  25. cognite/neat/_rules/exporters/_rules2dms.py +190 -200
  26. cognite/neat/_rules/importers/__init__.py +1 -3
  27. cognite/neat/_rules/importers/_base.py +1 -1
  28. cognite/neat/_rules/importers/_dms2rules.py +3 -25
  29. cognite/neat/_rules/importers/_rdf/__init__.py +5 -0
  30. cognite/neat/_rules/importers/_rdf/_base.py +34 -11
  31. cognite/neat/_rules/importers/_rdf/_imf2rules.py +91 -0
  32. cognite/neat/_rules/importers/_rdf/_inference2rules.py +40 -7
  33. cognite/neat/_rules/importers/_rdf/_owl2rules.py +80 -0
  34. cognite/neat/_rules/importers/_rdf/_shared.py +138 -441
  35. cognite/neat/_rules/models/_base_rules.py +19 -0
  36. cognite/neat/_rules/models/_types.py +5 -0
  37. cognite/neat/_rules/models/dms/__init__.py +2 -0
  38. cognite/neat/_rules/models/dms/_exporter.py +247 -123
  39. cognite/neat/_rules/models/dms/_rules.py +7 -49
  40. cognite/neat/_rules/models/dms/_rules_input.py +8 -3
  41. cognite/neat/_rules/models/dms/_validation.py +421 -123
  42. cognite/neat/_rules/models/entities/_multi_value.py +3 -0
  43. cognite/neat/_rules/models/information/__init__.py +2 -0
  44. cognite/neat/_rules/models/information/_rules.py +17 -61
  45. cognite/neat/_rules/models/information/_rules_input.py +11 -2
  46. cognite/neat/_rules/models/information/_validation.py +107 -11
  47. cognite/neat/_rules/models/mapping/_classic2core.py +1 -1
  48. cognite/neat/_rules/models/mapping/_classic2core.yaml +8 -4
  49. cognite/neat/_rules/transformers/__init__.py +2 -1
  50. cognite/neat/_rules/transformers/_converters.py +163 -61
  51. cognite/neat/_rules/transformers/_mapping.py +132 -2
  52. cognite/neat/_rules/transformers/_pipelines.py +1 -1
  53. cognite/neat/_rules/transformers/_verification.py +29 -4
  54. cognite/neat/_session/_base.py +46 -60
  55. cognite/neat/_session/_mapping.py +105 -5
  56. cognite/neat/_session/_prepare.py +49 -14
  57. cognite/neat/_session/_read.py +50 -4
  58. cognite/neat/_session/_set.py +1 -0
  59. cognite/neat/_session/_to.py +38 -12
  60. cognite/neat/_session/_wizard.py +5 -0
  61. cognite/neat/_session/engine/_interface.py +3 -2
  62. cognite/neat/_session/exceptions.py +4 -0
  63. cognite/neat/_store/_base.py +79 -19
  64. cognite/neat/_utils/collection_.py +22 -0
  65. cognite/neat/_utils/rdf_.py +30 -4
  66. cognite/neat/_version.py +2 -2
  67. cognite/neat/_workflows/steps/lib/current/rules_exporter.py +3 -91
  68. cognite/neat/_workflows/steps/lib/current/rules_importer.py +2 -16
  69. cognite/neat/_workflows/steps/lib/current/rules_validator.py +3 -5
  70. {cognite_neat-0.99.0.dist-info → cognite_neat-0.100.0.dist-info}/METADATA +1 -1
  71. {cognite_neat-0.99.0.dist-info → cognite_neat-0.100.0.dist-info}/RECORD +74 -82
  72. cognite/neat/_rules/importers/_rdf/_imf2rules/__init__.py +0 -3
  73. cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2classes.py +0 -86
  74. cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2metadata.py +0 -29
  75. cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2properties.py +0 -130
  76. cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2rules.py +0 -154
  77. cognite/neat/_rules/importers/_rdf/_owl2rules/__init__.py +0 -3
  78. cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2classes.py +0 -58
  79. cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2metadata.py +0 -65
  80. cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2properties.py +0 -59
  81. cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2rules.py +0 -39
  82. {cognite_neat-0.99.0.dist-info → cognite_neat-0.100.0.dist-info}/LICENSE +0 -0
  83. {cognite_neat-0.99.0.dist-info → cognite_neat-0.100.0.dist-info}/WHEEL +0 -0
  84. {cognite_neat-0.99.0.dist-info → cognite_neat-0.100.0.dist-info}/entry_points.txt +0 -0
@@ -1,5 +1,4 @@
1
1
  import math
2
- import sys
3
2
  from collections.abc import Hashable
4
3
  from typing import TYPE_CHECKING, Any, ClassVar
5
4
 
@@ -28,14 +27,15 @@ from cognite.neat._rules.models._types import (
28
27
  ClassEntityType,
29
28
  InformationPropertyType,
30
29
  MultiValueTypeType,
30
+ URIRefType,
31
31
  )
32
+
33
+ # NeatIdType,
32
34
  from cognite.neat._rules.models.data_types import DataType
33
35
  from cognite.neat._rules.models.entities import (
34
36
  ClassEntity,
35
37
  ClassEntityList,
36
38
  Entity,
37
- MultiValueTypeInfo,
38
- Undefined,
39
39
  UnknownEntity,
40
40
  )
41
41
 
@@ -43,19 +43,13 @@ if TYPE_CHECKING:
43
43
  from cognite.neat._rules.models import DMSRules
44
44
 
45
45
 
46
- if sys.version_info >= (3, 11):
47
- from typing import Self
48
- else:
49
- from typing_extensions import Self
50
-
51
-
52
46
  class InformationMetadata(BaseMetadata):
53
47
  role: ClassVar[RoleTypes] = RoleTypes.information
54
48
  aspect: ClassVar[DataModelAspect] = DataModelAspect.logical
55
49
 
56
50
  # Linking to Conceptual and Physical data model aspects
57
- physical: URIRef | None = Field(None, description="Link to the logical data model aspect")
58
- conceptual: URIRef | None = Field(None, description="Link to the logical data model aspect")
51
+ physical: URIRef | str | None = Field(None, description="Link to the physical data model aspect")
52
+ conceptual: URIRef | str | None = Field(None, description="Link to the conceptual data model aspect")
59
53
 
60
54
 
61
55
  def _get_metadata(context: Any) -> InformationMetadata | None:
@@ -79,6 +73,12 @@ class InformationClass(SheetRow):
79
73
  description: str | None = Field(alias="Description", default=None)
80
74
  implements: ClassEntityList | None = Field(alias="Implements", default=None)
81
75
 
76
+ physical: URIRefType | None = Field(
77
+ None,
78
+ description="Link to the class representation in the physical data model aspect",
79
+ )
80
+ conceptual: URIRefType | None = Field(None, description="Link to the conceptual data model aspect")
81
+
82
82
  def _identifier(self) -> tuple[Hashable, ...]:
83
83
  return (self.class_,)
84
84
 
@@ -137,6 +137,12 @@ class InformationProperty(SheetRow):
137
137
  description="Flag to indicate if the property is inherited, only use for internal purposes",
138
138
  )
139
139
 
140
+ physical: URIRefType | None = Field(
141
+ None,
142
+ description="Link to the class representation in the physical data model aspect",
143
+ )
144
+ conceptual: URIRefType | None = Field(None, description="Link to the conceptual data model aspect")
145
+
140
146
  def _identifier(self) -> tuple[Hashable, ...]:
141
147
  return self.class_, self.property_
142
148
 
@@ -155,21 +161,6 @@ class InformationProperty(SheetRow):
155
161
  else:
156
162
  raise NeatValueError(f"Invalid RDF Path: {value!s}")
157
163
 
158
- @model_validator(mode="after")
159
- def set_default_as_list(self):
160
- if (
161
- self.type_ == EntityTypes.data_property
162
- and self.default
163
- and self.is_list
164
- and not isinstance(self.default, list)
165
- ):
166
- if isinstance(self.default, str):
167
- if self.default:
168
- self.default = self.default.replace(", ", ",").split(",")
169
- else:
170
- self.default = [self.default]
171
- return self
172
-
173
164
  @model_validator(mode="after")
174
165
  def set_type_for_default(self):
175
166
  if self.type_ == EntityTypes.data_property and self.default:
@@ -243,41 +234,6 @@ class InformationRules(BaseRules):
243
234
  values = get_default_prefixes()
244
235
  return values
245
236
 
246
- @model_validator(mode="after")
247
- def update_entities_prefix(self) -> Self:
248
- # update expected_value_types
249
- for property_ in self.properties:
250
- if isinstance(property_.value_type, ClassEntity) and property_.value_type.prefix is Undefined:
251
- property_.value_type.prefix = self.metadata.prefix
252
-
253
- if isinstance(property_.value_type, MultiValueTypeInfo):
254
- property_.value_type.set_default_prefix(self.metadata.prefix)
255
-
256
- if property_.class_.prefix is Undefined:
257
- property_.class_.prefix = self.metadata.prefix
258
-
259
- # update implements
260
- for class_ in self.classes:
261
- if class_.implements:
262
- for parent in class_.implements:
263
- if not isinstance(parent.prefix, str):
264
- parent.prefix = self.metadata.prefix
265
- if class_.class_.prefix is Undefined:
266
- class_.class_.prefix = self.metadata.prefix
267
-
268
- return self
269
-
270
- @model_validator(mode="after")
271
- def post_validation(self) -> "InformationRules":
272
- from ._validation import InformationPostValidation
273
-
274
- issue_list = InformationPostValidation(self).validate()
275
- if issue_list.warnings:
276
- issue_list.trigger_warnings()
277
- if issue_list.has_errors:
278
- raise issue_list.as_exception()
279
- return self
280
-
281
237
  def as_dms_rules(self) -> "DMSRules":
282
238
  from cognite.neat._rules.transformers._converters import _InformationRulesConverter
283
239
 
@@ -33,8 +33,8 @@ class InformationInputMetadata(InputComponent[InformationMetadata]):
33
33
  description: str | None = None
34
34
  created: datetime | str | None = None
35
35
  updated: datetime | str | None = None
36
- physical: str | None = None
37
- conceptual: str | None = None
36
+ physical: str | URIRef | None = None
37
+ conceptual: str | URIRef | None = None
38
38
 
39
39
  @classmethod
40
40
  def _get_verified_cls(cls) -> type[InformationMetadata]:
@@ -81,6 +81,11 @@ class InformationInputProperty(InputComponent[InformationProperty]):
81
81
  transformation: str | None = None
82
82
  # Only used internally
83
83
  inherited: bool = False
84
+ neatId: str | URIRef | None = None
85
+
86
+ # linking
87
+ physical: str | URIRef | None = None
88
+ conceptual: str | URIRef | None = None
84
89
 
85
90
  @classmethod
86
91
  def _get_verified_cls(cls) -> type[InformationProperty]:
@@ -99,6 +104,10 @@ class InformationInputClass(InputComponent[InformationClass]):
99
104
  name: str | None = None
100
105
  description: str | None = None
101
106
  implements: str | list[ClassEntity] | None = None
107
+ neatId: str | URIRef | None = None
108
+ # linking
109
+ physical: str | URIRef | None = None
110
+ conceptual: str | URIRef | None = None
102
111
 
103
112
  @classmethod
104
113
  def _get_verified_cls(cls) -> type[InformationClass]:
@@ -1,17 +1,22 @@
1
1
  import itertools
2
2
  from collections import Counter
3
- from typing import cast
4
3
 
5
4
  from cognite.neat._issues import IssueList
6
- from cognite.neat._issues.errors import NeatValueError, ResourceNotDefinedError
5
+ from cognite.neat._issues.errors import NeatValueError
6
+ from cognite.neat._issues.errors._resources import ResourceNotDefinedError
7
7
  from cognite.neat._issues.warnings._models import UndefinedClassWarning
8
- from cognite.neat._rules._constants import EntityTypes
8
+ from cognite.neat._issues.warnings._resources import (
9
+ ResourceNotDefinedWarning,
10
+ ResourceRegexViolationWarning,
11
+ )
12
+ from cognite.neat._rules._constants import PATTERNS, EntityTypes
9
13
  from cognite.neat._rules.models.entities import ClassEntity, UnknownEntity
14
+ from cognite.neat._rules.models.entities._multi_value import MultiValueTypeInfo
10
15
 
11
16
  from ._rules import InformationRules
12
17
 
13
18
 
14
- class InformationPostValidation:
19
+ class InformationValidation:
15
20
  """This class does all the validation of the Information rules that have dependencies
16
21
  between components."""
17
22
 
@@ -25,14 +30,15 @@ class InformationPostValidation:
25
30
  def validate(self) -> IssueList:
26
31
  self._namespaces_reassigned()
27
32
  self._classes_without_properties()
33
+ self._undefined_classes()
28
34
  self._parent_class_defined()
29
35
  self._referenced_classes_exist()
30
36
  self._referenced_value_types_exist()
37
+ self._regex_compliance_with_dms()
31
38
 
32
39
  return self.issue_list
33
40
 
34
41
  def _classes_without_properties(self) -> None:
35
- # needs to be complete for this validation to pass
36
42
  defined_classes = {class_.class_ for class_ in self.classes}
37
43
  referred_classes = {property_.class_ for property_ in self.properties}
38
44
  class_parent_pairs = self._class_parent_pairs()
@@ -44,13 +50,27 @@ class InformationPostValidation:
44
50
  # same prefix, meaning same space
45
51
  if not class_parent_pairs[class_] and class_.prefix == self.metadata.prefix:
46
52
  self.issue_list.append(
47
- ResourceNotDefinedError[ClassEntity](
53
+ ResourceNotDefinedWarning(
48
54
  resource_type="class",
49
55
  identifier=class_,
50
- location="Classes sheet",
56
+ location="Properties sheet",
51
57
  )
52
58
  )
53
59
 
60
+ def _undefined_classes(self) -> None:
61
+ defined_classes = {class_.class_ for class_ in self.classes}
62
+ referred_classes = {property_.class_ for property_ in self.properties}
63
+
64
+ if undefined_classes := referred_classes.difference(defined_classes):
65
+ for class_ in undefined_classes:
66
+ self.issue_list.append(
67
+ ResourceNotDefinedError(
68
+ identifier=class_,
69
+ resource_type="class",
70
+ location="Classes sheet",
71
+ )
72
+ )
73
+
54
74
  def _parent_class_defined(self) -> None:
55
75
  """This is a validation to check if the parent class of a class is defined in the classes sheet."""
56
76
  class_parent_pairs = self._class_parent_pairs()
@@ -63,7 +83,7 @@ class InformationPostValidation:
63
83
  self.issue_list.append(UndefinedClassWarning(class_id=str(parent)))
64
84
  else:
65
85
  self.issue_list.append(
66
- ResourceNotDefinedError[ClassEntity](
86
+ ResourceNotDefinedWarning(
67
87
  resource_type="class",
68
88
  identifier=parent,
69
89
  location="Classes sheet",
@@ -79,7 +99,7 @@ class InformationPostValidation:
79
99
  if missing_classes := classes_with_explicit_properties.difference(defined_classes):
80
100
  for class_ in missing_classes:
81
101
  self.issue_list.append(
82
- ResourceNotDefinedError[ClassEntity](
102
+ ResourceNotDefinedWarning(
83
103
  resource_type="class",
84
104
  identifier=class_,
85
105
  location="Classes sheet",
@@ -99,13 +119,89 @@ class InformationPostValidation:
99
119
  # Todo: include row and column number
100
120
  for missing in missing_value_types:
101
121
  self.issue_list.append(
102
- ResourceNotDefinedError[ClassEntity](
122
+ ResourceNotDefinedWarning(
103
123
  resource_type="class",
104
- identifier=cast(ClassEntity, missing),
124
+ identifier=missing,
105
125
  location="Classes sheet",
106
126
  )
107
127
  )
108
128
 
129
+ def _regex_compliance_with_dms(self) -> None:
130
+ """Check regex compliance with DMS of properties, classes and value types."""
131
+
132
+ for prop_ in self.properties:
133
+ if not PATTERNS.dms_property_id_compliance.match(prop_.property_):
134
+ self.issue_list.append(
135
+ ResourceRegexViolationWarning(
136
+ prop_.property_,
137
+ "Property",
138
+ "Properties sheet, Property column",
139
+ PATTERNS.dms_property_id_compliance.pattern,
140
+ )
141
+ )
142
+ if not PATTERNS.view_id_compliance.match(prop_.class_.suffix):
143
+ self.issue_list.append(
144
+ ResourceRegexViolationWarning(
145
+ prop_.class_,
146
+ "Class",
147
+ "Properties sheet, Class column",
148
+ PATTERNS.view_id_compliance.pattern,
149
+ )
150
+ )
151
+
152
+ # Handling Value Type
153
+ if (
154
+ isinstance(prop_.value_type, ClassEntity)
155
+ and prop_.value_type != UnknownEntity()
156
+ and not PATTERNS.view_id_compliance.match(prop_.value_type.suffix)
157
+ ):
158
+ self.issue_list.append(
159
+ ResourceRegexViolationWarning(
160
+ prop_.value_type,
161
+ "Value Type",
162
+ "Properties sheet, Value Type column",
163
+ PATTERNS.view_id_compliance.pattern,
164
+ )
165
+ )
166
+ if isinstance(prop_.value_type, MultiValueTypeInfo):
167
+ for value_type in prop_.value_type.types:
168
+ if (
169
+ isinstance(prop_.value_type, ClassEntity)
170
+ and prop_.value_type != UnknownEntity()
171
+ and not PATTERNS.view_id_compliance.match(value_type.suffix)
172
+ ):
173
+ self.issue_list.append(
174
+ ResourceRegexViolationWarning(
175
+ value_type,
176
+ "Value Type",
177
+ "Properties sheet, Value Type column",
178
+ PATTERNS.view_id_compliance.pattern,
179
+ )
180
+ )
181
+
182
+ for class_ in self.classes:
183
+ if not PATTERNS.view_id_compliance.match(class_.class_.suffix):
184
+ self.issue_list.append(
185
+ ResourceRegexViolationWarning(
186
+ class_.class_,
187
+ "Class",
188
+ "Classes sheet, Class column",
189
+ PATTERNS.view_id_compliance.pattern,
190
+ )
191
+ )
192
+
193
+ if class_.implements:
194
+ for parent in class_.implements:
195
+ if not PATTERNS.view_id_compliance.match(parent.suffix):
196
+ self.issue_list.append(
197
+ ResourceRegexViolationWarning(
198
+ parent,
199
+ "Class",
200
+ "Classes sheet, Implements column",
201
+ PATTERNS.view_id_compliance.pattern,
202
+ )
203
+ )
204
+
109
205
  def _class_parent_pairs(self) -> dict[ClassEntity, list[ClassEntity]]:
110
206
  class_parent_pairs: dict[ClassEntity, list[ClassEntity]] = {}
111
207
  classes = self.rules.model_copy(deep=True).classes
@@ -32,7 +32,7 @@ def load_classic_to_core_mapping(org_name: str, source_space: str, source_versio
32
32
  if not isinstance(read.rules, DMSInputRules):
33
33
  raise NeatValueError(f"Expected DMS rules, but got {type(read.rules).__name__}")
34
34
 
35
- verified = VerifyDMSRules(errors="raise", post_validate=False).transform(read)
35
+ verified = VerifyDMSRules(errors="raise", validate=False).transform(read)
36
36
 
37
37
  if verified.rules is None:
38
38
  raise NeatValueError("Failed to verify the rules.")
@@ -65,7 +65,7 @@ properties:
65
65
  index: source
66
66
  is_list: false
67
67
  nullable: true
68
- value_type: cdf_cdm:SourceSystem(version=v1)
68
+ value_type: cdf_cdm:CogniteSourceSystem(version=v1)
69
69
  view: ClassicAsset
70
70
  view_property: source
71
71
  - container: cdf_cdm:CogniteDescribable
@@ -124,7 +124,7 @@ properties:
124
124
  index: source
125
125
  is_list: false
126
126
  nullable: true
127
- value_type: cdf_cdm:SourceSystem(version=v1)
127
+ value_type: cdf_cdm:CogniteSourceSystem(version=v1)
128
128
  view: ClassicEvent
129
129
  view_property: source
130
130
  - container: cdf_cdm:CogniteSchedulable
@@ -196,7 +196,7 @@ properties:
196
196
  index: source
197
197
  is_list: false
198
198
  nullable: true
199
- value_type: cdf_cdm:SourceSystem(version=v1)
199
+ value_type: cdf_cdm:CogniteSourceSystem(version=v1)
200
200
  view: ClassicFile
201
201
  view_property: source
202
202
  - container: cdf_cdm:CogniteSourceable
@@ -306,7 +306,7 @@ properties:
306
306
  is_list: false
307
307
  name: Unit
308
308
  nullable: true
309
- value_type: Unit
309
+ value_type: cdf_cdm:CogniteUnit(version=v1)
310
310
  view: ClassicTimeSeries
311
311
  view_property: unitExternalId
312
312
  views:
@@ -315,6 +315,10 @@ views:
315
315
  implements: cdf_cdm:CogniteDescribable(version=v1)
316
316
  in_model: true
317
317
  view: cdf_cdm:CogniteSourceSystem(version=v1)
318
+ - description: Represents a single unit of measurement
319
+ implements: cdf_cdm:CogniteDescribable(version=v1)
320
+ in_model: true
321
+ view: cdf_cdm:CogniteUnit(version=v1)
318
322
  - description: Assets represent systems that support industrial functions or processes.
319
323
  Assets are often called 'functional location'.
320
324
  implements: cdf_cdm:CogniteAsset(version=v1)
@@ -9,7 +9,7 @@ from ._converters import (
9
9
  ToCompliantEntities,
10
10
  ToExtension,
11
11
  )
12
- from ._mapping import MapOneToOne, RuleMapper
12
+ from ._mapping import AsParentPropertyId, MapOneToOne, RuleMapper
13
13
  from ._pipelines import ImporterPipeline
14
14
  from ._verification import VerifyAnyRules, VerifyDMSRules, VerifyInformationRules
15
15
 
@@ -30,4 +30,5 @@ __all__ = [
30
30
  "ToExtension",
31
31
  "ReduceCogniteModel",
32
32
  "SetIDDMSModel",
33
+ "AsParentPropertyId",
33
34
  ]