cognite-neat 1.0.20__py3-none-any.whl → 1.0.21__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.
- cognite/neat/_client/__init__.py +2 -1
- cognite/neat/_client/init/__init__.py +0 -0
- cognite/neat/_client/init/credentials.py +70 -0
- cognite/neat/_client/init/env_vars.py +131 -0
- cognite/neat/_client/init/main.py +51 -0
- cognite/neat/_data_model/_identifiers.py +1 -1
- cognite/neat/_data_model/exporters/_table_exporter/writer.py +59 -3
- cognite/neat/_data_model/importers/_table_importer/data_classes.py +46 -23
- cognite/neat/_data_model/importers/_table_importer/reader.py +54 -15
- cognite/neat/_data_model/models/conceptual/_data_model.py +1 -1
- cognite/neat/_data_model/models/dms/_space.py +1 -1
- cognite/neat/_data_model/models/entities/_identifiers.py +1 -1
- cognite/neat/_exceptions.py +12 -0
- cognite/neat/_store/_store.py +1 -2
- cognite/neat/_utils/auxiliary.py +10 -0
- cognite/neat/_utils/repo.py +19 -0
- cognite/neat/_version.py +1 -1
- {cognite_neat-1.0.20.dist-info → cognite_neat-1.0.21.dist-info}/METADATA +1 -1
- {cognite_neat-1.0.20.dist-info → cognite_neat-1.0.21.dist-info}/RECORD +20 -15
- {cognite_neat-1.0.20.dist-info → cognite_neat-1.0.21.dist-info}/WHEEL +1 -1
cognite/neat/_client/__init__.py
CHANGED
|
File without changes
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
|
|
3
|
+
from cognite.client.credentials import CredentialProvider, OAuthClientCredentials, OAuthInteractive, Token
|
|
4
|
+
|
|
5
|
+
from cognite.neat._utils.text import humanize_collection
|
|
6
|
+
|
|
7
|
+
from .env_vars import ClientEnvironmentVariables, LoginFlow
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_credentials(env_vars: ClientEnvironmentVariables) -> CredentialProvider:
|
|
11
|
+
options: dict[LoginFlow, Callable[[ClientEnvironmentVariables], CredentialProvider]] = {
|
|
12
|
+
"client_credentials": create_client_credentials,
|
|
13
|
+
"interactive": create_interactive_credentials,
|
|
14
|
+
"token": create_token_credentials,
|
|
15
|
+
"infer": create_infer_credentials,
|
|
16
|
+
}
|
|
17
|
+
return options[env_vars.LOGIN_FLOW](env_vars)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def create_client_credentials(env_vars: ClientEnvironmentVariables) -> CredentialProvider:
|
|
21
|
+
missing: list[str] = []
|
|
22
|
+
if not env_vars.IDP_CLIENT_ID:
|
|
23
|
+
missing.append("IDP_CLIENT_ID")
|
|
24
|
+
if not env_vars.IDP_CLIENT_SECRET:
|
|
25
|
+
missing.append("IDP_CLIENT_SECRET")
|
|
26
|
+
if env_vars.IDP_CLIENT_ID is None or env_vars.IDP_CLIENT_SECRET is None:
|
|
27
|
+
raise ValueError(
|
|
28
|
+
f"The following environment variables must be set for "
|
|
29
|
+
f"client credentials authentication: {humanize_collection(missing)}"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
if env_vars.PROVIDER == "cdf":
|
|
33
|
+
return OAuthClientCredentials(
|
|
34
|
+
client_id=env_vars.IDP_CLIENT_ID,
|
|
35
|
+
client_secret=env_vars.IDP_CLIENT_SECRET,
|
|
36
|
+
token_url=env_vars.idp_token_url,
|
|
37
|
+
scopes=None, # type: ignore[arg-type]
|
|
38
|
+
)
|
|
39
|
+
return OAuthClientCredentials(
|
|
40
|
+
client_id=env_vars.IDP_CLIENT_ID,
|
|
41
|
+
client_secret=env_vars.IDP_CLIENT_SECRET,
|
|
42
|
+
token_url=env_vars.idp_token_url,
|
|
43
|
+
audience=env_vars.idp_audience,
|
|
44
|
+
scopes=env_vars.idp_scopes,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def create_interactive_credentials(env_vars: ClientEnvironmentVariables) -> CredentialProvider:
|
|
49
|
+
if not env_vars.IDP_CLIENT_ID:
|
|
50
|
+
raise ValueError("IDP_CLIENT_ID environment variable must be set for interactive authentication.")
|
|
51
|
+
return OAuthInteractive(
|
|
52
|
+
client_id=env_vars.IDP_CLIENT_ID,
|
|
53
|
+
authority_url=env_vars.idp_authority_url,
|
|
54
|
+
scopes=env_vars.idp_scopes,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def create_token_credentials(env_vars: ClientEnvironmentVariables) -> CredentialProvider:
|
|
59
|
+
if not env_vars.CDF_TOKEN:
|
|
60
|
+
raise ValueError("CDF_TOKEN environment variable must be set for token authentication.")
|
|
61
|
+
return Token(env_vars.CDF_TOKEN)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def create_infer_credentials(env_vars: ClientEnvironmentVariables) -> CredentialProvider:
|
|
65
|
+
if env_vars.IDP_CLIENT_SECRET:
|
|
66
|
+
return create_client_credentials(env_vars)
|
|
67
|
+
elif env_vars.CDF_TOKEN:
|
|
68
|
+
return create_token_credentials(env_vars)
|
|
69
|
+
else:
|
|
70
|
+
return create_interactive_credentials(env_vars)
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any, Literal, TypeAlias, get_args
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, ConfigDict, ValidationError
|
|
6
|
+
|
|
7
|
+
from cognite.neat._utils.repo import get_repo_root
|
|
8
|
+
from cognite.neat._utils.validation import humanize_validation_error
|
|
9
|
+
|
|
10
|
+
if sys.version_info >= (3, 11):
|
|
11
|
+
from typing import Self
|
|
12
|
+
else:
|
|
13
|
+
from typing_extensions import Self
|
|
14
|
+
|
|
15
|
+
LoginFlow: TypeAlias = Literal["infer", "client_credentials", "interactive", "token"]
|
|
16
|
+
VALID_LOGIN_FLOWS = get_args(LoginFlow)
|
|
17
|
+
Provider: TypeAlias = Literal["entra_id", "auth0", "cdf", "other"]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ClientEnvironmentVariables(BaseModel):
|
|
21
|
+
"""Configuration for environment variables used by the NEAT client."""
|
|
22
|
+
|
|
23
|
+
model_config = ConfigDict(extra="forbid", frozen=True)
|
|
24
|
+
CDF_CLUSTER: str
|
|
25
|
+
CDF_PROJECT: str
|
|
26
|
+
PROVIDER: Provider = "entra_id"
|
|
27
|
+
LOGIN_FLOW: LoginFlow = "infer"
|
|
28
|
+
|
|
29
|
+
IDP_CLIENT_ID: str | None = None
|
|
30
|
+
IDP_CLIENT_SECRET: str | None = None
|
|
31
|
+
CDF_TOKEN: str | None = None
|
|
32
|
+
|
|
33
|
+
IDP_TENANT_ID: str | None = None
|
|
34
|
+
IDP_TOKEN_URL: str | None = None
|
|
35
|
+
|
|
36
|
+
CDF_URL: str | None = None
|
|
37
|
+
IDP_AUDIENCE: str | None = None
|
|
38
|
+
IDP_SCOPES: str | None = None
|
|
39
|
+
IDP_AUTHORITY_URL: str | None = None
|
|
40
|
+
IDP_DISCOVERY_URL: str | None = None
|
|
41
|
+
CDF_MAX_WORKERS: int | None = None
|
|
42
|
+
CDF_CLIENT_TIMEOUT: int | None = None
|
|
43
|
+
CDF_REDIRECT_PORT: int = 53_000
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def create_humanize(cls, values: dict[str, Any]) -> Self:
|
|
47
|
+
try:
|
|
48
|
+
return cls.model_validate(values)
|
|
49
|
+
except ValidationError as e:
|
|
50
|
+
errors = [humanize_validation_error(error) for error in e.errors()]
|
|
51
|
+
raise ValueError("Invalid environment variable configuration:\n" + "\n - ".join(errors)) from e
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def idp_tenant_id(self) -> str:
|
|
55
|
+
if self.IDP_TENANT_ID:
|
|
56
|
+
return self.IDP_TENANT_ID
|
|
57
|
+
# This line is technically unreachable due to the checks in idp_token_url and idp_authority_url
|
|
58
|
+
raise RuntimeError("IDP_TENANT_ID is missing")
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def idp_token_url(self) -> str:
|
|
62
|
+
if self.PROVIDER == "cdf":
|
|
63
|
+
return "https://auth.cognite.com/oauth2/token"
|
|
64
|
+
if self.IDP_TOKEN_URL:
|
|
65
|
+
return self.IDP_TOKEN_URL
|
|
66
|
+
if self.PROVIDER == "entra_id" and self.IDP_TENANT_ID:
|
|
67
|
+
return f"https://login.microsoftonline.com/{self.IDP_TENANT_ID}/oauth2/v2.0/token"
|
|
68
|
+
alternative = " or provide IDP_TENANT_ID" if self.PROVIDER == "entra_id" else ""
|
|
69
|
+
raise ValueError(
|
|
70
|
+
f"IDP_TOKEN_URL is missing. Please provide it{alternative} in the environment variables.",
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def cdf_url(self) -> str:
|
|
75
|
+
return self.CDF_URL or f"https://{self.CDF_CLUSTER}.cognitedata.com"
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def idp_audience(self) -> str:
|
|
79
|
+
if self.IDP_AUDIENCE:
|
|
80
|
+
return self.IDP_AUDIENCE
|
|
81
|
+
if self.PROVIDER == "auth0":
|
|
82
|
+
return f"https://{self.CDF_PROJECT}.fusion.cognite.com/{self.CDF_PROJECT}"
|
|
83
|
+
else:
|
|
84
|
+
return f"https://{self.CDF_CLUSTER}.cognitedata.com"
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def idp_scopes(self) -> list[str]:
|
|
88
|
+
if self.IDP_SCOPES:
|
|
89
|
+
return self.IDP_SCOPES.split(",")
|
|
90
|
+
if self.PROVIDER == "auth0":
|
|
91
|
+
return ["IDENTITY", "user_impersonation"]
|
|
92
|
+
return [f"https://{self.CDF_CLUSTER}.cognitedata.com/.default"]
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def idp_authority_url(self) -> str:
|
|
96
|
+
if self.IDP_AUTHORITY_URL:
|
|
97
|
+
return self.IDP_AUTHORITY_URL
|
|
98
|
+
if self.PROVIDER == "entra_id" and self.IDP_TENANT_ID:
|
|
99
|
+
return f"https://login.microsoftonline.com/{self.IDP_TENANT_ID}"
|
|
100
|
+
alternative = " or provide IDP_TENANT_ID" if self.PROVIDER == "entra_id" else ""
|
|
101
|
+
raise ValueError(
|
|
102
|
+
f"IDP_AUTHORITY_URL is missing. Please provide it{alternative} in the environment variables.",
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def get_environment_variables(env_file_name: str) -> ClientEnvironmentVariables:
|
|
107
|
+
to_search: list[tuple[str, Path]] = []
|
|
108
|
+
try:
|
|
109
|
+
repo_root = get_repo_root()
|
|
110
|
+
except RuntimeError:
|
|
111
|
+
...
|
|
112
|
+
else:
|
|
113
|
+
to_search.append(("repository root", repo_root))
|
|
114
|
+
to_search.append(("current working directory", Path.cwd()))
|
|
115
|
+
for location_desc, path in to_search:
|
|
116
|
+
env_path = path / env_file_name
|
|
117
|
+
if env_path.is_file():
|
|
118
|
+
print(f"Found {env_file_name} in {location_desc}.")
|
|
119
|
+
return _parse_env_file(env_path)
|
|
120
|
+
raise FileNotFoundError(f"Could not find {env_file_name} in the repository root or current working directory.")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _parse_env_file(env_file_path: Path) -> ClientEnvironmentVariables:
|
|
124
|
+
content = env_file_path.read_text()
|
|
125
|
+
variables: dict[str, Any] = {}
|
|
126
|
+
for line in content.splitlines():
|
|
127
|
+
if line.startswith("#") or "=" not in line:
|
|
128
|
+
continue
|
|
129
|
+
key, value = line.strip().split("=", 1)
|
|
130
|
+
variables[key] = value
|
|
131
|
+
return ClientEnvironmentVariables.create_humanize(variables)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from cognite.client import CogniteClient
|
|
2
|
+
from cognite.client.config import ClientConfig, global_config
|
|
3
|
+
|
|
4
|
+
from cognite.neat import _version
|
|
5
|
+
|
|
6
|
+
from .credentials import get_credentials
|
|
7
|
+
from .env_vars import ClientEnvironmentVariables, get_environment_variables
|
|
8
|
+
|
|
9
|
+
CLIENT_NAME = f"CogniteNeat:{_version.__version__}"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_cognite_client(env_file_name: str) -> CogniteClient:
|
|
13
|
+
"""Get a CogniteClient using environment variables from a .env file."
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
env_file_name: The name of the .env file to look for in the repository root / current working directory. If
|
|
17
|
+
the file is found, the variables will be loaded from the file. If the file is not found, the user will
|
|
18
|
+
be prompted to enter the variables and the file will be created.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
CogniteClient: An instance of CogniteClient configured with the loaded environment variables.
|
|
22
|
+
"""
|
|
23
|
+
try:
|
|
24
|
+
return get_cognite_client_internal(env_file_name)
|
|
25
|
+
except Exception as e:
|
|
26
|
+
raise RuntimeError(f"Failed to create client ❌: {e!s}") from None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def get_cognite_client_internal(env_file_name: str) -> CogniteClient:
|
|
30
|
+
# This function raises exceptions on failure
|
|
31
|
+
if not env_file_name.endswith(".env"):
|
|
32
|
+
raise ValueError(f"env_file_name must end with '.env'. Got: {env_file_name!r}")
|
|
33
|
+
global_config.disable_pypi_version_check = True
|
|
34
|
+
global_config.silence_feature_preview_warnings = True
|
|
35
|
+
env_vars = get_environment_variables(env_file_name)
|
|
36
|
+
client_config = create_client_config_from_env_vars(env_vars)
|
|
37
|
+
# Todo validate credentials by making a simple call to CDF
|
|
38
|
+
# Offer to store credentials securely if valid
|
|
39
|
+
#
|
|
40
|
+
return CogniteClient(client_config)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def create_client_config_from_env_vars(env_vars: ClientEnvironmentVariables) -> ClientConfig:
|
|
44
|
+
return ClientConfig(
|
|
45
|
+
client_name=CLIENT_NAME,
|
|
46
|
+
project=env_vars.CDF_PROJECT,
|
|
47
|
+
credentials=get_credentials(env_vars),
|
|
48
|
+
max_workers=env_vars.CDF_MAX_WORKERS,
|
|
49
|
+
timeout=env_vars.CDF_CLIENT_TIMEOUT,
|
|
50
|
+
base_url=env_vars.cdf_url,
|
|
51
|
+
)
|
|
@@ -3,6 +3,8 @@ from collections import defaultdict
|
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
4
|
from typing import Any, Literal
|
|
5
5
|
|
|
6
|
+
from pydantic import ValidationError
|
|
7
|
+
|
|
6
8
|
from cognite.neat._data_model._constants import DEFAULT_MAX_LIST_SIZE, DEFAULT_MAX_LIST_SIZE_DIRECT_RELATIONS
|
|
7
9
|
from cognite.neat._data_model.importers._table_importer.data_classes import (
|
|
8
10
|
CREATOR_KEY,
|
|
@@ -12,8 +14,11 @@ from cognite.neat._data_model.importers._table_importer.data_classes import (
|
|
|
12
14
|
DMSNode,
|
|
13
15
|
DMSProperty,
|
|
14
16
|
DMSView,
|
|
17
|
+
EntityTableFilter,
|
|
15
18
|
MetadataValue,
|
|
19
|
+
RAWFilterTableFilter,
|
|
16
20
|
TableDMS,
|
|
21
|
+
TableViewFilter,
|
|
17
22
|
)
|
|
18
23
|
from cognite.neat._data_model.models.dms import (
|
|
19
24
|
ContainerPropertyDefinition,
|
|
@@ -23,7 +28,11 @@ from cognite.neat._data_model.models.dms import (
|
|
|
23
28
|
DataType,
|
|
24
29
|
DirectNodeRelation,
|
|
25
30
|
EnumProperty,
|
|
31
|
+
EqualsFilterData,
|
|
32
|
+
Filter,
|
|
26
33
|
FilterAdapter,
|
|
34
|
+
HasDataFilter,
|
|
35
|
+
InFilterData,
|
|
27
36
|
ListablePropertyTypeDefinition,
|
|
28
37
|
NodeReference,
|
|
29
38
|
RequestSchema,
|
|
@@ -299,13 +308,60 @@ class DMSTableWriter:
|
|
|
299
308
|
implements=[self._create_view_entity(parent) for parent in view.implements]
|
|
300
309
|
if view.implements
|
|
301
310
|
else None,
|
|
302
|
-
filter=
|
|
303
|
-
if view.filter
|
|
304
|
-
else None,
|
|
311
|
+
filter=self.write_view_filter(view.filter),
|
|
305
312
|
)
|
|
306
313
|
for view in views
|
|
307
314
|
]
|
|
308
315
|
|
|
316
|
+
def write_view_filter(self, filter: Filter | None) -> TableViewFilter | None:
|
|
317
|
+
if filter is None:
|
|
318
|
+
return None
|
|
319
|
+
filter_type, entities = self._get_entity_filter(filter)
|
|
320
|
+
if filter_type is not None and entities:
|
|
321
|
+
return EntityTableFilter(type=filter_type, entities=entities)
|
|
322
|
+
else:
|
|
323
|
+
return RAWFilterTableFilter(filter=FilterAdapter.dump_json(filter, by_alias=True).decode(encoding="utf-8"))
|
|
324
|
+
|
|
325
|
+
def _get_entity_filter(self, filter: Filter) -> tuple[Literal["nodeType", "hasData"] | None, list[ParsedEntity]]:
|
|
326
|
+
"""If the filter is an entity-based filter (Equals or In on nodes), return the type and entities.
|
|
327
|
+
Otherwise, return (None, [])."""
|
|
328
|
+
if filter is None or len(filter) != 1:
|
|
329
|
+
return None, []
|
|
330
|
+
filter_name, body = next(iter(filter.items()))
|
|
331
|
+
if (
|
|
332
|
+
isinstance(body, EqualsFilterData)
|
|
333
|
+
and body.property == ["node", "type"]
|
|
334
|
+
and isinstance(body.value, dict)
|
|
335
|
+
and (node_reference := self._try_get_node_reference(body.value))
|
|
336
|
+
):
|
|
337
|
+
return "nodeType", [self._create_node_entity(node_reference)]
|
|
338
|
+
elif (
|
|
339
|
+
isinstance(body, InFilterData)
|
|
340
|
+
and body.property == ["node", "type"]
|
|
341
|
+
and isinstance(body.values, list)
|
|
342
|
+
# All values must be node references
|
|
343
|
+
and len(node_references := [ref for value in body.values if (ref := self._try_get_node_reference(value))])
|
|
344
|
+
== len(body.values)
|
|
345
|
+
):
|
|
346
|
+
return "nodeType", [self._create_node_entity(node) for node in node_references]
|
|
347
|
+
elif (
|
|
348
|
+
isinstance(body, HasDataFilter)
|
|
349
|
+
and
|
|
350
|
+
# All data must be container references, a single view reference makes it a raw filter
|
|
351
|
+
len(container_refs := [item for item in body.data if isinstance(item, ContainerReference)])
|
|
352
|
+
== len(body.data)
|
|
353
|
+
):
|
|
354
|
+
return "hasData", [self._create_container_entity(item) for item in container_refs]
|
|
355
|
+
else:
|
|
356
|
+
return None, []
|
|
357
|
+
|
|
358
|
+
@staticmethod
|
|
359
|
+
def _try_get_node_reference(value: Any) -> NodeReference | None:
|
|
360
|
+
try:
|
|
361
|
+
return NodeReference.model_validate(value)
|
|
362
|
+
except ValidationError:
|
|
363
|
+
return None
|
|
364
|
+
|
|
309
365
|
def write_view_properties(self, views: list[ViewRequest], container: ContainerProperties) -> ViewProperties:
|
|
310
366
|
output = ViewProperties()
|
|
311
367
|
for view in views:
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import json
|
|
2
1
|
from collections.abc import Mapping
|
|
3
2
|
from typing import Annotated, Literal, cast, get_args
|
|
4
3
|
|
|
@@ -18,11 +17,6 @@ from traitlets import Any
|
|
|
18
17
|
from cognite.neat._data_model.models.entities import ParsedEntity, parse_entities, parse_entity
|
|
19
18
|
from cognite.neat._utils.text import title_case
|
|
20
19
|
from cognite.neat._utils.useful_types import CellValueType
|
|
21
|
-
from cognite.neat._v0.core._data_model.models.entities import (
|
|
22
|
-
HasDataFilter,
|
|
23
|
-
NodeTypeFilter,
|
|
24
|
-
RawFilter,
|
|
25
|
-
)
|
|
26
20
|
|
|
27
21
|
# This marker is used to identify creator in the description field.
|
|
28
22
|
CREATOR_MARKER = "Creator: "
|
|
@@ -146,30 +140,59 @@ class DMSProperty(TableObj):
|
|
|
146
140
|
return self
|
|
147
141
|
|
|
148
142
|
|
|
143
|
+
class EntityTableFilter(BaseModel):
|
|
144
|
+
"""These are special formats that Neat Table format supports for filters."""
|
|
145
|
+
|
|
146
|
+
type: Literal["hasData", "nodeType"]
|
|
147
|
+
entities: EntityList
|
|
148
|
+
|
|
149
|
+
def __str__(self) -> str:
|
|
150
|
+
entities_str = ",".join(str(entity) for entity in self.entities)
|
|
151
|
+
return f"{self.type}({entities_str})"
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class RAWFilterTableFilter(BaseModel):
|
|
155
|
+
"""This is a generic filter that holds raw JSON filter."""
|
|
156
|
+
|
|
157
|
+
type: Literal["rawFilter"] = "rawFilter"
|
|
158
|
+
filter: str
|
|
159
|
+
|
|
160
|
+
def __str__(self) -> str:
|
|
161
|
+
return f"rawFilter({self.filter})"
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _parse_table_filter(v: str) -> dict[str, str] | EntityTableFilter | RAWFilterTableFilter:
|
|
165
|
+
if isinstance(v, EntityTableFilter | RAWFilterTableFilter):
|
|
166
|
+
return v
|
|
167
|
+
filter_configs = {
|
|
168
|
+
"hasdata(": ("hasData", "entities"),
|
|
169
|
+
"nodetype(": ("nodeType", "entities"),
|
|
170
|
+
"rawfilter(": ("rawFilter", "filter"),
|
|
171
|
+
}
|
|
172
|
+
v_lowered = v.casefold()
|
|
173
|
+
for prefix, (filter_type, field_name) in filter_configs.items():
|
|
174
|
+
if v_lowered.startswith(prefix) and v_lowered.endswith(")"):
|
|
175
|
+
return {"type": filter_type, field_name: v[len(prefix) : -1]}
|
|
176
|
+
# Fallback to raw filter with the whole string
|
|
177
|
+
return {"type": "rawFilter", "filter": v}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
TableViewFilter = Annotated[
|
|
181
|
+
EntityTableFilter | RAWFilterTableFilter,
|
|
182
|
+
Field(discriminator="type"),
|
|
183
|
+
BeforeValidator(_parse_table_filter, str),
|
|
184
|
+
PlainSerializer(func=str),
|
|
185
|
+
]
|
|
186
|
+
|
|
187
|
+
|
|
149
188
|
class DMSView(TableObj):
|
|
150
189
|
view: Entity
|
|
151
190
|
name: str | None = None
|
|
152
191
|
description: str | None = None
|
|
153
192
|
implements: EntityList | None = None
|
|
154
|
-
filter:
|
|
193
|
+
filter: TableViewFilter | None = None
|
|
155
194
|
in_model: bool | None = Field(None, exclude=True, description="Legacy column")
|
|
156
195
|
|
|
157
|
-
@field_validator("filter", mode="after")
|
|
158
|
-
def _legacy_filter(cls, value: str | None) -> str | None:
|
|
159
|
-
if value is None:
|
|
160
|
-
return value
|
|
161
|
-
|
|
162
|
-
value_lower = value.lower()
|
|
163
|
-
|
|
164
|
-
if value_lower.startswith("hasdata("):
|
|
165
|
-
return json.dumps(HasDataFilter.load(value).as_dms_filter().dump())
|
|
166
|
-
elif value_lower.startswith("nodetype("):
|
|
167
|
-
return json.dumps(NodeTypeFilter.load(value).as_dms_filter().dump())
|
|
168
|
-
elif value_lower.startswith("rawfilter("):
|
|
169
|
-
return json.dumps(RawFilter.load(value).as_dms_filter().dump())
|
|
170
|
-
|
|
171
|
-
return value
|
|
172
|
-
|
|
173
196
|
|
|
174
197
|
class DMSContainer(TableObj):
|
|
175
198
|
container: Entity
|
|
@@ -30,7 +30,19 @@ from cognite.neat._issues import ModelSyntaxError
|
|
|
30
30
|
from cognite.neat._utils.text import humanize_collection
|
|
31
31
|
from cognite.neat._utils.validation import ValidationContext, humanize_validation_error
|
|
32
32
|
|
|
33
|
-
from .data_classes import
|
|
33
|
+
from .data_classes import (
|
|
34
|
+
CREATOR_KEY,
|
|
35
|
+
CREATOR_MARKER,
|
|
36
|
+
DMSContainer,
|
|
37
|
+
DMSEnum,
|
|
38
|
+
DMSNode,
|
|
39
|
+
DMSProperty,
|
|
40
|
+
DMSView,
|
|
41
|
+
EntityTableFilter,
|
|
42
|
+
RAWFilterTableFilter,
|
|
43
|
+
TableDMS,
|
|
44
|
+
TableViewFilter,
|
|
45
|
+
)
|
|
34
46
|
from .source import TableSource
|
|
35
47
|
|
|
36
48
|
T_BaseModel = TypeVar("T_BaseModel", bound=BaseModel)
|
|
@@ -845,19 +857,6 @@ class DMSTableReader:
|
|
|
845
857
|
views_requests: list[ViewRequest] = []
|
|
846
858
|
rows_by_seen: dict[ParsedEntity, list[int]] = defaultdict(list)
|
|
847
859
|
for row_no, view in enumerate(views):
|
|
848
|
-
filter_dict: dict[str, Any] | None = None
|
|
849
|
-
if view.filter is not None:
|
|
850
|
-
try:
|
|
851
|
-
filter_dict = json.loads(view.filter)
|
|
852
|
-
except ValueError as e:
|
|
853
|
-
self.errors.append(
|
|
854
|
-
ModelSyntaxError(
|
|
855
|
-
message=(
|
|
856
|
-
f"In {self.source.location((self.Sheets.views, row_no, self.ViewColumns.filter))} "
|
|
857
|
-
f"must be valid json. Got error {e!s}"
|
|
858
|
-
)
|
|
859
|
-
)
|
|
860
|
-
)
|
|
861
860
|
view_request = self._validate_obj(
|
|
862
861
|
ViewRequest,
|
|
863
862
|
dict(
|
|
@@ -865,7 +864,7 @@ class DMSTableReader:
|
|
|
865
864
|
name=view.name,
|
|
866
865
|
description=view.description,
|
|
867
866
|
implements=[self._create_view_ref(impl) for impl in view.implements] if view.implements else None,
|
|
868
|
-
filter=
|
|
867
|
+
filter=self._create_filter_dict(view.filter, row_no) if view.filter else None,
|
|
869
868
|
properties=properties.get(view.view, {}),
|
|
870
869
|
),
|
|
871
870
|
(self.Sheets.views, row_no),
|
|
@@ -891,6 +890,46 @@ class DMSTableReader:
|
|
|
891
890
|
)
|
|
892
891
|
return views_requests, set(rows_by_seen.keys())
|
|
893
892
|
|
|
893
|
+
def _create_filter_dict(self, filter: TableViewFilter, row_no: int) -> dict[str, Any] | None:
|
|
894
|
+
if isinstance(filter, RAWFilterTableFilter):
|
|
895
|
+
try:
|
|
896
|
+
return json.loads(filter.filter)
|
|
897
|
+
except ValueError as e:
|
|
898
|
+
self.errors.append(
|
|
899
|
+
ModelSyntaxError(
|
|
900
|
+
message=(
|
|
901
|
+
f"In {self.source.location((self.Sheets.views, row_no, self.ViewColumns.filter))} "
|
|
902
|
+
f"must be valid json. Got error {e!s}"
|
|
903
|
+
)
|
|
904
|
+
)
|
|
905
|
+
)
|
|
906
|
+
return None
|
|
907
|
+
elif isinstance(filter, EntityTableFilter):
|
|
908
|
+
return self._create_entity_filter_dict(filter)
|
|
909
|
+
else:
|
|
910
|
+
# This is unreachable due to validation of the TableViewFilter model.
|
|
911
|
+
raise RuntimeError(f"Unknown filter type {filter.__class__.__name__}")
|
|
912
|
+
|
|
913
|
+
def _create_entity_filter_dict(self, filter: EntityTableFilter) -> dict[str, Any]:
|
|
914
|
+
"""Creates the filter dictionary from an EntityTableFilter."""
|
|
915
|
+
if filter.type == "hasData":
|
|
916
|
+
return {
|
|
917
|
+
"hasData": [{**self._create_container_ref(entity), "type": "container"} for entity in filter.entities]
|
|
918
|
+
}
|
|
919
|
+
elif filter.type == "nodeType":
|
|
920
|
+
if len(filter.entities) == 1:
|
|
921
|
+
return {"equals": {"property": ["node", "type"], "value": self._create_node_ref(filter.entities[0])}}
|
|
922
|
+
else:
|
|
923
|
+
return {
|
|
924
|
+
"in": {
|
|
925
|
+
"property": ["node", "type"],
|
|
926
|
+
"values": [self._create_node_ref(entity) for entity in filter.entities],
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
else:
|
|
930
|
+
# This is unreachable due to validation of the EntityTableFilter model.
|
|
931
|
+
raise RuntimeError(f"Unknown filter type {filter.__class__.__name__}")
|
|
932
|
+
|
|
894
933
|
def read_data_model(self, tables: TableDMS, valid_view_entities: set[ParsedEntity]) -> DataModelRequest:
|
|
895
934
|
data: dict[str, Any] = {
|
|
896
935
|
**{meta.key: meta.value for meta in tables.metadata},
|
|
@@ -2,9 +2,9 @@ from collections import Counter
|
|
|
2
2
|
|
|
3
3
|
from pydantic import Field, ValidationInfo, field_validator
|
|
4
4
|
|
|
5
|
+
from cognite.neat._data_model.models.entities import ConceptEntity
|
|
5
6
|
from cognite.neat._data_model.models.entities._constants import PREFIX_PATTERN, SUFFIX_PATTERN, VERSION_PATTERN
|
|
6
7
|
from cognite.neat._utils.text import humanize_collection
|
|
7
|
-
from cognite.neat._v0.core._data_model.models.entities._single_value import ConceptEntity
|
|
8
8
|
|
|
9
9
|
from ._base import ResourceMetadata
|
|
10
10
|
from ._concept import Concept
|
|
@@ -3,7 +3,7 @@ from abc import ABC
|
|
|
3
3
|
from pydantic import Field, field_validator
|
|
4
4
|
|
|
5
5
|
from cognite.neat._data_model.models.dms._references import SpaceReference
|
|
6
|
-
from cognite.neat.
|
|
6
|
+
from cognite.neat._utils.text import humanize_collection
|
|
7
7
|
|
|
8
8
|
from ._base import APIResource, Resource, WriteableResource
|
|
9
9
|
from ._constants import FORBIDDEN_SPACES, SPACE_FORMAT_PATTERN
|
cognite/neat/_exceptions.py
CHANGED
|
@@ -54,3 +54,15 @@ class UserInputError(NeatException):
|
|
|
54
54
|
|
|
55
55
|
def __str__(self) -> str:
|
|
56
56
|
return f"User input error: {self.message}"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class NeatImportError(NeatException, ImportError):
|
|
60
|
+
def __init__(self, module: str, neat_extra: str, functionality: str = "functionality") -> None:
|
|
61
|
+
message = (
|
|
62
|
+
f"The {functionality} requires {module}. You can include it in your neat "
|
|
63
|
+
f'installation with `pip install "cognite-neat[{neat_extra}]"`.'
|
|
64
|
+
)
|
|
65
|
+
super().__init__(message)
|
|
66
|
+
|
|
67
|
+
def __str__(self) -> str:
|
|
68
|
+
return self.args[0]
|
cognite/neat/_store/_store.py
CHANGED
|
@@ -13,7 +13,6 @@ from cognite.neat._data_model.exporters import DMSExporter, DMSFileExporter
|
|
|
13
13
|
from cognite.neat._data_model.exporters._api_exporter import DMSAPIExporter
|
|
14
14
|
from cognite.neat._data_model.exporters._table_exporter.exporter import DMSTableExporter
|
|
15
15
|
from cognite.neat._data_model.importers import DMSImporter, DMSTableImporter
|
|
16
|
-
from cognite.neat._data_model.importers._api_importer import DMSAPIImporter
|
|
17
16
|
from cognite.neat._data_model.models.dms import RequestSchema as PhysicalDataModel
|
|
18
17
|
from cognite.neat._data_model.models.dms._limits import SchemaLimits
|
|
19
18
|
from cognite.neat._exceptions import DataModelImportException
|
|
@@ -108,7 +107,7 @@ class NeatStore:
|
|
|
108
107
|
raise RuntimeError("No successful physical data model read found in provenance.")
|
|
109
108
|
|
|
110
109
|
# We do not want to modify the data model for API representations
|
|
111
|
-
if not
|
|
110
|
+
if not isinstance(writer, DMSTableExporter):
|
|
112
111
|
return self.physical_data_model[-1]
|
|
113
112
|
|
|
114
113
|
# This will handle data model that are partially and require to be converted to
|
cognite/neat/_utils/auxiliary.py
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import importlib
|
|
1
2
|
import inspect
|
|
2
3
|
from abc import ABC
|
|
4
|
+
from types import ModuleType
|
|
3
5
|
from typing import TypeVar
|
|
4
6
|
|
|
5
7
|
from cognite.neat import _version
|
|
8
|
+
from cognite.neat._exceptions import NeatImportError
|
|
6
9
|
|
|
7
10
|
|
|
8
11
|
def get_current_neat_version() -> str:
|
|
@@ -37,3 +40,10 @@ def get_concrete_subclasses(base_cls: type[T_Cls], exclude_direct_abc_inheritanc
|
|
|
37
40
|
seen.add(subclass)
|
|
38
41
|
to_check.append(subclass)
|
|
39
42
|
return subclasses
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def local_import(module: str, extra: str) -> ModuleType:
|
|
46
|
+
try:
|
|
47
|
+
return importlib.import_module(module)
|
|
48
|
+
except ImportError as e:
|
|
49
|
+
raise NeatImportError(module.split(".")[0], extra) from e
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def get_repo_root() -> Path:
|
|
6
|
+
"""Get the root path of the git repository.
|
|
7
|
+
|
|
8
|
+
Raises:
|
|
9
|
+
RuntimeError: If git is not installed or the current directory is not in a git repository
|
|
10
|
+
|
|
11
|
+
"""
|
|
12
|
+
try:
|
|
13
|
+
result = subprocess.run("git rev-parse --show-toplevel".split(), stdout=subprocess.PIPE)
|
|
14
|
+
except FileNotFoundError as e:
|
|
15
|
+
raise RuntimeError("Git is not installed or not found in PATH") from e
|
|
16
|
+
output = result.stdout.decode().strip()
|
|
17
|
+
if not output:
|
|
18
|
+
raise RuntimeError("Not in a git repository")
|
|
19
|
+
return Path(output)
|
cognite/neat/_version.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
__version__ = "1.0.
|
|
1
|
+
__version__ = "1.0.21"
|
|
2
2
|
__engine__ = "^2.0.4"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cognite-neat
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.21
|
|
4
4
|
Summary: Knowledge graph transformation
|
|
5
5
|
Author: Nikola Vasiljevic, Anders Albert
|
|
6
6
|
Author-email: Nikola Vasiljevic <nikola.vasiljevic@cognite.com>, Anders Albert <anders.albert@cognite.com>
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
cognite/neat/__init__.py,sha256=4RJ6p29cDU_VwQ3sVsgiFdb817BKqKASp-lIgQeD6BI,300
|
|
2
|
-
cognite/neat/_client/__init__.py,sha256=
|
|
2
|
+
cognite/neat/_client/__init__.py,sha256=DIHMeggZ81rVJwO97E5PVP8AwVAhhLpjBQu7Ns3_xdc,178
|
|
3
3
|
cognite/neat/_client/api.py,sha256=nbxCdWBXcTVM6MrQeT_VpB6ehfoI544JHPFq-ejQKCY,292
|
|
4
4
|
cognite/neat/_client/client.py,sha256=h0HELAHiBFxMNInkDu4AzbgfEIXqeM0BqqnMBmXjgi0,903
|
|
5
5
|
cognite/neat/_client/config.py,sha256=eIIdWaA13yncRP6X7vTYsTpmXmVcmkhZPv5oPnLUEVc,1484
|
|
6
6
|
cognite/neat/_client/containers_api.py,sha256=7bVIlL5PwoAG5Bks1ortW_bCG8iTkFqFVyL05pdJ3Pw,5176
|
|
7
7
|
cognite/neat/_client/data_classes.py,sha256=HYPsrAJGVCUmlWTSIxJgAnIHAOzcyDveMM6Z-cuA92M,1404
|
|
8
8
|
cognite/neat/_client/data_model_api.py,sha256=ogVHOabQ3HTqWaaoiGClmbtYdP-pl6DPN2zmPdH5LWY,4253
|
|
9
|
+
cognite/neat/_client/init/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
cognite/neat/_client/init/credentials.py,sha256=95JZFo-LoZO5CAWS18FplrpDvd6TRgG2SvBH0cAEug4,2751
|
|
11
|
+
cognite/neat/_client/init/env_vars.py,sha256=t0zf63TYA3jP_isFiV3rPG81AJ2v_1ULyRthNMKc15Q,4916
|
|
12
|
+
cognite/neat/_client/init/main.py,sha256=q9NA5WCXrtxF2HLAfXOu5UrTH9Ou6qlRoVI9XDtTbZQ,2067
|
|
9
13
|
cognite/neat/_client/spaces_api.py,sha256=xHtSMt_2k2YwZ5_8kH2dfa7fWxQQrky7wra4Ar2jwqs,4111
|
|
10
14
|
cognite/neat/_client/statistics_api.py,sha256=HcYb2nNC9M_iaI1xyjjLn2Cz1tcyu7BJeaqVps79tg4,773
|
|
11
15
|
cognite/neat/_client/views_api.py,sha256=Qzk_wiLtaWszxCQFDBoWCH1yDc4GOEJsVOcL061rcK0,5639
|
|
@@ -13,7 +17,7 @@ cognite/neat/_config.py,sha256=ZvCkcaRVAvH4-ClvinoWaLWhRJpRByqdvncGFsf5gLk,9886
|
|
|
13
17
|
cognite/neat/_data_model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
18
|
cognite/neat/_data_model/_analysis.py,sha256=lPiXF0td4y5TudrR1KPH5OUZ_YNBz8tO6cLg3RnJwEg,22413
|
|
15
19
|
cognite/neat/_data_model/_constants.py,sha256=E2axzdYjsIy7lTHsjW91wsv6r-pUwko8g6K8C_oRnxk,1707
|
|
16
|
-
cognite/neat/_data_model/_identifiers.py,sha256=
|
|
20
|
+
cognite/neat/_data_model/_identifiers.py,sha256=lDLvMvYDgRNFgk5GmxWzOUunG7M3synAciNjzJI0m_o,1913
|
|
17
21
|
cognite/neat/_data_model/_shared.py,sha256=H0gFqa8tKFNWuvdat5jL6OwySjCw3aQkLPY3wtb9Wrw,1302
|
|
18
22
|
cognite/neat/_data_model/_snapshot.py,sha256=JBaKmL0Tmprz59SZ1JeB49BPMB8Hqa-OAOt0Bai8cw4,6305
|
|
19
23
|
cognite/neat/_data_model/deployer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -30,20 +34,20 @@ cognite/neat/_data_model/exporters/_base.py,sha256=rG_qAU5i5Hh5hUMep2UmDFFZID4x3
|
|
|
30
34
|
cognite/neat/_data_model/exporters/_table_exporter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
35
|
cognite/neat/_data_model/exporters/_table_exporter/exporter.py,sha256=4BPu_Chtjh1EyOaKbThXYohsqllVOkCbSoNekNZuBXc,5159
|
|
32
36
|
cognite/neat/_data_model/exporters/_table_exporter/workbook.py,sha256=1Afk1WqeNe9tiNeSAm0HrF8jTQ1kTbIv1D9hMztKwO8,18482
|
|
33
|
-
cognite/neat/_data_model/exporters/_table_exporter/writer.py,sha256=
|
|
37
|
+
cognite/neat/_data_model/exporters/_table_exporter/writer.py,sha256=k1gPrI8OdS75x3ncLn27Z-wnWgkOJ_eiCFnfp-rgdyY,21748
|
|
34
38
|
cognite/neat/_data_model/importers/__init__.py,sha256=dHnKnC_AXk42z6wzEHK15dxIOh8xSEkuUf_AFRZls0E,193
|
|
35
39
|
cognite/neat/_data_model/importers/_api_importer.py,sha256=H8Ow3Tt7utuAuBhC6s7yWvhGqunHAtE0r0XRsVAr6IE,7280
|
|
36
40
|
cognite/neat/_data_model/importers/_base.py,sha256=NRB0FcEBj4GaethU68nRffBfTedBBA866A3zfJNfmiQ,433
|
|
37
41
|
cognite/neat/_data_model/importers/_table_importer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
|
-
cognite/neat/_data_model/importers/_table_importer/data_classes.py,sha256=
|
|
42
|
+
cognite/neat/_data_model/importers/_table_importer/data_classes.py,sha256=wnFMrzLRWAsPyMBMZ7W02JLMtjMJRG0VGsXDrj_Ww5Y,11487
|
|
39
43
|
cognite/neat/_data_model/importers/_table_importer/importer.py,sha256=lQ4_Gpv0haEwQEDYZJaxtR9dL6Y0ys9jbjFfWxH6s2o,8870
|
|
40
|
-
cognite/neat/_data_model/importers/_table_importer/reader.py,sha256=
|
|
44
|
+
cognite/neat/_data_model/importers/_table_importer/reader.py,sha256=5NkUvem9sR3WUM1vtfm6duu76oD3vQ0gi6UuBOcr3bo,50933
|
|
41
45
|
cognite/neat/_data_model/importers/_table_importer/source.py,sha256=h7u5ur5oetmvBs3wgj7Ody5uPF21QwxeAceoIhJ5qzo,3300
|
|
42
46
|
cognite/neat/_data_model/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
43
47
|
cognite/neat/_data_model/models/conceptual/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
44
48
|
cognite/neat/_data_model/models/conceptual/_base.py,sha256=SFkoBJDM51pqew_isHFJoB20OgfofpwVRnTrg-rKkNY,710
|
|
45
49
|
cognite/neat/_data_model/models/conceptual/_concept.py,sha256=0Pk4W2TJ_Y0Z7oPHpzely1kPXrAkmkyqw6a0n3il6LY,2248
|
|
46
|
-
cognite/neat/_data_model/models/conceptual/_data_model.py,sha256=
|
|
50
|
+
cognite/neat/_data_model/models/conceptual/_data_model.py,sha256=zvJZi0OqOFMviwY84Am3Oz_RmF1g3tOzANFHlrldBuU,1673
|
|
47
51
|
cognite/neat/_data_model/models/conceptual/_properties.py,sha256=CpF37vJYBTLT4DH4ZOu2U-JyWtkb_27V8fw52qiaE_k,4007
|
|
48
52
|
cognite/neat/_data_model/models/conceptual/_property.py,sha256=blSZQxX52zaILAtjUkldPzPeysz7wnG-UGSNU5tacI8,4138
|
|
49
53
|
cognite/neat/_data_model/models/dms/__init__.py,sha256=CW5NPMRrMyY4iyZgqYb8eZkRuwbbXUDSVNMWep3zEPI,5326
|
|
@@ -58,7 +62,7 @@ cognite/neat/_data_model/models/dms/_indexes.py,sha256=ZtXe8ABuRcsAwRIZ9FCanS3uw
|
|
|
58
62
|
cognite/neat/_data_model/models/dms/_limits.py,sha256=x_X7T50SkwPNo_aHTGCr35hDXI8FRdZLYIB9HpFqnIk,3520
|
|
59
63
|
cognite/neat/_data_model/models/dms/_references.py,sha256=Mx_nxfvOrvAx7nvebhhbFw6eRm3nHqeFW5P5AqADUlM,3890
|
|
60
64
|
cognite/neat/_data_model/models/dms/_schema.py,sha256=2JFLcm52smzPdtZ69Lf02UbYAD8I_hpRbI7ZAzdxJJs,641
|
|
61
|
-
cognite/neat/_data_model/models/dms/_space.py,sha256=
|
|
65
|
+
cognite/neat/_data_model/models/dms/_space.py,sha256=mj6gID4vcAGsHNtgfXm4_4FMOQbUOkMd3HaYEdy07XM,1895
|
|
62
66
|
cognite/neat/_data_model/models/dms/_types.py,sha256=5-cgC53AG186OZUqkltv7pMjcGNLuH7Etbn8IUcgk1c,447
|
|
63
67
|
cognite/neat/_data_model/models/dms/_view_filter.py,sha256=XxMffUH5kYtcg0xHgyUsY4nueWRoJu2CoJtOU7wbH4Y,11274
|
|
64
68
|
cognite/neat/_data_model/models/dms/_view_property.py,sha256=nJBPmw4KzJOdaQmvRfCE3A4FL-E13OsNUEufI64vLKo,9271
|
|
@@ -67,7 +71,7 @@ cognite/neat/_data_model/models/entities/__init__.py,sha256=7dDyES7fYl9LEREal59F
|
|
|
67
71
|
cognite/neat/_data_model/models/entities/_base.py,sha256=PaNrD29iwxuqTpRWbmESMTxRhhKXmRyDF_cLZEC69dg,3927
|
|
68
72
|
cognite/neat/_data_model/models/entities/_constants.py,sha256=EK9Bus8UgFgxK5cVFMTAqWSl6aWkDe7d59hpUmlHlBs,517
|
|
69
73
|
cognite/neat/_data_model/models/entities/_data_types.py,sha256=DfdEWGek7gODro-_0SiiInhPGwul4zn-ASACQfn8HUY,2838
|
|
70
|
-
cognite/neat/_data_model/models/entities/_identifiers.py,sha256=
|
|
74
|
+
cognite/neat/_data_model/models/entities/_identifiers.py,sha256=a7ojJKY1ErZgUANHscEwkctX4RJ7bWEEWOQt5g5Tsdk,1915
|
|
71
75
|
cognite/neat/_data_model/models/entities/_parser.py,sha256=zef_pSDZYMZrJl4IKreFDR577KutfhtN1xpH3Ayjt2o,7669
|
|
72
76
|
cognite/neat/_data_model/validation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
73
77
|
cognite/neat/_data_model/validation/dms/__init__.py,sha256=kKD18-Bg_G-w11Cs7Wv_TKV0C_q62Pm2RKLpOz27ar4,2642
|
|
@@ -79,7 +83,7 @@ cognite/neat/_data_model/validation/dms/_containers.py,sha256=5Lka1Cg-SaP9Ued0ck
|
|
|
79
83
|
cognite/neat/_data_model/validation/dms/_limits.py,sha256=U7z8sN-kAyJsF5hYHPNBBg25Fvz1F8njhzYVSQOIiOU,14779
|
|
80
84
|
cognite/neat/_data_model/validation/dms/_orchestrator.py,sha256=qiuUSUmNhekFyBARUUO2yhG-X9AeU_LL49UrJ65JXFA,2964
|
|
81
85
|
cognite/neat/_data_model/validation/dms/_views.py,sha256=Q0x7jdG69-AVc93VrwdZ1_rFHpq-I-OG98puM4lcweE,5068
|
|
82
|
-
cognite/neat/_exceptions.py,sha256=
|
|
86
|
+
cognite/neat/_exceptions.py,sha256=mO19TEecZYDNqSvzuc6JmCLFQ70eniT1-Gb0AEbgbzE,2090
|
|
83
87
|
cognite/neat/_issues.py,sha256=wH1mnkrpBsHUkQMGUHFLUIQWQlfJ_qMfdF7q0d9wNhY,1871
|
|
84
88
|
cognite/neat/_session/__init__.py,sha256=owqW5Mml2DSZx1AvPvwNRTBngfhBNrQ6EH-7CKL7Jp0,61
|
|
85
89
|
cognite/neat/_session/_html/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -113,16 +117,17 @@ cognite/neat/_state_machine/_base.py,sha256=-ZpeAhM6l6N6W70dET25tAzOxaaK5aa474ea
|
|
|
113
117
|
cognite/neat/_state_machine/_states.py,sha256=nmj4SmunpDYcBsNx8A284xnXGS43wuUuWpMMORha2DE,1170
|
|
114
118
|
cognite/neat/_store/__init__.py,sha256=TvM9CcFbtOSrxydPAuJi6Bv_iiGard1Mxfx42ZFoTl0,55
|
|
115
119
|
cognite/neat/_store/_provenance.py,sha256=1zzRDWjR9twZu2jVyIG3UdYdIXtQKJ7uF8a0hV7LEuA,3368
|
|
116
|
-
cognite/neat/_store/_store.py,sha256=
|
|
120
|
+
cognite/neat/_store/_store.py,sha256=jtJPBQ8PBG0UlgzSJJpzOIRkC2Np3fHNtV4omRC6H5A,9629
|
|
117
121
|
cognite/neat/_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
118
122
|
cognite/neat/_utils/_reader.py,sha256=9dXrODNNqWU0Gx1zXjRTOiiByFuDZlpQkQEzx3HAxYQ,5390
|
|
119
|
-
cognite/neat/_utils/auxiliary.py,sha256=
|
|
123
|
+
cognite/neat/_utils/auxiliary.py,sha256=YQMpqCxccex_slmLYrR5icVX9aeLbD793ou7IrbNTFs,1654
|
|
120
124
|
cognite/neat/_utils/collection.py,sha256=BIwRrFbUXNPvHhEVujLHgVoDJXzdPEMScrbSBhyCibk,446
|
|
121
125
|
cognite/neat/_utils/http_client/__init__.py,sha256=qaCLLLhi7H3b_cmbknX0S66KILT7JSKX1YSgZjNdd1U,786
|
|
122
126
|
cognite/neat/_utils/http_client/_client.py,sha256=TO9C77LcsqX0R3Fu-mP560nnV6rP5oRXki9kxRYtBlg,9658
|
|
123
127
|
cognite/neat/_utils/http_client/_config.py,sha256=C8IF1JoijmVMjA_FEMgAkiD1buEV1cY5Og3t-Ecyfmk,756
|
|
124
128
|
cognite/neat/_utils/http_client/_data_classes.py,sha256=McyCQZUcwkbOXdBmc99DdNsO6mQz8dNVsepDvXmaINA,10138
|
|
125
129
|
cognite/neat/_utils/http_client/_tracker.py,sha256=EBBnd-JZ7nc_jYNFJokCHN2UZ9sx0McFLZvlceUYYic,1215
|
|
130
|
+
cognite/neat/_utils/repo.py,sha256=nSpT9_XNbbExMip4LyNL0b89aAurHVx003q_Wky-qww,603
|
|
126
131
|
cognite/neat/_utils/text.py,sha256=-ujNaG_hLkdurKsUmZB9ZI_kJkddlCKEf8g-g_XCk10,2010
|
|
127
132
|
cognite/neat/_utils/useful_types.py,sha256=BwTjcWnpxnxN8rWXuYXMgU55O_YjVteMtYK0y25OmH0,1260
|
|
128
133
|
cognite/neat/_utils/validation.py,sha256=U422V0TY5KujFJFyfhRLONVj5A4AcCWgqIKVK6BUm7M,6938
|
|
@@ -316,9 +321,9 @@ cognite/neat/_v0/session/_template.py,sha256=BNcvrW5y7LWzRM1XFxZkfR1Nc7e8UgjBClH
|
|
|
316
321
|
cognite/neat/_v0/session/_to.py,sha256=AnsRSDDdfFyYwSgi0Z-904X7WdLtPfLlR0x1xsu_jAo,19447
|
|
317
322
|
cognite/neat/_v0/session/_wizard.py,sha256=baPJgXAAF3d1bn4nbIzon1gWfJOeS5T43UXRDJEnD3c,1490
|
|
318
323
|
cognite/neat/_v0/session/exceptions.py,sha256=jv52D-SjxGfgqaHR8vnpzo0SOJETIuwbyffSWAxSDJw,3495
|
|
319
|
-
cognite/neat/_version.py,sha256=
|
|
324
|
+
cognite/neat/_version.py,sha256=0Bv-euqjHzX0kdwCv6YRDD5BAUEFBhkf7f6PaEKGdd0,45
|
|
320
325
|
cognite/neat/legacy.py,sha256=eI2ecxOV8ilGHyLZlN54ve_abtoK34oXognkFv3yvF0,219
|
|
321
326
|
cognite/neat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
322
|
-
cognite_neat-1.0.
|
|
323
|
-
cognite_neat-1.0.
|
|
324
|
-
cognite_neat-1.0.
|
|
327
|
+
cognite_neat-1.0.21.dist-info/WHEEL,sha256=XjEbIc5-wIORjWaafhI6vBtlxDBp7S9KiujWF1EM7Ak,79
|
|
328
|
+
cognite_neat-1.0.21.dist-info/METADATA,sha256=QpA63SYiPB_pttmYhdDpmx7AbJl98Sd8V-wIbjoWCwI,6689
|
|
329
|
+
cognite_neat-1.0.21.dist-info/RECORD,,
|