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.
Files changed (103) hide show
  1. cognite/neat/_version.py +1 -1
  2. cognite/neat/graph/__init__.py +0 -3
  3. cognite/neat/graph/loaders/_base.py +6 -6
  4. cognite/neat/graph/loaders/_rdf2asset.py +28 -31
  5. cognite/neat/graph/loaders/_rdf2dms.py +24 -15
  6. cognite/neat/issues/__init__.py +14 -0
  7. cognite/neat/issues/_base.py +415 -0
  8. cognite/neat/issues/errors/__init__.py +72 -0
  9. cognite/neat/issues/errors/_external.py +67 -0
  10. cognite/neat/issues/errors/_general.py +28 -0
  11. cognite/neat/issues/errors/_properties.py +62 -0
  12. cognite/neat/issues/errors/_resources.py +111 -0
  13. cognite/neat/issues/errors/_workflow.py +36 -0
  14. cognite/neat/{rules/issues → issues}/formatters.py +10 -10
  15. cognite/neat/issues/warnings/__init__.py +66 -0
  16. cognite/neat/issues/warnings/_external.py +40 -0
  17. cognite/neat/issues/warnings/_general.py +29 -0
  18. cognite/neat/issues/warnings/_models.py +92 -0
  19. cognite/neat/issues/warnings/_properties.py +44 -0
  20. cognite/neat/issues/warnings/_resources.py +55 -0
  21. cognite/neat/issues/warnings/user_modeling.py +113 -0
  22. cognite/neat/rules/_shared.py +10 -2
  23. cognite/neat/rules/exporters/_base.py +6 -6
  24. cognite/neat/rules/exporters/_rules2dms.py +19 -11
  25. cognite/neat/rules/exporters/_rules2excel.py +4 -4
  26. cognite/neat/rules/exporters/_rules2ontology.py +74 -51
  27. cognite/neat/rules/exporters/_rules2yaml.py +3 -3
  28. cognite/neat/rules/exporters/_validation.py +11 -96
  29. cognite/neat/rules/importers/__init__.py +7 -3
  30. cognite/neat/rules/importers/_base.py +9 -13
  31. cognite/neat/rules/importers/_dms2rules.py +42 -24
  32. cognite/neat/rules/importers/_dtdl2rules/dtdl_converter.py +49 -53
  33. cognite/neat/rules/importers/_dtdl2rules/dtdl_importer.py +31 -23
  34. cognite/neat/rules/importers/_dtdl2rules/spec.py +7 -0
  35. cognite/neat/rules/importers/_rdf/_imf2rules/__init__.py +3 -0
  36. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2classes.py +82 -0
  37. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2metadata.py +34 -0
  38. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2properties.py +123 -0
  39. cognite/neat/rules/importers/{_owl2rules/_owl2rules.py → _rdf/_imf2rules/_imf2rules.py} +24 -18
  40. cognite/neat/rules/importers/{_inference2rules.py → _rdf/_inference2rules.py} +9 -9
  41. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2classes.py +58 -0
  42. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2metadata.py +68 -0
  43. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2properties.py +60 -0
  44. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2rules.py +76 -0
  45. cognite/neat/rules/importers/_rdf/_shared.py +586 -0
  46. cognite/neat/rules/importers/_spreadsheet2rules.py +35 -22
  47. cognite/neat/rules/importers/_yaml2rules.py +23 -21
  48. cognite/neat/rules/models/_constants.py +2 -1
  49. cognite/neat/rules/models/_rdfpath.py +4 -4
  50. cognite/neat/rules/models/_types/_field.py +9 -11
  51. cognite/neat/rules/models/asset/_rules.py +1 -3
  52. cognite/neat/rules/models/asset/_validation.py +14 -10
  53. cognite/neat/rules/models/dms/_converter.py +2 -4
  54. cognite/neat/rules/models/dms/_exporter.py +30 -8
  55. cognite/neat/rules/models/dms/_rules.py +23 -7
  56. cognite/neat/rules/models/dms/_schema.py +94 -62
  57. cognite/neat/rules/models/dms/_validation.py +105 -66
  58. cognite/neat/rules/models/entities.py +3 -0
  59. cognite/neat/rules/models/information/_converter.py +2 -2
  60. cognite/neat/rules/models/information/_rules.py +7 -8
  61. cognite/neat/rules/models/information/_validation.py +48 -25
  62. cognite/neat/rules/transformers/__init__.py +0 -0
  63. cognite/neat/rules/transformers/_base.py +15 -0
  64. cognite/neat/utils/auxiliary.py +2 -35
  65. cognite/neat/utils/text.py +17 -0
  66. cognite/neat/workflows/base.py +4 -4
  67. cognite/neat/workflows/cdf_store.py +3 -3
  68. cognite/neat/workflows/steps/data_contracts.py +1 -1
  69. cognite/neat/workflows/steps/lib/current/graph_extractor.py +3 -3
  70. cognite/neat/workflows/steps/lib/current/graph_loader.py +2 -2
  71. cognite/neat/workflows/steps/lib/current/graph_store.py +1 -1
  72. cognite/neat/workflows/steps/lib/current/rules_exporter.py +10 -10
  73. cognite/neat/workflows/steps/lib/current/rules_importer.py +78 -6
  74. cognite/neat/workflows/steps/lib/current/rules_validator.py +20 -9
  75. cognite/neat/workflows/steps/lib/io/io_steps.py +5 -5
  76. cognite/neat/workflows/steps_registry.py +4 -5
  77. {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.3.dist-info}/METADATA +1 -1
  78. {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.3.dist-info}/RECORD +86 -77
  79. cognite/neat/exceptions.py +0 -145
  80. cognite/neat/graph/exceptions.py +0 -90
  81. cognite/neat/graph/issues/loader.py +0 -104
  82. cognite/neat/issues.py +0 -158
  83. cognite/neat/rules/importers/_owl2rules/_owl2classes.py +0 -215
  84. cognite/neat/rules/importers/_owl2rules/_owl2metadata.py +0 -209
  85. cognite/neat/rules/importers/_owl2rules/_owl2properties.py +0 -203
  86. cognite/neat/rules/issues/__init__.py +0 -26
  87. cognite/neat/rules/issues/base.py +0 -82
  88. cognite/neat/rules/issues/dms.py +0 -683
  89. cognite/neat/rules/issues/fileread.py +0 -197
  90. cognite/neat/rules/issues/importing.py +0 -423
  91. cognite/neat/rules/issues/ontology.py +0 -298
  92. cognite/neat/rules/issues/spreadsheet.py +0 -563
  93. cognite/neat/rules/issues/spreadsheet_file.py +0 -151
  94. cognite/neat/rules/issues/tables.py +0 -72
  95. cognite/neat/workflows/_exceptions.py +0 -41
  96. /cognite/neat/{graph/issues → rules/importers/_rdf}/__init__.py +0 -0
  97. /cognite/neat/rules/importers/{_owl2rules → _rdf/_owl2rules}/__init__.py +0 -0
  98. /cognite/neat/{graph/stores → store}/__init__.py +0 -0
  99. /cognite/neat/{graph/stores → store}/_base.py +0 -0
  100. /cognite/neat/{graph/stores → store}/_provenance.py +0 -0
  101. {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.3.dist-info}/LICENSE +0 -0
  102. {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.3.dist-info}/WHEEL +0 -0
  103. {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.3.dist-info}/entry_points.txt +0 -0
@@ -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