cognite-neat 0.123.36__py3-none-any.whl → 0.123.38__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.

File without changes
@@ -0,0 +1,18 @@
1
+ from pydantic import BaseModel, Field
2
+ from pydantic.alias_generators import to_camel
3
+
4
+ from cognite.neat._data_model._identifiers import URI
5
+
6
+
7
+ class BaseModelObject(BaseModel, alias_generator=to_camel, extra="ignore", populate_by_name=True):
8
+ """Base class for all object. This includes resources and nested objects."""
9
+
10
+ ...
11
+
12
+
13
+ class ResourceMetadata(BaseModelObject):
14
+ name: str | None = Field(
15
+ None, description="Human readable / display name of resource being described.", max_length=1024
16
+ )
17
+ description: str | None = Field(None, description="The description of the resource.", max_length=255)
18
+ uri: URI | None = Field(None, description="The URI of the resource being described.")
@@ -0,0 +1,104 @@
1
+ from typing import Any
2
+
3
+ from pydantic import Field, ValidationInfo, field_validator, model_validator
4
+
5
+ from cognite.neat._data_model.models.entities import URI, ConceptEntity, DataType, UnknownEntity
6
+
7
+ from ._base import ResourceMetadata
8
+
9
+
10
+ class Property(ResourceMetadata):
11
+ value_type: DataType | ConceptEntity | UnknownEntity = Field(
12
+ union_mode="left_to_right",
13
+ description="Value type that the property can hold. It takes either subset of XSD type or a class defined.",
14
+ )
15
+ min_count: int | None = Field(
16
+ default=None,
17
+ ge=0,
18
+ description="Minimum number of values that the property can hold. "
19
+ "If no value is provided, the default value is None meaning `0`, "
20
+ "which means that the property is optional.",
21
+ )
22
+ max_count: int | None = Field(
23
+ default=None,
24
+ ge=0,
25
+ description="Maximum number of values that the property can hold. "
26
+ "If no value is provided, the default value is None meaning `inf`, "
27
+ "which means that the property can hold any number of values (listable).",
28
+ )
29
+ default: Any | None = Field(alias="Default", default=None, description="Default value of the property.")
30
+ instance_reference: list[URI] | None = Field(
31
+ default=None,
32
+ description="The URI(s) in the graph to get the value of the property.",
33
+ )
34
+
35
+ @model_validator(mode="after")
36
+ def check_min_max_count(self) -> "Property":
37
+ if self.min_count is not None and self.max_count is not None:
38
+ if self.min_count > self.max_count:
39
+ raise ValueError("min_count must be less than or equal to max_count")
40
+ return self
41
+
42
+ @field_validator("default", mode="after")
43
+ def check_default_value_primitive_type(cls, value: Any, info: ValidationInfo) -> Any:
44
+ if not value:
45
+ return value
46
+
47
+ value_type = info.data.get("value_type")
48
+ if not isinstance(value_type, DataType):
49
+ raise ValueError("Setting default value is only supported for primitive value types.")
50
+ return value
51
+
52
+ @field_validator("default", mode="after")
53
+ def check_default_value_python_type_exists(cls, value: Any, info: ValidationInfo) -> Any:
54
+ if not value:
55
+ return value
56
+
57
+ value_type = info.data.get("value_type")
58
+
59
+ if isinstance(value_type, DataType) and not hasattr(value_type, "python"):
60
+ raise ValueError(
61
+ f"DataType {value_type} does not have a python type defined."
62
+ " Setting default value for property is not possible."
63
+ )
64
+ return value
65
+
66
+ @field_validator("default", mode="after")
67
+ def check_default_value_not_list(cls, value: Any, info: ValidationInfo) -> Any:
68
+ if not value:
69
+ return value
70
+
71
+ if isinstance(value, list):
72
+ raise ValueError("Setting list as default value is not supported.")
73
+ return value
74
+
75
+ @field_validator("default", mode="after")
76
+ def check_default_value_single_valued(cls, value: Any, info: ValidationInfo) -> Any:
77
+ if not value:
78
+ return value
79
+
80
+ max_count = info.data.get("max_count")
81
+
82
+ if max_count is None or max_count > 1:
83
+ raise ValueError(
84
+ "Setting default value is only supported for single-valued properties."
85
+ f" Property has max_count={max_count or 'Inf'}."
86
+ )
87
+ return value
88
+
89
+ @field_validator("default", mode="after")
90
+ def check_default_value_type_match(cls, value: Any, info: ValidationInfo) -> Any:
91
+ if not value:
92
+ return value
93
+
94
+ value_type = info.data.get("value_type")
95
+
96
+ if (
97
+ isinstance(value_type, DataType)
98
+ and hasattr(value_type, "python")
99
+ and not isinstance(value, value_type.python)
100
+ ):
101
+ raise ValueError(
102
+ f"Default value type is {type(value)}, which does not match expected value type {value_type.python}."
103
+ )
104
+ return value
@@ -1,10 +1,69 @@
1
- from ._base import Resource, WriteableResource
2
- from ._space import Space, SpaceRequest, SpaceResponse
1
+ from cognite.neat._data_model.models.dms._base import Resource, WriteableResource
2
+ from cognite.neat._data_model.models.dms._constraints import (
3
+ Constraint,
4
+ ConstraintDefinition,
5
+ RequiresConstraintDefinition,
6
+ UniquenessConstraintDefinition,
7
+ )
8
+ from cognite.neat._data_model.models.dms._container import (
9
+ Container,
10
+ ContainerPropertyDefinition,
11
+ ContainerRequest,
12
+ ContainerResponse,
13
+ )
14
+ from cognite.neat._data_model.models.dms._data_types import (
15
+ BooleanProperty,
16
+ DataType,
17
+ DateProperty,
18
+ DirectNodeRelation,
19
+ EnumProperty,
20
+ FileCDFExternalIdReference,
21
+ FloatProperty,
22
+ Int32Property,
23
+ Int64Property,
24
+ JSONProperty,
25
+ ListablePropertyTypeDefinition,
26
+ PropertyTypeDefinition,
27
+ SequenceCDFExternalIdReference,
28
+ TextProperty,
29
+ TimeseriesCDFExternalIdReference,
30
+ TimestampProperty,
31
+ )
32
+ from cognite.neat._data_model.models.dms._indexes import BtreeIndex, Index, IndexDefinition, InvertedIndex
33
+ from cognite.neat._data_model.models.dms._space import Space, SpaceRequest, SpaceResponse
3
34
 
4
35
  __all__ = [
36
+ "BooleanProperty",
37
+ "BtreeIndex",
38
+ "Constraint",
39
+ "ConstraintDefinition",
40
+ "Container",
41
+ "ContainerPropertyDefinition",
42
+ "ContainerRequest",
43
+ "ContainerResponse",
44
+ "DataType",
45
+ "DateProperty",
46
+ "DirectNodeRelation",
47
+ "EnumProperty",
48
+ "FileCDFExternalIdReference",
49
+ "FloatProperty",
50
+ "Index",
51
+ "IndexDefinition",
52
+ "Int32Property",
53
+ "Int64Property",
54
+ "InvertedIndex",
55
+ "JSONProperty",
56
+ "ListablePropertyTypeDefinition",
57
+ "PropertyTypeDefinition",
58
+ "RequiresConstraintDefinition",
5
59
  "Resource",
60
+ "SequenceCDFExternalIdReference",
6
61
  "Space",
7
62
  "SpaceRequest",
8
63
  "SpaceResponse",
64
+ "TextProperty",
65
+ "TimeseriesCDFExternalIdReference",
66
+ "TimestampProperty",
67
+ "UniquenessConstraintDefinition",
9
68
  "WriteableResource",
10
69
  ]
@@ -1,2 +1,46 @@
1
- SPACE_FORMAT_PATTERN = r"[a-zA-Z][a-zA-Z0-9_-]{0,41}[a-zA-Z0-9]?$"
1
+ SPACE_FORMAT_PATTERN = r"^[a-zA-Z][a-zA-Z0-9_-]{0,41}[a-zA-Z0-9]?$"
2
+ DM_EXTERNAL_ID_PATTERN = r"^[a-zA-Z]([a-zA-Z0-9_]{0,253}[a-zA-Z0-9])?$"
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"^[^\\x00]{1,256}$"
5
+ ENUM_VALUE_IDENTIFIER_PATTERN = r"^[_A-Za-z][_0-9A-Za-z]{0,127}$"
6
+ FORBIDDEN_ENUM_VALUES = frozenset({"true", "false", "null"})
2
7
  FORBIDDEN_SPACES = frozenset(["space", "cdf", "dms", "pg3", "shared", "system", "node", "edge"])
8
+ FORBIDDEN_CONTAINER_AND_VIEW_EXTERNAL_IDS = frozenset(
9
+ [
10
+ "Query",
11
+ "Mutation",
12
+ "Subscription",
13
+ "String",
14
+ "Int32",
15
+ "Int64",
16
+ "Int",
17
+ "Float32",
18
+ "Float64",
19
+ "Float",
20
+ "Timestamp",
21
+ "JSONObject",
22
+ "Date",
23
+ "Numeric",
24
+ "Boolean",
25
+ "PageInfo",
26
+ "File",
27
+ "Sequence",
28
+ "TimeSeries",
29
+ ]
30
+ )
31
+ FORBIDDEN_CONTAINER_AND_VIEW_PROPERTIES_IDENTIFIER = frozenset(
32
+ [
33
+ "space",
34
+ "externalId",
35
+ "createdTime",
36
+ "lastUpdatedTime",
37
+ "deletedTime",
38
+ "edge_id",
39
+ "node_id",
40
+ "project_id",
41
+ "property_group",
42
+ "seq",
43
+ "tg_table_name",
44
+ "extensions",
45
+ ]
46
+ )
@@ -0,0 +1,30 @@
1
+ from abc import ABC
2
+ from typing import Annotated, Literal
3
+
4
+ from pydantic import Field
5
+
6
+ from ._base import BaseModelObject
7
+ from ._references import ContainerReference
8
+
9
+
10
+ class ConstraintDefinition(BaseModelObject, ABC):
11
+ constraint_type: str
12
+
13
+
14
+ class UniquenessConstraintDefinition(ConstraintDefinition):
15
+ constraint_type: Literal["uniqueness"] = "uniqueness"
16
+ properties: list[str] = Field(
17
+ description="List of properties included in the constraint.", min_length=1, max_length=10
18
+ )
19
+ by_space: bool | None = Field(default=None, description="Whether to make the constraint space-specific.")
20
+
21
+
22
+ class RequiresConstraintDefinition(ConstraintDefinition):
23
+ constraint_type: Literal["requires"] = "requires"
24
+ require: ContainerReference = Field(description="Reference to an existing container.")
25
+
26
+
27
+ Constraint = Annotated[
28
+ UniquenessConstraintDefinition | RequiresConstraintDefinition,
29
+ Field(discriminator="constraint_type"),
30
+ ]
@@ -0,0 +1,152 @@
1
+ import re
2
+ from abc import ABC
3
+ from typing import Any, Literal
4
+
5
+ from pydantic import Field, field_validator
6
+ from pydantic_core.core_schema import ValidationInfo
7
+
8
+ from cognite.neat._utils.text import humanize_collection
9
+
10
+ from ._base import BaseModelObject, Resource, WriteableResource
11
+ from ._constants import (
12
+ CONTAINER_AND_VIEW_PROPERTIES_IDENTIFIER_PATTERN,
13
+ DM_EXTERNAL_ID_PATTERN,
14
+ FORBIDDEN_CONTAINER_AND_VIEW_EXTERNAL_IDS,
15
+ FORBIDDEN_CONTAINER_AND_VIEW_PROPERTIES_IDENTIFIER,
16
+ SPACE_FORMAT_PATTERN,
17
+ )
18
+ from ._constraints import Constraint
19
+ from ._data_types import DataType
20
+ from ._indexes import Index
21
+
22
+ KEY_PATTERN = re.compile(CONTAINER_AND_VIEW_PROPERTIES_IDENTIFIER_PATTERN)
23
+
24
+
25
+ class ContainerPropertyDefinition(BaseModelObject):
26
+ immutable: bool | None = Field(
27
+ default=None,
28
+ description="Should updates to this property be rejected after the initial population?",
29
+ )
30
+ nullable: bool | None = Field(
31
+ default=None,
32
+ description="Does this property need to be set to a value, or not?",
33
+ )
34
+ auto_increment: bool | None = Field(
35
+ default=None,
36
+ description="Increment the property based on its highest current value (max value).",
37
+ )
38
+ default_value: str | int | bool | dict[str, Any] | None = Field(
39
+ default=None,
40
+ description="Default value to use when you do not specify a value for the property.",
41
+ )
42
+ description: str | None = Field(
43
+ default=None,
44
+ description="Description of the content and suggested use for this property.",
45
+ max_length=1024,
46
+ )
47
+ name: str | None = Field(
48
+ default=None,
49
+ description="Readable property name.",
50
+ max_length=255,
51
+ )
52
+ type: DataType = Field(description="The type of data you can store in this property.")
53
+
54
+
55
+ class Container(Resource, ABC):
56
+ space: str = Field(
57
+ description="The workspace for the container, a unique identifier for the space.",
58
+ min_length=1,
59
+ max_length=43,
60
+ pattern=SPACE_FORMAT_PATTERN,
61
+ )
62
+ external_id: str = Field(
63
+ description="External-id of the container.",
64
+ min_length=1,
65
+ max_length=255,
66
+ pattern=DM_EXTERNAL_ID_PATTERN,
67
+ )
68
+ name: str | None = Field(
69
+ default=None,
70
+ description="name for the container.",
71
+ max_length=255,
72
+ )
73
+ description: str | None = Field(
74
+ default=None,
75
+ description="Description of the container.",
76
+ max_length=1024,
77
+ )
78
+ used_for: Literal["node", "edge", "all"] | None = Field(
79
+ default=None,
80
+ description="Should this operation apply to nodes, edges or both.",
81
+ )
82
+ properties: dict[str, ContainerPropertyDefinition] = Field(
83
+ description="Set of properties to apply to the container.",
84
+ min_length=1,
85
+ )
86
+ constraints: dict[str, Constraint] | None = Field(
87
+ default=None,
88
+ description="Set of constraints to apply to the container.",
89
+ max_length=10,
90
+ )
91
+ indexes: dict[str, Index] | None = Field(
92
+ default=None,
93
+ description="Set of indexes to apply to the container.",
94
+ max_length=10,
95
+ )
96
+
97
+ @field_validator("indexes", "constraints", mode="after")
98
+ def validate_key_length(cls, val: dict[str, Any] | None, info: ValidationInfo) -> dict[str, Any] | None:
99
+ """Validate keys"""
100
+ if not isinstance(val, dict):
101
+ return val
102
+ invalid_keys = {key for key in val.keys() if not (1 <= len(key) <= 43)}
103
+ if invalid_keys:
104
+ raise ValueError(
105
+ f"{info.field_name} keys must be between 1 and 43 characters long. Invalid keys: "
106
+ f"{humanize_collection(invalid_keys)}"
107
+ )
108
+ return val
109
+
110
+ @field_validator("properties", mode="after")
111
+ def validate_property_keys(cls, val: dict[str, Any]) -> dict[str, Any]:
112
+ """Validate property keys"""
113
+ if invalid_keys := {key for key in val if not KEY_PATTERN.match(key)}:
114
+ raise ValueError(
115
+ f"Property keys must match pattern '{CONTAINER_AND_VIEW_PROPERTIES_IDENTIFIER_PATTERN}'. "
116
+ f"Invalid keys: {humanize_collection(invalid_keys)}"
117
+ )
118
+
119
+ if forbidden_keys := set(val.keys()).intersection(FORBIDDEN_CONTAINER_AND_VIEW_PROPERTIES_IDENTIFIER):
120
+ raise ValueError(
121
+ f"Property keys cannot be any of the following reserved values: {humanize_collection(forbidden_keys)}"
122
+ )
123
+ return val
124
+
125
+ @field_validator("external_id")
126
+ def check_forbidden_external_id_value(cls, val: str) -> str:
127
+ """Check the external_id not present in forbidden set"""
128
+ if val in FORBIDDEN_CONTAINER_AND_VIEW_EXTERNAL_IDS:
129
+ raise ValueError(
130
+ f"{val!r} is a reserved container External ID. Reserved External IDs are: "
131
+ f"{humanize_collection(FORBIDDEN_CONTAINER_AND_VIEW_EXTERNAL_IDS)}"
132
+ )
133
+ return val
134
+
135
+
136
+ class ContainerRequest(Container): ...
137
+
138
+
139
+ class ContainerResponse(Container, WriteableResource[ContainerRequest]):
140
+ created_time: int = Field(
141
+ description="When the container was created. The number of milliseconds since 00:00:00 "
142
+ "Thursday, 1 January 1970, "
143
+ "Coordinated Universal Time (UTC), minus leap seconds."
144
+ )
145
+ last_updated_time: int = Field(
146
+ description="When the container was last updated. The number of milliseconds since 00:00:00 Thursday, "
147
+ "1 January 1970, Coordinated Universal Time (UTC), minus leap seconds."
148
+ )
149
+ is_global: bool = Field(description="Whether the container is a global container.")
150
+
151
+ def as_request(self) -> "ContainerRequest":
152
+ return ContainerRequest.model_validate(self.model_dump(by_alias=True))
@@ -0,0 +1,167 @@
1
+ from abc import ABC
2
+ from typing import Annotated, Literal
3
+
4
+ from pydantic import Field, field_validator
5
+
6
+ from cognite.neat._utils.text import humanize_collection
7
+
8
+ from ._base import BaseModelObject
9
+ from ._constants import ENUM_VALUE_IDENTIFIER_PATTERN, FORBIDDEN_ENUM_VALUES, INSTANCE_ID_PATTERN
10
+ from ._references import ContainerReference
11
+
12
+
13
+ class PropertyTypeDefinition(BaseModelObject, ABC):
14
+ type: str
15
+
16
+
17
+ class ListablePropertyTypeDefinition(PropertyTypeDefinition, ABC):
18
+ list: bool | None = Field(
19
+ default=None,
20
+ description="Specifies that the data type is a list of values.",
21
+ )
22
+ max_list_size: int | None = Field(
23
+ default=None,
24
+ description="Specifies the maximum number of values in the list",
25
+ )
26
+
27
+
28
+ class TextProperty(ListablePropertyTypeDefinition):
29
+ type: Literal["text"] = "text"
30
+ max_text_size: int | None = Field(
31
+ default=None,
32
+ description="Specifies the maximum size in bytes of the text property, when encoded with utf-8.",
33
+ )
34
+ collation: str | None = Field(
35
+ default=None,
36
+ description="he set of language specific rules - used when sorting text fields.",
37
+ )
38
+
39
+
40
+ class Unit(BaseModelObject):
41
+ external_id: str = Field(
42
+ description="The external ID of the unit. Must match the unit in the Cognite Unit catalog.",
43
+ min_length=1,
44
+ max_length=256,
45
+ pattern=INSTANCE_ID_PATTERN,
46
+ )
47
+ source_unit: str | None = Field(
48
+ default=None,
49
+ description="The unit in the source system.",
50
+ )
51
+
52
+
53
+ class FloatProperty(ListablePropertyTypeDefinition, ABC):
54
+ unit: Unit | None = Field(default=None, description="The unit of the data stored in this property")
55
+
56
+
57
+ class Float32Property(FloatProperty):
58
+ type: Literal["float32"] = "float32"
59
+
60
+
61
+ class Float64Property(FloatProperty):
62
+ type: Literal["float64"] = "float64"
63
+
64
+
65
+ class BooleanProperty(ListablePropertyTypeDefinition):
66
+ type: Literal["boolean"] = "boolean"
67
+
68
+
69
+ class Int32Property(ListablePropertyTypeDefinition):
70
+ type: Literal["int32"] = "int32"
71
+
72
+
73
+ class Int64Property(ListablePropertyTypeDefinition):
74
+ type: Literal["int64"] = "int64"
75
+
76
+
77
+ class TimestampProperty(ListablePropertyTypeDefinition):
78
+ type: Literal["timestamp"] = "timestamp"
79
+
80
+
81
+ class DateProperty(ListablePropertyTypeDefinition):
82
+ type: Literal["date"] = "date"
83
+
84
+
85
+ class JSONProperty(ListablePropertyTypeDefinition):
86
+ type: Literal["json"] = "json"
87
+
88
+
89
+ class TimeseriesCDFExternalIdReference(ListablePropertyTypeDefinition):
90
+ type: Literal["timeseries"] = "timeseries"
91
+
92
+
93
+ class FileCDFExternalIdReference(ListablePropertyTypeDefinition):
94
+ type: Literal["file"] = "file"
95
+
96
+
97
+ class SequenceCDFExternalIdReference(ListablePropertyTypeDefinition):
98
+ type: Literal["sequence"] = "sequence"
99
+
100
+
101
+ class DirectNodeRelation(ListablePropertyTypeDefinition):
102
+ type: Literal["direct"] = "direct"
103
+ container: ContainerReference | None = Field(
104
+ default=None,
105
+ description="The (optional) required type for the node the direct relation points to. If specified, "
106
+ "the node must exist before the direct relation is referenced and of the specified type. "
107
+ "If no container specification is used, the node will be auto created with the built-in node "
108
+ "container type, and it does not explicitly have to be created before the node that references it.",
109
+ )
110
+
111
+
112
+ class EnumValue(BaseModelObject):
113
+ name: str | None = Field(
114
+ max_length=255,
115
+ description="The name of the enum value.",
116
+ )
117
+ description: str | None = Field(
118
+ default=None,
119
+ max_length=1024,
120
+ description="Description of the enum value.",
121
+ )
122
+
123
+
124
+ class EnumProperty(PropertyTypeDefinition):
125
+ type: Literal["enum"] = "enum"
126
+ unknown_value: str | None = Field(
127
+ default=None,
128
+ description="TThe value to use when the enum value is unknown. This can optionally be used to "
129
+ "provide forward-compatibility, Specifying what value to use if the client does not "
130
+ "recognize the returned value. It is not possible to ingest the unknown value, "
131
+ "but it must be part of the allowed values.",
132
+ )
133
+ values: dict[str, EnumValue] = Field(
134
+ description="A set of all possible values for the enum property.",
135
+ min_length=1,
136
+ max_length=32,
137
+ pattern=ENUM_VALUE_IDENTIFIER_PATTERN,
138
+ )
139
+
140
+ @field_validator("values", mode="after")
141
+ def _valid_enum_value(cls, val: dict[str, EnumValue]) -> dict[str, EnumValue]:
142
+ invalid_enum_values = set(val.keys()).intersection(FORBIDDEN_ENUM_VALUES)
143
+ if invalid_enum_values:
144
+ raise ValueError(
145
+ "Enum values cannot be any of the following reserved values: "
146
+ f"{humanize_collection(invalid_enum_values)}"
147
+ )
148
+ return val
149
+
150
+
151
+ DataType = Annotated[
152
+ TextProperty
153
+ | Float32Property
154
+ | Float64Property
155
+ | BooleanProperty
156
+ | Int32Property
157
+ | Int64Property
158
+ | TimestampProperty
159
+ | DateProperty
160
+ | JSONProperty
161
+ | TimeseriesCDFExternalIdReference
162
+ | FileCDFExternalIdReference
163
+ | SequenceCDFExternalIdReference
164
+ | DirectNodeRelation
165
+ | EnumProperty,
166
+ Field(discriminator="type"),
167
+ ]
@@ -0,0 +1,26 @@
1
+ from abc import ABC
2
+ from typing import Annotated, Literal
3
+
4
+ from pydantic import Field
5
+
6
+ from ._base import BaseModelObject
7
+
8
+
9
+ class IndexDefinition(BaseModelObject, ABC):
10
+ index_type: str
11
+ properties: list[str] = Field(description="List of properties to define the index across.")
12
+
13
+
14
+ class BtreeIndex(IndexDefinition):
15
+ index_type: Literal["btree"] = "btree"
16
+ by_space: bool | None = Field(default=None, description="Whether to make the index space-specific.")
17
+ cursorable: bool | None = Field(
18
+ default=None, description="Whether the index can be used for cursor-based pagination."
19
+ )
20
+
21
+
22
+ class InvertedIndex(IndexDefinition):
23
+ index_type: Literal["inverted"] = "inverted"
24
+
25
+
26
+ Index = Annotated[BtreeIndex | InvertedIndex, Field(discriminator="index_type")]
@@ -0,0 +1,22 @@
1
+ from typing import Literal
2
+
3
+ from pydantic import Field
4
+
5
+ from ._base import BaseModelObject
6
+ from ._constants import DM_EXTERNAL_ID_PATTERN, SPACE_FORMAT_PATTERN
7
+
8
+
9
+ class ContainerReference(BaseModelObject):
10
+ type: Literal["container"] = "container"
11
+ space: str = Field(
12
+ description="Id of the space hosting (containing) the container.",
13
+ min_length=1,
14
+ max_length=43,
15
+ pattern=SPACE_FORMAT_PATTERN,
16
+ )
17
+ external_id: str = Field(
18
+ description="External-id of the container.",
19
+ min_length=1,
20
+ max_length=255,
21
+ pattern=DM_EXTERNAL_ID_PATTERN,
22
+ )
@@ -15,8 +15,8 @@ class Space(WriteableResource["SpaceRequest"], ABC):
15
15
  max_length=43,
16
16
  pattern=SPACE_FORMAT_PATTERN,
17
17
  )
18
- name: str | None = Field(None, description="Name of the space.", max_length=1024)
19
- description: str | None = Field(None, description="The description of the space.", max_length=255)
18
+ name: str | None = Field(None, description="Name of the space.", max_length=255)
19
+ description: str | None = Field(None, description="The description of the space.", max_length=1024)
20
20
 
21
21
  @field_validator("space")
22
22
  def check_forbidden_space_value(cls, val: str) -> str:
@@ -1,3 +1,4 @@
1
+ from ._base import ConceptEntity, UnknownEntity
1
2
  from ._constants import Undefined, Unknown
2
3
  from ._data_types import (
3
4
  AnyURI,
@@ -24,6 +25,7 @@ __all__ = [
24
25
  "URI",
25
26
  "AnyURI",
26
27
  "Boolean",
28
+ "ConceptEntity",
27
29
  "DataType",
28
30
  "Date",
29
31
  "DateTime",
@@ -42,5 +44,6 @@ __all__ = [
42
44
  "Timeseries",
43
45
  "Undefined",
44
46
  "Unknown",
47
+ "UnknownEntity",
45
48
  "parse_entity",
46
49
  ]
@@ -0,0 +1,33 @@
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class ModelSyntaxError(BaseModel):
5
+ """If any syntax error is found. Stop validation
6
+ and ask user to fix the syntax error first."""
7
+
8
+ message: str
9
+
10
+
11
+ class ImplementationWarning(BaseModel):
12
+ """This is only for conceptual data model. It means that conversion to DMS
13
+ will fail unless user implements the missing part."""
14
+
15
+ message: str
16
+ fix: str
17
+
18
+
19
+ class ConsistencyError(BaseModel):
20
+ """If any consistency error is found, the deployment of the data model will fail. For example,
21
+ if a reverse direct relations points to a non-existing direct relation. This is only relevant for
22
+ DMS model.
23
+ """
24
+
25
+ message: str
26
+ fix: str
27
+
28
+
29
+ class Recommendation(BaseModel):
30
+ """Best practice recommendation."""
31
+
32
+ message: str
33
+ fix: str | None = None
@@ -0,0 +1,40 @@
1
+ from collections.abc import Collection
2
+ from typing import Any
3
+
4
+
5
+ def humanize_collection(collection: Collection[Any], /, *, sort: bool = True, bind_word: str = "and") -> str:
6
+ """Convert a collection of items to a human-readable string.
7
+
8
+ Args:
9
+ collection: The collection of items to convert.
10
+ sort: Whether to sort the collection before converting. Default is True.
11
+ bind_word: The word to use to bind the last two items. Default is "and".
12
+
13
+ Returns:
14
+ A human-readable string of the collection.
15
+
16
+ Examples:
17
+ >>> humanize_collection(["b", "c", "a"])
18
+ 'a, b and c'
19
+ >>> humanize_collection(["b", "c", "a"], sort=False)
20
+ 'b, c and a'
21
+ >>> humanize_collection(["a", "b"])
22
+ 'a and b'
23
+ >>> humanize_collection(["a"])
24
+ 'a'
25
+ >>> humanize_collection([])
26
+ ''
27
+
28
+ """
29
+ if not collection:
30
+ return ""
31
+ elif len(collection) == 1:
32
+ return str(next(iter(collection)))
33
+
34
+ strings = (str(item) for item in collection)
35
+ if sort:
36
+ sequence = sorted(strings)
37
+ else:
38
+ sequence = list(strings)
39
+
40
+ return f"{', '.join(sequence[:-1])} {bind_word} {sequence[-1]}"
@@ -0,0 +1,81 @@
1
+ from pydantic import ValidationError
2
+ from pydantic_core import ErrorDetails
3
+
4
+
5
+ def humanize_validation_error(error: ValidationError) -> list[str]:
6
+ """Converts a ValidationError to a human-readable format.
7
+
8
+ This overwrites the default error messages from Pydantic to be better suited for Toolkit users.
9
+
10
+ Args:
11
+ error: The ValidationError to convert.
12
+
13
+ Returns:
14
+ A list of human-readable error messages.
15
+ """
16
+ errors: list[str] = []
17
+ item: ErrorDetails
18
+
19
+ for item in error.errors(include_input=True, include_url=False):
20
+ loc = item["loc"]
21
+ error_type = item["type"]
22
+ if error_type == "missing":
23
+ msg = f"Missing required field: {loc[-1]!r}"
24
+ elif error_type == "extra_forbidden":
25
+ msg = f"Unused field: {loc[-1]!r}"
26
+ elif error_type == "value_error":
27
+ msg = str(item["ctx"]["error"])
28
+ elif error_type == "literal_error":
29
+ msg = f"{item['msg']}. Got {item['input']!r}."
30
+ elif error_type == "string_type":
31
+ msg = (
32
+ f"{item['msg']}. Got {item['input']!r} of type {type(item['input']).__name__}. "
33
+ f"Hint: Use double quotes to force string."
34
+ )
35
+ elif error_type == "model_type":
36
+ model_name = item["ctx"].get("class_name", "unknown")
37
+ msg = (
38
+ f"Input must be an object of type {model_name}. Got {item['input']!r} of "
39
+ f"type {type(item['input']).__name__}."
40
+ )
41
+ elif error_type.endswith("_type"):
42
+ msg = f"{item['msg']}. Got {item['input']!r} of type {type(item['input']).__name__}."
43
+ else:
44
+ # Default to the Pydantic error message
45
+ msg = item["msg"]
46
+
47
+ if error_type.endswith("dict_type") and len(loc) > 1:
48
+ # If this is a dict_type error for a JSON field, the location will be:
49
+ # dict[str,json-or-python[json=any,python=tagged-union[list[...],dict[str,...],str,bool,int,float,none]]]
50
+ # This is hard to read, so we simplify it to just the field name.
51
+ loc = tuple(["dict" if isinstance(x, str) and "json-or-python" in x else x for x in loc])
52
+
53
+ if len(loc) > 1 and error_type in {"extra_forbidden", "missing"}:
54
+ # We skip the last element as this is in the message already
55
+ msg = f"In {as_json_path(loc[:-1])} {msg[:1].casefold()}{msg[1:]}"
56
+ elif len(loc) > 1:
57
+ msg = f"In {as_json_path(loc)} {msg[:1].casefold()}{msg[1:]}"
58
+ elif len(loc) == 1 and isinstance(loc[0], str) and error_type not in {"extra_forbidden", "missing"}:
59
+ msg = f"In field {loc[0]} {msg[:1].casefold()}{msg[1:]}"
60
+ errors.append(msg)
61
+ return errors
62
+
63
+
64
+ def as_json_path(loc: tuple[str | int, ...]) -> str:
65
+ """Converts a location tuple to a JSON path.
66
+
67
+ Args:
68
+ loc: The location tuple to convert.
69
+
70
+ Returns:
71
+ A JSON path string.
72
+ """
73
+ if not loc:
74
+ return ""
75
+ # +1 to convert from 0-based to 1-based indexing
76
+ prefix = ""
77
+ if isinstance(loc[0], int):
78
+ prefix = "item "
79
+
80
+ suffix = ".".join([str(x) if isinstance(x, str) else f"[{x + 1}]" for x in loc]).replace(".[", "[")
81
+ return f"{prefix}{suffix}"
cognite/neat/_version.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "0.123.36"
1
+ __version__ = "0.123.38"
2
2
  __engine__ = "^2.0.4"
@@ -2,7 +2,7 @@ from ._base import BaseExporter, CDFExporter
2
2
  from ._data_model2dms import DMSExporter
3
3
  from ._data_model2excel import ExcelExporter
4
4
  from ._data_model2instance_template import InstanceTemplateExporter
5
- from ._data_model2ontology import GraphExporter, OWLExporter, SemanticDataModelExporter, SHACLExporter
5
+ from ._data_model2semantic_model import GraphExporter, OWLExporter, SHACLExporter
6
6
  from ._data_model2yaml import YAMLExporter
7
7
 
8
8
  __all__ = [
@@ -14,7 +14,6 @@ __all__ = [
14
14
  "InstanceTemplateExporter",
15
15
  "OWLExporter",
16
16
  "SHACLExporter",
17
- "SemanticDataModelExporter",
18
17
  "YAMLExporter",
19
18
  ]
20
19
 
@@ -32,6 +32,8 @@ if sys.version_info >= (3, 11):
32
32
  else:
33
33
  from typing_extensions import Self
34
34
 
35
+ SHACL = Namespace("http://www.w3.org/ns/shacl#")
36
+
35
37
 
36
38
  class GraphExporter(BaseExporter[ConceptualDataModel, Graph], ABC):
37
39
  def export_to_file(self, data_model: ConceptualDataModel, filepath: Path) -> None:
@@ -42,7 +44,7 @@ class OWLExporter(GraphExporter):
42
44
  """Exports verified conceptual data model to an OWL ontology."""
43
45
 
44
46
  def export(self, data_model: ConceptualDataModel) -> Graph:
45
- return Ontology.from_data_model(data_model).as_owl()
47
+ return Ontology.from_data_model(data_model).graph
46
48
 
47
49
  @property
48
50
  def description(self) -> str:
@@ -53,44 +55,31 @@ class SHACLExporter(GraphExporter):
53
55
  """Exports data_model to a SHACL graph."""
54
56
 
55
57
  def export(self, data_model: ConceptualDataModel) -> Graph:
56
- return Ontology.from_data_model(data_model).as_shacl()
57
-
58
- @property
59
- def description(self) -> str:
60
- return "Export verified information model to SHACL."
61
-
62
-
63
- class SemanticDataModelExporter(GraphExporter):
64
- """Exports verified information model to a semantic data model."""
65
-
66
- def export(self, data_model: ConceptualDataModel) -> Graph:
67
- return Ontology.from_data_model(data_model).as_semantic_data_model()
58
+ return ShaclShapes.from_data_model(data_model).graph
68
59
 
69
60
  @property
70
61
  def description(self) -> str:
71
- return "Export verified information model to a semantic data model."
62
+ return "Export verified conceptual data model to SHACL."
72
63
 
73
64
 
74
- class OntologyModel(BaseModel):
65
+ class _ModelConfig(BaseModel):
75
66
  model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True, strict=False, extra="allow")
76
67
 
77
68
 
78
- class Ontology(OntologyModel):
69
+ class Ontology(_ModelConfig):
79
70
  """
80
71
  Represents an ontology. This class is used to generate an OWL ontology from conceptual data model.
81
72
 
82
73
  Args:
83
74
  properties: A list of OWL properties.
84
75
  classes: A list of OWL classes.
85
- shapes: A list of SHACL node shapes.
86
76
  metadata: Metadata about the ontology.
87
77
  prefixes: A dictionary of prefixes and namespaces.
88
78
  """
89
79
 
80
+ metadata: "OWLMetadata"
90
81
  properties: list["OWLProperty"]
91
82
  classes: list["OWLClass"]
92
- shapes: list["SHACLNodeShape"]
93
- metadata: "OWLMetadata"
94
83
  prefixes: dict[str, Namespace]
95
84
 
96
85
  @classmethod
@@ -105,7 +94,6 @@ class Ontology(OntologyModel):
105
94
  An instance of Ontology.
106
95
  """
107
96
  analysis = DataModelAnalysis(data_model)
108
- concept_by_suffix = analysis.concept_by_suffix()
109
97
  return cls(
110
98
  properties=[
111
99
  OWLProperty.from_list_of_properties(definition, data_model.metadata.namespace)
@@ -115,46 +103,12 @@ class Ontology(OntologyModel):
115
103
  OWLClass.from_concept(definition, data_model.metadata.namespace, data_model.prefixes)
116
104
  for definition in data_model.concepts
117
105
  ],
118
- shapes=[
119
- SHACLNodeShape.from_data_model(
120
- concept_by_suffix[str(concept.suffix)],
121
- list(properties.values()),
122
- data_model.metadata.namespace,
123
- )
124
- for concept, properties in analysis.properties_by_id_by_concept().items()
125
- ]
126
- + [
127
- SHACLNodeShape.from_data_model(
128
- concept,
129
- [],
130
- data_model.metadata.namespace,
131
- )
132
- for concept in concept_by_suffix.values()
133
- ],
134
106
  metadata=OWLMetadata(**data_model.metadata.model_dump()),
135
107
  prefixes=data_model.prefixes,
136
108
  )
137
109
 
138
- def as_shacl(self) -> Graph:
139
- """
140
- Generates a SHACL graph from the ontology.
141
-
142
- Returns:
143
- A SHACL graph.
144
- """
145
-
146
- shacl = Graph()
147
- shacl.bind(self.metadata.prefix, self.metadata.namespace)
148
- for prefix, namespace in self.prefixes.items():
149
- shacl.bind(prefix, namespace)
150
-
151
- for shape in self.shapes:
152
- for triple in shape.triples:
153
- shacl.add(triple) # type: ignore[arg-type]
154
-
155
- return shacl
156
-
157
- def as_owl(self) -> Graph:
110
+ @property
111
+ def graph(self) -> Graph:
158
112
  """
159
113
  Generates an OWL graph from the ontology.
160
114
 
@@ -180,33 +134,6 @@ class Ontology(OntologyModel):
180
134
 
181
135
  return owl
182
136
 
183
- def as_semantic_data_model(self) -> Graph:
184
- return self.as_owl() + self.as_shacl()
185
-
186
- @property
187
- def owl_triples(self) -> list[tuple]:
188
- return list(self.as_owl())
189
-
190
- @property
191
- def shacl_triples(self) -> list[tuple]:
192
- return list(self.as_shacl())
193
-
194
- @property
195
- def triples(self) -> list[tuple]:
196
- return self.owl_triples + self.shacl_triples
197
-
198
- @property
199
- def ontology(self) -> str:
200
- return self.as_owl().serialize()
201
-
202
- @property
203
- def constraints(self) -> str:
204
- return self.as_shacl().serialize()
205
-
206
- @property
207
- def semantic_data_model(self) -> str:
208
- return (self.as_owl() + self.as_shacl()).serialize()
209
-
210
137
 
211
138
  class OWLMetadata(ConceptualMetadata):
212
139
  @property
@@ -233,7 +160,7 @@ class OWLMetadata(ConceptualMetadata):
233
160
  return triples
234
161
 
235
162
 
236
- class OWLClass(OntologyModel):
163
+ class OWLClass(_ModelConfig):
237
164
  id_: URIRef
238
165
  type_: URIRef = OWL.Class
239
166
  label: str | None
@@ -306,7 +233,7 @@ class OWLClass(OntologyModel):
306
233
  )
307
234
 
308
235
 
309
- class OWLProperty(OntologyModel):
236
+ class OWLProperty(_ModelConfig):
310
237
  id_: URIRef
311
238
  type_: set[URIRef]
312
239
  label: set[str]
@@ -510,10 +437,78 @@ class OWLProperty(OntologyModel):
510
437
  )
511
438
 
512
439
 
513
- SHACL = Namespace("http://www.w3.org/ns/shacl#")
440
+ class ShaclShapes(_ModelConfig):
441
+ """
442
+ Represents a SHACL shapes. This class is used to generate a SHACL graph from conceptual data model.
443
+
444
+ Args:
445
+ shapes: A list of SHACL node shapes.
446
+ prefixes: A dictionary of prefixes and namespaces.
447
+ """
514
448
 
449
+ shapes: list["SHACLNodeShape"]
450
+ prefixes: dict[str, Namespace]
515
451
 
516
- class SHACLNodeShape(OntologyModel):
452
+ @classmethod
453
+ def from_data_model(cls, data_model: ConceptualDataModel) -> Self:
454
+ """
455
+ Generates shacl shapes from a conceptual data model.
456
+
457
+ Args:
458
+ data_model: The data_model to generate the shacl shapes from.
459
+
460
+ Returns:
461
+ An instance of ShaclShapes.
462
+ """
463
+ analysis = DataModelAnalysis(data_model)
464
+ concepts_by_concept_entity = analysis.concept_by_concept_entity
465
+ properties_by_concept_entity = analysis.properties_by_concepts()
466
+ return cls(
467
+ shapes=[
468
+ # shapes that have property shapes as well
469
+ SHACLNodeShape.from_concept(
470
+ concept_entity,
471
+ concepts_by_concept_entity,
472
+ properties,
473
+ data_model.metadata.namespace,
474
+ )
475
+ for concept_entity, properties in properties_by_concept_entity.items()
476
+ ]
477
+ + [
478
+ # shapes without any property shapes
479
+ SHACLNodeShape.from_concept(
480
+ concept_entity,
481
+ concepts_by_concept_entity,
482
+ [],
483
+ data_model.metadata.namespace,
484
+ )
485
+ for concept_entity in concepts_by_concept_entity.keys()
486
+ if concept_entity not in properties_by_concept_entity
487
+ ],
488
+ prefixes=data_model.prefixes,
489
+ )
490
+
491
+ @property
492
+ def graph(self) -> Graph:
493
+ """
494
+ Generates a SHACL graph from the class instance.
495
+
496
+ Returns:
497
+ A SHACL graph.
498
+ """
499
+
500
+ shacl = Graph()
501
+ for prefix, namespace in self.prefixes.items():
502
+ shacl.bind(prefix, namespace)
503
+
504
+ for shape in self.shapes:
505
+ for triple in shape.triples:
506
+ shacl.add(triple) # type: ignore[arg-type]
507
+
508
+ return shacl
509
+
510
+
511
+ class SHACLNodeShape(_ModelConfig):
517
512
  id_: URIRef
518
513
  type_: URIRef = SHACL.NodeShape
519
514
  target_class: URIRef
@@ -555,26 +550,33 @@ class SHACLNodeShape(OntologyModel):
555
550
  )
556
551
 
557
552
  @classmethod
558
- def from_data_model(
553
+ def from_concept(
559
554
  cls,
560
- concept_definition: Concept,
561
- property_definitions: list[ConceptualProperty],
555
+ concept_entity: ConceptEntity,
556
+ concepts_by_concept_entity: dict[ConceptEntity, Concept],
557
+ properties: list[ConceptualProperty],
562
558
  namespace: Namespace,
563
559
  ) -> "SHACLNodeShape":
564
- if concept_definition.implements:
565
- parent = [namespace[str(parent.suffix) + "Shape"] for parent in concept_definition.implements]
560
+ if not (concept := concepts_by_concept_entity.get(concept_entity)):
561
+ raise ValueError(f"Concept {concept_entity} not found in data model!")
562
+
563
+ if concept.implements:
564
+ parent = [namespace[str(parent.suffix) + "Shape"] for parent in concept.implements]
566
565
  else:
567
566
  parent = None
568
567
  return cls(
569
- id_=namespace[f"{concept_definition.concept.suffix!s}Shape"],
570
- target_class=namespace[str(concept_definition.concept.suffix)],
568
+ id_=namespace[f"{concept.concept.suffix!s}Shape"],
569
+ target_class=concept.instance_source or namespace[str(concept.concept.suffix)],
571
570
  parent=parent,
572
- property_shapes=[SHACLPropertyShape.from_property(prop, namespace) for prop in property_definitions],
571
+ property_shapes=[
572
+ SHACLPropertyShape.from_property(property_, concepts_by_concept_entity, namespace)
573
+ for property_ in properties
574
+ ],
573
575
  namespace=namespace,
574
576
  )
575
577
 
576
578
 
577
- class SHACLPropertyShape(OntologyModel):
579
+ class SHACLPropertyShape(_ModelConfig):
578
580
  id_: BNode
579
581
  type_: URIRef = SHACL.property
580
582
  path: URIRef # URIRef to property in OWL
@@ -614,23 +616,31 @@ class SHACLPropertyShape(OntologyModel):
614
616
  return self.path_triples + self.node_kind_triples + self.cardinality_triples
615
617
 
616
618
  @classmethod
617
- def from_property(cls, definition: ConceptualProperty, namespace: Namespace) -> "SHACLPropertyShape":
618
- # TODO requires PR to fix MultiValueType and UnknownValueType
619
- if isinstance(definition.value_type, ConceptEntity):
620
- expected_value_type = namespace[f"{definition.value_type.suffix}Shape"]
621
- elif isinstance(definition.value_type, DataType):
622
- expected_value_type = XSD[definition.value_type.xsd]
619
+ def from_property(
620
+ cls,
621
+ property_: ConceptualProperty,
622
+ concepts_by_concept_entity: dict[ConceptEntity, Concept],
623
+ namespace: Namespace,
624
+ ) -> "SHACLPropertyShape":
625
+ if isinstance(property_.value_type, ConceptEntity):
626
+ concept = concepts_by_concept_entity.get(property_.value_type)
627
+ value_type_uri = concept.instance_source if concept else None
628
+ expected_value_type = value_type_uri or namespace[f"{property_.value_type.suffix}"]
629
+ elif isinstance(property_.value_type, DataType):
630
+ expected_value_type = XSD[property_.value_type.xsd]
623
631
  else:
624
- raise ValueError(f"Value type {definition.value_type.type_} is not supported")
632
+ raise NotImplementedError(f"Value type {property_.value_type.type_} is not supported yet")
625
633
 
626
634
  return cls(
627
635
  id_=BNode(),
628
- path=namespace[definition.property_],
629
- node_kind=SHACL.IRI if definition.type_ == EntityTypes.object_property else SHACL.Literal,
636
+ path=property_.instance_source[0]
637
+ if property_.instance_source and len(property_.instance_source) == 1
638
+ else namespace[property_.property_],
639
+ node_kind=SHACL.IRI if property_.type_ == EntityTypes.object_property else SHACL.Literal,
630
640
  expected_value_type=expected_value_type,
631
- min_count=definition.min_count,
641
+ min_count=property_.min_count,
632
642
  max_count=(
633
- int(definition.max_count) if definition.max_count and definition.max_count != float("inf") else None
643
+ int(property_.max_count) if property_.max_count and property_.max_count != float("inf") else None
634
644
  ),
635
645
  namespace=namespace,
636
646
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cognite-neat
3
- Version: 0.123.36
3
+ Version: 0.123.38
4
4
  Summary: Knowledge graph transformation
5
5
  Project-URL: Documentation, https://cognite-neat.readthedocs-hosted.com/
6
6
  Project-URL: Homepage, https://cognite-neat.readthedocs-hosted.com/
@@ -1,15 +1,24 @@
1
1
  cognite/neat/__init__.py,sha256=Lo4DbjDOwnhCYUoAgPp5RG1fDdF7OlnomalTe7n1ydw,211
2
- cognite/neat/_version.py,sha256=jaav_lFeEoGh_VeTDKjQPDYC__mrYSbc7TXSKhz9g7c,47
2
+ cognite/neat/_issues.py,sha256=uv0fkkWwTKqNmTmHqyoBB3L6yMCh42EZpEkLGmIJYOY,812
3
+ cognite/neat/_version.py,sha256=AcC3bBw58APEu-16ayi6h9wHbjFkLKdwAnhBj7XMeqk,47
3
4
  cognite/neat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
5
  cognite/neat/_data_model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
6
  cognite/neat/_data_model/_constants.py,sha256=NGGvWHlQqhkkSBP_AqoofGYjNph3SiZX6QPINlMsy04,107
6
7
  cognite/neat/_data_model/_identifiers.py,sha256=a0LcQ_h0NffxSKTCrzCDpYkrlaUTk-D_rfaQUh-BhWc,1921
7
8
  cognite/neat/_data_model/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- cognite/neat/_data_model/models/dms/__init__.py,sha256=LwuPR4zOPinhT89mN0XEB38d5deWmLbGFs_RvENVQlc,212
9
+ cognite/neat/_data_model/models/conceptual/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ cognite/neat/_data_model/models/conceptual/_base.py,sha256=SFkoBJDM51pqew_isHFJoB20OgfofpwVRnTrg-rKkNY,710
11
+ cognite/neat/_data_model/models/conceptual/_properties.py,sha256=CpF37vJYBTLT4DH4ZOu2U-JyWtkb_27V8fw52qiaE_k,4007
12
+ cognite/neat/_data_model/models/dms/__init__.py,sha256=0YalizBE9PK_5JtzG1_fhrRhrRuqCUsWwWBkY4X4PHo,1876
9
13
  cognite/neat/_data_model/models/dms/_base.py,sha256=R8SP3Zi9daTBqewYKGjuNEkrWc-j91f-6t34CN-9YJ0,719
10
- cognite/neat/_data_model/models/dms/_constants.py,sha256=TpnOZ5Q1O_r2H5Ez3sAvaCH2s5DbnUm0qeRC-K1iPAQ,164
11
- cognite/neat/_data_model/models/dms/_space.py,sha256=bLSTY5tTBnvS19kUacxM0p_c22lYY5FY9etofH1NNMc,1680
12
- cognite/neat/_data_model/models/entities/__init__.py,sha256=yZSlicz9g2j4PCUW9h4KDwBhfApYb6jI0341HSWewT8,708
14
+ cognite/neat/_data_model/models/dms/_constants.py,sha256=tLyle1N_ekNBhANleG7GvZB85P4uGaoWl2mqeR-vfmY,1272
15
+ cognite/neat/_data_model/models/dms/_constraints.py,sha256=7Nv-EoNl6lSHUQh6r15Ei0LzR3gWV006K3RlAi1Ic68,956
16
+ cognite/neat/_data_model/models/dms/_container.py,sha256=ovyAwsh2ACt0j9-j6ooDOdUl0uKlGdkjYA2UUvJfHrw,5756
17
+ cognite/neat/_data_model/models/dms/_data_types.py,sha256=XSGQWVzYFRYAzKsDln20nC2kqiHQC6JAvDeTzCBPT-0,5202
18
+ cognite/neat/_data_model/models/dms/_indexes.py,sha256=MsiHbGCH50QaF1mw_pIY-AZ5dY37vS3fQECOd2rBXWo,780
19
+ cognite/neat/_data_model/models/dms/_references.py,sha256=yrmMo2JNfupG3tppdjLOaEhUAsRSIjZlBOI6hCol1z4,613
20
+ cognite/neat/_data_model/models/dms/_space.py,sha256=-1LkRmQaAdIj2EYDcVv5Mcejl5uswgAEVv7DztpIUk4,1680
21
+ cognite/neat/_data_model/models/entities/__init__.py,sha256=qdtIpyy2hjfdMwEHya-efOCvWassaalQla15RnqK00E,798
13
22
  cognite/neat/_data_model/models/entities/_base.py,sha256=PREgBqc6DM9pLn3VXFWxPBMVK0sexl6s3twSHn9wsf0,3874
14
23
  cognite/neat/_data_model/models/entities/_constants.py,sha256=P56zgsL2xqfegWOxEAyPm9qrZcxrjb1ZXqMG7cDmQxc,333
15
24
  cognite/neat/_data_model/models/entities/_data_types.py,sha256=DfdEWGek7gODro-_0SiiInhPGwul4zn-ASACQfn8HUY,2838
@@ -17,7 +26,9 @@ cognite/neat/_data_model/models/entities/_identifiers.py,sha256=uBiK4ot3V0b_LGXu
17
26
  cognite/neat/_data_model/models/entities/_parser.py,sha256=ZLGw0cFV-B7JuaAUJ65Jbjf6o-vidz9_BZvilS6lAZw,6455
18
27
  cognite/neat/_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
28
  cognite/neat/_utils/auxiliary.py,sha256=Cx-LP8dfN782R3iUcm--q26zdzQ0k_RFnVbJ0bwVZMI,1345
29
+ cognite/neat/_utils/text.py,sha256=1el5Ty1T0tdhTF0gp6L8AAzUxaFmAUAIFy_VvfG_kkM,1194
20
30
  cognite/neat/_utils/useful_types.py,sha256=6Fpw_HlWFj8ZYjGPd0KzguBczuI8GFhj5wBceGsaeak,211
31
+ cognite/neat/_utils/validation.py,sha256=qBC3V3BpkZSrsDG4xfINaB_U0e05e2lCt85oIW3on4I,3253
21
32
  cognite/neat/_utils/http_client/__init__.py,sha256=gJBrOH1tIzEzLforHbeakYimTn4RlelyANps-jtpREI,894
22
33
  cognite/neat/_utils/http_client/_client.py,sha256=2RVwTbbPFlQ8eJVLKNUXwnc4Yq_783PkY44zwr6LlT8,11509
23
34
  cognite/neat/_utils/http_client/_config.py,sha256=C8IF1JoijmVMjA_FEMgAkiD1buEV1cY5Og3t-Ecyfmk,756
@@ -50,12 +61,12 @@ cognite/neat/v0/core/_data_model/catalog/__init__.py,sha256=zWG1-GONe8m05lV3gLAK
50
61
  cognite/neat/v0/core/_data_model/catalog/classic_model.xlsx,sha256=YkocpkKypizjsWYwOdn5yzIz_BSl8T8SQLxgm4GIjLQ,15014
51
62
  cognite/neat/v0/core/_data_model/catalog/conceptual-imf-data-model.xlsx,sha256=vrE5g8vBtsGpwJqygxG3t9I3x4SUAyQsi1vtWfZ8QW4,53682
52
63
  cognite/neat/v0/core/_data_model/catalog/hello_world_pump.xlsx,sha256=E63t5U1PQLIoUfXp1mEuhuq8I2TGKovZlEfIhO5bevw,23322
53
- cognite/neat/v0/core/_data_model/exporters/__init__.py,sha256=6UbiK-dzVUCtYo09s8ICe36BbqPCur6OWB71Lwiu50U,1207
64
+ cognite/neat/v0/core/_data_model/exporters/__init__.py,sha256=NSTeVtfgfkfrhf_Ruz5rHnlF0wIj2dIhAm3io1tEIkQ,1153
54
65
  cognite/neat/v0/core/_data_model/exporters/_base.py,sha256=pdtQDi5G89JVbHtGnvLHJDoujT1UVaCBw939Re1Gqv4,2412
55
66
  cognite/neat/v0/core/_data_model/exporters/_data_model2dms.py,sha256=LdLGgR73n9k5hHiWUSdvDc0lmaEO8UVQYFTiaVWHQ-c,19918
56
67
  cognite/neat/v0/core/_data_model/exporters/_data_model2excel.py,sha256=dT7ZHt57y3mca4TtCBnqMER0xlB7AyvivG0EZ2bGPzg,25484
57
68
  cognite/neat/v0/core/_data_model/exporters/_data_model2instance_template.py,sha256=cmyQBlc1UM5l42g1N_F2K1sVu39ontsmA2bfXJO5muQ,6115
58
- cognite/neat/v0/core/_data_model/exporters/_data_model2ontology.py,sha256=H12y7hZf9169xuVOnIIDnmvpNOegrTOESfG4-yoGpDw,22642
69
+ cognite/neat/v0/core/_data_model/exporters/_data_model2semantic_model.py,sha256=vxeDEWyvj7uv6geNlTQe6MfGcNZkeQJYz0vLzPI7e14,23154
59
70
  cognite/neat/v0/core/_data_model/exporters/_data_model2yaml.py,sha256=v7CgNVtVv4t0FXHPJM-HGkID0AqVDlwsQqUNjWqr_1U,3287
60
71
  cognite/neat/v0/core/_data_model/importers/__init__.py,sha256=jkDKSGv5VdJgl44lmn7VQtD6-rqo09VFOr-tTB5Lfyc,1290
61
72
  cognite/neat/v0/core/_data_model/importers/_base.py,sha256=SAC3nhJUBBl5PwnIs-bQvVam_0zEGjlOlNMvVOuJZzI,2028
@@ -212,7 +223,7 @@ cognite/neat/v0/session/engine/__init__.py,sha256=D3MxUorEs6-NtgoICqtZ8PISQrjrr4
212
223
  cognite/neat/v0/session/engine/_import.py,sha256=1QxA2_EK613lXYAHKQbZyw2yjo5P9XuiX4Z6_6-WMNQ,169
213
224
  cognite/neat/v0/session/engine/_interface.py,sha256=3W-cYr493c_mW3P5O6MKN1xEQg3cA7NHR_ev3zdF9Vk,533
214
225
  cognite/neat/v0/session/engine/_load.py,sha256=u0x7vuQCRoNcPt25KJBJRn8sJabonYK4vtSZpiTdP4k,5201
215
- cognite_neat-0.123.36.dist-info/METADATA,sha256=6blXCoQDpvS6J53dTnL1gs756MQJTNF5h3O3EyDdDvY,9148
216
- cognite_neat-0.123.36.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
217
- cognite_neat-0.123.36.dist-info/licenses/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
218
- cognite_neat-0.123.36.dist-info/RECORD,,
226
+ cognite_neat-0.123.38.dist-info/METADATA,sha256=iDFSXJ075Uh7qGQoJ-CP6VsKePjEuOdiKjf45BFYKWQ,9148
227
+ cognite_neat-0.123.38.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
228
+ cognite_neat-0.123.38.dist-info/licenses/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
229
+ cognite_neat-0.123.38.dist-info/RECORD,,