cognite-neat 0.125.1__py3-none-any.whl → 0.126.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/_client/__init__.py +4 -0
- cognite/neat/_client/api.py +8 -0
- cognite/neat/_client/client.py +19 -0
- cognite/neat/_client/config.py +40 -0
- cognite/neat/_client/containers_api.py +73 -0
- cognite/neat/_client/data_classes.py +10 -0
- cognite/neat/_client/data_model_api.py +63 -0
- cognite/neat/_client/spaces_api.py +67 -0
- cognite/neat/_client/views_api.py +82 -0
- cognite/neat/_data_model/_analysis.py +127 -0
- cognite/neat/_data_model/_constants.py +59 -0
- cognite/neat/_data_model/_shared.py +46 -0
- cognite/neat/_data_model/deployer/__init__.py +0 -0
- cognite/neat/_data_model/deployer/_differ.py +113 -0
- cognite/neat/_data_model/deployer/_differ_container.py +354 -0
- cognite/neat/_data_model/deployer/_differ_data_model.py +29 -0
- cognite/neat/_data_model/deployer/_differ_space.py +9 -0
- cognite/neat/_data_model/deployer/_differ_view.py +194 -0
- cognite/neat/_data_model/deployer/data_classes.py +176 -0
- cognite/neat/_data_model/exporters/__init__.py +4 -0
- cognite/neat/_data_model/exporters/_base.py +22 -0
- cognite/neat/_data_model/exporters/_table_exporter/__init__.py +0 -0
- cognite/neat/_data_model/exporters/_table_exporter/exporter.py +106 -0
- cognite/neat/_data_model/exporters/_table_exporter/workbook.py +414 -0
- cognite/neat/_data_model/exporters/_table_exporter/writer.py +391 -0
- cognite/neat/_data_model/importers/__init__.py +2 -1
- cognite/neat/_data_model/importers/_api_importer.py +88 -0
- cognite/neat/_data_model/importers/_table_importer/data_classes.py +48 -8
- cognite/neat/_data_model/importers/_table_importer/importer.py +102 -6
- cognite/neat/_data_model/importers/_table_importer/reader.py +860 -0
- cognite/neat/_data_model/models/dms/__init__.py +19 -1
- cognite/neat/_data_model/models/dms/_base.py +12 -8
- cognite/neat/_data_model/models/dms/_constants.py +1 -1
- cognite/neat/_data_model/models/dms/_constraints.py +2 -1
- cognite/neat/_data_model/models/dms/_container.py +5 -5
- cognite/neat/_data_model/models/dms/_data_model.py +3 -3
- cognite/neat/_data_model/models/dms/_data_types.py +8 -1
- cognite/neat/_data_model/models/dms/_http.py +18 -0
- cognite/neat/_data_model/models/dms/_indexes.py +2 -1
- cognite/neat/_data_model/models/dms/_references.py +17 -4
- cognite/neat/_data_model/models/dms/_space.py +11 -7
- cognite/neat/_data_model/models/dms/_view_property.py +7 -4
- cognite/neat/_data_model/models/dms/_views.py +16 -6
- cognite/neat/_data_model/validation/__init__.py +0 -0
- cognite/neat/_data_model/validation/_base.py +16 -0
- cognite/neat/_data_model/validation/dms/__init__.py +9 -0
- cognite/neat/_data_model/validation/dms/_orchestrator.py +68 -0
- cognite/neat/_data_model/validation/dms/_validators.py +139 -0
- cognite/neat/_exceptions.py +15 -3
- cognite/neat/_issues.py +39 -6
- cognite/neat/_session/__init__.py +3 -0
- cognite/neat/_session/_physical.py +88 -0
- cognite/neat/_session/_session.py +34 -25
- cognite/neat/_session/_wrappers.py +61 -0
- cognite/neat/_state_machine/__init__.py +10 -0
- cognite/neat/{_session/_state_machine → _state_machine}/_base.py +11 -1
- cognite/neat/_state_machine/_states.py +53 -0
- cognite/neat/_store/__init__.py +3 -0
- cognite/neat/_store/_provenance.py +55 -0
- cognite/neat/_store/_store.py +124 -0
- cognite/neat/_utils/_reader.py +194 -0
- cognite/neat/_utils/http_client/__init__.py +14 -20
- cognite/neat/_utils/http_client/_client.py +22 -61
- cognite/neat/_utils/http_client/_data_classes.py +167 -268
- cognite/neat/_utils/text.py +6 -0
- cognite/neat/_utils/useful_types.py +26 -2
- cognite/neat/_version.py +1 -1
- cognite/neat/v0/core/_data_model/importers/_rdf/_shared.py +2 -2
- cognite/neat/v0/core/_data_model/importers/_spreadsheet2data_model.py +2 -2
- cognite/neat/v0/core/_data_model/models/entities/_single_value.py +1 -1
- cognite/neat/v0/core/_data_model/models/physical/_unverified.py +1 -1
- cognite/neat/v0/core/_data_model/models/physical/_validation.py +2 -2
- cognite/neat/v0/core/_data_model/models/physical/_verified.py +3 -3
- cognite/neat/v0/core/_data_model/transformers/_converters.py +1 -1
- {cognite_neat-0.125.1.dist-info → cognite_neat-0.126.1.dist-info}/METADATA +1 -1
- {cognite_neat-0.125.1.dist-info → cognite_neat-0.126.1.dist-info}/RECORD +78 -40
- cognite/neat/_session/_state_machine/__init__.py +0 -23
- cognite/neat/_session/_state_machine/_states.py +0 -150
- {cognite_neat-0.125.1.dist-info → cognite_neat-0.126.1.dist-info}/WHEEL +0 -0
- {cognite_neat-0.125.1.dist-info → cognite_neat-0.126.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
from cognite.neat._data_model.models.dms._base import
|
|
1
|
+
from cognite.neat._data_model.models.dms._base import (
|
|
2
|
+
APIResource,
|
|
3
|
+
BaseModelObject,
|
|
4
|
+
Resource,
|
|
5
|
+
T_Resource,
|
|
6
|
+
WriteableResource,
|
|
7
|
+
)
|
|
2
8
|
from cognite.neat._data_model.models.dms._constraints import (
|
|
3
9
|
Constraint,
|
|
4
10
|
ConstraintAdapter,
|
|
@@ -13,6 +19,7 @@ from cognite.neat._data_model.models.dms._container import (
|
|
|
13
19
|
ContainerResponse,
|
|
14
20
|
)
|
|
15
21
|
from cognite.neat._data_model.models.dms._data_types import (
|
|
22
|
+
DMS_DATA_TYPES,
|
|
16
23
|
BooleanProperty,
|
|
17
24
|
DataType,
|
|
18
25
|
DataTypeAdapter,
|
|
@@ -38,11 +45,13 @@ from cognite.neat._data_model.models.dms._indexes import BtreeIndex, Index, Inde
|
|
|
38
45
|
from cognite.neat._data_model.models.dms._space import Space, SpaceRequest, SpaceResponse
|
|
39
46
|
|
|
40
47
|
from ._data_model import DataModelRequest, DataModelResponse
|
|
48
|
+
from ._http import DataModelBody, DataModelResource
|
|
41
49
|
from ._references import (
|
|
42
50
|
ContainerDirectReference,
|
|
43
51
|
ContainerReference,
|
|
44
52
|
DataModelReference,
|
|
45
53
|
NodeReference,
|
|
54
|
+
SpaceReference,
|
|
46
55
|
ViewDirectReference,
|
|
47
56
|
ViewReference,
|
|
48
57
|
)
|
|
@@ -60,6 +69,7 @@ from ._view_property import (
|
|
|
60
69
|
ViewCorePropertyResponse,
|
|
61
70
|
ViewPropertyDefinition,
|
|
62
71
|
ViewRequestProperty,
|
|
72
|
+
ViewRequestPropertyAdapter,
|
|
63
73
|
ViewResponseProperty,
|
|
64
74
|
)
|
|
65
75
|
from ._views import (
|
|
@@ -69,6 +79,9 @@ from ._views import (
|
|
|
69
79
|
)
|
|
70
80
|
|
|
71
81
|
__all__ = [
|
|
82
|
+
"DMS_DATA_TYPES",
|
|
83
|
+
"APIResource",
|
|
84
|
+
"BaseModelObject",
|
|
72
85
|
"BooleanProperty",
|
|
73
86
|
"BtreeIndex",
|
|
74
87
|
"ConnectionPropertyDefinition",
|
|
@@ -82,8 +95,10 @@ __all__ = [
|
|
|
82
95
|
"ContainerReference",
|
|
83
96
|
"ContainerRequest",
|
|
84
97
|
"ContainerResponse",
|
|
98
|
+
"DataModelBody",
|
|
85
99
|
"DataModelReference",
|
|
86
100
|
"DataModelRequest",
|
|
101
|
+
"DataModelResource",
|
|
87
102
|
"DataModelResponse",
|
|
88
103
|
"DataType",
|
|
89
104
|
"DataTypeAdapter",
|
|
@@ -117,8 +132,10 @@ __all__ = [
|
|
|
117
132
|
"SingleReverseDirectRelationPropertyRequest",
|
|
118
133
|
"SingleReverseDirectRelationPropertyResponse",
|
|
119
134
|
"Space",
|
|
135
|
+
"SpaceReference",
|
|
120
136
|
"SpaceRequest",
|
|
121
137
|
"SpaceResponse",
|
|
138
|
+
"T_Resource",
|
|
122
139
|
"TextProperty",
|
|
123
140
|
"TextProperty",
|
|
124
141
|
"TimeseriesCDFExternalIdReference",
|
|
@@ -135,6 +152,7 @@ __all__ = [
|
|
|
135
152
|
"ViewReference",
|
|
136
153
|
"ViewRequest",
|
|
137
154
|
"ViewRequestProperty",
|
|
155
|
+
"ViewRequestPropertyAdapter",
|
|
138
156
|
"ViewResponse",
|
|
139
157
|
"ViewResponseProperty",
|
|
140
158
|
"WriteableResource",
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
from typing import Generic, TypeVar
|
|
3
3
|
|
|
4
|
-
from
|
|
5
|
-
from pydantic.alias_generators import to_camel
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class BaseModelObject(BaseModel, alias_generator=to_camel, extra="ignore"):
|
|
9
|
-
"""Base class for all object. This includes resources and nested objects."""
|
|
10
|
-
|
|
11
|
-
...
|
|
4
|
+
from cognite.neat._utils.useful_types import BaseModelObject, T_Reference
|
|
12
5
|
|
|
13
6
|
|
|
14
7
|
class Resource(BaseModelObject):
|
|
@@ -21,7 +14,18 @@ T_Resource = TypeVar("T_Resource", bound=Resource)
|
|
|
21
14
|
|
|
22
15
|
|
|
23
16
|
class WriteableResource(Resource, Generic[T_Resource], ABC):
|
|
17
|
+
"""Base class for all writeable data modeling resources."""
|
|
18
|
+
|
|
24
19
|
@abstractmethod
|
|
25
20
|
def as_request(self) -> T_Resource:
|
|
26
21
|
"""Convert the response model to a request model by removing read-only fields."""
|
|
27
22
|
raise NotImplementedError()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class APIResource(Generic[T_Reference], ABC):
|
|
26
|
+
"""Base class for all API data modeling resources."""
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def as_reference(self) -> T_Reference:
|
|
30
|
+
"""Convert the resource to a reference object (identifier)."""
|
|
31
|
+
raise NotImplementedError()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
SPACE_FORMAT_PATTERN = r"^[a-zA-Z][a-zA-Z0-9_-]{0,41}[a-zA-Z0-9]?$"
|
|
2
2
|
DM_EXTERNAL_ID_PATTERN = r"^[a-zA-Z]([a-zA-Z0-9_]{0,253}[a-zA-Z0-9])?$"
|
|
3
3
|
CONTAINER_AND_VIEW_PROPERTIES_IDENTIFIER_PATTERN = r"^[a-zA-Z0-9][a-zA-Z0-9_-]{0,253}[a-zA-Z0-9]?$"
|
|
4
|
-
INSTANCE_ID_PATTERN = r"^[
|
|
4
|
+
INSTANCE_ID_PATTERN = r"^[^\x00]{1,256}$"
|
|
5
5
|
ENUM_VALUE_IDENTIFIER_PATTERN = r"^[_A-Za-z][_0-9A-Za-z]{0,127}$"
|
|
6
6
|
DM_VERSION_PATTERN = r"^[a-zA-Z0-9]([.a-zA-Z0-9_-]{0,41}[a-zA-Z0-9])?$"
|
|
7
7
|
FORBIDDEN_ENUM_VALUES = frozenset({"true", "false", "null"})
|
|
@@ -6,8 +6,9 @@ from pydantic import Field, field_validator
|
|
|
6
6
|
from pydantic_core.core_schema import ValidationInfo
|
|
7
7
|
|
|
8
8
|
from cognite.neat._utils.text import humanize_collection
|
|
9
|
+
from cognite.neat._utils.useful_types import BaseModelObject
|
|
9
10
|
|
|
10
|
-
from ._base import
|
|
11
|
+
from ._base import APIResource, Resource, WriteableResource
|
|
11
12
|
from ._constants import (
|
|
12
13
|
CONTAINER_AND_VIEW_PROPERTIES_IDENTIFIER_PATTERN,
|
|
13
14
|
DM_EXTERNAL_ID_PATTERN,
|
|
@@ -36,7 +37,7 @@ class ContainerPropertyDefinition(BaseModelObject):
|
|
|
36
37
|
default=None,
|
|
37
38
|
description="Increment the property based on its highest current value (max value).",
|
|
38
39
|
)
|
|
39
|
-
default_value: str | int | bool | dict[str, Any] | None = Field(
|
|
40
|
+
default_value: str | int | float | bool | dict[str, Any] | None = Field(
|
|
40
41
|
default=None,
|
|
41
42
|
description="Default value to use when you do not specify a value for the property.",
|
|
42
43
|
)
|
|
@@ -53,7 +54,7 @@ class ContainerPropertyDefinition(BaseModelObject):
|
|
|
53
54
|
type: DataType = Field(description="The type of data you can store in this property.")
|
|
54
55
|
|
|
55
56
|
|
|
56
|
-
class Container(Resource, ABC):
|
|
57
|
+
class Container(Resource, APIResource[ContainerReference], ABC):
|
|
57
58
|
space: str = Field(
|
|
58
59
|
description="The workspace for the container, a unique identifier for the space.",
|
|
59
60
|
min_length=1,
|
|
@@ -82,7 +83,6 @@ class Container(Resource, ABC):
|
|
|
82
83
|
)
|
|
83
84
|
properties: dict[str, ContainerPropertyDefinition] = Field(
|
|
84
85
|
description="Set of properties to apply to the container.",
|
|
85
|
-
min_length=1,
|
|
86
86
|
)
|
|
87
87
|
constraints: dict[str, Constraint] | None = Field(
|
|
88
88
|
default=None,
|
|
@@ -136,7 +136,7 @@ class Container(Resource, ABC):
|
|
|
136
136
|
def as_reference(self) -> ContainerReference:
|
|
137
137
|
return ContainerReference(
|
|
138
138
|
space=self.space,
|
|
139
|
-
|
|
139
|
+
external_id=self.external_id,
|
|
140
140
|
)
|
|
141
141
|
|
|
142
142
|
|
|
@@ -2,7 +2,7 @@ from abc import ABC
|
|
|
2
2
|
|
|
3
3
|
from pydantic import Field
|
|
4
4
|
|
|
5
|
-
from ._base import Resource, WriteableResource
|
|
5
|
+
from ._base import APIResource, Resource, WriteableResource
|
|
6
6
|
from ._constants import (
|
|
7
7
|
DM_EXTERNAL_ID_PATTERN,
|
|
8
8
|
DM_VERSION_PATTERN,
|
|
@@ -11,7 +11,7 @@ from ._constants import (
|
|
|
11
11
|
from ._references import DataModelReference, ViewReference
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
class DataModel(Resource, ABC):
|
|
14
|
+
class DataModel(Resource, APIResource[DataModelReference], ABC):
|
|
15
15
|
"""Cognite Data Model resource.
|
|
16
16
|
|
|
17
17
|
Data models group and structure views into reusable collections.
|
|
@@ -55,7 +55,7 @@ class DataModel(Resource, ABC):
|
|
|
55
55
|
def as_reference(self) -> DataModelReference:
|
|
56
56
|
return DataModelReference(
|
|
57
57
|
space=self.space,
|
|
58
|
-
|
|
58
|
+
external_id=self.external_id,
|
|
59
59
|
version=self.version,
|
|
60
60
|
)
|
|
61
61
|
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import re
|
|
2
2
|
from abc import ABC
|
|
3
|
+
from collections.abc import Mapping
|
|
3
4
|
from typing import Annotated, Literal
|
|
4
5
|
|
|
5
6
|
from pydantic import Field, TypeAdapter, field_validator
|
|
6
7
|
|
|
7
|
-
from .
|
|
8
|
+
from cognite.neat._utils.auxiliary import get_concrete_subclasses
|
|
9
|
+
from cognite.neat._utils.useful_types import BaseModelObject
|
|
10
|
+
|
|
8
11
|
from ._constants import ENUM_VALUE_IDENTIFIER_PATTERN, FORBIDDEN_ENUM_VALUES, INSTANCE_ID_PATTERN
|
|
9
12
|
from ._references import ContainerReference
|
|
10
13
|
|
|
@@ -181,3 +184,7 @@ DataType = Annotated[
|
|
|
181
184
|
]
|
|
182
185
|
|
|
183
186
|
DataTypeAdapter: TypeAdapter[DataType] = TypeAdapter(DataType)
|
|
187
|
+
|
|
188
|
+
DMS_DATA_TYPES: Mapping[str, type[PropertyTypeDefinition]] = {
|
|
189
|
+
cls_.model_fields["type"].default: cls_ for cls_ in get_concrete_subclasses(PropertyTypeDefinition)
|
|
190
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from typing import TypeAlias, TypeVar
|
|
2
|
+
|
|
3
|
+
from cognite.neat._utils.http_client import ItemBody
|
|
4
|
+
from cognite.neat._utils.useful_types import ReferenceObject
|
|
5
|
+
|
|
6
|
+
from ._container import ContainerRequest
|
|
7
|
+
from ._data_model import DataModelRequest
|
|
8
|
+
from ._space import SpaceRequest
|
|
9
|
+
from ._views import ViewRequest
|
|
10
|
+
|
|
11
|
+
DataModelResource: TypeAlias = SpaceRequest | DataModelRequest | ViewRequest | ContainerRequest
|
|
12
|
+
|
|
13
|
+
T_DataModelResource = TypeVar("T_DataModelResource", bound=DataModelResource)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DataModelBody(ItemBody[ReferenceObject, DataModelResource]):
|
|
17
|
+
def as_ids(self) -> list[ReferenceObject]:
|
|
18
|
+
return [item.as_reference() for item in self.items]
|
|
@@ -2,7 +2,8 @@ from typing import Literal
|
|
|
2
2
|
|
|
3
3
|
from pydantic import Field
|
|
4
4
|
|
|
5
|
-
from .
|
|
5
|
+
from cognite.neat._utils.useful_types import ReferenceObject
|
|
6
|
+
|
|
6
7
|
from ._constants import (
|
|
7
8
|
CONTAINER_AND_VIEW_PROPERTIES_IDENTIFIER_PATTERN,
|
|
8
9
|
DM_EXTERNAL_ID_PATTERN,
|
|
@@ -12,11 +13,17 @@ from ._constants import (
|
|
|
12
13
|
)
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
class ReferenceObject
|
|
16
|
+
class SpaceReference(ReferenceObject):
|
|
17
|
+
space: str = Field(
|
|
18
|
+
description="Id of the space.",
|
|
19
|
+
min_length=1,
|
|
20
|
+
max_length=43,
|
|
21
|
+
pattern=SPACE_FORMAT_PATTERN,
|
|
22
|
+
)
|
|
16
23
|
|
|
17
24
|
|
|
18
25
|
class ContainerReference(ReferenceObject):
|
|
19
|
-
type: Literal["container"] = "container"
|
|
26
|
+
type: Literal["container"] = Field("container", exclude=True)
|
|
20
27
|
space: str = Field(
|
|
21
28
|
description="Id of the space hosting (containing) the container.",
|
|
22
29
|
min_length=1,
|
|
@@ -30,9 +37,12 @@ class ContainerReference(ReferenceObject):
|
|
|
30
37
|
pattern=DM_EXTERNAL_ID_PATTERN,
|
|
31
38
|
)
|
|
32
39
|
|
|
40
|
+
def __str__(self) -> str:
|
|
41
|
+
return f"{self.space}:{self.external_id}"
|
|
42
|
+
|
|
33
43
|
|
|
34
44
|
class ViewReference(ReferenceObject):
|
|
35
|
-
type: Literal["view"] = "view"
|
|
45
|
+
type: Literal["view"] = Field("view", exclude=True)
|
|
36
46
|
space: str = Field(
|
|
37
47
|
description="Id of the space that the view belongs to.",
|
|
38
48
|
min_length=1,
|
|
@@ -51,6 +61,9 @@ class ViewReference(ReferenceObject):
|
|
|
51
61
|
pattern=DM_VERSION_PATTERN,
|
|
52
62
|
)
|
|
53
63
|
|
|
64
|
+
def __str__(self) -> str:
|
|
65
|
+
return f"{self.space}:{self.external_id}(version={self.version})"
|
|
66
|
+
|
|
54
67
|
|
|
55
68
|
class DataModelReference(ReferenceObject):
|
|
56
69
|
space: str = Field(
|
|
@@ -2,13 +2,14 @@ from abc import ABC
|
|
|
2
2
|
|
|
3
3
|
from pydantic import Field, field_validator
|
|
4
4
|
|
|
5
|
+
from cognite.neat._data_model.models.dms._references import SpaceReference
|
|
5
6
|
from cognite.neat.v0.core._utils.text import humanize_collection
|
|
6
7
|
|
|
7
|
-
from ._base import WriteableResource
|
|
8
|
+
from ._base import APIResource, Resource, WriteableResource
|
|
8
9
|
from ._constants import FORBIDDEN_SPACES, SPACE_FORMAT_PATTERN
|
|
9
10
|
|
|
10
11
|
|
|
11
|
-
class Space(
|
|
12
|
+
class Space(Resource, APIResource[SpaceReference], ABC):
|
|
12
13
|
space: str = Field(
|
|
13
14
|
description="The Space identifier (id).",
|
|
14
15
|
min_length=1,
|
|
@@ -25,11 +26,14 @@ class Space(WriteableResource["SpaceRequest"], ABC):
|
|
|
25
26
|
raise ValueError(f"{val!r} is a reserved space. Reserved Spaces: {humanize_collection(FORBIDDEN_SPACES)}")
|
|
26
27
|
return val
|
|
27
28
|
|
|
28
|
-
def
|
|
29
|
-
return
|
|
29
|
+
def as_reference(self) -> SpaceReference:
|
|
30
|
+
return SpaceReference(space=self.space)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class SpaceRequest(Space): ...
|
|
30
34
|
|
|
31
35
|
|
|
32
|
-
class SpaceResponse(Space):
|
|
36
|
+
class SpaceResponse(Space, WriteableResource[Space]):
|
|
33
37
|
created_time: int = Field(
|
|
34
38
|
description="When the space was created. The number of milliseconds since 00:00:00 Thursday, 1 January 1970, "
|
|
35
39
|
"Coordinated Universal Time (UTC), minus leap seconds."
|
|
@@ -40,5 +44,5 @@ class SpaceResponse(Space):
|
|
|
40
44
|
)
|
|
41
45
|
is_global: bool = Field(description="Whether the space is a global space.")
|
|
42
46
|
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
def as_request(self) -> "SpaceRequest":
|
|
48
|
+
return SpaceRequest.model_validate(self.model_dump(by_alias=True))
|
|
@@ -3,7 +3,9 @@ from typing import Annotated, Literal
|
|
|
3
3
|
|
|
4
4
|
from pydantic import Field, Json, TypeAdapter
|
|
5
5
|
|
|
6
|
-
from .
|
|
6
|
+
from cognite.neat._utils.useful_types import BaseModelObject
|
|
7
|
+
|
|
8
|
+
from ._base import Resource, WriteableResource
|
|
7
9
|
from ._constants import CONTAINER_AND_VIEW_PROPERTIES_IDENTIFIER_PATTERN
|
|
8
10
|
from ._data_types import DataType
|
|
9
11
|
from ._references import ContainerDirectReference, ContainerReference, NodeReference, ViewDirectReference, ViewReference
|
|
@@ -49,6 +51,7 @@ class ViewCorePropertyRequest(ViewCoreProperty): ...
|
|
|
49
51
|
|
|
50
52
|
class ConstraintOrIndexState(BaseModelObject):
|
|
51
53
|
nullability: Literal["current", "pending", "failed"] | None = Field(
|
|
54
|
+
None,
|
|
52
55
|
description="""For properties that have isNullable set to false, this field describes the validity of the
|
|
53
56
|
not-null constraint. It is not specified for nullable properties.
|
|
54
57
|
|
|
@@ -58,7 +61,7 @@ Possible values are:
|
|
|
58
61
|
existing nulls was made non-nullable. New null values will still be rejected.
|
|
59
62
|
"current": The constraint is satisfied; all values in the property are not null.
|
|
60
63
|
"pending": The constraint validity has not yet been computed.
|
|
61
|
-
"""
|
|
64
|
+
""",
|
|
62
65
|
)
|
|
63
66
|
|
|
64
67
|
|
|
@@ -147,7 +150,7 @@ class SingleReverseDirectRelationPropertyResponse(
|
|
|
147
150
|
ReverseDirectRelationProperty, WriteableResource[SingleReverseDirectRelationPropertyRequest]
|
|
148
151
|
):
|
|
149
152
|
connection_type: Literal["single_reverse_direct_relation"] = "single_reverse_direct_relation"
|
|
150
|
-
|
|
153
|
+
targets_list: bool = Field(
|
|
151
154
|
description="Whether or not this reverse direct relation targets a list of direct relations.",
|
|
152
155
|
)
|
|
153
156
|
|
|
@@ -159,7 +162,7 @@ class MultiReverseDirectRelationPropertyResponse(
|
|
|
159
162
|
ReverseDirectRelationProperty, WriteableResource[MultiReverseDirectRelationPropertyRequest]
|
|
160
163
|
):
|
|
161
164
|
connection_type: Literal["multi_reverse_direct_relation"] = "multi_reverse_direct_relation"
|
|
162
|
-
|
|
165
|
+
targets_list: bool = Field(
|
|
163
166
|
description="Whether or not this reverse direct relation targets a list of direct relations.",
|
|
164
167
|
)
|
|
165
168
|
|
|
@@ -2,11 +2,11 @@ import re
|
|
|
2
2
|
from abc import ABC
|
|
3
3
|
from typing import Literal, TypeVar
|
|
4
4
|
|
|
5
|
-
from pydantic import Field,
|
|
5
|
+
from pydantic import Field, JsonValue, field_validator, model_validator
|
|
6
6
|
|
|
7
7
|
from cognite.neat._utils.text import humanize_collection
|
|
8
8
|
|
|
9
|
-
from ._base import Resource, WriteableResource
|
|
9
|
+
from ._base import APIResource, Resource, WriteableResource
|
|
10
10
|
from ._constants import (
|
|
11
11
|
CONTAINER_AND_VIEW_PROPERTIES_IDENTIFIER_PATTERN,
|
|
12
12
|
DM_EXTERNAL_ID_PATTERN,
|
|
@@ -15,8 +15,9 @@ from ._constants import (
|
|
|
15
15
|
FORBIDDEN_CONTAINER_AND_VIEW_PROPERTIES_IDENTIFIER,
|
|
16
16
|
SPACE_FORMAT_PATTERN,
|
|
17
17
|
)
|
|
18
|
-
from ._references import ContainerReference, ViewReference
|
|
18
|
+
from ._references import ContainerReference, NodeReference, ViewReference
|
|
19
19
|
from ._view_property import (
|
|
20
|
+
EdgeProperty,
|
|
20
21
|
ViewRequestProperty,
|
|
21
22
|
ViewResponseProperty,
|
|
22
23
|
)
|
|
@@ -24,7 +25,7 @@ from ._view_property import (
|
|
|
24
25
|
KEY_PATTERN = re.compile(CONTAINER_AND_VIEW_PROPERTIES_IDENTIFIER_PATTERN)
|
|
25
26
|
|
|
26
27
|
|
|
27
|
-
class View(Resource, ABC):
|
|
28
|
+
class View(Resource, APIResource[ViewReference], ABC):
|
|
28
29
|
space: str = Field(
|
|
29
30
|
description="Id of the space that the view belongs to.",
|
|
30
31
|
min_length=1,
|
|
@@ -52,7 +53,7 @@ class View(Resource, ABC):
|
|
|
52
53
|
description="Description of the view.",
|
|
53
54
|
max_length=1024,
|
|
54
55
|
)
|
|
55
|
-
filter: dict[str,
|
|
56
|
+
filter: dict[str, JsonValue] | None = Field(
|
|
56
57
|
default=None,
|
|
57
58
|
description="A filter Domain Specific Language (DSL) used to create advanced filter queries.",
|
|
58
59
|
)
|
|
@@ -62,7 +63,7 @@ class View(Resource, ABC):
|
|
|
62
63
|
)
|
|
63
64
|
|
|
64
65
|
def as_reference(self) -> ViewReference:
|
|
65
|
-
return ViewReference(space=self.space,
|
|
66
|
+
return ViewReference(space=self.space, external_id=self.external_id, version=self.version)
|
|
66
67
|
|
|
67
68
|
@model_validator(mode="before")
|
|
68
69
|
def set_connection_type_on_primary_properties(cls, data: dict) -> dict:
|
|
@@ -134,6 +135,15 @@ class ViewResponse(View, WriteableResource[ViewRequest]):
|
|
|
134
135
|
"""Validate properties Identifier"""
|
|
135
136
|
return _validate_properties_keys(val)
|
|
136
137
|
|
|
138
|
+
@property
|
|
139
|
+
def node_types(self) -> list[NodeReference]:
|
|
140
|
+
"""Get all node types referenced by this view."""
|
|
141
|
+
nodes_refs: set[NodeReference] = set()
|
|
142
|
+
for prop in self.properties.values():
|
|
143
|
+
if isinstance(prop, EdgeProperty):
|
|
144
|
+
nodes_refs.add(prop.type)
|
|
145
|
+
return list(nodes_refs)
|
|
146
|
+
|
|
137
147
|
def as_request(self) -> ViewRequest:
|
|
138
148
|
dumped = self.model_dump(by_alias=True, exclude={"properties"})
|
|
139
149
|
dumped["properties"] = {
|
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import ClassVar
|
|
3
|
+
|
|
4
|
+
from cognite.neat._issues import ConsistencyError, Recommendation
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DataModelValidator(ABC):
|
|
8
|
+
"""Assessors for fundamental data model principles."""
|
|
9
|
+
|
|
10
|
+
code: ClassVar[str]
|
|
11
|
+
|
|
12
|
+
@abstractmethod
|
|
13
|
+
def run(self) -> list[ConsistencyError] | list[Recommendation]:
|
|
14
|
+
"""Execute the success handler on the data model."""
|
|
15
|
+
# do something with data model
|
|
16
|
+
pass
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from ._orchestrator import DmsDataModelValidation
|
|
2
|
+
from ._validators import UndefinedConnectionEndNodeTypes, VersionSpaceInconsistency, ViewsWithoutProperties
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"DmsDataModelValidation",
|
|
6
|
+
"UndefinedConnectionEndNodeTypes",
|
|
7
|
+
"VersionSpaceInconsistency",
|
|
8
|
+
"ViewsWithoutProperties",
|
|
9
|
+
]
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from cognite.neat._client import NeatClient
|
|
2
|
+
from cognite.neat._data_model._analysis import DataModelAnalysis
|
|
3
|
+
from cognite.neat._data_model._shared import OnSuccessIssuesChecker
|
|
4
|
+
from cognite.neat._data_model.models.dms._references import ViewReference
|
|
5
|
+
from cognite.neat._data_model.models.dms._schema import RequestSchema
|
|
6
|
+
from cognite.neat._data_model.models.dms._views import ViewRequest
|
|
7
|
+
from cognite.neat._data_model.validation._base import DataModelValidator
|
|
8
|
+
|
|
9
|
+
from ._validators import UndefinedConnectionEndNodeTypes, VersionSpaceInconsistency, ViewsWithoutProperties
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DmsDataModelValidation(OnSuccessIssuesChecker):
|
|
13
|
+
"""Placeholder for DMS Quality Assessment functionality."""
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self, client: NeatClient | None = None, codes: list[str] | None = None, modus_operandi: str | None = None
|
|
17
|
+
) -> None:
|
|
18
|
+
super().__init__(client)
|
|
19
|
+
self._codes = codes or ["all"]
|
|
20
|
+
self._modus_operandi = modus_operandi # will be used later to trigger how validators will behave
|
|
21
|
+
|
|
22
|
+
def run(self, data_model: RequestSchema) -> None:
|
|
23
|
+
"""Run quality assessment on the DMS data model."""
|
|
24
|
+
|
|
25
|
+
# Helper wrangled data model components
|
|
26
|
+
analysis = DataModelAnalysis(data_model)
|
|
27
|
+
local_views_by_reference = analysis.view_by_reference(include_inherited_properties=True)
|
|
28
|
+
local_connection_end_node_types = analysis.connection_end_node_types
|
|
29
|
+
cdf_views_by_reference = self._cdf_view_by_reference(
|
|
30
|
+
list(analysis.referenced_views(include_connection_end_node_types=True)),
|
|
31
|
+
include_inherited_properties=True,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
validators: list[DataModelValidator] = [
|
|
35
|
+
ViewsWithoutProperties(
|
|
36
|
+
local_views_by_reference=local_views_by_reference,
|
|
37
|
+
cdf_views_by_reference=cdf_views_by_reference,
|
|
38
|
+
),
|
|
39
|
+
UndefinedConnectionEndNodeTypes(
|
|
40
|
+
local_connection_end_node_types=local_connection_end_node_types,
|
|
41
|
+
local_views_by_reference=local_views_by_reference,
|
|
42
|
+
cdf_views_by_reference=cdf_views_by_reference,
|
|
43
|
+
),
|
|
44
|
+
VersionSpaceInconsistency(
|
|
45
|
+
data_model_reference=data_model.data_model.as_reference(),
|
|
46
|
+
view_references=list(local_views_by_reference.keys()),
|
|
47
|
+
),
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
for validator in validators:
|
|
51
|
+
if "all" in self._codes or validator.code in self._codes:
|
|
52
|
+
self._issues.extend(validator.run())
|
|
53
|
+
|
|
54
|
+
self._has_run = True
|
|
55
|
+
|
|
56
|
+
def _cdf_view_by_reference(
|
|
57
|
+
self, views: list[ViewReference], include_inherited_properties: bool = True
|
|
58
|
+
) -> dict[ViewReference, ViewRequest]:
|
|
59
|
+
"""Fetch view definition from CDF."""
|
|
60
|
+
|
|
61
|
+
if not self._client:
|
|
62
|
+
return {}
|
|
63
|
+
return {
|
|
64
|
+
response.as_reference(): response.as_request()
|
|
65
|
+
for response in self._client.views.retrieve(
|
|
66
|
+
views, include_inherited_properties=include_inherited_properties
|
|
67
|
+
)
|
|
68
|
+
}
|