cognite-neat 0.97.2__py3-none-any.whl → 0.98.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 (66) hide show
  1. cognite/neat/_graph/loaders/__init__.py +1 -2
  2. cognite/neat/_graph/queries/_base.py +25 -4
  3. cognite/neat/_issues/warnings/_models.py +9 -0
  4. cognite/neat/_rules/_shared.py +3 -8
  5. cognite/neat/_rules/analysis/__init__.py +1 -2
  6. cognite/neat/_rules/analysis/_base.py +2 -23
  7. cognite/neat/_rules/analysis/_dms.py +4 -10
  8. cognite/neat/_rules/analysis/_information.py +2 -10
  9. cognite/neat/_rules/catalog/info-rules-imf.xlsx +0 -0
  10. cognite/neat/_rules/exporters/_rules2excel.py +15 -72
  11. cognite/neat/_rules/exporters/_rules2ontology.py +4 -4
  12. cognite/neat/_rules/importers/_base.py +3 -4
  13. cognite/neat/_rules/importers/_dms2rules.py +17 -40
  14. cognite/neat/_rules/importers/_dtdl2rules/dtdl_converter.py +1 -7
  15. cognite/neat/_rules/importers/_dtdl2rules/dtdl_importer.py +7 -10
  16. cognite/neat/_rules/importers/_rdf/_base.py +17 -29
  17. cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2classes.py +2 -2
  18. cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2metadata.py +5 -10
  19. cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2properties.py +1 -2
  20. cognite/neat/_rules/importers/_rdf/_inference2rules.py +30 -18
  21. cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2classes.py +2 -2
  22. cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2metadata.py +5 -8
  23. cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2properties.py +1 -2
  24. cognite/neat/_rules/importers/_rdf/_shared.py +25 -140
  25. cognite/neat/_rules/importers/_spreadsheet2rules.py +10 -41
  26. cognite/neat/_rules/models/__init__.py +2 -16
  27. cognite/neat/_rules/models/_base_rules.py +98 -52
  28. cognite/neat/_rules/models/dms/_exporter.py +7 -160
  29. cognite/neat/_rules/models/dms/_rules.py +18 -126
  30. cognite/neat/_rules/models/dms/_rules_input.py +20 -48
  31. cognite/neat/_rules/models/dms/_schema.py +11 -0
  32. cognite/neat/_rules/models/dms/_validation.py +9 -122
  33. cognite/neat/_rules/models/information/_rules.py +19 -114
  34. cognite/neat/_rules/models/information/_rules_input.py +32 -41
  35. cognite/neat/_rules/models/information/_validation.py +34 -102
  36. cognite/neat/_rules/transformers/__init__.py +1 -4
  37. cognite/neat/_rules/transformers/_converters.py +18 -195
  38. cognite/neat/_rules/transformers/_mapping.py +1 -5
  39. cognite/neat/_rules/transformers/_verification.py +0 -14
  40. cognite/neat/_session/_base.py +37 -13
  41. cognite/neat/_session/_collector.py +126 -0
  42. cognite/neat/_session/_inspect.py +5 -5
  43. cognite/neat/_session/_prepare.py +37 -11
  44. cognite/neat/_session/_read.py +62 -9
  45. cognite/neat/_session/_set.py +2 -2
  46. cognite/neat/_session/_show.py +11 -11
  47. cognite/neat/_session/_to.py +24 -11
  48. cognite/neat/_session/exceptions.py +20 -3
  49. cognite/neat/_store/_provenance.py +2 -2
  50. cognite/neat/_utils/auxiliary.py +19 -0
  51. cognite/neat/_version.py +1 -1
  52. cognite/neat/_workflows/steps/data_contracts.py +2 -10
  53. cognite/neat/_workflows/steps/lib/current/rules_exporter.py +6 -46
  54. cognite/neat/_workflows/steps/lib/current/rules_validator.py +2 -7
  55. {cognite_neat-0.97.2.dist-info → cognite_neat-0.98.0.dist-info}/METADATA +2 -1
  56. {cognite_neat-0.97.2.dist-info → cognite_neat-0.98.0.dist-info}/RECORD +59 -65
  57. cognite/neat/_graph/loaders/_rdf2asset.py +0 -416
  58. cognite/neat/_rules/analysis/_asset.py +0 -173
  59. cognite/neat/_rules/models/asset/__init__.py +0 -13
  60. cognite/neat/_rules/models/asset/_rules.py +0 -109
  61. cognite/neat/_rules/models/asset/_rules_input.py +0 -101
  62. cognite/neat/_rules/models/asset/_validation.py +0 -45
  63. cognite/neat/_rules/models/domain.py +0 -136
  64. {cognite_neat-0.97.2.dist-info → cognite_neat-0.98.0.dist-info}/LICENSE +0 -0
  65. {cognite_neat-0.97.2.dist-info → cognite_neat-0.98.0.dist-info}/WHEEL +0 -0
  66. {cognite_neat-0.97.2.dist-info → cognite_neat-0.98.0.dist-info}/entry_points.txt +0 -0
@@ -4,10 +4,9 @@ from typing import cast
4
4
 
5
5
  from cognite.neat._issues import IssueList
6
6
  from cognite.neat._issues.errors import NeatValueError, ResourceNotDefinedError
7
+ from cognite.neat._issues.warnings._models import UndefinedClassWarning
7
8
  from cognite.neat._rules._constants import EntityTypes
8
- from cognite.neat._rules.models._base_rules import DataModelType, SchemaCompleteness
9
9
  from cognite.neat._rules.models.entities import ClassEntity, UnknownEntity
10
- from cognite.neat._utils.rdf_ import get_inheritance_path
11
10
 
12
11
  from ._rules import InformationRules
13
12
 
@@ -24,72 +23,60 @@ class InformationPostValidation:
24
23
  self.issue_list = IssueList()
25
24
 
26
25
  def validate(self) -> IssueList:
27
- if self.metadata.schema_ == SchemaCompleteness.partial:
28
- return self.issue_list
29
-
30
- if self.metadata.data_model_type == DataModelType.solution and not self.rules.reference:
31
- raise ValueError("Reference data model is missing")
32
-
33
- if self.metadata.schema_ == SchemaCompleteness.extended and not self.rules.last:
34
- raise ValueError("Last version is missing")
35
-
36
- self._dangling_classes()
37
- self._referenced_parent_classes_exist()
26
+ self._namespaces_reassigned()
27
+ self._classes_without_properties()
28
+ self._parent_class_defined()
38
29
  self._referenced_classes_exist()
39
30
  self._referenced_value_types_exist()
40
- self._namespaces_reassigned()
41
31
 
42
32
  return self.issue_list
43
33
 
44
- def _dangling_classes(self) -> None:
34
+ def _classes_without_properties(self) -> None:
45
35
  # needs to be complete for this validation to pass
46
36
  defined_classes = {class_.class_ for class_ in self.classes}
47
37
  referred_classes = {property_.class_ for property_ in self.properties}
48
38
  class_parent_pairs = self._class_parent_pairs()
49
- dangling_classes = set()
50
39
 
51
40
  if classes_without_properties := defined_classes.difference(referred_classes):
52
41
  for class_ in classes_without_properties:
53
- # USE CASE: class has no direct properties and no parents
54
- if class_ not in class_parent_pairs:
55
- dangling_classes.add(class_)
56
42
  # USE CASE: class has no direct properties and no parents with properties
57
- elif class_ not in class_parent_pairs and not any(
58
- parent in referred_classes for parent in get_inheritance_path(class_, class_parent_pairs)
59
- ):
60
- dangling_classes.add(class_)
61
-
62
- for class_ in dangling_classes:
63
- self.issue_list.append(
64
- NeatValueError(f"Class {class_} has no properties and is not a parent of any class with properties")
65
- )
43
+ # and it is a class in the prefix of data model, as long as it is in the
44
+ # same prefix, meaning same space
45
+ if not class_parent_pairs[class_] and class_.prefix == self.metadata.prefix:
46
+ self.issue_list.append(
47
+ ResourceNotDefinedError[ClassEntity](
48
+ resource_type="class",
49
+ identifier=class_,
50
+ location="Classes sheet",
51
+ )
52
+ )
66
53
 
67
- def _referenced_parent_classes_exist(self) -> None:
68
- # needs to be complete for this validation to pass
54
+ def _parent_class_defined(self) -> None:
55
+ """This is a validation to check if the parent class of a class is defined in the classes sheet."""
69
56
  class_parent_pairs = self._class_parent_pairs()
70
57
  classes = set(class_parent_pairs.keys())
71
58
  parents = set(itertools.chain.from_iterable(class_parent_pairs.values()))
72
59
 
73
60
  if undefined_parents := parents.difference(classes):
74
61
  for parent in undefined_parents:
75
- # Todo: include row and column number
76
- self.issue_list.append(
77
- ResourceNotDefinedError[ClassEntity](
78
- resource_type="class",
79
- identifier=parent,
80
- location="Classes sheet",
62
+ if parent.prefix != self.metadata.prefix:
63
+ self.issue_list.append(UndefinedClassWarning(class_id=str(parent)))
64
+ else:
65
+ self.issue_list.append(
66
+ ResourceNotDefinedError[ClassEntity](
67
+ resource_type="class",
68
+ identifier=parent,
69
+ location="Classes sheet",
70
+ )
81
71
  )
82
- )
83
72
 
84
73
  def _referenced_classes_exist(self) -> None:
85
74
  # needs to be complete for this validation to pass
86
75
  defined_classes = {class_.class_ for class_ in self.classes}
87
- referred_classes = {property_.class_ for property_ in self.properties}
76
+ classes_with_explicit_properties = {property_.class_ for property_ in self.properties}
88
77
 
89
78
  # USE CASE: models are complete
90
- if self.metadata.schema_ == SchemaCompleteness.complete and (
91
- missing_classes := referred_classes.difference(defined_classes)
92
- ):
79
+ if missing_classes := classes_with_explicit_properties.difference(defined_classes):
93
80
  for class_ in missing_classes:
94
81
  self.issue_list.append(
95
82
  ResourceNotDefinedError[ClassEntity](
@@ -99,19 +86,6 @@ class InformationPostValidation:
99
86
  )
100
87
  )
101
88
 
102
- # USE CASE: models are extended (user + last = complete)
103
- if self.metadata.schema_ == SchemaCompleteness.extended:
104
- defined_classes |= {class_.class_ for class_ in cast(InformationRules, self.rules.last).classes}
105
- if missing_classes := referred_classes.difference(defined_classes):
106
- for class_ in missing_classes:
107
- self.issue_list.append(
108
- ResourceNotDefinedError[ClassEntity](
109
- resource_type="class",
110
- identifier=class_,
111
- location="Classes sheet",
112
- )
113
- )
114
-
115
89
  def _referenced_value_types_exist(self) -> None:
116
90
  # adding UnknownEntity to the set of defined classes to handle the case where a property references an unknown
117
91
  defined_classes = {class_.class_ for class_ in self.classes} | {UnknownEntity()}
@@ -121,10 +95,7 @@ class InformationPostValidation:
121
95
  if property_.type_ == EntityTypes.object_property
122
96
  }
123
97
 
124
- # USE CASE: models are complete
125
- if self.metadata.schema_ == SchemaCompleteness.complete and (
126
- missing_value_types := referred_object_types.difference(defined_classes)
127
- ):
98
+ if missing_value_types := referred_object_types.difference(defined_classes):
128
99
  # Todo: include row and column number
129
100
  for missing in missing_value_types:
130
101
  self.issue_list.append(
@@ -135,56 +106,17 @@ class InformationPostValidation:
135
106
  )
136
107
  )
137
108
 
138
- # USE CASE: models are extended (user + last = complete)
139
- if self.metadata.schema_ == SchemaCompleteness.extended:
140
- defined_classes |= {class_.class_ for class_ in cast(InformationRules, self.rules.last).classes}
141
- if missing_value_types := referred_object_types.difference(defined_classes):
142
- # Todo: include row and column number
143
- for missing in missing_value_types:
144
- self.issue_list.append(
145
- ResourceNotDefinedError(
146
- resource_type="class",
147
- identifier=cast(ClassEntity, missing),
148
- location="Classes sheet",
149
- )
150
- )
151
-
152
109
  def _class_parent_pairs(self) -> dict[ClassEntity, list[ClassEntity]]:
153
- class_subclass_pairs: dict[ClassEntity, list[ClassEntity]] = {}
154
-
110
+ class_parent_pairs: dict[ClassEntity, list[ClassEntity]] = {}
155
111
  classes = self.rules.model_copy(deep=True).classes
156
112
 
157
- # USE CASE: Solution model being extended (user + last + reference = complete)
158
- if (
159
- self.metadata.schema_ == SchemaCompleteness.extended
160
- and self.metadata.data_model_type == DataModelType.solution
161
- ):
162
- classes += (
163
- cast(InformationRules, self.rules.last).model_copy(deep=True).classes
164
- + cast(InformationRules, self.rules.reference).model_copy(deep=True).classes
165
- )
166
-
167
- # USE CASE: Solution model being created from scratch (user + reference = complete)
168
- elif (
169
- self.metadata.schema_ == SchemaCompleteness.complete
170
- and self.metadata.data_model_type == DataModelType.solution
171
- ):
172
- classes += cast(InformationRules, self.rules.reference).model_copy(deep=True).classes
173
-
174
- # USE CASE: Enterprise model being extended (user + last = complete)
175
- elif (
176
- self.metadata.schema_ == SchemaCompleteness.extended
177
- and self.metadata.data_model_type == DataModelType.enterprise
178
- ):
179
- classes += cast(InformationRules, self.rules.last).model_copy(deep=True).classes
180
-
181
113
  for class_ in classes:
182
- class_subclass_pairs[class_.class_] = []
183
- if class_.parent is None:
114
+ class_parent_pairs[class_.class_] = []
115
+ if class_.implements is None:
184
116
  continue
185
- class_subclass_pairs[class_.class_].extend(class_.parent)
117
+ class_parent_pairs[class_.class_].extend(class_.implements)
186
118
 
187
- return class_subclass_pairs
119
+ return class_parent_pairs
188
120
 
189
121
  def _namespaces_reassigned(self) -> None:
190
122
  prefixes = self.rules.prefixes.copy()
@@ -1,9 +1,7 @@
1
1
  from ._base import RulesPipeline, RulesTransformer
2
2
  from ._converters import (
3
- AssetToInformation,
4
3
  ConvertToRules,
5
4
  DMSToInformation,
6
- InformationToAsset,
7
5
  InformationToDMS,
8
6
  ReduceCogniteModel,
9
7
  SetIDDMSModel,
@@ -12,7 +10,7 @@ from ._converters import (
12
10
  )
13
11
  from ._mapping import MapOneToOne, RuleMapper
14
12
  from ._pipelines import ImporterPipeline
15
- from ._verification import VerifyAnyRules, VerifyAssetRules, VerifyDMSRules, VerifyInformationRules
13
+ from ._verification import VerifyAnyRules, VerifyDMSRules, VerifyInformationRules
16
14
 
17
15
  __all__ = [
18
16
  "ImporterPipeline",
@@ -23,7 +21,6 @@ __all__ = [
23
21
  "ConvertToRules",
24
22
  "AssetToInformation",
25
23
  "DMSToInformation",
26
- "VerifyAssetRules",
27
24
  "VerifyDMSRules",
28
25
  "VerifyInformationRules",
29
26
  "VerifyAnyRules",