cognite-neat 0.88.0__py3-none-any.whl → 0.88.2__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 (99) hide show
  1. cognite/neat/_version.py +1 -1
  2. cognite/neat/app/api/routers/configuration.py +1 -1
  3. cognite/neat/app/ui/neat-app/build/asset-manifest.json +7 -7
  4. cognite/neat/app/ui/neat-app/build/index.html +1 -1
  5. cognite/neat/app/ui/neat-app/build/static/css/{main.38a62222.css → main.72e3d92e.css} +2 -2
  6. cognite/neat/app/ui/neat-app/build/static/css/main.72e3d92e.css.map +1 -0
  7. cognite/neat/app/ui/neat-app/build/static/js/main.5a52cf09.js +3 -0
  8. cognite/neat/app/ui/neat-app/build/static/js/{main.ec7f72e2.js.LICENSE.txt → main.5a52cf09.js.LICENSE.txt} +0 -9
  9. cognite/neat/app/ui/neat-app/build/static/js/main.5a52cf09.js.map +1 -0
  10. cognite/neat/config.py +44 -27
  11. cognite/neat/exceptions.py +8 -2
  12. cognite/neat/graph/extractors/_classic_cdf/_assets.py +21 -73
  13. cognite/neat/graph/extractors/_classic_cdf/_base.py +102 -0
  14. cognite/neat/graph/extractors/_classic_cdf/_events.py +46 -42
  15. cognite/neat/graph/extractors/_classic_cdf/_files.py +41 -45
  16. cognite/neat/graph/extractors/_classic_cdf/_labels.py +75 -52
  17. cognite/neat/graph/extractors/_classic_cdf/_relationships.py +49 -27
  18. cognite/neat/graph/extractors/_classic_cdf/_sequences.py +47 -50
  19. cognite/neat/graph/extractors/_classic_cdf/_timeseries.py +47 -49
  20. cognite/neat/graph/loaders/_base.py +4 -4
  21. cognite/neat/graph/loaders/_rdf2asset.py +12 -14
  22. cognite/neat/graph/loaders/_rdf2dms.py +14 -10
  23. cognite/neat/graph/queries/_base.py +22 -29
  24. cognite/neat/graph/queries/_shared.py +1 -1
  25. cognite/neat/graph/stores/_base.py +19 -11
  26. cognite/neat/graph/transformers/_rdfpath.py +3 -2
  27. cognite/neat/issues/__init__.py +16 -0
  28. cognite/neat/{issues.py → issues/_base.py} +78 -2
  29. cognite/neat/issues/errors/external.py +21 -0
  30. cognite/neat/issues/errors/properties.py +75 -0
  31. cognite/neat/issues/errors/resources.py +123 -0
  32. cognite/neat/issues/errors/schema.py +0 -0
  33. cognite/neat/{rules/issues → issues}/formatters.py +9 -9
  34. cognite/neat/issues/neat_warnings/__init__.py +2 -0
  35. cognite/neat/issues/neat_warnings/identifier.py +27 -0
  36. cognite/neat/issues/neat_warnings/models.py +22 -0
  37. cognite/neat/issues/neat_warnings/properties.py +77 -0
  38. cognite/neat/issues/neat_warnings/resources.py +125 -0
  39. cognite/neat/rules/exporters/_rules2dms.py +3 -2
  40. cognite/neat/rules/exporters/_rules2ontology.py +28 -20
  41. cognite/neat/rules/exporters/_validation.py +15 -21
  42. cognite/neat/rules/importers/__init__.py +7 -3
  43. cognite/neat/rules/importers/_base.py +3 -3
  44. cognite/neat/rules/importers/_dms2rules.py +39 -18
  45. cognite/neat/rules/importers/_dtdl2rules/dtdl_converter.py +44 -53
  46. cognite/neat/rules/importers/_dtdl2rules/dtdl_importer.py +6 -5
  47. cognite/neat/rules/importers/_rdf/__init__.py +0 -0
  48. cognite/neat/rules/importers/_rdf/_imf2rules/__init__.py +3 -0
  49. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2classes.py +82 -0
  50. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2metadata.py +34 -0
  51. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2properties.py +123 -0
  52. cognite/neat/rules/importers/{_owl2rules/_owl2rules.py → _rdf/_imf2rules/_imf2rules.py} +15 -11
  53. cognite/neat/rules/importers/{_inference2rules.py → _rdf/_inference2rules.py} +1 -1
  54. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2classes.py +57 -0
  55. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2metadata.py +68 -0
  56. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2properties.py +59 -0
  57. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2rules.py +76 -0
  58. cognite/neat/rules/importers/_rdf/_shared.py +586 -0
  59. cognite/neat/rules/importers/_spreadsheet2rules.py +31 -28
  60. cognite/neat/rules/importers/_yaml2rules.py +2 -1
  61. cognite/neat/rules/issues/__init__.py +1 -5
  62. cognite/neat/rules/issues/base.py +2 -21
  63. cognite/neat/rules/issues/dms.py +20 -134
  64. cognite/neat/rules/issues/ontology.py +298 -0
  65. cognite/neat/rules/issues/spreadsheet.py +51 -3
  66. cognite/neat/rules/issues/tables.py +72 -0
  67. cognite/neat/rules/models/_rdfpath.py +4 -4
  68. cognite/neat/rules/models/_types/_field.py +14 -21
  69. cognite/neat/rules/models/asset/_validation.py +1 -1
  70. cognite/neat/rules/models/dms/_schema.py +53 -30
  71. cognite/neat/rules/models/dms/_validation.py +2 -2
  72. cognite/neat/rules/models/entities.py +3 -0
  73. cognite/neat/rules/models/information/_rules.py +5 -4
  74. cognite/neat/rules/models/information/_validation.py +1 -1
  75. cognite/neat/utils/rdf_.py +17 -9
  76. cognite/neat/utils/regex_patterns.py +52 -0
  77. cognite/neat/workflows/steps/lib/current/rules_importer.py +73 -1
  78. cognite/neat/workflows/steps/lib/current/rules_validator.py +19 -7
  79. {cognite_neat-0.88.0.dist-info → cognite_neat-0.88.2.dist-info}/METADATA +2 -6
  80. {cognite_neat-0.88.0.dist-info → cognite_neat-0.88.2.dist-info}/RECORD +85 -72
  81. cognite/neat/app/ui/neat-app/build/static/css/main.38a62222.css.map +0 -1
  82. cognite/neat/app/ui/neat-app/build/static/js/main.ec7f72e2.js +0 -3
  83. cognite/neat/app/ui/neat-app/build/static/js/main.ec7f72e2.js.map +0 -1
  84. cognite/neat/graph/issues/loader.py +0 -104
  85. cognite/neat/graph/stores/_oxrdflib.py +0 -247
  86. cognite/neat/rules/exceptions.py +0 -2972
  87. cognite/neat/rules/importers/_owl2rules/_owl2classes.py +0 -215
  88. cognite/neat/rules/importers/_owl2rules/_owl2metadata.py +0 -213
  89. cognite/neat/rules/importers/_owl2rules/_owl2properties.py +0 -203
  90. cognite/neat/rules/issues/importing.py +0 -408
  91. cognite/neat/rules/models/_types/_base.py +0 -16
  92. cognite/neat/workflows/examples/Export_Rules_to_Ontology/workflow.yaml +0 -152
  93. cognite/neat/workflows/examples/Extract_DEXPI_Graph_and_Export_Rules/workflow.yaml +0 -139
  94. cognite/neat/workflows/examples/Ontology_to_Data_Model/workflow.yaml +0 -116
  95. /cognite/neat/{graph/issues → issues/errors}/__init__.py +0 -0
  96. /cognite/neat/rules/importers/{_owl2rules → _rdf/_owl2rules}/__init__.py +0 -0
  97. {cognite_neat-0.88.0.dist-info → cognite_neat-0.88.2.dist-info}/LICENSE +0 -0
  98. {cognite_neat-0.88.0.dist-info → cognite_neat-0.88.2.dist-info}/WHEEL +0 -0
  99. {cognite_neat-0.88.0.dist-info → cognite_neat-0.88.2.dist-info}/entry_points.txt +0 -0
@@ -1,9 +1,8 @@
1
1
  from cognite.neat.issues import MultiValueError
2
2
 
3
- from . import dms, fileread, formatters, importing, spreadsheet, spreadsheet_file
3
+ from . import dms, fileread, spreadsheet, spreadsheet_file
4
4
  from .base import (
5
5
  DefaultPydanticError,
6
- IssueList,
7
6
  NeatValidationError,
8
7
  ValidationIssue,
9
8
  ValidationWarning,
@@ -12,15 +11,12 @@ from .base import (
12
11
  __all__ = [
13
12
  "DefaultPydanticError",
14
13
  "MultiValueError",
15
- "IssueList",
16
14
  "NeatValidationError",
17
15
  "ValidationIssue",
18
16
  "ValidationIssue",
19
17
  "ValidationWarning",
20
18
  "dms",
21
19
  "fileread",
22
- "formatters",
23
- "importing",
24
20
  "spreadsheet",
25
21
  "spreadsheet_file",
26
22
  ]
@@ -4,14 +4,13 @@ from typing import Any
4
4
 
5
5
  from pydantic_core import ErrorDetails
6
6
 
7
- from cognite.neat.issues import MultiValueError, NeatError, NeatIssue, NeatIssueList, NeatWarning
7
+ from cognite.neat.issues import MultiValueError, NeatError, NeatIssue, NeatWarning
8
8
 
9
9
  __all__ = [
10
10
  "ValidationIssue",
11
11
  "NeatValidationError",
12
12
  "DefaultPydanticError",
13
13
  "ValidationWarning",
14
- "IssueList",
15
14
  "MultiValueError",
16
15
  ]
17
16
 
@@ -21,22 +20,7 @@ class ValidationIssue(NeatIssue, ABC): ...
21
20
 
22
21
 
23
22
  @dataclass(frozen=True)
24
- class NeatValidationError(NeatError, ValidationIssue, ABC):
25
- @classmethod
26
- def from_pydantic_errors(cls, errors: list[ErrorDetails], **kwargs) -> "list[NeatValidationError]":
27
- """Convert a list of pydantic errors to a list of Error instances.
28
-
29
- This is intended to be overridden in subclasses to handle specific error types.
30
- """
31
- all_errors: list[NeatValidationError] = []
32
- for error in errors:
33
- if isinstance(ctx := error.get("ctx"), dict) and isinstance(
34
- multi_error := ctx.get("error"), MultiValueError
35
- ):
36
- all_errors.extend(multi_error.errors) # type: ignore[arg-type]
37
- else:
38
- all_errors.append(DefaultPydanticError.from_pydantic_error(error))
39
- return all_errors
23
+ class NeatValidationError(NeatError, ValidationIssue, ABC): ...
40
24
 
41
25
 
42
26
  @dataclass(frozen=True)
@@ -77,6 +61,3 @@ class DefaultPydanticError(NeatValidationError):
77
61
 
78
62
  @dataclass(frozen=True)
79
63
  class ValidationWarning(NeatWarning, ValidationIssue, ABC): ...
80
-
81
-
82
- class IssueList(NeatIssueList[ValidationIssue]): ...
@@ -10,13 +10,6 @@ __all__ = [
10
10
  "DMSSchemaError",
11
11
  "DMSSchemaWarning",
12
12
  "IncompleteSchemaError",
13
- "MissingSpaceError",
14
- "MissingContainerError",
15
- "MissingContainerPropertyError",
16
- "MissingViewError",
17
- "MissingParentViewError",
18
- "MissingSourceViewError",
19
- "MissingEdgeViewError",
20
13
  "DirectRelationMissingSourceWarning",
21
14
  "ViewModelVersionNotMatchingWarning",
22
15
  "ViewModelSpaceNotMatchingWarning",
@@ -87,133 +80,6 @@ class IncompleteSchemaError(DMSSchemaError):
87
80
  return output
88
81
 
89
82
 
90
- @dataclass(frozen=True)
91
- class MissingSpaceError(DMSSchemaError):
92
- description = "The spaced referred to by the Container/View/Node/Edge/DataModel does not exist"
93
- fix = "Create the space"
94
- space: str
95
- referred_by: dm.ContainerId | dm.ViewId | dm.NodeId | dm.EdgeId | dm.DataModelId
96
-
97
- def message(self) -> str:
98
- return f"The space {self.space} referred to by {self.referred_by} does not exist"
99
-
100
- def dump(self) -> dict[str, Any]:
101
- output = super().dump()
102
- output["space"] = self.space
103
- output["referred_by"] = self.referred_by
104
- return output
105
-
106
-
107
- @dataclass(frozen=True)
108
- class MissingContainerError(DMSSchemaError):
109
- description = "The container referred to by the View does not exist"
110
- fix = "Create the container"
111
- error_name: ClassVar[str] = "MissingContainer"
112
- container: dm.ContainerId
113
- referred_by: dm.ViewId | dm.ContainerId
114
-
115
- def message(self) -> str:
116
- return f"The container {self.container} referred to by {self.referred_by} does not exist"
117
-
118
- def dump(self) -> dict[str, Any]:
119
- output = super().dump()
120
- output["container"] = self.container
121
- output["referred_by"] = self.referred_by
122
- return output
123
-
124
-
125
- @dataclass(frozen=True)
126
- class MissingContainerPropertyError(DMSSchemaError):
127
- description = "The property referred to by the View does not exist in the container"
128
- fix = "Create the property"
129
- error_name: ClassVar[str] = "MissingContainerProperty"
130
- container: dm.ContainerId
131
- property: str
132
- referred_by: dm.ViewId
133
-
134
- def message(self) -> str:
135
- return (
136
- f"The property {self.property} referred to by the container {self.container} "
137
- f"does not exist in {self.referred_by}"
138
- )
139
-
140
- def dump(self) -> dict[str, Any]:
141
- output = super().dump()
142
- output["container"] = self.container
143
- output["property"] = self.property
144
- output["referred_by"] = self.referred_by
145
- return output
146
-
147
-
148
- @dataclass(frozen=True)
149
- class MissingViewError(DMSSchemaError):
150
- description = "The view referred to by the View/DataModel does not exist"
151
- fix = "Create the view"
152
- error_name: ClassVar[str] = "MissingView"
153
- view: dm.ViewId
154
- referred_by: dm.DataModelId | dm.ViewId
155
-
156
- def message(self) -> str:
157
- return f"The view {self.view} referred to by {self.referred_by} does not exist"
158
-
159
- def dump(self) -> dict[str, Any]:
160
- output = super().dump()
161
- output["view"] = self.view
162
- output["referred_by"] = self.referred_by
163
- return output
164
-
165
-
166
- @dataclass(frozen=True)
167
- class MissingParentViewError(MissingViewError):
168
- description = "The parent view referred to by the View does not exist"
169
- fix = "Create the parent view"
170
- error_name: ClassVar[str] = "MissingParentView"
171
- referred_by: dm.ViewId
172
-
173
- def message(self) -> str:
174
- return f"The parent view {self.view} referred to by {self.referred_by} does not exist"
175
-
176
- def dump(self) -> dict[str, Any]:
177
- output = super().dump()
178
- output["referred_by"] = self.referred_by
179
- return output
180
-
181
-
182
- @dataclass(frozen=True)
183
- class MissingSourceViewError(MissingViewError):
184
- description = "The source view referred to by the View does not exist"
185
- fix = "Create the source view"
186
- error_name: ClassVar[str] = "MissingSourceView"
187
- property: str
188
- referred_by: dm.ViewId
189
-
190
- def message(self) -> str:
191
- return f"The source view {self.view} referred to by {self.referred_by}.{self.property} does not exist"
192
-
193
- def dump(self) -> dict[str, Any]:
194
- output = super().dump()
195
- output["property"] = self.property
196
- return output
197
-
198
-
199
- @dataclass(frozen=True)
200
- class MissingEdgeViewError(MissingViewError):
201
- description = "The edge view referred to by the View does not exist"
202
- fix = "Create the edge view"
203
- error_name: ClassVar[str] = "MissingEdgeView"
204
- property: str
205
- referred_by: dm.ViewId
206
-
207
- def message(self) -> str:
208
- return f"The edge view {self.view} referred to by {self.referred_by}.{self.property} does not exist"
209
-
210
- def dump(self) -> dict[str, Any]:
211
- output = super().dump()
212
- output["property"] = self.property
213
- output["referred_by"] = self.referred_by
214
- return output
215
-
216
-
217
83
  @dataclass(frozen=True)
218
84
  class DuplicatedViewInDataModelError(DMSSchemaError):
219
85
  description = "The view is duplicated in the DataModel"
@@ -432,6 +298,26 @@ class ChangingViewError(DMSSchemaError):
432
298
  return output
433
299
 
434
300
 
301
+ @dataclass(frozen=True)
302
+ class EntityIDNotDMSCompliantWarning(DMSSchemaWarning):
303
+ description = "The entity ID, {entity_id} of type {entity_type}, is not DMS compliant. Violating regex {regex}"
304
+ fix = "Change the entity ID to be DMS compliant"
305
+ error_name: ClassVar[str] = "EntityIDNotDMSCompliantWarning"
306
+ entity_id: str
307
+ entity_type: str
308
+ regex: str
309
+
310
+ def message(self) -> str:
311
+ return self.description.format(entity_id=self.entity_id, entity_type=self.entity_type, regex=self.regex)
312
+
313
+ def dump(self) -> dict[str, Any]:
314
+ output = super().dump()
315
+ output["entity_id"] = self.entity_id
316
+ output["dms_type"] = self.entity_type
317
+ output["regex"] = self.regex
318
+ return output
319
+
320
+
435
321
  @dataclass(frozen=True)
436
322
  class EmptyContainerWarning(DMSSchemaWarning):
437
323
  description = "The container is empty"
@@ -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
@@ -9,7 +9,7 @@ from cognite.client.data_classes.data_modeling import ContainerId, ViewId
9
9
  from pydantic_core import ErrorDetails
10
10
  from rdflib import Namespace
11
11
 
12
- from cognite.neat.issues import MultiValueError
12
+ from cognite.neat.issues import MultiValueError, NeatError
13
13
  from cognite.neat.utils.spreadsheet import SpreadsheetRead
14
14
 
15
15
  from .base import DefaultPydanticError, NeatValidationError
@@ -38,6 +38,7 @@ __all__ = [
38
38
  "MultiDefaultError",
39
39
  "MultiIndexError",
40
40
  "MultiUniqueConstraintError",
41
+ "RegexViolationError",
41
42
  ]
42
43
 
43
44
 
@@ -58,8 +59,8 @@ class InvalidSheetError(NeatValidationError, ABC):
58
59
  errors: list[ErrorDetails],
59
60
  read_info_by_sheet: dict[str, SpreadsheetRead] | None = None,
60
61
  **kwargs: Any,
61
- ) -> "list[NeatValidationError]":
62
- output: list[NeatValidationError] = []
62
+ ) -> "list[NeatError]":
63
+ output: list[NeatError] = []
63
64
  for error in errors:
64
65
  if raised_error := error.get("ctx", {}).get("error"):
65
66
  if isinstance(raised_error, MultiValueError):
@@ -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."