cognite-neat 0.88.2__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 (97) hide show
  1. cognite/neat/_version.py +1 -1
  2. cognite/neat/graph/__init__.py +0 -3
  3. cognite/neat/graph/loaders/_base.py +3 -3
  4. cognite/neat/graph/loaders/_rdf2asset.py +24 -25
  5. cognite/neat/graph/loaders/_rdf2dms.py +20 -15
  6. cognite/neat/issues/__init__.py +1 -3
  7. cognite/neat/issues/_base.py +259 -70
  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/issues/formatters.py +1 -1
  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 +18 -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/_base.py +8 -12
  30. cognite/neat/rules/importers/_dms2rules.py +21 -24
  31. cognite/neat/rules/importers/_dtdl2rules/dtdl_converter.py +22 -17
  32. cognite/neat/rules/importers/_dtdl2rules/dtdl_importer.py +26 -19
  33. cognite/neat/rules/importers/_dtdl2rules/spec.py +7 -0
  34. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2classes.py +1 -1
  35. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2rules.py +9 -7
  36. cognite/neat/rules/importers/_rdf/_inference2rules.py +8 -8
  37. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2classes.py +1 -0
  38. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2properties.py +1 -0
  39. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2rules.py +4 -4
  40. cognite/neat/rules/importers/_rdf/_shared.py +3 -3
  41. cognite/neat/rules/importers/_spreadsheet2rules.py +35 -22
  42. cognite/neat/rules/importers/_yaml2rules.py +23 -22
  43. cognite/neat/rules/models/_constants.py +2 -1
  44. cognite/neat/rules/models/_rdfpath.py +4 -4
  45. cognite/neat/rules/models/_types/_field.py +5 -10
  46. cognite/neat/rules/models/asset/_rules.py +1 -3
  47. cognite/neat/rules/models/asset/_validation.py +13 -9
  48. cognite/neat/rules/models/dms/_converter.py +2 -4
  49. cognite/neat/rules/models/dms/_exporter.py +30 -8
  50. cognite/neat/rules/models/dms/_rules.py +23 -7
  51. cognite/neat/rules/models/dms/_schema.py +87 -78
  52. cognite/neat/rules/models/dms/_validation.py +104 -65
  53. cognite/neat/rules/models/information/_converter.py +2 -2
  54. cognite/neat/rules/models/information/_rules.py +7 -8
  55. cognite/neat/rules/models/information/_validation.py +47 -24
  56. cognite/neat/rules/transformers/_base.py +15 -0
  57. cognite/neat/utils/auxiliary.py +2 -35
  58. cognite/neat/utils/text.py +17 -0
  59. cognite/neat/workflows/base.py +4 -4
  60. cognite/neat/workflows/cdf_store.py +3 -3
  61. cognite/neat/workflows/steps/data_contracts.py +1 -1
  62. cognite/neat/workflows/steps/lib/current/graph_extractor.py +3 -3
  63. cognite/neat/workflows/steps/lib/current/graph_loader.py +2 -2
  64. cognite/neat/workflows/steps/lib/current/graph_store.py +1 -1
  65. cognite/neat/workflows/steps/lib/current/rules_exporter.py +10 -10
  66. cognite/neat/workflows/steps/lib/current/rules_importer.py +6 -6
  67. cognite/neat/workflows/steps/lib/current/rules_validator.py +5 -6
  68. cognite/neat/workflows/steps/lib/io/io_steps.py +5 -5
  69. cognite/neat/workflows/steps_registry.py +4 -5
  70. {cognite_neat-0.88.2.dist-info → cognite_neat-0.88.3.dist-info}/METADATA +1 -1
  71. {cognite_neat-0.88.2.dist-info → cognite_neat-0.88.3.dist-info}/RECORD +78 -84
  72. cognite/neat/exceptions.py +0 -145
  73. cognite/neat/graph/exceptions.py +0 -90
  74. cognite/neat/issues/errors/external.py +0 -21
  75. cognite/neat/issues/errors/properties.py +0 -75
  76. cognite/neat/issues/errors/resources.py +0 -123
  77. cognite/neat/issues/neat_warnings/__init__.py +0 -2
  78. cognite/neat/issues/neat_warnings/identifier.py +0 -27
  79. cognite/neat/issues/neat_warnings/models.py +0 -22
  80. cognite/neat/issues/neat_warnings/properties.py +0 -77
  81. cognite/neat/issues/neat_warnings/resources.py +0 -125
  82. cognite/neat/rules/issues/__init__.py +0 -22
  83. cognite/neat/rules/issues/base.py +0 -63
  84. cognite/neat/rules/issues/dms.py +0 -549
  85. cognite/neat/rules/issues/fileread.py +0 -197
  86. cognite/neat/rules/issues/ontology.py +0 -298
  87. cognite/neat/rules/issues/spreadsheet.py +0 -563
  88. cognite/neat/rules/issues/spreadsheet_file.py +0 -151
  89. cognite/neat/rules/issues/tables.py +0 -72
  90. cognite/neat/workflows/_exceptions.py +0 -41
  91. /cognite/neat/{issues/errors/schema.py → rules/transformers/__init__.py} +0 -0
  92. /cognite/neat/{graph/stores → store}/__init__.py +0 -0
  93. /cognite/neat/{graph/stores → store}/_base.py +0 -0
  94. /cognite/neat/{graph/stores → store}/_provenance.py +0 -0
  95. {cognite_neat-0.88.2.dist-info → cognite_neat-0.88.3.dist-info}/LICENSE +0 -0
  96. {cognite_neat-0.88.2.dist-info → cognite_neat-0.88.3.dist-info}/WHEEL +0 -0
  97. {cognite_neat-0.88.2.dist-info → cognite_neat-0.88.3.dist-info}/entry_points.txt +0 -0
@@ -1,563 +0,0 @@
1
- import sys
2
- from abc import ABC, abstractmethod
3
- from dataclasses import dataclass
4
- from functools import total_ordering
5
- from typing import Any, ClassVar
6
-
7
- from cognite.client.data_classes import data_modeling as dm
8
- from cognite.client.data_classes.data_modeling import ContainerId, ViewId
9
- from pydantic_core import ErrorDetails
10
- from rdflib import Namespace
11
-
12
- from cognite.neat.issues import MultiValueError, NeatError
13
- from cognite.neat.utils.spreadsheet import SpreadsheetRead
14
-
15
- from .base import DefaultPydanticError, NeatValidationError
16
-
17
- if sys.version_info >= (3, 11):
18
- from typing import Self
19
- else:
20
- from typing_extensions import Self
21
-
22
- __all__ = [
23
- "InvalidSheetError",
24
- "InvalidRowError",
25
- "InvalidPropertyError",
26
- "InvalidClassError",
27
- "PrefixNamespaceCollisionError",
28
- "InvalidContainerError",
29
- "InvalidViewError",
30
- "InvalidRowUnknownSheetError",
31
- "NonExistingContainerError",
32
- "NonExistingViewError",
33
- "ClassNoPropertiesNoParentError",
34
- "InconsistentContainerDefinitionError",
35
- "MultiValueTypeError",
36
- "MultiValueIsListError",
37
- "MultiNullableError",
38
- "MultiDefaultError",
39
- "MultiIndexError",
40
- "MultiUniqueConstraintError",
41
- "RegexViolationError",
42
- ]
43
-
44
-
45
- @dataclass(frozen=True)
46
- class InvalidSheetError(NeatValidationError, ABC):
47
- @classmethod
48
- @abstractmethod
49
- def from_pydantic_error(
50
- cls,
51
- error: ErrorDetails,
52
- read_info_by_sheet: dict[str, SpreadsheetRead] | None = None,
53
- ) -> Self:
54
- raise NotImplementedError
55
-
56
- @classmethod
57
- def from_pydantic_errors(
58
- cls,
59
- errors: list[ErrorDetails],
60
- read_info_by_sheet: dict[str, SpreadsheetRead] | None = None,
61
- **kwargs: Any,
62
- ) -> "list[NeatError]":
63
- output: list[NeatError] = []
64
- for error in errors:
65
- if raised_error := error.get("ctx", {}).get("error"):
66
- if isinstance(raised_error, MultiValueError):
67
- for caught_error in raised_error.errors:
68
- reader = (read_info_by_sheet or {}).get("Properties", SpreadsheetRead())
69
- if isinstance(caught_error, InconsistentContainerDefinitionError):
70
- row_numbers = list(caught_error.row_numbers)
71
- # The Error classes are immutable, so we have to reuse the set.
72
- caught_error.row_numbers.clear()
73
- for row_no in row_numbers:
74
- # Adjusting the row number to the actual row number in the spreadsheet
75
- caught_error.row_numbers.add(reader.adjusted_row_number(row_no))
76
- if isinstance(caught_error, InvalidRowError):
77
- # Adjusting the row number to the actual row number in the spreadsheet
78
- new_row = reader.adjusted_row_number(caught_error.row)
79
- # The error is frozen, so we have to use __setattr__ to change the row number
80
- object.__setattr__(caught_error, "row", new_row)
81
- output.append(caught_error) # type: ignore[arg-type]
82
- continue
83
-
84
- if len(error["loc"]) >= 4:
85
- sheet_name, *_ = error["loc"]
86
- error_cls = _INVALID_ROW_ERROR_BY_SHEET_NAME.get(str(sheet_name), InvalidRowUnknownSheetError)
87
- output.append(error_cls.from_pydantic_error(error, read_info_by_sheet))
88
- continue
89
-
90
- output.append(DefaultPydanticError.from_pydantic_error(error))
91
- return output
92
-
93
-
94
- @dataclass(frozen=True)
95
- @total_ordering
96
- class InvalidRowError(InvalidSheetError, ABC):
97
- description: ClassVar[str] = "This is a generic class for all invalid row specifications."
98
- fix: ClassVar[str] = "Follow the instruction in the error message."
99
- sheet_name: ClassVar[str]
100
-
101
- column: str
102
- row: int
103
- type: str
104
- msg: str
105
- input: Any
106
- url: str | None
107
-
108
- def __lt__(self, other: object) -> bool:
109
- if not isinstance(other, InvalidRowError):
110
- return NotImplemented
111
- return (self.sheet_name, self.row, self.column) < (
112
- other.sheet_name,
113
- other.row,
114
- other.column,
115
- )
116
-
117
- def __eq__(self, other: object) -> bool:
118
- if not isinstance(other, InvalidRowError):
119
- return NotImplemented
120
- return (self.sheet_name, self.row, self.column) == (
121
- other.sheet_name,
122
- other.row,
123
- other.column,
124
- )
125
-
126
- @classmethod
127
- def from_pydantic_error(
128
- cls,
129
- error: ErrorDetails,
130
- read_info_by_sheet: dict[str, SpreadsheetRead] | None = None,
131
- ) -> Self:
132
- sheet_name, _, row, column, *__ = error["loc"]
133
- reader = (read_info_by_sheet or {}).get(str(sheet_name), SpreadsheetRead())
134
- return cls(
135
- column=str(column),
136
- row=reader.adjusted_row_number(int(row)),
137
- type=error["type"],
138
- msg=error["msg"],
139
- input=error.get("input"),
140
- url=str(url) if (url := error.get("url")) else None,
141
- )
142
-
143
- def dump(self) -> dict[str, Any]:
144
- output = super().dump()
145
- output["sheet_name"] = self.sheet_name
146
- output["column"] = self.column
147
- output["row"] = self.row
148
- output["type"] = self.type
149
- output["msg"] = self.msg
150
- output["input"] = self.input
151
- output["url"] = self.url
152
- return output
153
-
154
- def message(self) -> str:
155
- input_str = str(self.input) if self.input is not None else ""
156
- input_str = input_str[:50] + "..." if len(input_str) > 50 else input_str
157
- output = (
158
- f"In {self.sheet_name}, row={self.row}, column={self.column}: {self.msg}. "
159
- f"[type={self.type}, input_value={input_str}]"
160
- )
161
- if self.url:
162
- output += f" For further information visit {self.url}"
163
- return output
164
-
165
-
166
- @dataclass(frozen=True)
167
- class InvalidPropertyError(InvalidRowError):
168
- sheet_name = "Properties"
169
-
170
-
171
- @dataclass(frozen=True)
172
- class InvalidClassError(InvalidRowError):
173
- sheet_name = "Classes"
174
-
175
-
176
- @dataclass(frozen=True)
177
- class InvalidContainerError(InvalidRowError):
178
- sheet_name = "Containers"
179
-
180
-
181
- @dataclass(frozen=True)
182
- class InvalidViewError(InvalidRowError):
183
- sheet_name = "Views"
184
-
185
-
186
- @dataclass(frozen=True)
187
- class InvalidRowUnknownSheetError(InvalidRowError):
188
- sheet_name = "Unknown"
189
-
190
- actual_sheet_name: str
191
-
192
- @classmethod
193
- def from_pydantic_error(
194
- cls,
195
- error: ErrorDetails,
196
- read_info_by_sheet: dict[str, SpreadsheetRead] | None = None,
197
- ) -> Self:
198
- sheet_name, _, row, column, *__ = error["loc"]
199
- reader = (read_info_by_sheet or {}).get(str(sheet_name), SpreadsheetRead())
200
- try:
201
- return cls(
202
- column=str(column),
203
- row=reader.adjusted_row_number(int(row)),
204
- actual_sheet_name=str(sheet_name),
205
- type=error["type"],
206
- msg=error["msg"],
207
- input=error.get("input"),
208
- url=str(url) if (url := error.get("url")) else None,
209
- )
210
- except ValueError:
211
- return DefaultPydanticError.from_pydantic_error(error) # type: ignore[return-value]
212
-
213
- def dump(self) -> dict[str, Any]:
214
- output = super().dump()
215
- output["actual_sheet_name"] = self.actual_sheet_name
216
- return output
217
-
218
-
219
- _INVALID_ROW_ERROR_BY_SHEET_NAME = {
220
- cls_.sheet_name: cls_ for cls_ in InvalidRowError.__subclasses__() if cls_ is not InvalidRowError
221
- }
222
-
223
-
224
- @dataclass(frozen=True)
225
- class NonExistingContainerError(InvalidPropertyError):
226
- description = "The container referenced by the property is missing in the container sheet"
227
- fix = "Add the container to the container sheet"
228
-
229
- container_id: ContainerId
230
-
231
- def message(self) -> str:
232
- return (
233
- f"In {self.sheet_name}, row={self.row}, column={self.column}: The container with "
234
- f"id {self.container_id} is missing in the container sheet."
235
- )
236
-
237
- def dump(self) -> dict[str, Any]:
238
- output = super().dump()
239
- output["container_id"] = self.container_id
240
- return output
241
-
242
-
243
- @dataclass(frozen=True)
244
- class NonExistingViewError(InvalidPropertyError):
245
- description = "The view referenced by the property is missing in the view sheet"
246
- fix = "Add the view to the view sheet"
247
-
248
- view_id: ViewId
249
-
250
- def message(self) -> str:
251
- return (
252
- f"In {self.sheet_name}, row={self.row}, column={self.column}: The view with "
253
- f"id {self.view_id} is missing in the view sheet."
254
- )
255
-
256
- def dump(self) -> dict[str, Any]:
257
- output = super().dump()
258
- output["view_id"] = self.view_id
259
- return output
260
-
261
-
262
- @dataclass(frozen=True)
263
- class PropertiesDefinedForUndefinedClassesError(NeatValidationError):
264
- description = "Properties are defined for undefined classes."
265
- fix = "Make sure to define class in the Classes sheet."
266
-
267
- classes: list[str]
268
-
269
- def dump(self) -> dict[str, list[str]]:
270
- output = super().dump()
271
- output["classes"] = self.classes
272
- return output
273
-
274
- def message(self) -> str:
275
- return (
276
- f"Classes {', '.join(self.classes)} have properties assigned to them, but"
277
- " they are not defined in the Classes sheet."
278
- )
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
-
299
- @dataclass(frozen=True)
300
- class ClassNoPropertiesNoParentError(NeatValidationError):
301
- description = "Class has no properties and no parents."
302
- fix = "Check if the class should have properties or parents."
303
-
304
- classes: list[str]
305
-
306
- def dump(self) -> dict[str, list[str]]:
307
- output = super().dump()
308
- output["classes"] = self.classes
309
- return output
310
-
311
- def message(self) -> str:
312
- if len(self.classes) > 1:
313
- return f"Classes {', '.join(self.classes)} have no direct or inherited properties. This may be a mistake."
314
- return f"Class {self.classes[0]} have no direct or inherited properties. This may be a mistake."
315
-
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
-
346
- @dataclass(frozen=True)
347
- class AssetRulesHaveCircularDependencyError(NeatValidationError):
348
- description = "Asset rules have circular dependencies."
349
- fix = "Linking between classes via property that maps to parent_external_id must yield hierarchy structure."
350
-
351
- classes: list[str]
352
-
353
- def dump(self) -> dict[str, list[tuple[str, str]]]:
354
- output = super().dump()
355
- output["classes"] = self.classes
356
- return output
357
-
358
- def message(self) -> str:
359
- return f"Asset rules have circular dependencies between classes {', '.join(self.classes)}."
360
-
361
-
362
- @dataclass(frozen=True)
363
- class AssetParentPropertyPointsToDataValueTypeError(NeatValidationError):
364
- description = "Parent property points to a data value type instead of a class."
365
- fix = "Make sure that the parent property points to a class."
366
-
367
- class_property_with_data_value_type: list[tuple[str, str]]
368
-
369
- def dump(self) -> dict[str, list[tuple[str, str]]]:
370
- output = super().dump()
371
- output["class_property"] = self.class_property_with_data_value_type
372
- return output
373
-
374
- def message(self) -> str:
375
- text = [
376
- f"class {class_} property {property_}" for class_, property_ in self.class_property_with_data_value_type
377
- ]
378
- return f"Following {', and'.join(text)} point to data value type instead to classes. This is a mistake."
379
-
380
-
381
- @dataclass(frozen=True)
382
- class ParentClassesNotDefinedError(NeatValidationError):
383
- description = "Parent classes are not defined."
384
- fix = "Check if the parent classes are defined in Classes sheet."
385
-
386
- classes: list[str]
387
-
388
- def dump(self) -> dict[str, list[str]]:
389
- output = super().dump()
390
- output["classes"] = self.classes
391
- return output
392
-
393
- def message(self) -> str:
394
- if len(self.classes) > 1:
395
- return f"Parent classes {', '.join(self.classes)} are not defined. This may be a mistake."
396
- return f"Parent classes {', '.join(self.classes[0])} are not defined. This may be a mistake."
397
-
398
-
399
- @dataclass(frozen=True)
400
- class PrefixNamespaceCollisionError(NeatValidationError):
401
- description = "Same namespaces are assigned to different prefixes."
402
- fix = "Make sure that each unique namespace is assigned to a unique prefix"
403
-
404
- namespaces: list[Namespace]
405
- prefixes: list[str]
406
-
407
- def dump(self) -> dict[str, list[str]]:
408
- output = super().dump()
409
- output["prefixes"] = self.prefixes
410
- output["namespaces"] = self.namespaces
411
- return output
412
-
413
- def message(self) -> str:
414
- return (
415
- f"Namespaces {', '.join(self.namespaces)} are assigned multiple times."
416
- f" Impacted prefixes: {', '.join(self.prefixes)}."
417
- )
418
-
419
-
420
- @dataclass(frozen=True)
421
- class ValueTypeNotDefinedError(NeatValidationError):
422
- description = "Value types referred by properties are not defined in Rules."
423
- fix = "Make sure that all value types are defined in Rules."
424
-
425
- value_types: list[str]
426
-
427
- def dump(self) -> dict[str, list[str]]:
428
- output = super().dump()
429
- output["classes"] = self.value_types
430
- return output
431
-
432
- def message(self) -> str:
433
- if len(self.value_types) > 1:
434
- return f"Value types {', '.join(self.value_types)} are not defined. This may be a mistake."
435
- return f"Value types {', '.join(self.value_types[0])} are not defined. This may be a mistake."
436
-
437
-
438
- @dataclass(frozen=True)
439
- class InconsistentContainerDefinitionError(NeatValidationError, ABC):
440
- description = "This is a base class for all errors related to inconsistent container definitions"
441
- fix = "Ensure all properties using the same container have the same type, constraints, and indexes."
442
- container: dm.ContainerId
443
- property_name: str
444
- row_numbers: set[int]
445
-
446
- def dump(self) -> dict[str, Any]:
447
- output = super().dump()
448
- output.update(
449
- {
450
- "container": self.container.dump(),
451
- "property_name": self.property_name,
452
- "row_numbers": sorted(self.row_numbers),
453
- }
454
- )
455
- return output
456
-
457
-
458
- @dataclass(frozen=True)
459
- class MultiValueTypeError(InconsistentContainerDefinitionError):
460
- description = "The property has multiple value types"
461
- fix = "Use the same value type for all properties using the same container."
462
- value_types: set[str]
463
-
464
- def message(self) -> str:
465
- return (
466
- f"{self.container}.{self.property_name} defined in rows: {sorted(self.row_numbers)} "
467
- f"has different value types: {self.value_types}"
468
- )
469
-
470
- def dump(self) -> dict[str, Any]:
471
- output = super().dump()
472
- output["value_types"] = sorted(self.value_types)
473
- return output
474
-
475
-
476
- @dataclass(frozen=True)
477
- class MultiValueIsListError(InconsistentContainerDefinitionError):
478
- description = "The property has multiple list definitions"
479
- fix = "Use the same list definition for all properties using the same container."
480
- list_definitions: set[bool]
481
-
482
- def message(self) -> str:
483
- return (
484
- f"{self.container}.{self.property_name} defined in rows: {sorted(self.row_numbers)} "
485
- f"has different list definitions: {self.list_definitions}"
486
- )
487
-
488
- def dump(self) -> dict[str, Any]:
489
- output = super().dump()
490
- output["list_definitions"] = sorted(self.list_definitions)
491
- return output
492
-
493
-
494
- @dataclass(frozen=True)
495
- class MultiNullableError(InconsistentContainerDefinitionError):
496
- description = "The property has multiple nullable definitions"
497
- fix = "Use the same nullable definition for all properties using the same container."
498
- nullable_definitions: set[bool]
499
-
500
- def message(self) -> str:
501
- return (
502
- f"{self.container}.{self.property_name} defined in rows: {sorted(self.row_numbers)} "
503
- f"has different nullable definitions: {self.nullable_definitions}"
504
- )
505
-
506
- def dump(self) -> dict[str, Any]:
507
- output = super().dump()
508
- output["nullable_definitions"] = sorted(self.nullable_definitions)
509
- return output
510
-
511
-
512
- @dataclass(frozen=True)
513
- class MultiDefaultError(InconsistentContainerDefinitionError):
514
- description = "The property has multiple default definitions"
515
- fix = "Use the same default definition for all properties using the same container."
516
- default_definitions: list[str | int | dict | None]
517
-
518
- def message(self) -> str:
519
- return (
520
- f"{self.container}.{self.property_name} defined in rows: {sorted(self.row_numbers)} "
521
- f"has different default definitions: {self.default_definitions}"
522
- )
523
-
524
- def dump(self) -> dict[str, Any]:
525
- output = super().dump()
526
- output["default_definitions"] = self.default_definitions
527
- return output
528
-
529
-
530
- @dataclass(frozen=True)
531
- class MultiIndexError(InconsistentContainerDefinitionError):
532
- description = "The property has multiple index definitions"
533
- fix = "Use the same index definition for all properties using the same container."
534
- index_definitions: set[str]
535
-
536
- def message(self) -> str:
537
- return (
538
- f"{self.container}.{self.property_name} defined in rows: {sorted(self.row_numbers)} "
539
- f"has different index definitions: {self.index_definitions}"
540
- )
541
-
542
- def dump(self) -> dict[str, Any]:
543
- output = super().dump()
544
- output["index_definitions"] = sorted(self.index_definitions)
545
- return output
546
-
547
-
548
- @dataclass(frozen=True)
549
- class MultiUniqueConstraintError(InconsistentContainerDefinitionError):
550
- description = "The property has multiple unique constraint definitions"
551
- fix = "Use the same unique constraint definition for all properties using the same container."
552
- unique_constraint_definitions: set[str]
553
-
554
- def message(self) -> str:
555
- return (
556
- f"{self.container}.{self.property_name} defined in rows: {sorted(self.row_numbers)} "
557
- f"has different unique constraint definitions: {self.unique_constraint_definitions}"
558
- )
559
-
560
- def dump(self) -> dict[str, Any]:
561
- output = super().dump()
562
- output["unique_constraint_definitions"] = sorted(self.unique_constraint_definitions)
563
- return output