cognite-neat 0.87.6__py3-none-any.whl → 0.88.1__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 (171) hide show
  1. cognite/neat/_version.py +1 -1
  2. cognite/neat/app/api/data_classes/rest.py +0 -19
  3. cognite/neat/app/api/explorer.py +6 -4
  4. cognite/neat/app/api/routers/configuration.py +1 -1
  5. cognite/neat/app/api/routers/crud.py +11 -21
  6. cognite/neat/app/api/routers/workflows.py +24 -94
  7. cognite/neat/app/ui/neat-app/build/asset-manifest.json +7 -7
  8. cognite/neat/app/ui/neat-app/build/index.html +1 -1
  9. cognite/neat/app/ui/neat-app/build/static/css/{main.38a62222.css → main.72e3d92e.css} +2 -2
  10. cognite/neat/app/ui/neat-app/build/static/css/main.72e3d92e.css.map +1 -0
  11. cognite/neat/app/ui/neat-app/build/static/js/main.5a52cf09.js +3 -0
  12. cognite/neat/app/ui/neat-app/build/static/js/{main.ec7f72e2.js.LICENSE.txt → main.5a52cf09.js.LICENSE.txt} +0 -9
  13. cognite/neat/app/ui/neat-app/build/static/js/main.5a52cf09.js.map +1 -0
  14. cognite/neat/config.py +44 -27
  15. cognite/neat/exceptions.py +6 -0
  16. cognite/neat/graph/extractors/_classic_cdf/_assets.py +21 -73
  17. cognite/neat/graph/extractors/_classic_cdf/_base.py +102 -0
  18. cognite/neat/graph/extractors/_classic_cdf/_events.py +46 -42
  19. cognite/neat/graph/extractors/_classic_cdf/_files.py +41 -45
  20. cognite/neat/graph/extractors/_classic_cdf/_labels.py +75 -52
  21. cognite/neat/graph/extractors/_classic_cdf/_relationships.py +49 -27
  22. cognite/neat/graph/extractors/_classic_cdf/_sequences.py +47 -50
  23. cognite/neat/graph/extractors/_classic_cdf/_timeseries.py +47 -49
  24. cognite/neat/graph/queries/_base.py +22 -29
  25. cognite/neat/graph/queries/_shared.py +1 -1
  26. cognite/neat/graph/stores/_base.py +24 -11
  27. cognite/neat/graph/transformers/_rdfpath.py +3 -2
  28. cognite/neat/issues.py +8 -0
  29. cognite/neat/rules/exporters/_rules2ontology.py +28 -20
  30. cognite/neat/rules/exporters/_validation.py +15 -21
  31. cognite/neat/rules/importers/_inference2rules.py +31 -35
  32. cognite/neat/rules/importers/_owl2rules/_owl2metadata.py +3 -7
  33. cognite/neat/rules/importers/_spreadsheet2rules.py +30 -27
  34. cognite/neat/rules/issues/dms.py +20 -0
  35. cognite/neat/rules/issues/importing.py +15 -0
  36. cognite/neat/rules/issues/ontology.py +298 -0
  37. cognite/neat/rules/issues/spreadsheet.py +48 -0
  38. cognite/neat/rules/issues/tables.py +72 -0
  39. cognite/neat/rules/models/_rdfpath.py +4 -4
  40. cognite/neat/rules/models/_types/_field.py +9 -19
  41. cognite/neat/rules/models/information/_rules.py +5 -4
  42. cognite/neat/utils/rdf_.py +17 -9
  43. cognite/neat/utils/regex_patterns.py +52 -0
  44. cognite/neat/workflows/steps/data_contracts.py +17 -43
  45. cognite/neat/workflows/steps/lib/current/graph_extractor.py +28 -24
  46. cognite/neat/workflows/steps/lib/current/graph_loader.py +4 -21
  47. cognite/neat/workflows/steps/lib/current/graph_store.py +18 -134
  48. cognite/neat/workflows/steps_registry.py +5 -7
  49. {cognite_neat-0.87.6.dist-info → cognite_neat-0.88.1.dist-info}/METADATA +2 -6
  50. cognite_neat-0.88.1.dist-info/RECORD +209 -0
  51. cognite/neat/app/api/routers/core.py +0 -91
  52. cognite/neat/app/api/routers/data_exploration.py +0 -336
  53. cognite/neat/app/api/routers/rules.py +0 -203
  54. cognite/neat/app/ui/neat-app/build/static/css/main.38a62222.css.map +0 -1
  55. cognite/neat/app/ui/neat-app/build/static/js/main.ec7f72e2.js +0 -3
  56. cognite/neat/app/ui/neat-app/build/static/js/main.ec7f72e2.js.map +0 -1
  57. cognite/neat/graph/stores/_oxrdflib.py +0 -247
  58. cognite/neat/legacy/__init__.py +0 -0
  59. cognite/neat/legacy/graph/__init__.py +0 -3
  60. cognite/neat/legacy/graph/examples/Knowledge-Graph-Nordic44-dirty.xml +0 -20182
  61. cognite/neat/legacy/graph/examples/Knowledge-Graph-Nordic44.xml +0 -20163
  62. cognite/neat/legacy/graph/examples/__init__.py +0 -10
  63. cognite/neat/legacy/graph/examples/skos-capturing-sheet-wind-topics.xlsx +0 -0
  64. cognite/neat/legacy/graph/exceptions.py +0 -90
  65. cognite/neat/legacy/graph/extractors/__init__.py +0 -6
  66. cognite/neat/legacy/graph/extractors/_base.py +0 -14
  67. cognite/neat/legacy/graph/extractors/_dexpi.py +0 -44
  68. cognite/neat/legacy/graph/extractors/_graph_capturing_sheet.py +0 -403
  69. cognite/neat/legacy/graph/extractors/_mock_graph_generator.py +0 -361
  70. cognite/neat/legacy/graph/loaders/__init__.py +0 -23
  71. cognite/neat/legacy/graph/loaders/_asset_loader.py +0 -511
  72. cognite/neat/legacy/graph/loaders/_base.py +0 -67
  73. cognite/neat/legacy/graph/loaders/_exceptions.py +0 -85
  74. cognite/neat/legacy/graph/loaders/core/__init__.py +0 -0
  75. cognite/neat/legacy/graph/loaders/core/labels.py +0 -58
  76. cognite/neat/legacy/graph/loaders/core/models.py +0 -136
  77. cognite/neat/legacy/graph/loaders/core/rdf_to_assets.py +0 -1046
  78. cognite/neat/legacy/graph/loaders/core/rdf_to_relationships.py +0 -559
  79. cognite/neat/legacy/graph/loaders/rdf_to_dms.py +0 -309
  80. cognite/neat/legacy/graph/loaders/validator.py +0 -87
  81. cognite/neat/legacy/graph/models.py +0 -6
  82. cognite/neat/legacy/graph/stores/__init__.py +0 -13
  83. cognite/neat/legacy/graph/stores/_base.py +0 -400
  84. cognite/neat/legacy/graph/stores/_graphdb_store.py +0 -52
  85. cognite/neat/legacy/graph/stores/_memory_store.py +0 -43
  86. cognite/neat/legacy/graph/stores/_oxigraph_store.py +0 -151
  87. cognite/neat/legacy/graph/stores/_oxrdflib.py +0 -247
  88. cognite/neat/legacy/graph/stores/_rdf_to_graph.py +0 -42
  89. cognite/neat/legacy/graph/transformations/__init__.py +0 -0
  90. cognite/neat/legacy/graph/transformations/entity_matcher.py +0 -101
  91. cognite/neat/legacy/graph/transformations/query_generator/__init__.py +0 -3
  92. cognite/neat/legacy/graph/transformations/query_generator/sparql.py +0 -575
  93. cognite/neat/legacy/graph/transformations/transformer.py +0 -322
  94. cognite/neat/legacy/rules/__init__.py +0 -0
  95. cognite/neat/legacy/rules/analysis.py +0 -231
  96. cognite/neat/legacy/rules/examples/Rules-Nordic44-to-graphql.xlsx +0 -0
  97. cognite/neat/legacy/rules/examples/Rules-Nordic44.xlsx +0 -0
  98. cognite/neat/legacy/rules/examples/__init__.py +0 -18
  99. cognite/neat/legacy/rules/examples/power-grid-containers.yaml +0 -124
  100. cognite/neat/legacy/rules/examples/power-grid-example.xlsx +0 -0
  101. cognite/neat/legacy/rules/examples/power-grid-model.yaml +0 -224
  102. cognite/neat/legacy/rules/examples/rules-template.xlsx +0 -0
  103. cognite/neat/legacy/rules/examples/sheet2cdf-transformation-rules.xlsx +0 -0
  104. cognite/neat/legacy/rules/examples/skos-rules.xlsx +0 -0
  105. cognite/neat/legacy/rules/examples/source-to-solution-mapping-rules.xlsx +0 -0
  106. cognite/neat/legacy/rules/examples/wind-energy.owl +0 -1511
  107. cognite/neat/legacy/rules/exceptions.py +0 -2972
  108. cognite/neat/legacy/rules/exporters/__init__.py +0 -20
  109. cognite/neat/legacy/rules/exporters/_base.py +0 -45
  110. cognite/neat/legacy/rules/exporters/_core/__init__.py +0 -5
  111. cognite/neat/legacy/rules/exporters/_core/rules2labels.py +0 -24
  112. cognite/neat/legacy/rules/exporters/_rules2dms.py +0 -885
  113. cognite/neat/legacy/rules/exporters/_rules2excel.py +0 -213
  114. cognite/neat/legacy/rules/exporters/_rules2graphql.py +0 -183
  115. cognite/neat/legacy/rules/exporters/_rules2ontology.py +0 -524
  116. cognite/neat/legacy/rules/exporters/_rules2pydantic_models.py +0 -748
  117. cognite/neat/legacy/rules/exporters/_rules2rules.py +0 -105
  118. cognite/neat/legacy/rules/exporters/_rules2triples.py +0 -38
  119. cognite/neat/legacy/rules/exporters/_validation.py +0 -146
  120. cognite/neat/legacy/rules/importers/__init__.py +0 -22
  121. cognite/neat/legacy/rules/importers/_base.py +0 -66
  122. cognite/neat/legacy/rules/importers/_dict2rules.py +0 -158
  123. cognite/neat/legacy/rules/importers/_dms2rules.py +0 -194
  124. cognite/neat/legacy/rules/importers/_graph2rules.py +0 -308
  125. cognite/neat/legacy/rules/importers/_json2rules.py +0 -39
  126. cognite/neat/legacy/rules/importers/_owl2rules/__init__.py +0 -3
  127. cognite/neat/legacy/rules/importers/_owl2rules/_owl2classes.py +0 -239
  128. cognite/neat/legacy/rules/importers/_owl2rules/_owl2metadata.py +0 -260
  129. cognite/neat/legacy/rules/importers/_owl2rules/_owl2properties.py +0 -217
  130. cognite/neat/legacy/rules/importers/_owl2rules/_owl2rules.py +0 -290
  131. cognite/neat/legacy/rules/importers/_spreadsheet2rules.py +0 -45
  132. cognite/neat/legacy/rules/importers/_xsd2rules.py +0 -20
  133. cognite/neat/legacy/rules/importers/_yaml2rules.py +0 -39
  134. cognite/neat/legacy/rules/models/__init__.py +0 -5
  135. cognite/neat/legacy/rules/models/_base.py +0 -151
  136. cognite/neat/legacy/rules/models/raw_rules.py +0 -316
  137. cognite/neat/legacy/rules/models/rdfpath.py +0 -237
  138. cognite/neat/legacy/rules/models/rules.py +0 -1289
  139. cognite/neat/legacy/rules/models/tables.py +0 -9
  140. cognite/neat/legacy/rules/models/value_types.py +0 -118
  141. cognite/neat/legacy/workflows/examples/Export_DMS/workflow.yaml +0 -89
  142. cognite/neat/legacy/workflows/examples/Export_Rules_to_Ontology/workflow.yaml +0 -152
  143. cognite/neat/legacy/workflows/examples/Extract_DEXPI_Graph_and_Export_Rules/workflow.yaml +0 -139
  144. cognite/neat/legacy/workflows/examples/Extract_RDF_Graph_and_Generate_Assets/workflow.yaml +0 -270
  145. cognite/neat/legacy/workflows/examples/Import_DMS/workflow.yaml +0 -65
  146. cognite/neat/legacy/workflows/examples/Ontology_to_Data_Model/workflow.yaml +0 -116
  147. cognite/neat/legacy/workflows/examples/Validate_Rules/workflow.yaml +0 -67
  148. cognite/neat/legacy/workflows/examples/Validate_Solution_Model/workflow.yaml +0 -64
  149. cognite/neat/legacy/workflows/examples/Visualize_Data_Model_Using_Mock_Graph/workflow.yaml +0 -95
  150. cognite/neat/legacy/workflows/examples/Visualize_Semantic_Data_Model/workflow.yaml +0 -111
  151. cognite/neat/rules/exceptions.py +0 -2972
  152. cognite/neat/rules/models/_types/_base.py +0 -16
  153. cognite/neat/workflows/examples/Export_Rules_to_Ontology/workflow.yaml +0 -152
  154. cognite/neat/workflows/examples/Extract_DEXPI_Graph_and_Export_Rules/workflow.yaml +0 -139
  155. cognite/neat/workflows/examples/Extract_RDF_Graph_and_Generate_Assets/workflow.yaml +0 -270
  156. cognite/neat/workflows/examples/Ontology_to_Data_Model/workflow.yaml +0 -116
  157. cognite/neat/workflows/migration/__init__.py +0 -0
  158. cognite/neat/workflows/migration/steps.py +0 -91
  159. cognite/neat/workflows/migration/wf_manifests.py +0 -33
  160. cognite/neat/workflows/steps/lib/legacy/__init__.py +0 -7
  161. cognite/neat/workflows/steps/lib/legacy/graph_contextualization.py +0 -82
  162. cognite/neat/workflows/steps/lib/legacy/graph_extractor.py +0 -746
  163. cognite/neat/workflows/steps/lib/legacy/graph_loader.py +0 -606
  164. cognite/neat/workflows/steps/lib/legacy/graph_store.py +0 -307
  165. cognite/neat/workflows/steps/lib/legacy/graph_transformer.py +0 -58
  166. cognite/neat/workflows/steps/lib/legacy/rules_exporter.py +0 -511
  167. cognite/neat/workflows/steps/lib/legacy/rules_importer.py +0 -612
  168. cognite_neat-0.87.6.dist-info/RECORD +0 -319
  169. {cognite_neat-0.87.6.dist-info → cognite_neat-0.88.1.dist-info}/LICENSE +0 -0
  170. {cognite_neat-0.87.6.dist-info → cognite_neat-0.88.1.dist-info}/WHEEL +0 -0
  171. {cognite_neat-0.87.6.dist-info → cognite_neat-0.88.1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,298 @@
1
+ from abc import ABC
2
+ from dataclasses import dataclass
3
+ from typing import ClassVar
4
+
5
+ from .base import NeatValidationError, ValidationWarning
6
+
7
+ __all__ = [
8
+ "OntologyError",
9
+ "OntologyWarning",
10
+ ]
11
+
12
+
13
+ @dataclass(frozen=True)
14
+ class OntologyError(NeatValidationError, ABC): ...
15
+
16
+
17
+ @dataclass(frozen=True)
18
+ class OntologyWarning(ValidationWarning, ABC): ...
19
+
20
+
21
+ @dataclass(frozen=True)
22
+ class OntologyMultiLabeledPropertyWarning(OntologyWarning):
23
+ """This warning occurs when a property is given multiple labels, typically if the
24
+ same property is defined for different classes but different name is given
25
+
26
+ Args:
27
+ property_id: property id that raised warning due to multiple labels
28
+ names: list of names of property
29
+
30
+ Notes:
31
+ This would be automatically fixed by taking the first label (aka name) of the property.
32
+ """
33
+
34
+ description = (
35
+ "This warning occurs when a property is given multiple labels,"
36
+ " typically if the same property is defined for different "
37
+ "classes but different name is given."
38
+ )
39
+ fix = "This would be automatically fixed by taking the first label (aka name) of the property."
40
+
41
+ property_id: str
42
+ names: list[str] | None = None
43
+
44
+ def message(self) -> str:
45
+ message = (
46
+ "Property should have single preferred label (human readable name)."
47
+ f"Currently property '{self.property_id}' has multiple preferred labels: {', '.join(self.names or [])} !"
48
+ f"Only the first name, i.e. '{self.names[0] if self.names else ''}' will be considered!"
49
+ )
50
+ message += f"\nDescription: {self.description}"
51
+ message += f"\nFix: {self.fix}"
52
+ return message
53
+
54
+
55
+ @dataclass(frozen=True)
56
+ class OntologyMultiDefinitionPropertyWarning(OntologyWarning):
57
+ """This warning occurs when a property is given multiple human readable definitions,
58
+ typically if the same property is defined for different classes where each definition
59
+ is different.
60
+
61
+ Args:
62
+ property_id: property id that raised warning due to multiple definitions
63
+
64
+ Notes:
65
+ This would be automatically fixed by concatenating all definitions.
66
+ """
67
+
68
+ description = (
69
+ "This warning occurs when a property is given multiple human readable definitions,"
70
+ " typically if the same property is defined for different "
71
+ "classes where each definition is different."
72
+ )
73
+ fix = "This would be automatically fixed by concatenating all definitions."
74
+
75
+ property_id: str
76
+
77
+ def message(self):
78
+ message = (
79
+ f"Multiple definitions (aka comments) of property '{self.property_id}' detected."
80
+ " Definitions will be concatenated."
81
+ )
82
+ message += f"\nDescription: {self.description}"
83
+ message += f"\nFix: {self.fix}"
84
+ return message
85
+
86
+
87
+ @dataclass(frozen=True)
88
+ class OntologyMultiTypePropertyWarning(OntologyWarning):
89
+ """This warning occurs when a same property is define for two object/classes where
90
+ its expected value type is different in one definition, e.g. acts as an edge, while in
91
+ other definition acts as and attribute
92
+
93
+ Args:
94
+ property_id: property id that raised warning due to multi type definition
95
+ types: list of types of property
96
+
97
+ Notes:
98
+ If a property takes different value types for different objects, simply define
99
+ new property. It is bad practice to have multi type property!
100
+ """
101
+
102
+ description = (
103
+ "This warning occurs when a same property is define for two object/classes where"
104
+ " its expected value type is different in one definition, e.g. acts as an edge, while in "
105
+ "other definition acts as and attribute"
106
+ )
107
+ fix = "If a property takes different value types for different objects, simply define new property"
108
+
109
+ property_id: str
110
+ types: list[str] | None = None
111
+
112
+ def message(self) -> str:
113
+ message = (
114
+ "It is bad practice to have multi type property! "
115
+ f"Currently property '{self.property_id}' is defined as multi type property: {', '.join(self.types or [])}"
116
+ )
117
+ message += f"\nDescription: {self.description}"
118
+ message += f"\nFix: {self.fix}"
119
+ return message
120
+
121
+
122
+ @dataclass(frozen=True)
123
+ class OntologyMultiRangePropertyWarning(OntologyWarning):
124
+ """This warning occurs when a property takes range of values which consists of union
125
+ of multiple value types
126
+
127
+ Args:
128
+ property_id: property id that raised warning due to multi range definition
129
+ range_of_values: list of ranges that property takes
130
+
131
+ Notes:
132
+ If a property takes different range of values, simply define new property.
133
+ """
134
+
135
+ description = (
136
+ "This warning occurs when a property takes range of values which consists of union of multiple value types."
137
+ )
138
+ fix = "If a property takes different range of values, simply define new property"
139
+ property_id: str
140
+ range_of_values: list[str] | None = None
141
+
142
+ def message(self) -> str:
143
+ message = (
144
+ "It is bad practice to have property that take various range of values! "
145
+ f"Currently property '{self.property_id}' has multiple ranges: {', '.join(self.range_of_values or [])}"
146
+ )
147
+ message += f"\nDescription: {self.description}"
148
+ message += f"\nFix: {self.fix}"
149
+ return message
150
+
151
+
152
+ @dataclass(frozen=True)
153
+ class OntologyMultiDomainPropertyWarning(OntologyWarning):
154
+ """This warning occurs when a property is reused for more than one classes
155
+
156
+ Args:
157
+ property_id: property id that raised warning due to reuse definition
158
+ classes: list of classes that use the same property
159
+ verbose: flag that indicates whether to provide enhanced exception message, by default False
160
+
161
+ Notes:
162
+ No need to fix this, but make sure that property type is consistent across different
163
+ classes and that ideally takes the same range of values
164
+ """
165
+
166
+ description = "This warning occurs when a property is reused for more than one classes."
167
+ fix = (
168
+ "No need to fix this, but make sure that property type is consistent"
169
+ " across different classes and that ideally takes the same range of values"
170
+ )
171
+ property_id: str
172
+ classes: list[str] | None = None
173
+
174
+ def message(self) -> str:
175
+ message = (
176
+ f"Currently property '{self.property_id}' is defined for multiple classes: {', '.join(self.classes or [])}"
177
+ )
178
+ message += f"\nDescription: {self.description}"
179
+ message += f"\nFix: {self.fix}"
180
+ return message
181
+
182
+
183
+ @dataclass(frozen=True)
184
+ class PropertiesDefinedMultipleTimesError(OntologyError):
185
+ """This error is raised during export of Transformation Rules to DMS schema when
186
+ when properties are defined multiple times for the same class.
187
+
188
+ Args:
189
+ report: report on properties which are defined multiple times
190
+ verbose: flag that indicates whether to provide enhanced exception message, by default False
191
+
192
+ Notes:
193
+ Make sure to check validation report of Transformation Rules and fix DMS related warnings.
194
+ """
195
+
196
+ description = (
197
+ "This error is raised during export of Transformation Rules to "
198
+ "DMS schema when properties are defined multiple times for the same class."
199
+ )
200
+ fix = "Make sure to check validation report of Transformation Rules and fix DMS related warnings."
201
+
202
+ report: str
203
+
204
+ def message(self) -> str:
205
+ message = f"Following properties defined multiple times for the same class(es): {self.report}"
206
+
207
+ message += f"\nDescription: {self.description}"
208
+ message += f"\nFix: {self.fix}"
209
+ return message
210
+
211
+
212
+ @dataclass(frozen=True)
213
+ class PropertyDefinitionsNotForSamePropertyError(OntologyError):
214
+ """This error is raised if property definitions are not for linked to the same
215
+ property id when exporting rules to ontological representation.
216
+
217
+ Args:
218
+ verbose: flag that indicates whether to provide enhanced exception message, by default False
219
+ """
220
+
221
+ description = "This error is raised if property definitions are not for linked to the same property id"
222
+
223
+ def message(self):
224
+ message = "All definitions should have the same property_id! Aborting."
225
+
226
+ message += f"\nDescription: {self.description}"
227
+ return message
228
+
229
+
230
+ @dataclass(frozen=True)
231
+ class PrefixMissingError(OntologyError):
232
+ """Prefix, which is in the 'Metadata' sheet, is missing.
233
+
234
+ Args:
235
+ verbose: flag that indicates whether to provide enhanced exception message, by default False
236
+
237
+ """
238
+
239
+ description = "Prefix is missing from the 'Metadata' sheet."
240
+ example = "There is no prefix in the 'Metadata' sheet."
241
+ fix = "Specify the prefix if prefix in the 'Metadata' sheet."
242
+
243
+ def message(self) -> str:
244
+ message = "Missing prefix stored in 'Metadata' sheet."
245
+ message += f"\nDescription: {self.description}"
246
+ message += f"\nExample: {self.example}"
247
+ message += f"\nFix: {self.fix}"
248
+ return message
249
+
250
+
251
+ @dataclass(frozen=True)
252
+ class MissingDataModelPrefixOrNamespaceWarning(ValidationWarning):
253
+ """Prefix and/or namespace are missing in the 'Metadata' sheet
254
+
255
+ Args:
256
+ verbose: flag that indicates whether to provide enhanced exception message, by default False
257
+
258
+ Notes:
259
+ Add missing prefix and/or namespace in the 'Metadata' sheet
260
+ """
261
+
262
+ description = "Either prefix or namespace or both are missing in the 'Metadata' sheet"
263
+ fix = "Add missing prefix and/or namespace in the 'Metadata' sheet"
264
+
265
+ def message(self) -> str:
266
+ message = (
267
+ "Instances sheet is present but prefix and/or namespace are missing in 'Metadata' sheet."
268
+ "Instances sheet will not be processed!"
269
+ )
270
+ message += f"\nDescription: {self.description}"
271
+ message += f"\nFix: {self.fix}"
272
+ return message
273
+
274
+
275
+ @dataclass(frozen=True)
276
+ class MetadataSheetNamespaceNotDefinedError(OntologyError):
277
+ """namespace, which is in the 'Metadata' sheet, is not defined
278
+
279
+ Args:
280
+ namespace: namespace that raised exception
281
+ verbose: flag that indicates whether to provide enhanced exception message, by default False
282
+
283
+ Notes:
284
+ Check if `namespace` in the `Metadata` sheet is properly constructed as valid URL
285
+ containing only allowed characters.
286
+
287
+ """
288
+
289
+ description = "namespace, which is in the 'Metadata' sheet, is missing"
290
+ example: ClassVar[str] = "Example of a valid namespace 'http://www.w3.org/ns/sparql#'"
291
+ fix = "Define the 'namespace' in the 'Metadata' sheet."
292
+
293
+ def message(self) -> str:
294
+ message = "Missing namespace in 'Metadata' sheet."
295
+ message += f"\nDescription: {self.description}"
296
+ message += f"\nExample: {self.example}"
297
+ message += f"\nFix: {self.fix}"
298
+ return message
@@ -38,6 +38,7 @@ __all__ = [
38
38
  "MultiDefaultError",
39
39
  "MultiIndexError",
40
40
  "MultiUniqueConstraintError",
41
+ "RegexViolationError",
41
42
  ]
42
43
 
43
44
 
@@ -277,6 +278,24 @@ class PropertiesDefinedForUndefinedClassesError(NeatValidationError):
277
278
  )
278
279
 
279
280
 
281
+ @dataclass(frozen=True)
282
+ class RegexViolationError(NeatValidationError):
283
+ description = "Value, {value} failed regex, {regex}, validation."
284
+ fix = "Make sure that the name follows the regex pattern."
285
+
286
+ value: str
287
+ regex: str
288
+
289
+ def dump(self) -> dict[str, str]:
290
+ output = super().dump()
291
+ output["value"] = self.value
292
+ output["regex"] = self.regex
293
+ return output
294
+
295
+ def message(self) -> str:
296
+ return self.description.format(value=self.value, regex=self.regex)
297
+
298
+
280
299
  @dataclass(frozen=True)
281
300
  class ClassNoPropertiesNoParentError(NeatValidationError):
282
301
  description = "Class has no properties and no parents."
@@ -295,6 +314,35 @@ class ClassNoPropertiesNoParentError(NeatValidationError):
295
314
  return f"Class {self.classes[0]} have no direct or inherited properties. This may be a mistake."
296
315
 
297
316
 
317
+ @dataclass(frozen=True)
318
+ class DefaultValueTypeNotProperError(NeatValidationError):
319
+ """This exceptions is raised when default value type is not proper, i.e. it is not
320
+ according to the expected value type set in Rules.
321
+
322
+
323
+ Args:
324
+ default_value_type: default value type that raised exception
325
+ expected_value_type: expected value type that raised exception
326
+
327
+ """
328
+
329
+ description = (
330
+ "This exceptions is raised when default value type is not proper, i.e. it is not "
331
+ "according to the expected value type set in Rules."
332
+ )
333
+ property_id: str
334
+ default_value_type: str
335
+ expected_value_type: str
336
+
337
+ def message(self) -> str:
338
+ message = (
339
+ f"Default value for property {self.property_id} is of type {self.default_value_type} "
340
+ f"which is different from the expected value type {self.expected_value_type}!"
341
+ )
342
+ message += f"\nDescription: {self.description}"
343
+ return message
344
+
345
+
298
346
  @dataclass(frozen=True)
299
347
  class AssetRulesHaveCircularDependencyError(NeatValidationError):
300
348
  description = "Asset rules have circular dependencies."
@@ -0,0 +1,72 @@
1
+ from dataclasses import dataclass
2
+
3
+ from .base import NeatValidationError
4
+
5
+
6
+ @dataclass(frozen=True)
7
+ class NotValidRDFPathError(NeatValidationError):
8
+ """Provided `rdfpath` is not valid, i.e. it cannot be converted to SPARQL query.
9
+
10
+ Args:
11
+ rdf_path: `rdfpath` that raised exception
12
+
13
+ Notes:
14
+ Get familiar with `rdfpath` to avoid this exception.
15
+ """
16
+
17
+ description = "Provided `rdfpath` is not valid, i.e. it cannot be converted to SPARQL query"
18
+ fix = "Get familiar with `rdfpath` and check if provided path is valid!"
19
+ rdf_path: str
20
+
21
+ def message(self) -> str:
22
+ message = f"{self.rdf_path} is not a valid rdfpath!"
23
+
24
+ message += f"\nDescription: {self.description}"
25
+ message += f"\nFix: {self.fix}"
26
+ return message
27
+
28
+
29
+ @dataclass(frozen=True)
30
+ class NotValidTableLookUpError(NeatValidationError):
31
+ """Provided `table lookup` is not valid, i.e. it cannot be converted to CDF lookup.
32
+
33
+ Args:
34
+ table_look_up: `table_look_up`, a part of `rawlookup`, that raised exception
35
+
36
+ Notes:
37
+ Get familiar with `rawlookup` and `rdfpath` to avoid this exception.
38
+ """
39
+
40
+ description = "Provided table lookup is not valid, i.e. it cannot be converted to CDF lookup"
41
+ fix = "Get familiar with RAW look up and RDF paths and check if provided rawlookup is valid"
42
+ table_look_up: str
43
+
44
+ def message(self) -> str:
45
+ message = f"{self.table_look_up} is not a valid table lookup"
46
+
47
+ message += f"\nDescription: {self.description}"
48
+ message += f"\nFix: {self.fix}"
49
+ return message
50
+
51
+
52
+ @dataclass(frozen=True)
53
+ class NotValidRAWLookUpError(NeatValidationError):
54
+ """Provided `rawlookup` is not valid, i.e. it cannot be converted to SPARQL query and CDF lookup
55
+
56
+ Args:
57
+ raw_look_up: `rawlookup` rule that raised exception
58
+
59
+ Notes:
60
+ Get familiar with `rawlookup` and `rdfpath` to avoid this exception.
61
+ """
62
+
63
+ description = "Provided rawlookup is not valid, i.e. it cannot be converted to SPARQL query and CDF lookup"
64
+ fix = "Get familiar with `rawlookup` and `rdfpath` to avoid this exception"
65
+ raw_look_up: str
66
+
67
+ def message(self):
68
+ message = f"Invalid rawlookup expected traversal | table lookup, got {self.raw_look_up}"
69
+
70
+ message += f"\nDescription: {self.description}"
71
+ message += f"\nFix: {self.fix}"
72
+ return message
@@ -8,7 +8,7 @@ from typing import ClassVar, Literal
8
8
 
9
9
  from pydantic import BaseModel, field_validator, model_serializer
10
10
 
11
- from cognite.neat.rules import exceptions
11
+ from cognite.neat.rules.issues.tables import NotValidRAWLookUpError, NotValidRDFPathError, NotValidTableLookUpError
12
12
 
13
13
  if sys.version_info >= (3, 11):
14
14
  from enum import StrEnum
@@ -313,7 +313,7 @@ def parse_traversal(raw: str) -> SelfReferenceProperty | SingleProperty | Hop:
313
313
  elif result := HOP_REGEX_COMPILED.match(raw):
314
314
  return Hop.from_string(class_=result.group("origin"), traversal=result.group(_traversal))
315
315
  else:
316
- raise exceptions.NotValidRDFPath(raw).to_pydantic_custom_error()
316
+ raise NotValidRDFPathError(raw).as_pydantic_exception()
317
317
 
318
318
 
319
319
  def parse_table_lookup(raw: str) -> TableLookup:
@@ -323,7 +323,7 @@ def parse_table_lookup(raw: str) -> TableLookup:
323
323
  key=result.group(Lookup.key),
324
324
  value=result.group(Lookup.value),
325
325
  )
326
- raise exceptions.NotValidTableLookUp(raw).to_pydantic_custom_error()
326
+ raise NotValidTableLookUpError(raw).as_pydantic_exception()
327
327
 
328
328
 
329
329
  def parse_rule(rule_raw: str, rule_type: TransformationRuleType | None) -> RDFPath:
@@ -334,7 +334,7 @@ def parse_rule(rule_raw: str, rule_type: TransformationRuleType | None) -> RDFPa
334
334
  case TransformationRuleType.rawlookup:
335
335
  rule_raw = rule_raw.replace(" ", "")
336
336
  if Counter(rule_raw).get("|") != 1:
337
- raise exceptions.NotValidRAWLookUp(rule_raw).to_pydantic_custom_error()
337
+ raise NotValidRAWLookUpError(rule_raw).as_pydantic_exception()
338
338
  traversal, table_lookup = rule_raw.split("|")
339
339
  return RawLookup(
340
340
  traversal=parse_traversal(traversal),
@@ -1,7 +1,6 @@
1
- import re
2
1
  import warnings
3
2
  from collections.abc import Callable
4
- from typing import Annotated, Any, cast
3
+ from typing import Annotated, Any
5
4
 
6
5
  import rdflib
7
6
  from pydantic import (
@@ -17,11 +16,10 @@ from pydantic import (
17
16
  from pydantic.functional_serializers import PlainSerializer
18
17
  from pydantic_core import PydanticCustomError
19
18
 
20
- from cognite.neat.rules import exceptions
21
19
  from cognite.neat.rules.issues.importing import MoreThanOneNonAlphanumericCharacterWarning
22
-
23
- from ._base import (
24
- MORE_THAN_ONE_NONE_ALPHANUMERIC_REGEX,
20
+ from cognite.neat.rules.issues.spreadsheet import RegexViolationError
21
+ from cognite.neat.utils.regex_patterns import (
22
+ PATTERNS,
25
23
  PREFIX_COMPLIANCE_REGEX,
26
24
  PROPERTY_ID_COMPLIANCE_REGEX,
27
25
  VERSION_COMPLIANCE_REGEX,
@@ -74,11 +72,7 @@ NamespaceType = Annotated[
74
72
  PrefixType = Annotated[
75
73
  str,
76
74
  StringConstraints(pattern=PREFIX_COMPLIANCE_REGEX),
77
- _custom_error(
78
- lambda _, value: exceptions.PrefixesRegexViolation(
79
- cast(list[str], [value]), PREFIX_COMPLIANCE_REGEX
80
- ).to_pydantic_custom_error()
81
- ),
75
+ _custom_error(lambda _, value: RegexViolationError(value, PREFIX_COMPLIANCE_REGEX).as_pydantic_exception()),
82
76
  ]
83
77
 
84
78
  ExternalIdType = Annotated[
@@ -89,18 +83,14 @@ ExternalIdType = Annotated[
89
83
  VersionType = Annotated[
90
84
  str,
91
85
  StringConstraints(pattern=VERSION_COMPLIANCE_REGEX),
92
- _custom_error(
93
- lambda _, value: exceptions.VersionRegexViolation(
94
- version=cast(str, value), regex_expression=VERSION_COMPLIANCE_REGEX
95
- ).to_pydantic_custom_error()
96
- ),
86
+ _custom_error(lambda _, value: RegexViolationError(value, VERSION_COMPLIANCE_REGEX).as_pydantic_exception()),
97
87
  ]
98
88
 
99
89
 
100
90
  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):
91
+ if not PATTERNS.property_id_compliance.match(value):
92
+ _raise(RegexViolationError(value, PROPERTY_ID_COMPLIANCE_REGEX).as_pydantic_exception())
93
+ if PATTERNS.more_than_one_alphanumeric.search(value):
104
94
  warnings.warn(MoreThanOneNonAlphanumericCharacterWarning("property", value), stacklevel=2)
105
95
  return value
106
96
 
@@ -9,7 +9,8 @@ from rdflib import Namespace
9
9
 
10
10
  from cognite.neat.constants import get_default_prefixes
11
11
  from cognite.neat.issues import MultiValueError
12
- from cognite.neat.rules import exceptions, issues
12
+ from cognite.neat.rules import issues
13
+ from cognite.neat.rules.issues.spreadsheet import DefaultValueTypeNotProperError
13
14
  from cognite.neat.rules.models._base import (
14
15
  BaseMetadata,
15
16
  BaseRules,
@@ -227,11 +228,11 @@ class InformationProperty(SheetEntity):
227
228
  self.default = self.value_type.python(self.default)
228
229
 
229
230
  except Exception:
230
- exceptions.DefaultValueTypeNotProper(
231
+ raise DefaultValueTypeNotProperError(
231
232
  self.property_,
232
233
  type(self.default),
233
- self.value_type.python,
234
- )
234
+ str(self.value_type.python),
235
+ ).as_exception() from None
235
236
  return self
236
237
 
237
238
  @property
@@ -1,6 +1,8 @@
1
1
  import re
2
- from typing import Any, Literal, TypeAlias, cast, overload
2
+ from collections.abc import Iterable
3
+ from typing import Any, Literal, TypeAlias, overload
3
4
 
5
+ from cognite.client.utils.useful_types import SequenceNotStr
4
6
  from pydantic import HttpUrl, TypeAdapter, ValidationError
5
7
  from rdflib import Literal as RdfLiteral
6
8
  from rdflib import Namespace, URIRef
@@ -10,7 +12,8 @@ Triple: TypeAlias = tuple[URIRef, URIRef, RdfLiteral | URIRef]
10
12
 
11
13
  @overload
12
14
  def remove_namespace_from_uri(
13
- *URI: URIRef | str,
15
+ URI: URIRef | str,
16
+ *,
14
17
  special_separator: str = "#_",
15
18
  validation: Literal["full", "prefix"] = "prefix",
16
19
  ) -> str: ...
@@ -18,17 +21,19 @@ def remove_namespace_from_uri(
18
21
 
19
22
  @overload
20
23
  def remove_namespace_from_uri(
21
- *URI: tuple[URIRef | str, ...],
24
+ URI: SequenceNotStr[URIRef | str],
25
+ *,
22
26
  special_separator: str = "#_",
23
27
  validation: Literal["full", "prefix"] = "prefix",
24
- ) -> tuple[str, ...]: ...
28
+ ) -> list[str]: ...
25
29
 
26
30
 
27
31
  def remove_namespace_from_uri(
28
- *URI: URIRef | str | tuple[URIRef | str, ...],
32
+ URI: URIRef | str | SequenceNotStr[URIRef | str],
33
+ *,
29
34
  special_separator: str = "#_",
30
35
  validation: Literal["full", "prefix"] = "prefix",
31
- ) -> tuple[str, ...] | str:
36
+ ) -> str | list[str]:
32
37
  """Removes namespace from URI
33
38
 
34
39
  Args
@@ -51,11 +56,14 @@ def remove_namespace_from_uri(
51
56
  >>> remove_namespace_from_uri("http://www.example.org/index.html#section2", "http://www.example.org/index.html#section3")
52
57
  ('section2', 'section3')
53
58
  """
59
+ is_single = False
60
+ uris: Iterable[str | URIRef]
54
61
  if isinstance(URI, str | URIRef):
55
62
  uris = (URI,)
56
- elif isinstance(URI, tuple):
63
+ is_single = True
64
+ elif isinstance(URI, SequenceNotStr):
57
65
  # Assume that all elements in the tuple are of the same type following type hint
58
- uris = cast(tuple[URIRef | str, ...], URI)
66
+ uris = URI
59
67
  else:
60
68
  raise TypeError(f"URI must be of type URIRef or str, got {type(URI)}")
61
69
 
@@ -73,7 +81,7 @@ def remove_namespace_from_uri(
73
81
  else:
74
82
  output.append(str(u))
75
83
 
76
- return tuple(output) if len(output) > 1 else output[0]
84
+ return output[0] if is_single else output
77
85
 
78
86
 
79
87
  def get_namespace(URI: URIRef, special_separator: str = "#_") -> str:
@@ -0,0 +1,52 @@
1
+ import re
2
+ from functools import cached_property
3
+
4
+ MORE_THAN_ONE_NONE_ALPHANUMERIC_REGEX = r"([_-]{2,})"
5
+ PREFIX_COMPLIANCE_REGEX = r"^([a-zA-Z]+)([a-zA-Z0-9]*[_-]{0,1}[a-zA-Z0-9_-]*)([a-zA-Z0-9]*)$"
6
+
7
+ VIEW_ID_COMPLIANCE_REGEX = (
8
+ r"(?!^(Query|Mutation|Subscription|String|Int32|Int64|Int|Float32|Float64|Float|"
9
+ r"Timestamp|JSONObject|Date|Numeric|Boolean|PageInfo|File|Sequence|TimeSeries)$)"
10
+ r"(^[a-zA-Z][a-zA-Z0-9_]{0,253}[a-zA-Z0-9]?$)"
11
+ )
12
+ DMS_PROPERTY_ID_COMPLIANCE_REGEX = (
13
+ r"(?!^(space|externalId|createdTime|lastUpdatedTime|deletedTime|edge_id|"
14
+ r"node_id|project_id|property_group|seq|tg_table_name|extensions)$)"
15
+ r"(^[a-zA-Z][a-zA-Z0-9_]{0,253}[a-zA-Z0-9]?$)"
16
+ )
17
+ CLASS_ID_COMPLIANCE_REGEX = r"(?!^(Class|class)$)(^[a-zA-Z][a-zA-Z0-9._-]{0,253}[a-zA-Z0-9]?$)"
18
+ PROPERTY_ID_COMPLIANCE_REGEX = r"^(\*)|(?!^(Property|property)$)(^[a-zA-Z][a-zA-Z0-9._-]{0,253}[a-zA-Z0-9]?$)"
19
+ VERSION_COMPLIANCE_REGEX = r"^[a-zA-Z0-9]([.a-zA-Z0-9_-]{0,41}[a-zA-Z0-9])?$"
20
+
21
+
22
+ class _Patterns:
23
+ @cached_property
24
+ def more_than_one_alphanumeric(self) -> re.Pattern:
25
+ return re.compile(MORE_THAN_ONE_NONE_ALPHANUMERIC_REGEX)
26
+
27
+ @cached_property
28
+ def prefix_compliance(self) -> re.Pattern[str]:
29
+ return re.compile(PREFIX_COMPLIANCE_REGEX)
30
+
31
+ @cached_property
32
+ def view_id_compliance(self) -> re.Pattern[str]:
33
+ return re.compile(VIEW_ID_COMPLIANCE_REGEX)
34
+
35
+ @cached_property
36
+ def dms_property_id_compliance(self) -> re.Pattern[str]:
37
+ return re.compile(DMS_PROPERTY_ID_COMPLIANCE_REGEX)
38
+
39
+ @cached_property
40
+ def class_id_compliance(self) -> re.Pattern[str]:
41
+ return re.compile(CLASS_ID_COMPLIANCE_REGEX)
42
+
43
+ @cached_property
44
+ def property_id_compliance(self) -> re.Pattern[str]:
45
+ return re.compile(PROPERTY_ID_COMPLIANCE_REGEX)
46
+
47
+ @cached_property
48
+ def version_compliance(self) -> re.Pattern[str]:
49
+ return re.compile(VERSION_COMPLIANCE_REGEX)
50
+
51
+
52
+ PATTERNS = _Patterns()