cognite-toolkit 0.6.89__py3-none-any.whl → 0.6.91__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-toolkit might be problematic. Click here for more details.
- cognite_toolkit/_cdf_tk/client/_toolkit_client.py +5 -0
- cognite_toolkit/_cdf_tk/client/api/infield.py +156 -0
- cognite_toolkit/_cdf_tk/client/data_classes/api_classes.py +17 -0
- cognite_toolkit/_cdf_tk/client/data_classes/base.py +63 -0
- cognite_toolkit/_cdf_tk/client/data_classes/infield.py +102 -0
- cognite_toolkit/_cdf_tk/client/data_classes/instance_api.py +157 -0
- cognite_toolkit/_cdf_tk/client/testing.py +3 -0
- cognite_toolkit/_cdf_tk/commands/_utils.py +1 -24
- cognite_toolkit/_cdf_tk/commands/build_cmd.py +1 -1
- cognite_toolkit/_cdf_tk/commands/clean.py +11 -5
- cognite_toolkit/_cdf_tk/commands/deploy.py +14 -10
- cognite_toolkit/_cdf_tk/commands/pull.py +19 -13
- cognite_toolkit/_cdf_tk/cruds/__init__.py +3 -0
- cognite_toolkit/_cdf_tk/cruds/_base_cruds.py +28 -25
- cognite_toolkit/_cdf_tk/cruds/_data_cruds.py +10 -7
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/__init__.py +2 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/fieldops.py +111 -2
- cognite_toolkit/_cdf_tk/cruds/_worker.py +24 -20
- cognite_toolkit/_cdf_tk/data_classes/_build_variables.py +120 -14
- cognite_toolkit/_cdf_tk/data_classes/_built_resources.py +1 -1
- cognite_toolkit/_cdf_tk/protocols.py +97 -0
- cognite_toolkit/_cdf_tk/resource_classes/__init__.py +2 -0
- cognite_toolkit/_cdf_tk/resource_classes/agent.py +1 -0
- cognite_toolkit/_cdf_tk/resource_classes/infield_cdmv1.py +94 -0
- cognite_toolkit/_cdf_tk/utils/text.py +23 -0
- cognite_toolkit/_repo_files/GitHub/.github/workflows/deploy.yaml +1 -1
- cognite_toolkit/_repo_files/GitHub/.github/workflows/dry-run.yaml +1 -1
- cognite_toolkit/_resources/cdf.toml +1 -1
- cognite_toolkit/_version.py +1 -1
- {cognite_toolkit-0.6.89.dist-info → cognite_toolkit-0.6.91.dist-info}/METADATA +1 -1
- {cognite_toolkit-0.6.89.dist-info → cognite_toolkit-0.6.91.dist-info}/RECORD +34 -27
- {cognite_toolkit-0.6.89.dist-info → cognite_toolkit-0.6.91.dist-info}/WHEEL +0 -0
- {cognite_toolkit-0.6.89.dist-info → cognite_toolkit-0.6.91.dist-info}/entry_points.txt +0 -0
- {cognite_toolkit-0.6.89.dist-info → cognite_toolkit-0.6.91.dist-info}/licenses/LICENSE +0 -0
|
@@ -8,11 +8,11 @@ from functools import cached_property
|
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
from typing import Any, Literal, SupportsIndex, overload
|
|
10
10
|
|
|
11
|
+
from cognite_toolkit._cdf_tk.cruds._resource_cruds.transformation import TransformationCRUD
|
|
12
|
+
from cognite_toolkit._cdf_tk.data_classes._module_directories import ModuleLocation
|
|
11
13
|
from cognite_toolkit._cdf_tk.exceptions import ToolkitValueError
|
|
12
14
|
from cognite_toolkit._cdf_tk.feature_flags import Flags
|
|
13
15
|
|
|
14
|
-
from ._module_directories import ModuleLocation
|
|
15
|
-
|
|
16
16
|
if sys.version_info >= (3, 11):
|
|
17
17
|
from typing import Self
|
|
18
18
|
else:
|
|
@@ -161,16 +161,19 @@ class BuildVariables(tuple, Sequence[BuildVariable]):
|
|
|
161
161
|
]
|
|
162
162
|
|
|
163
163
|
@overload
|
|
164
|
-
def replace(self, content: str,
|
|
164
|
+
def replace(self, content: str, file_path: Path | None = None, use_placeholder: Literal[False] = False) -> str: ...
|
|
165
165
|
|
|
166
166
|
@overload
|
|
167
167
|
def replace(
|
|
168
|
-
self, content: str,
|
|
168
|
+
self, content: str, file_path: Path | None = None, use_placeholder: Literal[True] = True
|
|
169
169
|
) -> tuple[str, dict[str, BuildVariable]]: ...
|
|
170
170
|
|
|
171
171
|
def replace(
|
|
172
|
-
self, content: str,
|
|
172
|
+
self, content: str, file_path: Path | None = None, use_placeholder: bool = False
|
|
173
173
|
) -> str | tuple[str, dict[str, BuildVariable]]:
|
|
174
|
+
# Extract file suffix from path, default to .yaml if not provided
|
|
175
|
+
file_suffix = file_path.suffix if file_path and file_path.suffix else ".yaml"
|
|
176
|
+
|
|
174
177
|
variable_by_placeholder: dict[str, BuildVariable] = {}
|
|
175
178
|
for variable in self:
|
|
176
179
|
if not use_placeholder:
|
|
@@ -180,22 +183,125 @@ class BuildVariables(tuple, Sequence[BuildVariable]):
|
|
|
180
183
|
variable_by_placeholder[replace] = variable
|
|
181
184
|
|
|
182
185
|
_core_pattern = rf"{{{{\s*{variable.key}\s*}}}}"
|
|
183
|
-
if file_suffix
|
|
184
|
-
#
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
186
|
+
if file_suffix == ".sql":
|
|
187
|
+
# For SQL files, convert lists to SQL-style tuples
|
|
188
|
+
if isinstance(replace, list):
|
|
189
|
+
replace = self._format_list_as_sql_tuple(replace)
|
|
190
|
+
content = re.sub(_core_pattern, str(replace), content)
|
|
191
|
+
elif file_suffix in {".yaml", ".yml", ".json"}:
|
|
192
|
+
# Check if this is a transformation file (ends with Transformation.yaml/yml)
|
|
193
|
+
is_transformation_file = file_path is not None and f".{TransformationCRUD.kind}." in file_path.name
|
|
194
|
+
# Check if variable is within a query field (SQL context)
|
|
195
|
+
is_in_query_field = self._is_in_query_field(content, variable.key)
|
|
196
|
+
|
|
197
|
+
# For lists in query fields, use SQL-style tuples
|
|
198
|
+
# For transformation files, ensure SQL conversion is applied to query property variables
|
|
199
|
+
if is_transformation_file and is_in_query_field and isinstance(replace, list):
|
|
200
|
+
replace = self._format_list_as_sql_tuple(replace)
|
|
201
|
+
# Use simple pattern for SQL context (no YAML quoting needed)
|
|
202
|
+
content = re.sub(_core_pattern, str(replace), content)
|
|
203
|
+
else:
|
|
204
|
+
# Preserve data types for YAML
|
|
205
|
+
pattern = _core_pattern
|
|
206
|
+
if isinstance(replace, str) and (replace.isdigit() or replace.endswith(":")):
|
|
207
|
+
replace = f'"{replace}"'
|
|
208
|
+
pattern = rf"'{_core_pattern}'|{_core_pattern}|" + rf'"{_core_pattern}"'
|
|
209
|
+
elif replace is None:
|
|
210
|
+
replace = "null"
|
|
211
|
+
content = re.sub(pattern, str(replace), content)
|
|
192
212
|
else:
|
|
213
|
+
# For other file types, use simple string replacement
|
|
193
214
|
content = re.sub(_core_pattern, str(replace), content)
|
|
194
215
|
if use_placeholder:
|
|
195
216
|
return content, variable_by_placeholder
|
|
196
217
|
else:
|
|
197
218
|
return content
|
|
198
219
|
|
|
220
|
+
@staticmethod
|
|
221
|
+
def _is_transformation_file(file_path: Path) -> bool:
|
|
222
|
+
"""Check if the file path indicates a transformation YAML file.
|
|
223
|
+
|
|
224
|
+
Transformation files are YAML files in the "transformations" folder.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
file_path: The file path to check
|
|
228
|
+
|
|
229
|
+
Returns:
|
|
230
|
+
True if the file is a transformation YAML file
|
|
231
|
+
"""
|
|
232
|
+
# Check if path contains "transformations" folder and ends with .yaml/.yml
|
|
233
|
+
path_str = file_path.as_posix().lower()
|
|
234
|
+
return "transformations" in path_str and file_path.suffix.lower() in {".yaml", ".yml"}
|
|
235
|
+
|
|
236
|
+
@staticmethod
|
|
237
|
+
def _format_list_as_sql_tuple(replace: list[Any]) -> str:
|
|
238
|
+
"""Format a list as a SQL-style tuple string.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
replace: The list to format
|
|
242
|
+
|
|
243
|
+
Returns:
|
|
244
|
+
SQL tuple string, e.g., "('A', 'B', 'C')" or "()" for empty lists
|
|
245
|
+
"""
|
|
246
|
+
if not replace:
|
|
247
|
+
# Empty list becomes empty SQL tuple
|
|
248
|
+
return "()"
|
|
249
|
+
else:
|
|
250
|
+
# Format list as SQL tuple: ('A', 'B', 'C')
|
|
251
|
+
formatted_items = []
|
|
252
|
+
for item in replace:
|
|
253
|
+
if item is None:
|
|
254
|
+
formatted_items.append("NULL")
|
|
255
|
+
elif isinstance(item, str):
|
|
256
|
+
formatted_items.append(f"'{item}'")
|
|
257
|
+
else:
|
|
258
|
+
formatted_items.append(str(item))
|
|
259
|
+
return f"({', '.join(formatted_items)})"
|
|
260
|
+
|
|
261
|
+
@staticmethod
|
|
262
|
+
def _is_in_query_field(content: str, variable_key: str) -> bool:
|
|
263
|
+
"""Check if a variable is within a query field in YAML.
|
|
264
|
+
|
|
265
|
+
Assumes query is a top-level property. This detects various YAML formats:
|
|
266
|
+
- query: >-
|
|
267
|
+
- query: |
|
|
268
|
+
- query: "..."
|
|
269
|
+
- query: ...
|
|
270
|
+
"""
|
|
271
|
+
lines = content.split("\n")
|
|
272
|
+
variable_pattern = rf"{{{{\s*{re.escape(variable_key)}\s*}}}}"
|
|
273
|
+
in_query_field = False
|
|
274
|
+
|
|
275
|
+
for line in lines:
|
|
276
|
+
# Check if this line starts a top-level query field
|
|
277
|
+
query_match = re.match(r"^query\s*:\s*(.*)$", line)
|
|
278
|
+
if query_match:
|
|
279
|
+
in_query_field = True
|
|
280
|
+
query_content_start = query_match.group(1).strip()
|
|
281
|
+
|
|
282
|
+
# Check if variable is on the same line as query: declaration
|
|
283
|
+
if re.search(variable_pattern, line):
|
|
284
|
+
return True
|
|
285
|
+
|
|
286
|
+
# If query content starts on same line (not a block scalar), check it
|
|
287
|
+
if query_content_start and not query_content_start.startswith(("|", ">", "|-", ">-", "|+", ">+")):
|
|
288
|
+
if re.search(variable_pattern, query_content_start):
|
|
289
|
+
return True
|
|
290
|
+
continue
|
|
291
|
+
|
|
292
|
+
# Check if we're still in the query field
|
|
293
|
+
if in_query_field:
|
|
294
|
+
# If we hit another top-level property, we've exited the query field
|
|
295
|
+
if re.match(r"^\w+\s*:", line):
|
|
296
|
+
in_query_field = False
|
|
297
|
+
continue
|
|
298
|
+
|
|
299
|
+
# We're still in the query field, check for variable
|
|
300
|
+
if re.search(variable_pattern, line):
|
|
301
|
+
return True
|
|
302
|
+
|
|
303
|
+
return False
|
|
304
|
+
|
|
199
305
|
# Implemented to get correct type hints
|
|
200
306
|
def __iter__(self) -> Iterator[BuildVariable]:
|
|
201
307
|
return super().__iter__()
|
|
@@ -158,7 +158,7 @@ class BuiltResourceFull(BuiltResource[T_ID]):
|
|
|
158
158
|
def load_resource_dict(
|
|
159
159
|
self, environment_variables: dict[str, str | None], validate: bool = False
|
|
160
160
|
) -> dict[str, Any]:
|
|
161
|
-
content = self.build_variables.replace(safe_read(self.source.path))
|
|
161
|
+
content = self.build_variables.replace(safe_read(self.source.path), self.source.path)
|
|
162
162
|
loader = cast(ResourceCRUD, get_crud(self.resource_dir, self.kind))
|
|
163
163
|
raw = load_yaml_inject_variables(
|
|
164
164
|
content,
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from collections.abc import Collection, Iterator
|
|
3
|
+
from typing import Any, Generic, Protocol, TypeVar
|
|
4
|
+
|
|
5
|
+
from cognite.client import CogniteClient
|
|
6
|
+
|
|
7
|
+
if sys.version_info >= (3, 11):
|
|
8
|
+
from typing import Self
|
|
9
|
+
else:
|
|
10
|
+
from typing_extensions import Self
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ResourceRequestProtocol(Protocol):
|
|
14
|
+
@classmethod
|
|
15
|
+
def _load(cls, data: dict[str, Any]) -> Self: ...
|
|
16
|
+
|
|
17
|
+
def dump(self, camel_case: bool = True) -> dict[str, Any]: ...
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ResourceResponseProtocol(Protocol):
|
|
21
|
+
def as_write(self) -> ResourceRequestProtocol: ...
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
T_ResourceRequest = TypeVar("T_ResourceRequest", bound=ResourceRequestProtocol)
|
|
25
|
+
T_ResourceResponse = TypeVar("T_ResourceResponse", bound=ResourceResponseProtocol)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ResourceRequestListProtocol(Protocol, Generic[T_ResourceRequest]):
|
|
29
|
+
def __init__(self, collection: Collection[T_ResourceRequest]): ...
|
|
30
|
+
|
|
31
|
+
def __getitem__(self, index: int) -> T_ResourceRequest: ...
|
|
32
|
+
|
|
33
|
+
def __setitem__(self, index: int, value: T_ResourceRequest) -> None: ...
|
|
34
|
+
|
|
35
|
+
def __delitem__(self, index: int) -> None: ...
|
|
36
|
+
|
|
37
|
+
def __len__(self) -> int: ...
|
|
38
|
+
|
|
39
|
+
def __iter__(self) -> Iterator[T_ResourceRequest]: ...
|
|
40
|
+
|
|
41
|
+
def __contains__(self, value: object) -> bool: ...
|
|
42
|
+
|
|
43
|
+
def __reversed__(self) -> Iterator[T_ResourceRequest]: ...
|
|
44
|
+
|
|
45
|
+
def insert(self, index: int, value: T_ResourceRequest) -> None: ...
|
|
46
|
+
|
|
47
|
+
def append(self, value: T_ResourceRequest) -> None: ...
|
|
48
|
+
|
|
49
|
+
def extend(self, values: Collection[T_ResourceRequest]) -> None: ...
|
|
50
|
+
|
|
51
|
+
def pop(self, index: int = -1) -> T_ResourceRequest: ...
|
|
52
|
+
|
|
53
|
+
def remove(self, value: T_ResourceRequest) -> None: ...
|
|
54
|
+
|
|
55
|
+
def clear(self) -> None: ...
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def load(cls, data: list[dict[str, Any]], cognite_client: CogniteClient | None = None) -> Self: ...
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class ResourceResponseListProtocol(Protocol, Generic[T_ResourceResponse]):
|
|
62
|
+
def __init__(self, collection: Collection[T_ResourceResponse]): ...
|
|
63
|
+
|
|
64
|
+
def __getitem__(self, index: int) -> T_ResourceResponse: ...
|
|
65
|
+
|
|
66
|
+
def __setitem__(self, index: int, value: T_ResourceResponse) -> None: ...
|
|
67
|
+
|
|
68
|
+
def __delitem__(self, index: int) -> None: ...
|
|
69
|
+
|
|
70
|
+
def __len__(self) -> int: ...
|
|
71
|
+
|
|
72
|
+
def __iter__(self) -> Iterator[T_ResourceResponse]: ...
|
|
73
|
+
|
|
74
|
+
def __contains__(self, value: object) -> bool: ...
|
|
75
|
+
|
|
76
|
+
def __reversed__(self) -> Iterator[T_ResourceResponse]: ...
|
|
77
|
+
|
|
78
|
+
def insert(self, index: int, value: T_ResourceResponse) -> None: ...
|
|
79
|
+
|
|
80
|
+
def append(self, value: T_ResourceResponse) -> None: ...
|
|
81
|
+
|
|
82
|
+
def extend(self, values: Collection[T_ResourceResponse]) -> None: ...
|
|
83
|
+
|
|
84
|
+
def pop(self, index: int = -1) -> T_ResourceResponse: ...
|
|
85
|
+
|
|
86
|
+
def remove(self, value: T_ResourceResponse) -> None: ...
|
|
87
|
+
|
|
88
|
+
def clear(self) -> None: ...
|
|
89
|
+
|
|
90
|
+
def as_write(self) -> ResourceRequestListProtocol: ...
|
|
91
|
+
|
|
92
|
+
@classmethod
|
|
93
|
+
def load(cls, data: list[dict[str, Any]], cognite_client: CogniteClient | None = None) -> Self: ...
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
T_ResourceRequestList = TypeVar("T_ResourceRequestList", bound=ResourceRequestListProtocol)
|
|
97
|
+
T_ResourceResponseList = TypeVar("T_ResourceResponseList", bound=ResourceResponseListProtocol)
|
|
@@ -27,6 +27,7 @@ from .hosted_extractor_destination import HostedExtractorDestinationYAML
|
|
|
27
27
|
from .hosted_extractor_job import HostedExtractorJobYAML
|
|
28
28
|
from .hosted_extractor_mapping import HostedExtractorMappingYAML
|
|
29
29
|
from .hosted_extractor_source import HostedExtractorSourceYAML
|
|
30
|
+
from .infield_cdmv1 import InfieldLocationConfigYAML
|
|
30
31
|
from .infield_v1 import InfieldV1YAML
|
|
31
32
|
from .instance import EdgeYAML, NodeYAML
|
|
32
33
|
from .labels import LabelsYAML
|
|
@@ -74,6 +75,7 @@ __all__ = [
|
|
|
74
75
|
"HostedExtractorJobYAML",
|
|
75
76
|
"HostedExtractorMappingYAML",
|
|
76
77
|
"HostedExtractorSourceYAML",
|
|
78
|
+
"InfieldLocationConfigYAML",
|
|
77
79
|
"InfieldV1YAML",
|
|
78
80
|
"LabelsYAML",
|
|
79
81
|
"LocationYAML",
|
|
@@ -55,3 +55,4 @@ class AgentYAML(ToolkitResource):
|
|
|
55
55
|
"azure/gpt-4o-mini", description="The name of the model to use. Defaults to your CDF project's default model."
|
|
56
56
|
)
|
|
57
57
|
tools: list[AgentTool] | None = Field(None, description="A list of tools available to the agent.", max_length=20)
|
|
58
|
+
runtime_version: str | None = Field(None, description="The runtime version")
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from .base import BaseModelResource, ToolkitResource
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ObservationFeatureToggles(BaseModelResource):
|
|
7
|
+
"""Feature toggles for observations."""
|
|
8
|
+
|
|
9
|
+
is_enabled: bool | None = None
|
|
10
|
+
is_write_back_enabled: bool | None = None
|
|
11
|
+
notifications_endpoint_external_id: str | None = None
|
|
12
|
+
attachments_endpoint_external_id: str | None = None
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class FeatureToggles(BaseModelResource):
|
|
16
|
+
"""Feature toggles for InField location configuration."""
|
|
17
|
+
|
|
18
|
+
three_d: bool | None = None
|
|
19
|
+
trends: bool | None = None
|
|
20
|
+
documents: bool | None = None
|
|
21
|
+
workorders: bool | None = None
|
|
22
|
+
notifications: bool | None = None
|
|
23
|
+
media: bool | None = None
|
|
24
|
+
template_checklist_flow: bool | None = None
|
|
25
|
+
workorder_checklist_flow: bool | None = None
|
|
26
|
+
observations: ObservationFeatureToggles | None = None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class AccessManagement(BaseModelResource):
|
|
30
|
+
"""Access management configuration."""
|
|
31
|
+
|
|
32
|
+
template_admins: list[str] | None = None # list of CDF group external IDs
|
|
33
|
+
checklist_admins: list[str] | None = None # list of CDF group external IDs
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ResourceFilters(BaseModelResource):
|
|
37
|
+
"""Resource filters."""
|
|
38
|
+
|
|
39
|
+
spaces: list[str] | None = None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class RootLocationDataFilters(BaseModelResource):
|
|
43
|
+
"""Data filters for root location."""
|
|
44
|
+
|
|
45
|
+
general: ResourceFilters | None = None
|
|
46
|
+
assets: ResourceFilters | None = None
|
|
47
|
+
files: ResourceFilters | None = None
|
|
48
|
+
timeseries: ResourceFilters | None = None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class DataExplorationConfig(BaseModelResource):
|
|
52
|
+
"""Properties for DataExplorationConfig node.
|
|
53
|
+
|
|
54
|
+
Contains configuration for data exploration features:
|
|
55
|
+
- observations: Observations feature configuration
|
|
56
|
+
- activities: Activities configuration
|
|
57
|
+
- documents: Document configuration
|
|
58
|
+
- notifications: Notifications configuration
|
|
59
|
+
- assets: Asset page configuration
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
space: str | None = None
|
|
63
|
+
external_id: str | None = None
|
|
64
|
+
|
|
65
|
+
observations: dict[str, Any] | None = None # ObservationsConfigFeature
|
|
66
|
+
activities: dict[str, Any] | None = None # ActivitiesConfiguration
|
|
67
|
+
documents: dict[str, Any] | None = None # DocumentConfiguration
|
|
68
|
+
notifications: dict[str, Any] | None = None # NotificationsConfiguration
|
|
69
|
+
assets: dict[str, Any] | None = None # AssetPageConfiguration
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class InfieldLocationConfigYAML(ToolkitResource):
|
|
73
|
+
"""Properties for InFieldLocationConfig node.
|
|
74
|
+
|
|
75
|
+
Currently migrated fields:
|
|
76
|
+
- root_location_external_id: Reference to the LocationFilterDTO external ID
|
|
77
|
+
- feature_toggles: Feature toggles migrated from old configuration
|
|
78
|
+
- rootAsset: Direct relation to the root asset (space and externalId)
|
|
79
|
+
- app_instance_space: Application instance space from appDataInstanceSpace
|
|
80
|
+
- access_management: Template and checklist admin groups (from templateAdmins and checklistAdmins)
|
|
81
|
+
- disciplines: List of disciplines (from disciplines in FeatureConfiguration)
|
|
82
|
+
- data_filters: Data filters for general, assets, files, and timeseries (from dataFilters in old configuration)
|
|
83
|
+
- data_exploration_config: Direct relation to the DataExplorationConfig node (shared across all locations)
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
space: str
|
|
87
|
+
external_id: str
|
|
88
|
+
|
|
89
|
+
root_location_external_id: str | None = None
|
|
90
|
+
feature_toggles: FeatureToggles | None = None
|
|
91
|
+
app_instance_space: str | None = None
|
|
92
|
+
access_management: AccessManagement | None = None
|
|
93
|
+
data_filters: RootLocationDataFilters | None = None
|
|
94
|
+
data_exploration_config: DataExplorationConfig | None = None
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import hashlib
|
|
1
2
|
import re
|
|
2
3
|
from collections.abc import Hashable
|
|
3
4
|
|
|
4
5
|
from rich.console import Console
|
|
5
6
|
|
|
7
|
+
from cognite_toolkit._cdf_tk.exceptions import ToolkitValueError
|
|
6
8
|
from cognite_toolkit._cdf_tk.tk_warnings import LowSeverityWarning
|
|
7
9
|
|
|
8
10
|
INVALID_TITLE_REGEX = re.compile(r"[\\*?:/\[\]]")
|
|
@@ -90,3 +92,24 @@ def to_sentence_case(text: str) -> str:
|
|
|
90
92
|
text = re.sub(r"(?<=[a-z])([A-Z])", r" \1", text)
|
|
91
93
|
# Convert to lowercase
|
|
92
94
|
return text.casefold()
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def sanitize_instance_external_id(external_id: str) -> str:
|
|
98
|
+
"""Sanitize an instance external ID to be compatible with CDF requirements.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
external_id: The external ID to sanitize.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
The sanitized external ID.
|
|
105
|
+
"""
|
|
106
|
+
# CDF instance external IDs must be between 1 and 256 characters,
|
|
107
|
+
if not external_id or external_id == "\x00":
|
|
108
|
+
raise ToolkitValueError("External ID cannot be empty.")
|
|
109
|
+
elif len(external_id) <= 256:
|
|
110
|
+
return external_id
|
|
111
|
+
hasher = hashlib.sha256()
|
|
112
|
+
hasher.update(external_id.encode("utf-8"))
|
|
113
|
+
hash_digest = hasher.hexdigest()[:8]
|
|
114
|
+
sanitized_external_id = f"{external_id[:247]}_{hash_digest}"
|
|
115
|
+
return sanitized_external_id
|
|
@@ -4,7 +4,7 @@ default_env = "<DEFAULT_ENV_PLACEHOLDER>"
|
|
|
4
4
|
[modules]
|
|
5
5
|
# This is the version of the modules. It should not be changed manually.
|
|
6
6
|
# It will be updated by the 'cdf modules upgrade' command.
|
|
7
|
-
version = "0.6.
|
|
7
|
+
version = "0.6.91"
|
|
8
8
|
|
|
9
9
|
[alpha_flags]
|
|
10
10
|
external-libraries = true
|
cognite_toolkit/_version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.6.
|
|
1
|
+
__version__ = "0.6.91"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cognite_toolkit
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.91
|
|
4
4
|
Summary: Official Cognite Data Fusion tool for project templates and configuration deployment
|
|
5
5
|
Project-URL: Homepage, https://docs.cognite.com/cdf/deploy/cdf_toolkit/
|
|
6
6
|
Project-URL: Changelog, https://github.com/cognitedata/toolkit/releases
|