cognite-neat 0.88.1__py3-none-any.whl → 0.88.3__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.
- cognite/neat/_version.py +1 -1
- cognite/neat/graph/__init__.py +0 -3
- cognite/neat/graph/loaders/_base.py +6 -6
- cognite/neat/graph/loaders/_rdf2asset.py +28 -31
- cognite/neat/graph/loaders/_rdf2dms.py +24 -15
- cognite/neat/issues/__init__.py +14 -0
- cognite/neat/issues/_base.py +415 -0
- cognite/neat/issues/errors/__init__.py +72 -0
- cognite/neat/issues/errors/_external.py +67 -0
- cognite/neat/issues/errors/_general.py +28 -0
- cognite/neat/issues/errors/_properties.py +62 -0
- cognite/neat/issues/errors/_resources.py +111 -0
- cognite/neat/issues/errors/_workflow.py +36 -0
- cognite/neat/{rules/issues → issues}/formatters.py +10 -10
- cognite/neat/issues/warnings/__init__.py +66 -0
- cognite/neat/issues/warnings/_external.py +40 -0
- cognite/neat/issues/warnings/_general.py +29 -0
- cognite/neat/issues/warnings/_models.py +92 -0
- cognite/neat/issues/warnings/_properties.py +44 -0
- cognite/neat/issues/warnings/_resources.py +55 -0
- cognite/neat/issues/warnings/user_modeling.py +113 -0
- cognite/neat/rules/_shared.py +10 -2
- cognite/neat/rules/exporters/_base.py +6 -6
- cognite/neat/rules/exporters/_rules2dms.py +19 -11
- cognite/neat/rules/exporters/_rules2excel.py +4 -4
- cognite/neat/rules/exporters/_rules2ontology.py +74 -51
- cognite/neat/rules/exporters/_rules2yaml.py +3 -3
- cognite/neat/rules/exporters/_validation.py +11 -96
- cognite/neat/rules/importers/__init__.py +7 -3
- cognite/neat/rules/importers/_base.py +9 -13
- cognite/neat/rules/importers/_dms2rules.py +42 -24
- cognite/neat/rules/importers/_dtdl2rules/dtdl_converter.py +49 -53
- cognite/neat/rules/importers/_dtdl2rules/dtdl_importer.py +31 -23
- cognite/neat/rules/importers/_dtdl2rules/spec.py +7 -0
- cognite/neat/rules/importers/_rdf/_imf2rules/__init__.py +3 -0
- cognite/neat/rules/importers/_rdf/_imf2rules/_imf2classes.py +82 -0
- cognite/neat/rules/importers/_rdf/_imf2rules/_imf2metadata.py +34 -0
- cognite/neat/rules/importers/_rdf/_imf2rules/_imf2properties.py +123 -0
- cognite/neat/rules/importers/{_owl2rules/_owl2rules.py → _rdf/_imf2rules/_imf2rules.py} +24 -18
- cognite/neat/rules/importers/{_inference2rules.py → _rdf/_inference2rules.py} +9 -9
- cognite/neat/rules/importers/_rdf/_owl2rules/_owl2classes.py +58 -0
- cognite/neat/rules/importers/_rdf/_owl2rules/_owl2metadata.py +68 -0
- cognite/neat/rules/importers/_rdf/_owl2rules/_owl2properties.py +60 -0
- cognite/neat/rules/importers/_rdf/_owl2rules/_owl2rules.py +76 -0
- cognite/neat/rules/importers/_rdf/_shared.py +586 -0
- cognite/neat/rules/importers/_spreadsheet2rules.py +35 -22
- cognite/neat/rules/importers/_yaml2rules.py +23 -21
- cognite/neat/rules/models/_constants.py +2 -1
- cognite/neat/rules/models/_rdfpath.py +4 -4
- cognite/neat/rules/models/_types/_field.py +9 -11
- cognite/neat/rules/models/asset/_rules.py +1 -3
- cognite/neat/rules/models/asset/_validation.py +14 -10
- cognite/neat/rules/models/dms/_converter.py +2 -4
- cognite/neat/rules/models/dms/_exporter.py +30 -8
- cognite/neat/rules/models/dms/_rules.py +23 -7
- cognite/neat/rules/models/dms/_schema.py +94 -62
- cognite/neat/rules/models/dms/_validation.py +105 -66
- cognite/neat/rules/models/entities.py +3 -0
- cognite/neat/rules/models/information/_converter.py +2 -2
- cognite/neat/rules/models/information/_rules.py +7 -8
- cognite/neat/rules/models/information/_validation.py +48 -25
- cognite/neat/rules/transformers/__init__.py +0 -0
- cognite/neat/rules/transformers/_base.py +15 -0
- cognite/neat/utils/auxiliary.py +2 -35
- cognite/neat/utils/text.py +17 -0
- cognite/neat/workflows/base.py +4 -4
- cognite/neat/workflows/cdf_store.py +3 -3
- cognite/neat/workflows/steps/data_contracts.py +1 -1
- cognite/neat/workflows/steps/lib/current/graph_extractor.py +3 -3
- cognite/neat/workflows/steps/lib/current/graph_loader.py +2 -2
- cognite/neat/workflows/steps/lib/current/graph_store.py +1 -1
- cognite/neat/workflows/steps/lib/current/rules_exporter.py +10 -10
- cognite/neat/workflows/steps/lib/current/rules_importer.py +78 -6
- cognite/neat/workflows/steps/lib/current/rules_validator.py +20 -9
- cognite/neat/workflows/steps/lib/io/io_steps.py +5 -5
- cognite/neat/workflows/steps_registry.py +4 -5
- {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.3.dist-info}/METADATA +1 -1
- {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.3.dist-info}/RECORD +86 -77
- cognite/neat/exceptions.py +0 -145
- cognite/neat/graph/exceptions.py +0 -90
- cognite/neat/graph/issues/loader.py +0 -104
- cognite/neat/issues.py +0 -158
- cognite/neat/rules/importers/_owl2rules/_owl2classes.py +0 -215
- cognite/neat/rules/importers/_owl2rules/_owl2metadata.py +0 -209
- cognite/neat/rules/importers/_owl2rules/_owl2properties.py +0 -203
- cognite/neat/rules/issues/__init__.py +0 -26
- cognite/neat/rules/issues/base.py +0 -82
- cognite/neat/rules/issues/dms.py +0 -683
- cognite/neat/rules/issues/fileread.py +0 -197
- cognite/neat/rules/issues/importing.py +0 -423
- cognite/neat/rules/issues/ontology.py +0 -298
- cognite/neat/rules/issues/spreadsheet.py +0 -563
- cognite/neat/rules/issues/spreadsheet_file.py +0 -151
- cognite/neat/rules/issues/tables.py +0 -72
- cognite/neat/workflows/_exceptions.py +0 -41
- /cognite/neat/{graph/issues → rules/importers/_rdf}/__init__.py +0 -0
- /cognite/neat/rules/importers/{_owl2rules → _rdf/_owl2rules}/__init__.py +0 -0
- /cognite/neat/{graph/stores → store}/__init__.py +0 -0
- /cognite/neat/{graph/stores → store}/_base.py +0 -0
- /cognite/neat/{graph/stores → store}/_provenance.py +0 -0
- {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.3.dist-info}/LICENSE +0 -0
- {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.3.dist-info}/WHEEL +0 -0
- {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.3.dist-info}/entry_points.txt +0 -0
cognite/neat/rules/issues/dms.py
DELETED
|
@@ -1,683 +0,0 @@
|
|
|
1
|
-
from abc import ABC
|
|
2
|
-
from dataclasses import dataclass
|
|
3
|
-
from typing import Any, ClassVar
|
|
4
|
-
|
|
5
|
-
from cognite.client.data_classes import data_modeling as dm
|
|
6
|
-
|
|
7
|
-
from .base import NeatValidationError, ValidationWarning
|
|
8
|
-
|
|
9
|
-
__all__ = [
|
|
10
|
-
"DMSSchemaError",
|
|
11
|
-
"DMSSchemaWarning",
|
|
12
|
-
"IncompleteSchemaError",
|
|
13
|
-
"MissingSpaceError",
|
|
14
|
-
"MissingContainerError",
|
|
15
|
-
"MissingContainerPropertyError",
|
|
16
|
-
"MissingViewError",
|
|
17
|
-
"MissingParentViewError",
|
|
18
|
-
"MissingSourceViewError",
|
|
19
|
-
"MissingEdgeViewError",
|
|
20
|
-
"DirectRelationMissingSourceWarning",
|
|
21
|
-
"ViewModelVersionNotMatchingWarning",
|
|
22
|
-
"ViewModelSpaceNotMatchingWarning",
|
|
23
|
-
"ViewMapsToTooManyContainersWarning",
|
|
24
|
-
"DuplicatedViewInDataModelError",
|
|
25
|
-
"ContainerPropertyUsedMultipleTimesError",
|
|
26
|
-
"EmptyContainerWarning",
|
|
27
|
-
"UnsupportedConnectionWarning",
|
|
28
|
-
"MultipleReferenceWarning",
|
|
29
|
-
"HasDataFilterOnNoPropertiesViewWarning",
|
|
30
|
-
"HasDataFilterAppliedToTooManyContainersWarning",
|
|
31
|
-
"ReverseRelationMissingOtherSideWarning",
|
|
32
|
-
"NodeTypeFilterOnParentViewWarning",
|
|
33
|
-
"MissingViewInModelWarning",
|
|
34
|
-
"ViewSizeWarning",
|
|
35
|
-
"ChangingContainerError",
|
|
36
|
-
"ChangingViewError",
|
|
37
|
-
]
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@dataclass(frozen=True)
|
|
41
|
-
class DMSSchemaError(NeatValidationError, ABC): ...
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
@dataclass(frozen=True)
|
|
45
|
-
class DMSSchemaWarning(ValidationWarning, ABC): ...
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
@dataclass(frozen=True)
|
|
49
|
-
class ViewSizeWarning(DMSSchemaWarning):
|
|
50
|
-
description = (
|
|
51
|
-
"The number of properties in the {view} view is {count} which is more than "
|
|
52
|
-
"the recommended limit of {limit} properties. This can lead to performance issues."
|
|
53
|
-
)
|
|
54
|
-
fix = "Reduce the size of the view"
|
|
55
|
-
error_name: ClassVar[str] = "ViewSizeWarning"
|
|
56
|
-
|
|
57
|
-
view_id: dm.ViewId
|
|
58
|
-
limit: int
|
|
59
|
-
count: int
|
|
60
|
-
|
|
61
|
-
def message(self) -> str:
|
|
62
|
-
return self.description.format(view=repr(self.view_id), count=self.count, limit=self.limit)
|
|
63
|
-
|
|
64
|
-
def dump(self) -> dict[str, Any]:
|
|
65
|
-
output = super().dump()
|
|
66
|
-
output["view_id"] = self.view_id.dump()
|
|
67
|
-
output["limit"] = self.limit
|
|
68
|
-
output["count"] = self.count
|
|
69
|
-
return output
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
@dataclass(frozen=True)
|
|
73
|
-
class IncompleteSchemaError(DMSSchemaError):
|
|
74
|
-
description = "This error is raised when the schema is claimed to be complete but missing some components"
|
|
75
|
-
fix = "Either provide the missing components or change the schema to partial"
|
|
76
|
-
missing_component: dm.ContainerId | dm.ViewId
|
|
77
|
-
|
|
78
|
-
def message(self) -> str:
|
|
79
|
-
return (
|
|
80
|
-
"The data model schema is set to be complete, however, "
|
|
81
|
-
f"the referred component {self.missing_component} is not preset."
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
def dump(self) -> dict[str, Any]:
|
|
85
|
-
output = super().dump()
|
|
86
|
-
output["missing_component"] = self.missing_component
|
|
87
|
-
return output
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
@dataclass(frozen=True)
|
|
218
|
-
class DuplicatedViewInDataModelError(DMSSchemaError):
|
|
219
|
-
description = "The view is duplicated in the DataModel"
|
|
220
|
-
fix = "Remove the duplicated view"
|
|
221
|
-
error_name: ClassVar[str] = "DuplicatedViewInDataModel"
|
|
222
|
-
referred_by: dm.DataModelId
|
|
223
|
-
view: dm.ViewId
|
|
224
|
-
|
|
225
|
-
def message(self) -> str:
|
|
226
|
-
return f"The view {self.view} is duplicated in the DataModel {self.referred_by}"
|
|
227
|
-
|
|
228
|
-
def dump(self) -> dict[str, Any]:
|
|
229
|
-
output = super().dump()
|
|
230
|
-
output["referred_by"] = self.referred_by
|
|
231
|
-
output["view"] = self.view
|
|
232
|
-
return output
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
@dataclass(frozen=True)
|
|
236
|
-
class DirectRelationMissingSourceWarning(DMSSchemaWarning):
|
|
237
|
-
description = "The source view referred to by the DirectRelation does not exist"
|
|
238
|
-
fix = "Create the source view"
|
|
239
|
-
error_name: ClassVar[str] = "DirectRelationMissingSource"
|
|
240
|
-
view_id: dm.ViewId
|
|
241
|
-
property: str
|
|
242
|
-
|
|
243
|
-
def message(self) -> str:
|
|
244
|
-
return f"The source view referred to by '{self.view_id.external_id}.{self.property}' does not exist."
|
|
245
|
-
|
|
246
|
-
def dump(self) -> dict[str, Any]:
|
|
247
|
-
output = super().dump()
|
|
248
|
-
output["view_id"] = self.view_id
|
|
249
|
-
output["property"] = self.property
|
|
250
|
-
return output
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
@dataclass(frozen=True)
|
|
254
|
-
class ViewModelVersionNotMatchingWarning(DMSSchemaWarning):
|
|
255
|
-
description = "The view model version does not match the data model version"
|
|
256
|
-
fix = "Update the view model version to match the data model version"
|
|
257
|
-
error_name: ClassVar[str] = "ViewModelVersionNotMatching"
|
|
258
|
-
view_ids: list[dm.ViewId]
|
|
259
|
-
data_model_version: str
|
|
260
|
-
|
|
261
|
-
def message(self) -> str:
|
|
262
|
-
return (
|
|
263
|
-
f"The version in the views {self.view_ids} does not match the version in the data model "
|
|
264
|
-
f"{self.data_model_version}. This is not recommended as it easily leads to confusion and errors. "
|
|
265
|
-
f"Views are very cheap and we recommend you update the version of the views to match the data"
|
|
266
|
-
f" model version, irrespective of whether the views have changed or not."
|
|
267
|
-
" The approach of having same version of model components as the model itself "
|
|
268
|
-
" is a globally recognized data modeling practice."
|
|
269
|
-
)
|
|
270
|
-
|
|
271
|
-
def dump(self) -> dict[str, Any]:
|
|
272
|
-
output = super().dump()
|
|
273
|
-
output["view_id"] = [view_id.dump() for view_id in self.view_ids]
|
|
274
|
-
output["data_model_version"] = self.data_model_version
|
|
275
|
-
return output
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
@dataclass(frozen=True)
|
|
279
|
-
class ViewModelSpaceNotMatchingWarning(DMSSchemaWarning):
|
|
280
|
-
description = "The view model space does not match the data model space"
|
|
281
|
-
fix = "Update the view model space to match the data model space"
|
|
282
|
-
error_name: ClassVar[str] = "ViewModelSpaceNotMatching"
|
|
283
|
-
view_ids: list[dm.ViewId]
|
|
284
|
-
data_model_space: str
|
|
285
|
-
|
|
286
|
-
def message(self) -> str:
|
|
287
|
-
return (
|
|
288
|
-
f"The space in the views {self.view_ids} does not match the space in the data model "
|
|
289
|
-
f"{self.data_model_space}. This is not recommended as it easily leads to confusion and errors. "
|
|
290
|
-
f"Views are very cheap and we recommend you always have views in the same space as the data model."
|
|
291
|
-
)
|
|
292
|
-
|
|
293
|
-
def dump(self) -> dict[str, Any]:
|
|
294
|
-
output = super().dump()
|
|
295
|
-
output["view_id"] = [view_id.dump() for view_id in self.view_ids]
|
|
296
|
-
output["data_model_space"] = self.data_model_space
|
|
297
|
-
return output
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
@dataclass(frozen=True)
|
|
301
|
-
class ViewMapsToTooManyContainersWarning(DMSSchemaWarning):
|
|
302
|
-
description = "The view maps to more than 10 containers which impacts read/write performance of data model"
|
|
303
|
-
fix = "Try to have as few containers as possible to which the view maps to"
|
|
304
|
-
error_name: ClassVar[str] = "ViewMapsToTooManyContainers"
|
|
305
|
-
view_id: dm.ViewId
|
|
306
|
-
container_ids: set[dm.ContainerId]
|
|
307
|
-
|
|
308
|
-
def message(self) -> str:
|
|
309
|
-
return (
|
|
310
|
-
f"The view {self.view_id} maps to total of {len(self.container_ids)},."
|
|
311
|
-
"Mapping to more than 10 containers is not recommended and can lead to poor performances."
|
|
312
|
-
"Re-iterate the data model design to reduce the number of containers to which the view maps to."
|
|
313
|
-
)
|
|
314
|
-
|
|
315
|
-
def dump(self) -> dict[str, Any]:
|
|
316
|
-
output = super().dump()
|
|
317
|
-
output["view_id"] = self.view_id.dump()
|
|
318
|
-
output["container_ids"] = [container_id.dump() for container_id in self.container_ids]
|
|
319
|
-
return output
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
@dataclass(frozen=True)
|
|
323
|
-
class MissingViewInModelWarning(DMSSchemaWarning):
|
|
324
|
-
description = "The data model contains view pointing to views not present in the data model"
|
|
325
|
-
fix = "Add the view(s) to the data model"
|
|
326
|
-
error_name: ClassVar[str] = "MissingViewInModel"
|
|
327
|
-
data_model_id: dm.DataModelId
|
|
328
|
-
view_ids: set[dm.ViewId]
|
|
329
|
-
|
|
330
|
-
def message(self) -> str:
|
|
331
|
-
return f"The view(s) {self.view_ids} are missing in the data model {self.data_model_id}"
|
|
332
|
-
|
|
333
|
-
def dump(self) -> dict[str, Any]:
|
|
334
|
-
output = super().dump()
|
|
335
|
-
output["data_model_id"] = self.data_model_id.dump()
|
|
336
|
-
output["view_id"] = [view_id.dump() for view_id in self.view_ids]
|
|
337
|
-
return output
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
@dataclass(frozen=True)
|
|
341
|
-
class ContainerPropertyUsedMultipleTimesError(DMSSchemaError):
|
|
342
|
-
description = "The container property is used multiple times by the same view property"
|
|
343
|
-
fix = "Use unique container properties for when mapping to the same container"
|
|
344
|
-
error_name: ClassVar[str] = "ContainerPropertyUsedMultipleTimes"
|
|
345
|
-
container: dm.ContainerId
|
|
346
|
-
property: str
|
|
347
|
-
referred_by: frozenset[tuple[dm.ViewId, str]]
|
|
348
|
-
|
|
349
|
-
def message(self) -> str:
|
|
350
|
-
return (
|
|
351
|
-
f"The container property {self.property} of {self.container} is used multiple times "
|
|
352
|
-
f"by the same view {self.referred_by}"
|
|
353
|
-
)
|
|
354
|
-
|
|
355
|
-
def dump(self) -> dict[str, Any]:
|
|
356
|
-
output = super().dump()
|
|
357
|
-
output["container"] = self.container
|
|
358
|
-
output["property"] = self.property
|
|
359
|
-
output["referred_by"] = sorted(self.referred_by)
|
|
360
|
-
return output
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
@dataclass(frozen=True)
|
|
364
|
-
class ChangingContainerError(DMSSchemaError):
|
|
365
|
-
description = "You are adding to an existing model. "
|
|
366
|
-
fix = "Keep the container the same"
|
|
367
|
-
error_name: ClassVar[str] = "ChangingContainerError"
|
|
368
|
-
container_id: dm.ContainerId
|
|
369
|
-
changed_properties: list[str] | None = None
|
|
370
|
-
changed_attributes: list[str] | None = None
|
|
371
|
-
|
|
372
|
-
def __post_init__(self):
|
|
373
|
-
# Sorting for deterministic output
|
|
374
|
-
if self.changed_properties:
|
|
375
|
-
self.changed_properties.sort()
|
|
376
|
-
if self.changed_attributes:
|
|
377
|
-
self.changed_attributes.sort()
|
|
378
|
-
|
|
379
|
-
def message(self) -> str:
|
|
380
|
-
if self.changed_properties:
|
|
381
|
-
changed = f" properties {self.changed_properties}."
|
|
382
|
-
elif self.changed_attributes:
|
|
383
|
-
changed = f" attributes {self.changed_attributes}."
|
|
384
|
-
else:
|
|
385
|
-
changed = "."
|
|
386
|
-
return (
|
|
387
|
-
f"The container {self.container_id} has changed{changed}"
|
|
388
|
-
"When extending model with extension set to addition or reshape, the container "
|
|
389
|
-
"properties must remain the same"
|
|
390
|
-
)
|
|
391
|
-
|
|
392
|
-
def dump(self) -> dict[str, Any]:
|
|
393
|
-
output = super().dump()
|
|
394
|
-
output["container_id"] = self.container_id.dump()
|
|
395
|
-
output["changed_properties"] = self.changed_properties
|
|
396
|
-
return output
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
@dataclass(frozen=True)
|
|
400
|
-
class ChangingViewError(DMSSchemaError):
|
|
401
|
-
description = "You are adding to an existing model. "
|
|
402
|
-
fix = "Keep the view the same"
|
|
403
|
-
error_name: ClassVar[str] = "ChangingViewError"
|
|
404
|
-
view_id: dm.ViewId
|
|
405
|
-
changed_properties: list[str] | None = None
|
|
406
|
-
changed_attributes: list[str] | None = None
|
|
407
|
-
|
|
408
|
-
def __post_init__(self):
|
|
409
|
-
# Sorting for deterministic output
|
|
410
|
-
if self.changed_properties:
|
|
411
|
-
self.changed_properties.sort()
|
|
412
|
-
if self.changed_attributes:
|
|
413
|
-
self.changed_attributes.sort()
|
|
414
|
-
|
|
415
|
-
def message(self) -> str:
|
|
416
|
-
if self.changed_properties:
|
|
417
|
-
changed = f" properties {self.changed_properties}."
|
|
418
|
-
elif self.changed_attributes:
|
|
419
|
-
changed = f" attributes {self.changed_attributes}."
|
|
420
|
-
else:
|
|
421
|
-
changed = "."
|
|
422
|
-
|
|
423
|
-
return (
|
|
424
|
-
f"The view {self.view_id} has changed{changed}"
|
|
425
|
-
"When extending model with extension set to addition, the view properties must remain the same"
|
|
426
|
-
)
|
|
427
|
-
|
|
428
|
-
def dump(self) -> dict[str, Any]:
|
|
429
|
-
output = super().dump()
|
|
430
|
-
output["view_id"] = self.view_id.dump()
|
|
431
|
-
output["difference"] = self.changed_properties
|
|
432
|
-
return output
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
@dataclass(frozen=True)
|
|
436
|
-
class EntityIDNotDMSCompliantWarning(DMSSchemaWarning):
|
|
437
|
-
description = "The entity ID, {entity_id} of type {entity_type}, is not DMS compliant. Violating regex {regex}"
|
|
438
|
-
fix = "Change the entity ID to be DMS compliant"
|
|
439
|
-
error_name: ClassVar[str] = "EntityIDNotDMSCompliantWarning"
|
|
440
|
-
entity_id: str
|
|
441
|
-
entity_type: str
|
|
442
|
-
regex: str
|
|
443
|
-
|
|
444
|
-
def message(self) -> str:
|
|
445
|
-
return self.description.format(entity_id=self.entity_id, entity_type=self.entity_type, regex=self.regex)
|
|
446
|
-
|
|
447
|
-
def dump(self) -> dict[str, Any]:
|
|
448
|
-
output = super().dump()
|
|
449
|
-
output["entity_id"] = self.entity_id
|
|
450
|
-
output["dms_type"] = self.entity_type
|
|
451
|
-
output["regex"] = self.regex
|
|
452
|
-
return output
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
@dataclass(frozen=True)
|
|
456
|
-
class EmptyContainerWarning(DMSSchemaWarning):
|
|
457
|
-
description = "The container is empty"
|
|
458
|
-
fix = "Add data to the container"
|
|
459
|
-
error_name: ClassVar[str] = "EmptyContainerWarning"
|
|
460
|
-
container_id: dm.ContainerId
|
|
461
|
-
|
|
462
|
-
def message(self) -> str:
|
|
463
|
-
return (
|
|
464
|
-
f"The container {self.container_id} is empty. Is this intended? Skipping this container "
|
|
465
|
-
"in the data model."
|
|
466
|
-
)
|
|
467
|
-
|
|
468
|
-
def dump(self) -> dict[str, Any]:
|
|
469
|
-
output = super().dump()
|
|
470
|
-
output["container_id"] = self.container_id.dump()
|
|
471
|
-
return output
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
@dataclass(frozen=True)
|
|
475
|
-
class UnsupportedConnectionWarning(DMSSchemaWarning):
|
|
476
|
-
description = "The connection type is not supported by neat"
|
|
477
|
-
fix = "Change the connection to a supported type"
|
|
478
|
-
error_name: ClassVar[str] = "UnsupportedConnectionWarning"
|
|
479
|
-
view_id: dm.ViewId
|
|
480
|
-
property: str
|
|
481
|
-
connection: str
|
|
482
|
-
|
|
483
|
-
def message(self) -> str:
|
|
484
|
-
return (
|
|
485
|
-
f"The connection {self.connection} in {self.view_id}.{self.property} is not supported."
|
|
486
|
-
"This property will be ignored."
|
|
487
|
-
)
|
|
488
|
-
|
|
489
|
-
def dump(self) -> dict[str, Any]:
|
|
490
|
-
output = super().dump()
|
|
491
|
-
output["view_id"] = self.view_id.dump()
|
|
492
|
-
output["property"] = self.property
|
|
493
|
-
output["connection"] = self.connection
|
|
494
|
-
return output
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
@dataclass(frozen=True)
|
|
498
|
-
class ReverseRelationMissingOtherSideWarning(DMSSchemaWarning):
|
|
499
|
-
description = "The relation is missing the other side"
|
|
500
|
-
fix = "Add the other side of the relation"
|
|
501
|
-
error_name: ClassVar[str] = "ReverseRelationMissingOtherSideWarning"
|
|
502
|
-
view_id: dm.ViewId
|
|
503
|
-
property: str
|
|
504
|
-
|
|
505
|
-
def message(self) -> str:
|
|
506
|
-
return f"The reverse relation specified in {self.view_id}.{self.property} is missing the other side."
|
|
507
|
-
|
|
508
|
-
def dump(self) -> dict[str, Any]:
|
|
509
|
-
output = super().dump()
|
|
510
|
-
output["view_id"] = self.view_id.dump()
|
|
511
|
-
output["property"] = self.property
|
|
512
|
-
return output
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
@dataclass(frozen=True)
|
|
516
|
-
class MultipleReferenceWarning(DMSSchemaWarning):
|
|
517
|
-
description = "The view is implements multiple views from other spaces"
|
|
518
|
-
fix = "Neat expects maximum one implementation of a view from another space"
|
|
519
|
-
error_name: ClassVar[str] = "MultipleReferenceWarning"
|
|
520
|
-
view_id: dm.ViewId
|
|
521
|
-
implements: list[dm.ViewId]
|
|
522
|
-
|
|
523
|
-
def message(self) -> str:
|
|
524
|
-
return f"The view {self.view_id} implements multiple views from other spaces: {self.implements}. " + self.fix
|
|
525
|
-
|
|
526
|
-
def dump(self) -> dict[str, Any]:
|
|
527
|
-
output = super().dump()
|
|
528
|
-
output["view_id"] = self.view_id.dump()
|
|
529
|
-
output["implements"] = [view.dump() for view in self.implements]
|
|
530
|
-
return output
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
@dataclass(frozen=True)
|
|
534
|
-
class HasDataFilterOnNoPropertiesViewWarning(DMSSchemaWarning):
|
|
535
|
-
description = "Attempting to set a HasData filter on a view without properties."
|
|
536
|
-
fix = "Add properties to the view or use a node type filter"
|
|
537
|
-
error_name: ClassVar[str] = "HasDataFilterOnNoPropertiesViewWarning"
|
|
538
|
-
view_id: dm.ViewId
|
|
539
|
-
|
|
540
|
-
def message(self) -> str:
|
|
541
|
-
return (
|
|
542
|
-
f"Cannot set hasData filter on view {self.view_id} as it does not have properties in any containers. "
|
|
543
|
-
"Using a node type filter instead."
|
|
544
|
-
)
|
|
545
|
-
|
|
546
|
-
def dump(self) -> dict[str, Any]:
|
|
547
|
-
output = super().dump()
|
|
548
|
-
output["view_id"] = self.view_id.dump()
|
|
549
|
-
return output
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
@dataclass(frozen=True)
|
|
553
|
-
class HasDataFilterAppliedToTooManyContainersWarning(DMSSchemaWarning):
|
|
554
|
-
description = "The view filter hasData applied to more than 10 containers this will cause DMS API Error"
|
|
555
|
-
fix = "Do not map to more than 10 containers, alternatively override the filter by using rawFilter"
|
|
556
|
-
error_name: ClassVar[str] = "HasDataFilterAppliedToTooManyContainers"
|
|
557
|
-
view_id: dm.ViewId
|
|
558
|
-
container_ids: set[dm.ContainerId]
|
|
559
|
-
|
|
560
|
-
def message(self) -> str:
|
|
561
|
-
return (
|
|
562
|
-
f"The view {self.view_id} HasData filter applied to total of {len(self.container_ids)},."
|
|
563
|
-
"Applying HasData filter to more than 10 containers is not recommended and can lead to DMS API error."
|
|
564
|
-
"Re-iterate the data model design to reduce the number of containers to which the view maps to."
|
|
565
|
-
)
|
|
566
|
-
|
|
567
|
-
def dump(self) -> dict[str, Any]:
|
|
568
|
-
output = super().dump()
|
|
569
|
-
output["view_id"] = self.view_id.dump()
|
|
570
|
-
output["container_ids"] = [container_id.dump() for container_id in self.container_ids]
|
|
571
|
-
return output
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
@dataclass(frozen=True)
|
|
575
|
-
class RawFilterAppliedToViewWarning(DMSSchemaWarning):
|
|
576
|
-
description = "Raw filter is applied to a view, which is against the neat data modeling lifecycle."
|
|
577
|
-
fix = "Do not use raw filter, instead use HasData filter or nodeType filter or change the data model design."
|
|
578
|
-
error_name: ClassVar[str] = "RawFilterAppliedToView"
|
|
579
|
-
view_id: dm.ViewId
|
|
580
|
-
|
|
581
|
-
def message(self) -> str:
|
|
582
|
-
return (
|
|
583
|
-
f"RawFilter applied to the view {self.view_id}."
|
|
584
|
-
" The usage of RawFilter is against the neat team recommendations and the neat data modeling lifecycle."
|
|
585
|
-
" When opting for raw filter, the user is responsible for any errors that arise in neat."
|
|
586
|
-
)
|
|
587
|
-
|
|
588
|
-
def dump(self) -> dict[str, Any]:
|
|
589
|
-
output = super().dump()
|
|
590
|
-
output["view_id"] = self.view_id.dump()
|
|
591
|
-
return output
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
@dataclass(frozen=True)
|
|
595
|
-
class NodeTypeFilterOnParentViewWarning(DMSSchemaWarning):
|
|
596
|
-
description = (
|
|
597
|
-
"Setting a node type filter on a parent view. This is not "
|
|
598
|
-
"recommended as parent views are typically used for multiple type of nodes."
|
|
599
|
-
)
|
|
600
|
-
fix = "Use a HasData filter instead"
|
|
601
|
-
error_name: ClassVar[str] = "NodeTypeFilterOnParentViewWarning"
|
|
602
|
-
view_id: dm.ViewId
|
|
603
|
-
|
|
604
|
-
def message(self) -> str:
|
|
605
|
-
return (
|
|
606
|
-
f"Setting a node type filter on parent view {self.view_id}. This is not recommended as "
|
|
607
|
-
"parent views are typically used for multiple types of nodes."
|
|
608
|
-
)
|
|
609
|
-
|
|
610
|
-
def dump(self) -> dict[str, Any]:
|
|
611
|
-
output = super().dump()
|
|
612
|
-
output["view_id"] = self.view_id.dump()
|
|
613
|
-
return output
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
@dataclass(frozen=True)
|
|
617
|
-
class HasDataFilterOnViewWithReferencesWarning(DMSSchemaWarning):
|
|
618
|
-
description = (
|
|
619
|
-
"Setting a hasData filter on a solution view which reference other containers is not recommended."
|
|
620
|
-
"This will lead to no nodes being returned when querying the solution view."
|
|
621
|
-
)
|
|
622
|
-
fix = "Use a node type filter instead"
|
|
623
|
-
error_name: ClassVar[str] = "HasDataFilterOnReferencedViewWarning"
|
|
624
|
-
|
|
625
|
-
view_id: dm.ViewId
|
|
626
|
-
references: list[dm.ViewId]
|
|
627
|
-
|
|
628
|
-
def message(self) -> str:
|
|
629
|
-
return (
|
|
630
|
-
f"Setting a hasData filter on view {self.view_id} which references other views {self.references}. "
|
|
631
|
-
"This is not recommended as it will lead to no nodes being returned when querying the solution view."
|
|
632
|
-
)
|
|
633
|
-
|
|
634
|
-
def dump(self) -> dict[str, Any]:
|
|
635
|
-
output = super().dump()
|
|
636
|
-
output["view_id"] = self.view_id.dump()
|
|
637
|
-
output["references"] = [view.dump() for view in sorted(self.references, key=lambda x: x.as_tuple())]
|
|
638
|
-
return output
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
@dataclass(frozen=True)
|
|
642
|
-
class OtherDataModelsInSpaceWarning(DMSSchemaWarning):
|
|
643
|
-
description = "The space contains other data models"
|
|
644
|
-
fix = "Move the data models to their respective spaces."
|
|
645
|
-
error_name: ClassVar[str] = "OtherDataModelsInSpaceWarning"
|
|
646
|
-
space: str
|
|
647
|
-
data_models: list[dm.DataModelId]
|
|
648
|
-
|
|
649
|
-
def message(self) -> str:
|
|
650
|
-
return (
|
|
651
|
-
f"The space {self.space} contains data models from other spaces: {self.data_models}. {self.fix}"
|
|
652
|
-
" It is recommended to only have one data model per space. This avoid potential conflicts and "
|
|
653
|
-
"makes it easier to manage the data models."
|
|
654
|
-
)
|
|
655
|
-
|
|
656
|
-
def dump(self) -> dict[str, Any]:
|
|
657
|
-
output = super().dump()
|
|
658
|
-
output["space"] = self.space
|
|
659
|
-
output["data_models"] = [data_model.dump() for data_model in self.data_models]
|
|
660
|
-
return output
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
@dataclass(frozen=True)
|
|
664
|
-
class SolutionOnTopOfSolutionModelWarning(DMSSchemaWarning):
|
|
665
|
-
description = "The data model is a solution on top of another solution"
|
|
666
|
-
fix = "Use the base solution as the data model"
|
|
667
|
-
error_name: ClassVar[str] = "SolutionOnTopOfSolutionModelWarning"
|
|
668
|
-
data_model: dm.DataModelId
|
|
669
|
-
base_data_model: dm.DataModelId
|
|
670
|
-
|
|
671
|
-
def message(self) -> str:
|
|
672
|
-
return (
|
|
673
|
-
f"The data model {self.data_model} is a solution model on top of another solution {self.base_data_model} "
|
|
674
|
-
"model. This is not recommended as it can lead to confusion and errors. It is very hard to "
|
|
675
|
-
"maintain a nested structure of solution models. Instead, only build solution models on "
|
|
676
|
-
"top of enterprise models."
|
|
677
|
-
)
|
|
678
|
-
|
|
679
|
-
def dump(self) -> dict[str, Any]:
|
|
680
|
-
output = super().dump()
|
|
681
|
-
output["data_model"] = self.data_model.dump()
|
|
682
|
-
output["base_data_model"] = self.base_data_model.dump()
|
|
683
|
-
return output
|