cognite-neat 0.88.3__py3-none-any.whl → 0.90.0__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/constants.py +6 -3
- cognite/neat/graph/extractors/__init__.py +2 -0
- cognite/neat/graph/extractors/_classic_cdf/_base.py +2 -2
- cognite/neat/graph/extractors/_dms.py +158 -0
- cognite/neat/graph/extractors/_mock_graph_generator.py +50 -9
- cognite/neat/graph/loaders/_rdf2dms.py +16 -13
- cognite/neat/graph/models.py +1 -0
- cognite/neat/graph/queries/_base.py +4 -2
- cognite/neat/issues/_base.py +3 -1
- cognite/neat/issues/errors/__init__.py +2 -1
- cognite/neat/issues/errors/_general.py +7 -0
- cognite/neat/issues/warnings/__init__.py +2 -0
- cognite/neat/issues/warnings/_models.py +1 -1
- cognite/neat/issues/warnings/_properties.py +12 -0
- cognite/neat/issues/warnings/user_modeling.py +1 -1
- cognite/neat/rules/_shared.py +49 -6
- cognite/neat/rules/analysis/_base.py +1 -1
- cognite/neat/rules/exporters/_base.py +7 -18
- cognite/neat/rules/exporters/_rules2dms.py +8 -18
- cognite/neat/rules/exporters/_rules2excel.py +5 -12
- cognite/neat/rules/exporters/_rules2ontology.py +9 -19
- cognite/neat/rules/exporters/_rules2yaml.py +3 -6
- cognite/neat/rules/importers/_base.py +7 -52
- cognite/neat/rules/importers/_dms2rules.py +172 -116
- cognite/neat/rules/importers/_dtdl2rules/dtdl_converter.py +26 -18
- cognite/neat/rules/importers/_dtdl2rules/dtdl_importer.py +14 -30
- cognite/neat/rules/importers/_rdf/_imf2rules/_imf2classes.py +7 -3
- cognite/neat/rules/importers/_rdf/_imf2rules/_imf2metadata.py +3 -3
- cognite/neat/rules/importers/_rdf/_imf2rules/_imf2properties.py +18 -11
- cognite/neat/rules/importers/_rdf/_imf2rules/_imf2rules.py +9 -18
- cognite/neat/rules/importers/_rdf/_inference2rules.py +37 -65
- cognite/neat/rules/importers/_rdf/_owl2rules/_owl2rules.py +9 -20
- cognite/neat/rules/importers/_rdf/_shared.py +1 -1
- cognite/neat/rules/importers/_spreadsheet2rules.py +22 -86
- cognite/neat/rules/importers/_yaml2rules.py +14 -41
- cognite/neat/rules/models/__init__.py +21 -5
- cognite/neat/rules/models/_base_input.py +162 -0
- cognite/neat/rules/models/{_base.py → _base_rules.py} +1 -12
- cognite/neat/rules/models/asset/__init__.py +5 -2
- cognite/neat/rules/models/asset/_rules.py +2 -20
- cognite/neat/rules/models/asset/_rules_input.py +40 -115
- cognite/neat/rules/models/asset/_validation.py +1 -1
- cognite/neat/rules/models/data_types.py +150 -44
- cognite/neat/rules/models/dms/__init__.py +19 -7
- cognite/neat/rules/models/dms/_exporter.py +82 -39
- cognite/neat/rules/models/dms/_rules.py +42 -155
- cognite/neat/rules/models/dms/_rules_input.py +186 -254
- cognite/neat/rules/models/dms/_serializer.py +44 -3
- cognite/neat/rules/models/dms/_validation.py +3 -4
- cognite/neat/rules/models/domain.py +52 -1
- cognite/neat/rules/models/entities/__init__.py +63 -0
- cognite/neat/rules/models/entities/_constants.py +73 -0
- cognite/neat/rules/models/entities/_loaders.py +76 -0
- cognite/neat/rules/models/entities/_multi_value.py +67 -0
- cognite/neat/rules/models/{entities.py → entities/_single_value.py} +74 -232
- cognite/neat/rules/models/entities/_types.py +86 -0
- cognite/neat/rules/models/{wrapped_entities.py → entities/_wrapped.py} +1 -1
- cognite/neat/rules/models/information/__init__.py +10 -2
- cognite/neat/rules/models/information/_rules.py +3 -14
- cognite/neat/rules/models/information/_rules_input.py +57 -204
- cognite/neat/rules/models/information/_validation.py +1 -1
- cognite/neat/rules/transformers/__init__.py +21 -0
- cognite/neat/rules/transformers/_base.py +69 -3
- cognite/neat/rules/{models/information/_converter.py → transformers/_converters.py} +226 -21
- cognite/neat/rules/transformers/_map_onto.py +97 -0
- cognite/neat/rules/transformers/_pipelines.py +61 -0
- cognite/neat/rules/transformers/_verification.py +136 -0
- cognite/neat/store/_base.py +2 -2
- cognite/neat/store/_provenance.py +10 -1
- cognite/neat/utils/cdf/data_classes.py +20 -0
- cognite/neat/utils/regex_patterns.py +6 -0
- cognite/neat/workflows/steps/lib/current/rules_exporter.py +106 -37
- cognite/neat/workflows/steps/lib/current/rules_importer.py +24 -22
- {cognite_neat-0.88.3.dist-info → cognite_neat-0.90.0.dist-info}/METADATA +1 -1
- {cognite_neat-0.88.3.dist-info → cognite_neat-0.90.0.dist-info}/RECORD +80 -74
- cognite/neat/rules/models/_constants.py +0 -2
- cognite/neat/rules/models/_types/__init__.py +0 -19
- cognite/neat/rules/models/asset/_converter.py +0 -4
- cognite/neat/rules/models/dms/_converter.py +0 -143
- /cognite/neat/rules/models/{_types/_field.py → _types.py} +0 -0
- {cognite_neat-0.88.3.dist-info → cognite_neat-0.90.0.dist-info}/LICENSE +0 -0
- {cognite_neat-0.88.3.dist-info → cognite_neat-0.90.0.dist-info}/WHEEL +0 -0
- {cognite_neat-0.88.3.dist-info → cognite_neat-0.90.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,29 +1,33 @@
|
|
|
1
|
-
from collections.abc import Sequence
|
|
2
1
|
from dataclasses import dataclass
|
|
3
|
-
from typing import Any
|
|
2
|
+
from typing import Any
|
|
4
3
|
|
|
5
|
-
from
|
|
4
|
+
from rdflib import Namespace
|
|
5
|
+
|
|
6
|
+
from cognite.neat.rules.models._base_input import InputComponent, InputRules
|
|
6
7
|
from cognite.neat.rules.models.data_types import DataType
|
|
7
8
|
from cognite.neat.rules.models.entities import (
|
|
8
9
|
ClassEntity,
|
|
9
10
|
MultiValueTypeInfo,
|
|
10
|
-
Unknown,
|
|
11
11
|
UnknownEntity,
|
|
12
|
+
load_value_type,
|
|
12
13
|
)
|
|
13
|
-
from cognite.neat.rules.models.information._rules_input import
|
|
14
|
+
from cognite.neat.rules.models.information._rules_input import InformationInputClass, InformationInputMetadata
|
|
14
15
|
|
|
15
|
-
from ._rules import AssetProperty, AssetRules
|
|
16
|
+
from ._rules import AssetClass, AssetMetadata, AssetProperty, AssetRules
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
@dataclass
|
|
19
|
-
class
|
|
20
|
+
class AssetInputMetadata(InformationInputMetadata):
|
|
21
|
+
@classmethod
|
|
22
|
+
def _get_verified_cls(cls) -> type[AssetMetadata]:
|
|
23
|
+
return AssetMetadata
|
|
20
24
|
|
|
21
25
|
|
|
22
26
|
@dataclass
|
|
23
|
-
class
|
|
24
|
-
class_: str
|
|
27
|
+
class AssetInputProperty(InputComponent[AssetProperty]):
|
|
28
|
+
class_: ClassEntity | str
|
|
25
29
|
property_: str
|
|
26
|
-
value_type: str
|
|
30
|
+
value_type: DataType | ClassEntity | MultiValueTypeInfo | UnknownEntity | str
|
|
27
31
|
name: str | None = None
|
|
28
32
|
description: str | None = None
|
|
29
33
|
comment: str | None = None
|
|
@@ -34,133 +38,54 @@ class AssetPropertyInput:
|
|
|
34
38
|
match_type: str | None = None
|
|
35
39
|
transformation: str | None = None
|
|
36
40
|
implementation: str | None = None
|
|
41
|
+
# Only used internally
|
|
42
|
+
inherited: bool = False
|
|
37
43
|
|
|
38
44
|
@classmethod
|
|
39
|
-
|
|
40
|
-
|
|
45
|
+
def _get_verified_cls(cls) -> type[AssetProperty]:
|
|
46
|
+
return AssetProperty
|
|
41
47
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
def dump(self, default_prefix: str) -> dict[str, Any]: # type: ignore[override]
|
|
49
|
+
output = super().dump()
|
|
50
|
+
output["Class"] = ClassEntity.load(self.class_, prefix=default_prefix)
|
|
51
|
+
output["Value Type"] = load_value_type(self.value_type, default_prefix)
|
|
52
|
+
return output
|
|
45
53
|
|
|
46
|
-
@classmethod
|
|
47
|
-
@overload
|
|
48
|
-
def load(cls, data: list[dict[str, Any]]) -> list["AssetPropertyInput"]: ...
|
|
49
54
|
|
|
55
|
+
@dataclass
|
|
56
|
+
class AssetInputClass(InformationInputClass):
|
|
50
57
|
@classmethod
|
|
51
|
-
def
|
|
52
|
-
|
|
53
|
-
) -> "AssetPropertyInput | list[AssetPropertyInput] | None":
|
|
54
|
-
if data is None:
|
|
55
|
-
return None
|
|
56
|
-
if isinstance(data, list) or (isinstance(data, dict) and isinstance(data.get("data"), list)):
|
|
57
|
-
items = cast(list[dict[str, Any]], data.get("data") if isinstance(data, dict) else data)
|
|
58
|
-
return [loaded for item in items if (loaded := cls.load(item)) is not None]
|
|
59
|
-
|
|
60
|
-
_add_alias(data, AssetProperty)
|
|
61
|
-
return cls(
|
|
62
|
-
class_=data.get("class_"), # type: ignore[arg-type]
|
|
63
|
-
property_=data.get("property_"), # type: ignore[arg-type]
|
|
64
|
-
name=data.get("name", None),
|
|
65
|
-
description=data.get("description", None),
|
|
66
|
-
comment=data.get("comment", None),
|
|
67
|
-
value_type=data.get("value_type"), # type: ignore[arg-type]
|
|
68
|
-
min_count=data.get("min_count", None),
|
|
69
|
-
max_count=data.get("max_count", None),
|
|
70
|
-
default=data.get("default", None),
|
|
71
|
-
reference=data.get("reference", None),
|
|
72
|
-
match_type=data.get("match_type", None),
|
|
73
|
-
transformation=data.get("transformation", None),
|
|
74
|
-
implementation=data.get("implementation", None),
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
def dump(self, default_prefix: str) -> dict[str, Any]:
|
|
78
|
-
value_type: MultiValueTypeInfo | DataType | ClassEntity | UnknownEntity
|
|
79
|
-
|
|
80
|
-
# property holding xsd data type
|
|
81
|
-
# check if it is multi value type
|
|
82
|
-
if "|" in self.value_type:
|
|
83
|
-
value_type = MultiValueTypeInfo.load(self.value_type)
|
|
84
|
-
value_type.set_default_prefix(default_prefix)
|
|
85
|
-
|
|
86
|
-
elif DataType.is_data_type(self.value_type):
|
|
87
|
-
value_type = DataType.load(self.value_type)
|
|
88
|
-
|
|
89
|
-
# unknown value type
|
|
90
|
-
elif self.value_type == str(Unknown):
|
|
91
|
-
value_type = UnknownEntity()
|
|
92
|
-
|
|
93
|
-
# property holding link to class
|
|
94
|
-
else:
|
|
95
|
-
value_type = ClassEntity.load(self.value_type, prefix=default_prefix)
|
|
96
|
-
|
|
97
|
-
return {
|
|
98
|
-
"Class": ClassEntity.load(self.class_, prefix=default_prefix),
|
|
99
|
-
"Property": self.property_,
|
|
100
|
-
"Name": self.name,
|
|
101
|
-
"Description": self.description,
|
|
102
|
-
"Comment": self.comment,
|
|
103
|
-
"Value Type": value_type,
|
|
104
|
-
"Min Count": self.min_count,
|
|
105
|
-
"Max Count": self.max_count,
|
|
106
|
-
"Default": self.default,
|
|
107
|
-
"Reference": self.reference,
|
|
108
|
-
"Match Type": self.match_type,
|
|
109
|
-
"Transformation": self.transformation,
|
|
110
|
-
"Implementation": self.implementation,
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
class AssetClassInput(InformationClassInput): ...
|
|
58
|
+
def _get_verified_cls(cls) -> type[AssetClass]:
|
|
59
|
+
return AssetClass
|
|
115
60
|
|
|
116
61
|
|
|
117
62
|
@dataclass
|
|
118
|
-
class
|
|
119
|
-
metadata:
|
|
120
|
-
properties:
|
|
121
|
-
classes:
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
@classmethod
|
|
126
|
-
@overload
|
|
127
|
-
def load(cls, data: dict[str, Any]) -> "AssetRulesInput": ...
|
|
128
|
-
|
|
129
|
-
@classmethod
|
|
130
|
-
@overload
|
|
131
|
-
def load(cls, data: None) -> None: ...
|
|
63
|
+
class AssetInputRules(InputRules[AssetRules]):
|
|
64
|
+
metadata: AssetInputMetadata
|
|
65
|
+
properties: list[AssetInputProperty]
|
|
66
|
+
classes: list[AssetInputClass]
|
|
67
|
+
prefixes: dict[str, Namespace] | None = None
|
|
68
|
+
last: "AssetInputRules | None" = None
|
|
69
|
+
reference: "AssetInputRules | None" = None
|
|
132
70
|
|
|
133
71
|
@classmethod
|
|
134
|
-
def
|
|
135
|
-
|
|
136
|
-
return None
|
|
137
|
-
_add_alias(data, AssetRules)
|
|
138
|
-
|
|
139
|
-
return cls(
|
|
140
|
-
metadata=AssetMetadataInput.load(data.get("metadata")), # type: ignore[arg-type]
|
|
141
|
-
properties=AssetPropertyInput.load(data.get("properties")), # type: ignore[arg-type]
|
|
142
|
-
classes=InformationClassInput.load(data.get("classes")), # type: ignore[arg-type]
|
|
143
|
-
last=AssetRulesInput.load(data.get("last")),
|
|
144
|
-
reference=AssetRulesInput.load(data.get("reference")),
|
|
145
|
-
)
|
|
146
|
-
|
|
147
|
-
def as_rules(self) -> AssetRules:
|
|
148
|
-
return AssetRules.model_validate(self.dump())
|
|
72
|
+
def _get_verified_cls(cls) -> type[AssetRules]:
|
|
73
|
+
return AssetRules
|
|
149
74
|
|
|
150
75
|
def dump(self) -> dict[str, Any]:
|
|
151
76
|
default_prefix = self.metadata.prefix
|
|
152
77
|
reference: dict[str, Any] | None = None
|
|
153
|
-
if isinstance(self.reference,
|
|
78
|
+
if isinstance(self.reference, AssetInputRules):
|
|
154
79
|
reference = self.reference.dump()
|
|
155
80
|
elif isinstance(self.reference, AssetRules):
|
|
156
81
|
# We need to load through the AssetRulesInput to set the correct default space and version
|
|
157
|
-
reference =
|
|
82
|
+
reference = AssetInputRules.load(self.reference.model_dump()).dump()
|
|
158
83
|
last: dict[str, Any] | None = None
|
|
159
|
-
if isinstance(self.last,
|
|
84
|
+
if isinstance(self.last, AssetInputRules):
|
|
160
85
|
last = self.last.dump()
|
|
161
86
|
elif isinstance(self.last, AssetRules):
|
|
162
87
|
# We need to load through the AssetRulesInput to set the correct default space and version
|
|
163
|
-
last =
|
|
88
|
+
last = AssetInputRules.load(self.last.model_dump()).dump()
|
|
164
89
|
|
|
165
90
|
return dict(
|
|
166
91
|
Metadata=self.metadata.dump(),
|
|
@@ -3,7 +3,7 @@ from typing import cast
|
|
|
3
3
|
|
|
4
4
|
from cognite.neat.issues import IssueList
|
|
5
5
|
from cognite.neat.issues.errors import NeatValueError, PropertyDefinitionError
|
|
6
|
-
from cognite.neat.rules.models.
|
|
6
|
+
from cognite.neat.rules.models._base_rules import SheetList
|
|
7
7
|
from cognite.neat.rules.models.asset._rules import AssetProperty, AssetRules
|
|
8
8
|
from cognite.neat.rules.models.entities import AssetEntity, AssetFields, ClassEntity
|
|
9
9
|
from cognite.neat.rules.models.information._validation import InformationPostValidation
|
|
@@ -1,30 +1,62 @@
|
|
|
1
|
+
import re
|
|
1
2
|
import sys
|
|
3
|
+
import typing
|
|
2
4
|
from datetime import date, datetime
|
|
3
5
|
from typing import Any, ClassVar
|
|
4
6
|
|
|
5
7
|
from cognite.client.data_classes import data_modeling as dms
|
|
6
|
-
from
|
|
8
|
+
from cognite.client.data_classes.data_modeling.data_types import Enum as DMSEnum
|
|
9
|
+
from pydantic import BaseModel, Field, model_serializer, model_validator
|
|
7
10
|
from pydantic.functional_validators import ModelWrapValidatorHandler
|
|
8
11
|
|
|
12
|
+
from cognite.neat.rules.models.entities._single_value import ClassEntity, UnitEntity
|
|
13
|
+
from cognite.neat.utils.regex_patterns import SPLIT_ON_COMMA_PATTERN, SPLIT_ON_EQUAL_PATTERN
|
|
14
|
+
|
|
9
15
|
if sys.version_info >= (3, 11):
|
|
10
16
|
from typing import Self
|
|
11
17
|
else:
|
|
12
18
|
from typing_extensions import Self
|
|
13
19
|
|
|
20
|
+
# This patterns matches a string that is a data type, with optional content in parentheses.
|
|
21
|
+
# For example, it matches "float(unit=power:megaw)" as name="float" and content="unit=power:megaw"
|
|
22
|
+
_DATATYPE_PATTERN = re.compile(r"^(?P<name>[^(:]*)(\((?P<content>.+)\))?$")
|
|
14
23
|
|
|
15
|
-
class DataType(BaseModel):
|
|
16
|
-
# These are necessary for Pydantic to work
|
|
17
|
-
# pydantic gets confused as we have no fields.
|
|
18
|
-
__pydantic_extra__ = None
|
|
19
|
-
__pydantic_fields_set__ = set()
|
|
20
|
-
__pydantic_private__ = {}
|
|
21
24
|
|
|
22
|
-
|
|
25
|
+
class DataType(BaseModel):
|
|
23
26
|
python: ClassVar[type]
|
|
24
27
|
dms: ClassVar[type[dms.PropertyType]]
|
|
25
28
|
graphql: ClassVar[str]
|
|
26
29
|
xsd: ClassVar[str]
|
|
27
30
|
sql: ClassVar[str]
|
|
31
|
+
_dms_loaded: bool = False
|
|
32
|
+
# Repeat all here, just to make mypy happy
|
|
33
|
+
name: typing.Literal[
|
|
34
|
+
"boolean",
|
|
35
|
+
"token",
|
|
36
|
+
"float",
|
|
37
|
+
"double",
|
|
38
|
+
"integer",
|
|
39
|
+
"nonPositiveInteger",
|
|
40
|
+
"nonNegativeInteger",
|
|
41
|
+
"long",
|
|
42
|
+
"negativeInteger",
|
|
43
|
+
"string",
|
|
44
|
+
"langString",
|
|
45
|
+
"anyURI",
|
|
46
|
+
"normalizedString",
|
|
47
|
+
"dateTime",
|
|
48
|
+
"timestamp",
|
|
49
|
+
"dateTimeStamp",
|
|
50
|
+
"date",
|
|
51
|
+
"plainLiteral",
|
|
52
|
+
"Literal",
|
|
53
|
+
"timeseries",
|
|
54
|
+
"file",
|
|
55
|
+
"sequence",
|
|
56
|
+
"json",
|
|
57
|
+
"enum",
|
|
58
|
+
"",
|
|
59
|
+
] = ""
|
|
28
60
|
|
|
29
61
|
@classmethod
|
|
30
62
|
def load(cls, data: Any) -> Self:
|
|
@@ -35,15 +67,31 @@ class DataType(BaseModel):
|
|
|
35
67
|
|
|
36
68
|
@model_validator(mode="wrap")
|
|
37
69
|
def _load(cls, value: Any, handler: ModelWrapValidatorHandler["DataType"]) -> Any:
|
|
38
|
-
if isinstance(value,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
70
|
+
if cls is not DataType or isinstance(value, DataType):
|
|
71
|
+
# This is a subclass, let the subclass handle it
|
|
72
|
+
return handler(value)
|
|
73
|
+
elif isinstance(value, str) and (match := _DATATYPE_PATTERN.match(value)):
|
|
74
|
+
name = match.group("name").casefold()
|
|
75
|
+
cls_: type[DataType]
|
|
76
|
+
if name in _DATA_TYPE_BY_DMS_TYPE:
|
|
77
|
+
cls_ = _DATA_TYPE_BY_DMS_TYPE[name]
|
|
78
|
+
dms_loaded = True
|
|
79
|
+
elif name in _DATA_TYPE_BY_NAME:
|
|
80
|
+
cls_ = _DATA_TYPE_BY_NAME[name]
|
|
81
|
+
dms_loaded = False
|
|
82
|
+
else:
|
|
83
|
+
raise ValueError(f"Unknown data type: {value}") from None
|
|
84
|
+
extra_args: dict[str, Any] = {}
|
|
85
|
+
if content := match.group("content"):
|
|
86
|
+
extra_args = dict(
|
|
87
|
+
SPLIT_ON_EQUAL_PATTERN.split(pair.strip()) for pair in SPLIT_ON_COMMA_PATTERN.split(content)
|
|
88
|
+
)
|
|
89
|
+
# Todo? Raise warning if extra_args contains keys that are not in the model fields
|
|
90
|
+
instance = cls_(**extra_args)
|
|
91
|
+
created = handler(instance)
|
|
92
|
+
# Private attributes are not validated or set. We need to set it manually
|
|
93
|
+
created._dms_loaded = dms_loaded
|
|
94
|
+
return created
|
|
47
95
|
raise ValueError(f"Cannot load {cls.__name__} from {value}")
|
|
48
96
|
|
|
49
97
|
@model_serializer(when_used="unless-none", return_type=str)
|
|
@@ -51,227 +99,285 @@ class DataType(BaseModel):
|
|
|
51
99
|
return str(self)
|
|
52
100
|
|
|
53
101
|
def __str__(self) -> str:
|
|
54
|
-
|
|
102
|
+
if self._dms_loaded:
|
|
103
|
+
base = self.dms._type
|
|
104
|
+
else:
|
|
105
|
+
base = self.model_fields["name"].default
|
|
106
|
+
return self._suffix_extra_args(base)
|
|
107
|
+
|
|
108
|
+
def _suffix_extra_args(self, base: str) -> str:
|
|
109
|
+
extra_fields: dict[str, str] = {}
|
|
110
|
+
for field_id, field_ in self.model_fields.items():
|
|
111
|
+
if field_id == "name":
|
|
112
|
+
continue
|
|
113
|
+
value = getattr(self, field_id)
|
|
114
|
+
if value is None:
|
|
115
|
+
continue
|
|
116
|
+
extra_fields[field_.alias or field_id] = str(value)
|
|
117
|
+
if extra_fields:
|
|
118
|
+
content = ",".join(f"{key}={value}" for key, value in sorted(extra_fields.items(), key=lambda x: x[0]))
|
|
119
|
+
return f"{base}({content})"
|
|
120
|
+
return base
|
|
55
121
|
|
|
56
122
|
def __eq__(self, other: Any) -> bool:
|
|
57
|
-
return isinstance(other, type(self))
|
|
123
|
+
return isinstance(other, type(self)) and str(self) == str(other)
|
|
58
124
|
|
|
59
125
|
def __hash__(self) -> int:
|
|
60
126
|
return hash(str(self))
|
|
61
127
|
|
|
62
128
|
@classmethod
|
|
63
129
|
def is_data_type(cls, value: str) -> bool:
|
|
64
|
-
|
|
130
|
+
if match := _DATATYPE_PATTERN.match(value):
|
|
131
|
+
name = match.group("name").casefold()
|
|
132
|
+
return name in _DATA_TYPE_BY_NAME or name in _DATA_TYPE_BY_DMS_TYPE
|
|
133
|
+
return False
|
|
65
134
|
|
|
66
135
|
|
|
67
136
|
class Boolean(DataType):
|
|
68
|
-
name = "boolean"
|
|
69
137
|
python = bool
|
|
70
138
|
dms = dms.Boolean
|
|
71
139
|
graphql = "Boolean"
|
|
72
140
|
xsd = "boolean"
|
|
73
141
|
sql = "BOOLEAN"
|
|
142
|
+
name: typing.Literal["boolean"] = "boolean"
|
|
74
143
|
|
|
75
144
|
|
|
76
145
|
class Float(DataType):
|
|
77
|
-
name = "float"
|
|
78
146
|
python = float
|
|
79
147
|
dms = dms.Float32
|
|
80
148
|
graphql = "Float"
|
|
81
149
|
xsd = "float"
|
|
82
150
|
sql = "FLOAT"
|
|
83
151
|
|
|
152
|
+
name: typing.Literal["float"] = "float"
|
|
153
|
+
unit: UnitEntity | None = None
|
|
154
|
+
|
|
84
155
|
|
|
85
156
|
class Double(DataType):
|
|
86
|
-
name = "double"
|
|
87
157
|
python = float
|
|
88
158
|
dms = dms.Float64
|
|
89
159
|
graphql = "Float"
|
|
90
160
|
xsd = "double"
|
|
91
161
|
sql = "FLOAT"
|
|
92
162
|
|
|
163
|
+
name: typing.Literal["double"] = "double"
|
|
164
|
+
unit: UnitEntity | None = None
|
|
165
|
+
|
|
93
166
|
|
|
94
167
|
class Integer(DataType):
|
|
95
|
-
name = "integer"
|
|
96
168
|
python = int
|
|
97
169
|
dms = dms.Int32
|
|
98
170
|
graphql = "Int"
|
|
99
171
|
xsd = "integer"
|
|
100
172
|
sql = "INTEGER"
|
|
101
173
|
|
|
174
|
+
name: typing.Literal["integer"] = "integer"
|
|
175
|
+
|
|
102
176
|
|
|
103
177
|
class NonPositiveInteger(DataType):
|
|
104
|
-
name = "nonPositiveInteger"
|
|
105
178
|
python = int
|
|
106
179
|
dms = dms.Int32
|
|
107
180
|
graphql = "Int"
|
|
108
181
|
xsd = "nonPositiveInteger"
|
|
109
182
|
sql = "INTEGER"
|
|
110
183
|
|
|
184
|
+
name: typing.Literal["nonPositiveInteger"] = "nonPositiveInteger"
|
|
185
|
+
|
|
111
186
|
|
|
112
187
|
class NonNegativeInteger(DataType):
|
|
113
|
-
name = "nonNegativeInteger"
|
|
114
188
|
python = int
|
|
115
189
|
dms = dms.Int32
|
|
116
190
|
graphql = "Int"
|
|
117
191
|
xsd = "nonNegativeInteger"
|
|
118
192
|
sql = "INTEGER"
|
|
119
193
|
|
|
194
|
+
name: typing.Literal["nonNegativeInteger"] = "nonNegativeInteger"
|
|
195
|
+
|
|
120
196
|
|
|
121
197
|
class NegativeInteger(DataType):
|
|
122
|
-
name = "negativeInteger"
|
|
123
198
|
python = int
|
|
124
199
|
dms = dms.Int32
|
|
125
200
|
graphql = "Int"
|
|
126
201
|
xsd = "negativeInteger"
|
|
127
202
|
sql = "INTEGER"
|
|
128
203
|
|
|
204
|
+
name: typing.Literal["negativeInteger"] = "negativeInteger"
|
|
205
|
+
|
|
129
206
|
|
|
130
207
|
class Long(DataType):
|
|
131
|
-
name = "long"
|
|
132
208
|
python = int
|
|
133
209
|
dms = dms.Int64
|
|
134
210
|
graphql = "Int"
|
|
135
211
|
xsd = "long"
|
|
136
212
|
sql = "BIGINT"
|
|
137
213
|
|
|
214
|
+
name: typing.Literal["long"] = "long"
|
|
215
|
+
|
|
138
216
|
|
|
139
217
|
class String(DataType):
|
|
140
|
-
name = "string"
|
|
141
218
|
python = str
|
|
142
219
|
dms = dms.Text
|
|
143
220
|
graphql = "String"
|
|
144
221
|
xsd = "string"
|
|
145
222
|
sql = "STRING"
|
|
146
223
|
|
|
224
|
+
name: typing.Literal["string"] = "string"
|
|
225
|
+
|
|
147
226
|
|
|
148
227
|
class LangString(DataType):
|
|
149
|
-
name = "langString"
|
|
150
228
|
python = str
|
|
151
229
|
dms = dms.Text
|
|
152
230
|
graphql = "String"
|
|
153
231
|
xsd = "string"
|
|
154
232
|
sql = "STRING"
|
|
155
233
|
|
|
234
|
+
name: typing.Literal["langString"] = "langString"
|
|
235
|
+
|
|
156
236
|
|
|
157
237
|
class AnyURI(DataType):
|
|
158
|
-
name = "anyURI"
|
|
159
238
|
python = str
|
|
160
239
|
dms = dms.Text
|
|
161
240
|
graphql = "String"
|
|
162
241
|
xsd = "anyURI"
|
|
163
242
|
sql = "STRING"
|
|
164
243
|
|
|
244
|
+
name: typing.Literal["anyURI"] = "anyURI"
|
|
245
|
+
|
|
165
246
|
|
|
166
247
|
class NormalizedString(DataType):
|
|
167
|
-
name = "normalizedString"
|
|
168
248
|
python = str
|
|
169
249
|
dms = dms.Text
|
|
170
250
|
graphql = "String"
|
|
171
251
|
xsd = "normalizedString"
|
|
172
252
|
sql = "STRING"
|
|
173
253
|
|
|
254
|
+
name: typing.Literal["normalizedString"] = "normalizedString"
|
|
255
|
+
|
|
174
256
|
|
|
175
257
|
class Token(DataType):
|
|
176
|
-
name = "token"
|
|
177
258
|
python = str
|
|
178
259
|
dms = dms.Text
|
|
179
260
|
graphql = "String"
|
|
180
261
|
xsd = "string"
|
|
181
262
|
sql = "STRING"
|
|
182
263
|
|
|
264
|
+
name: typing.Literal["token"] = "token"
|
|
265
|
+
|
|
183
266
|
|
|
184
267
|
class DateTime(DataType):
|
|
185
|
-
name = "dateTime"
|
|
186
268
|
python = datetime
|
|
187
269
|
dms = dms.Timestamp
|
|
188
270
|
graphql = "Timestamp"
|
|
189
271
|
xsd = "dateTimeStamp"
|
|
190
272
|
sql = "TIMESTAMP"
|
|
191
273
|
|
|
274
|
+
name: typing.Literal["dateTime"] = "dateTime"
|
|
275
|
+
|
|
192
276
|
|
|
193
277
|
class Timestamp(DataType):
|
|
194
|
-
name = "timestamp"
|
|
195
278
|
python = datetime
|
|
196
279
|
dms = dms.Timestamp
|
|
197
280
|
graphql = "Timestamp"
|
|
198
281
|
xsd = "dateTimeStamp"
|
|
199
282
|
sql = "TIMESTAMP"
|
|
200
283
|
|
|
284
|
+
name: typing.Literal["timestamp"] = "timestamp"
|
|
285
|
+
|
|
201
286
|
|
|
202
287
|
class DateTimeStamp(DataType):
|
|
203
|
-
name = "dateTimeStamp"
|
|
204
288
|
python = datetime
|
|
205
289
|
dms = dms.Timestamp
|
|
206
290
|
graphql = "Timestamp"
|
|
207
291
|
xsd = "dateTimeStamp"
|
|
208
292
|
sql = "TIMESTAMP"
|
|
209
293
|
|
|
294
|
+
name: typing.Literal["dateTimeStamp"] = "dateTimeStamp"
|
|
295
|
+
|
|
210
296
|
|
|
211
297
|
class Date(DataType):
|
|
212
|
-
name = "date"
|
|
213
298
|
python = date
|
|
214
299
|
dms = dms.Date
|
|
215
300
|
graphql = "String"
|
|
216
301
|
xsd = "date"
|
|
217
302
|
sql = "DATE"
|
|
218
303
|
|
|
304
|
+
name: typing.Literal["date"] = "date"
|
|
305
|
+
|
|
219
306
|
|
|
220
307
|
class PlainLiteral(DataType):
|
|
221
|
-
name = "PlainLiteral"
|
|
222
308
|
python = str
|
|
223
309
|
dms = dms.Text
|
|
224
310
|
graphql = "String"
|
|
225
311
|
xsd = "plainLiteral"
|
|
226
312
|
sql = "STRING"
|
|
227
313
|
|
|
314
|
+
name: typing.Literal["plainLiteral"] = "plainLiteral"
|
|
315
|
+
|
|
228
316
|
|
|
229
317
|
class Literal(DataType):
|
|
230
|
-
name = "Literal"
|
|
231
318
|
python = str
|
|
232
319
|
dms = dms.Text
|
|
233
320
|
graphql = "String"
|
|
234
321
|
xsd = "string"
|
|
235
322
|
sql = "STRING"
|
|
236
323
|
|
|
324
|
+
name: typing.Literal["Literal"] = "Literal"
|
|
325
|
+
|
|
237
326
|
|
|
238
327
|
class Timeseries(DataType):
|
|
239
|
-
name = "timeseries"
|
|
240
328
|
python = str
|
|
241
329
|
dms = dms.TimeSeriesReference
|
|
242
330
|
graphql = "TimeSeries"
|
|
243
331
|
xsd = "string"
|
|
244
332
|
sql = "STRING"
|
|
245
333
|
|
|
334
|
+
name: typing.Literal["timeseries"] = "timeseries"
|
|
335
|
+
|
|
246
336
|
|
|
247
337
|
class File(DataType):
|
|
248
|
-
name = "file"
|
|
249
338
|
python = str
|
|
250
339
|
dms = dms.FileReference
|
|
251
340
|
graphql = "File"
|
|
252
341
|
xsd = "string"
|
|
253
342
|
sql = "STRING"
|
|
254
343
|
|
|
344
|
+
name: typing.Literal["file"] = "file"
|
|
345
|
+
|
|
255
346
|
|
|
256
347
|
class Sequence(DataType):
|
|
257
|
-
name = "sequence"
|
|
258
348
|
python = str
|
|
259
349
|
dms = dms.SequenceReference
|
|
260
350
|
graphql = "Sequence"
|
|
261
351
|
xsd = "string"
|
|
262
352
|
sql = "STRING"
|
|
263
353
|
|
|
354
|
+
name: typing.Literal["sequence"] = "sequence"
|
|
355
|
+
|
|
264
356
|
|
|
265
357
|
class Json(DataType):
|
|
266
|
-
name = "json"
|
|
267
358
|
python = dict
|
|
268
359
|
dms = dms.Json
|
|
269
360
|
graphql = "Json"
|
|
270
361
|
xsd = "json"
|
|
271
362
|
sql = "STRING"
|
|
272
363
|
|
|
364
|
+
name: typing.Literal["json"] = "json"
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
class Enum(DataType):
|
|
368
|
+
python = str
|
|
369
|
+
dms = DMSEnum
|
|
370
|
+
graphql = "Enum"
|
|
371
|
+
xsd = "string"
|
|
372
|
+
sql = "STRING"
|
|
373
|
+
|
|
374
|
+
name: typing.Literal["enum"] = "enum"
|
|
375
|
+
|
|
376
|
+
collection: ClassEntity
|
|
377
|
+
unknown_value: str | None = Field(None, alias="unknownValue")
|
|
378
|
+
|
|
273
379
|
|
|
274
|
-
_DATA_TYPE_BY_NAME = {cls.name.casefold(): cls for cls in DataType.__subclasses__()}
|
|
380
|
+
_DATA_TYPE_BY_NAME = {cls.model_fields["name"].default.casefold(): cls for cls in DataType.__subclasses__()}
|
|
275
381
|
_seen = set()
|
|
276
382
|
_DATA_TYPE_BY_DMS_TYPE = {
|
|
277
383
|
cls.dms._type.casefold(): cls
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
from ._rules import DMSContainer, DMSMetadata, DMSProperty, DMSRules, DMSView
|
|
2
|
-
from ._rules_input import
|
|
1
|
+
from ._rules import DMSContainer, DMSEnum, DMSMetadata, DMSNode, DMSProperty, DMSRules, DMSView
|
|
2
|
+
from ._rules_input import (
|
|
3
|
+
DMSInputContainer,
|
|
4
|
+
DMSInputEnum,
|
|
5
|
+
DMSInputMetadata,
|
|
6
|
+
DMSInputNode,
|
|
7
|
+
DMSInputProperty,
|
|
8
|
+
DMSInputRules,
|
|
9
|
+
DMSInputView,
|
|
10
|
+
)
|
|
3
11
|
from ._schema import DMSSchema, PipelineSchema
|
|
4
12
|
|
|
5
13
|
__all__ = [
|
|
@@ -9,10 +17,14 @@ __all__ = [
|
|
|
9
17
|
"DMSView",
|
|
10
18
|
"DMSProperty",
|
|
11
19
|
"DMSContainer",
|
|
20
|
+
"DMSNode",
|
|
21
|
+
"DMSEnum",
|
|
12
22
|
"PipelineSchema",
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
23
|
+
"DMSInputRules",
|
|
24
|
+
"DMSInputMetadata",
|
|
25
|
+
"DMSInputView",
|
|
26
|
+
"DMSInputProperty",
|
|
27
|
+
"DMSInputContainer",
|
|
28
|
+
"DMSInputNode",
|
|
29
|
+
"DMSInputEnum",
|
|
18
30
|
]
|