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