cognite-toolkit 0.7.47__py3-none-any.whl → 0.7.48__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_toolkit/_cdf_tk/apps/_migrate_app.py +6 -6
- cognite_toolkit/_cdf_tk/client/_toolkit_client.py +6 -4
- cognite_toolkit/_cdf_tk/client/api/instances.py +139 -0
- cognite_toolkit/_cdf_tk/client/api/location_filters.py +177 -0
- cognite_toolkit/_cdf_tk/client/api/raw.py +2 -2
- cognite_toolkit/_cdf_tk/client/api/robotics.py +19 -0
- cognite_toolkit/_cdf_tk/client/api/robotics_capabilities.py +127 -0
- cognite_toolkit/_cdf_tk/client/api/robotics_data_postprocessing.py +138 -0
- cognite_toolkit/_cdf_tk/client/api/robotics_frames.py +122 -0
- cognite_toolkit/_cdf_tk/client/api/robotics_locations.py +127 -0
- cognite_toolkit/_cdf_tk/client/api/robotics_maps.py +122 -0
- cognite_toolkit/_cdf_tk/client/api/robotics_robots.py +122 -0
- cognite_toolkit/_cdf_tk/client/api/search_config.py +101 -0
- cognite_toolkit/_cdf_tk/client/api/streams.py +63 -55
- cognite_toolkit/_cdf_tk/client/api/three_d.py +293 -277
- cognite_toolkit/_cdf_tk/client/cdf_client/api.py +34 -5
- cognite_toolkit/_cdf_tk/client/http_client/_client.py +5 -2
- cognite_toolkit/_cdf_tk/client/http_client/_data_classes2.py +4 -3
- cognite_toolkit/_cdf_tk/client/request_classes/filters.py +45 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/apm_config.py +128 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/cognite_file.py +53 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/__init__.py +4 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_instance.py +22 -11
- cognite_toolkit/_cdf_tk/client/resource_classes/identifiers.py +7 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/location_filter.py +9 -2
- cognite_toolkit/_cdf_tk/client/resource_classes/resource_view_mapping.py +38 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/robotics/_map.py +6 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/robotics/_robot.py +10 -5
- cognite_toolkit/_cdf_tk/client/resource_classes/streams.py +1 -20
- cognite_toolkit/_cdf_tk/client/resource_classes/three_d.py +30 -9
- cognite_toolkit/_cdf_tk/client/testing.py +2 -2
- cognite_toolkit/_cdf_tk/commands/_migrate/data_mapper.py +5 -5
- cognite_toolkit/_cdf_tk/commands/_migrate/migration_io.py +11 -7
- cognite_toolkit/_cdf_tk/commands/build_v2/_module_parser.py +138 -0
- cognite_toolkit/_cdf_tk/commands/build_v2/_modules_parser.py +163 -0
- cognite_toolkit/_cdf_tk/commands/build_v2/build_cmd.py +83 -96
- cognite_toolkit/_cdf_tk/commands/build_v2/{build_input.py → build_parameters.py} +8 -22
- cognite_toolkit/_cdf_tk/commands/build_v2/data_classes/_modules.py +27 -0
- cognite_toolkit/_cdf_tk/commands/build_v2/data_classes/_resource.py +22 -0
- cognite_toolkit/_cdf_tk/cruds/__init__.py +11 -5
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/streams.py +14 -30
- cognite_toolkit/_cdf_tk/data_classes/__init__.py +3 -0
- cognite_toolkit/_cdf_tk/data_classes/_issues.py +36 -0
- cognite_toolkit/_cdf_tk/data_classes/_module_directories.py +2 -1
- cognite_toolkit/_cdf_tk/storageio/_base.py +2 -0
- cognite_toolkit/_cdf_tk/storageio/logger.py +163 -0
- cognite_toolkit/_cdf_tk/utils/__init__.py +8 -1
- cognite_toolkit/_cdf_tk/utils/interactive_select.py +3 -1
- cognite_toolkit/_cdf_tk/utils/modules.py +7 -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.7.47.dist-info → cognite_toolkit-0.7.48.dist-info}/METADATA +1 -1
- {cognite_toolkit-0.7.47.dist-info → cognite_toolkit-0.7.48.dist-info}/RECORD +58 -40
- cognite_toolkit/_cdf_tk/commands/build_v2/build_issues.py +0 -27
- /cognite_toolkit/_cdf_tk/client/resource_classes/{search_config_resource.py → search_config.py} +0 -0
- {cognite_toolkit-0.7.47.dist-info → cognite_toolkit-0.7.48.dist-info}/WHEEL +0 -0
- {cognite_toolkit-0.7.47.dist-info → cognite_toolkit-0.7.48.dist-info}/entry_points.txt +0 -0
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from itertools import groupby
|
|
1
3
|
from pathlib import Path
|
|
2
|
-
from typing import Any, Literal
|
|
4
|
+
from typing import Any, Literal
|
|
3
5
|
|
|
4
6
|
from rich import print
|
|
5
7
|
from rich.panel import Panel
|
|
@@ -7,39 +9,29 @@ from rich.panel import Panel
|
|
|
7
9
|
from cognite_toolkit._cdf_tk.client import ToolkitClient
|
|
8
10
|
from cognite_toolkit._cdf_tk.commands._base import ToolkitCommand
|
|
9
11
|
from cognite_toolkit._cdf_tk.commands.build_cmd import BuildCommand as OldBuildCommand
|
|
10
|
-
from cognite_toolkit._cdf_tk.commands.build_v2.
|
|
11
|
-
from cognite_toolkit._cdf_tk.commands.build_v2.
|
|
12
|
-
from cognite_toolkit._cdf_tk.data_classes import
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
BuiltModuleList,
|
|
16
|
-
ModuleDirectories,
|
|
17
|
-
)
|
|
12
|
+
from cognite_toolkit._cdf_tk.commands.build_v2._modules_parser import ModulesParser
|
|
13
|
+
from cognite_toolkit._cdf_tk.commands.build_v2.build_parameters import BuildParameters
|
|
14
|
+
from cognite_toolkit._cdf_tk.commands.build_v2.data_classes._modules import Module
|
|
15
|
+
from cognite_toolkit._cdf_tk.data_classes import BuildConfigYAML, BuildVariables, BuiltModuleList
|
|
16
|
+
from cognite_toolkit._cdf_tk.data_classes._issues import Issue, IssueList
|
|
18
17
|
from cognite_toolkit._cdf_tk.exceptions import ToolkitError
|
|
19
|
-
from cognite_toolkit._cdf_tk.hints import verify_module_directory
|
|
20
18
|
from cognite_toolkit._cdf_tk.tk_warnings import ToolkitWarning, WarningList
|
|
21
19
|
from cognite_toolkit._cdf_tk.utils.file import safe_rmtree
|
|
22
|
-
from cognite_toolkit._cdf_tk.validation import validate_module_selection, validate_modules_variables
|
|
23
20
|
from cognite_toolkit._version import __version__
|
|
24
21
|
|
|
25
22
|
|
|
26
|
-
class BuildWarnings(TypedDict):
|
|
27
|
-
warning: ToolkitWarning
|
|
28
|
-
location: list[Path]
|
|
29
|
-
|
|
30
|
-
|
|
31
23
|
class BuildCommand(ToolkitCommand):
|
|
32
24
|
def __init__(self, print_warning: bool = True, skip_tracking: bool = False, silent: bool = False) -> None:
|
|
33
25
|
super().__init__(print_warning, skip_tracking, silent)
|
|
34
|
-
self.issues =
|
|
26
|
+
self.issues = IssueList()
|
|
35
27
|
|
|
36
28
|
def execute(
|
|
37
29
|
self,
|
|
38
30
|
verbose: bool,
|
|
39
|
-
|
|
31
|
+
base_dir: Path,
|
|
40
32
|
build_dir: Path,
|
|
41
33
|
selected: list[str | Path] | None,
|
|
42
|
-
|
|
34
|
+
build_env: str | None,
|
|
43
35
|
no_clean: bool,
|
|
44
36
|
client: ToolkitClient | None = None,
|
|
45
37
|
on_error: Literal["continue", "raise"] = "continue",
|
|
@@ -51,30 +43,48 @@ class BuildCommand(ToolkitCommand):
|
|
|
51
43
|
self.verbose = verbose
|
|
52
44
|
self.on_error = on_error
|
|
53
45
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
46
|
+
build_parameters = BuildParameters.load(
|
|
47
|
+
organization_dir=base_dir,
|
|
48
|
+
build_dir=build_dir,
|
|
49
|
+
build_env_name=build_env,
|
|
50
|
+
client=client,
|
|
51
|
+
user_selected=selected,
|
|
52
|
+
)
|
|
61
53
|
|
|
62
54
|
# Print the build input.
|
|
63
55
|
if self.verbose:
|
|
64
|
-
self._print_build_input(
|
|
56
|
+
self._print_build_input(build_parameters)
|
|
65
57
|
|
|
66
|
-
#
|
|
67
|
-
if
|
|
68
|
-
self.
|
|
58
|
+
# Tracking the project and cluster for the build.
|
|
59
|
+
if build_parameters.client:
|
|
60
|
+
self._additional_tracking_info.project = build_parameters.client.config.project
|
|
61
|
+
self._additional_tracking_info.cluster = build_parameters.client.config.cdf_cluster
|
|
62
|
+
|
|
63
|
+
# Load modules
|
|
64
|
+
modules_parser = ModulesParser(organization_dir=base_dir, selected=selected)
|
|
65
|
+
module_paths = modules_parser.parse()
|
|
66
|
+
module_loading_issues = modules_parser.issues
|
|
67
|
+
if module_loading_issues:
|
|
68
|
+
self.issues.extend(module_loading_issues)
|
|
69
|
+
self._print_or_log_issues_by_category(self.issues)
|
|
70
|
+
raise ToolkitError("Module loading issues encountered. Cannot continue. See above for details.")
|
|
71
|
+
|
|
72
|
+
# Load modules
|
|
73
|
+
if module_paths:
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
# modules = [Module.load(path) for path in module_paths]
|
|
77
|
+
# for module in modules:
|
|
78
|
+
# continue
|
|
69
79
|
|
|
70
80
|
# Logistics: clean and create build directory
|
|
71
|
-
if prepare_issues := self._prepare_target_directory(
|
|
81
|
+
if prepare_issues := self._prepare_target_directory(build_dir, not no_clean):
|
|
72
82
|
self.issues.extend(prepare_issues)
|
|
73
83
|
|
|
74
84
|
# Compile the configuration and variables,
|
|
75
85
|
# check syntax on module and resource level
|
|
76
86
|
# for any "compilation errors and warnings"
|
|
77
|
-
built_modules, build_integrity_issues = self._build_configuration(
|
|
87
|
+
built_modules, build_integrity_issues = self._build_configuration(build_parameters)
|
|
78
88
|
if build_integrity_issues:
|
|
79
89
|
self.issues.extend(build_integrity_issues)
|
|
80
90
|
|
|
@@ -83,84 +93,48 @@ class BuildCommand(ToolkitCommand):
|
|
|
83
93
|
self.issues.extend(build_quality_issues)
|
|
84
94
|
|
|
85
95
|
# Finally, print warnings grouped by category/code and location.
|
|
86
|
-
self.
|
|
96
|
+
self._print_or_log_issues_by_category(self.issues)
|
|
87
97
|
|
|
88
98
|
return built_modules
|
|
89
99
|
|
|
90
|
-
def _print_build_input(self,
|
|
100
|
+
def _print_build_input(self, build_input: BuildParameters) -> None:
|
|
91
101
|
print(
|
|
92
102
|
Panel(
|
|
93
|
-
f"Building {
|
|
94
|
-
f" - Environment name {
|
|
95
|
-
f" - Config '{
|
|
103
|
+
f"Building {build_input.organization_dir!s}:\n - Toolkit Version '{__version__!s}'\n"
|
|
104
|
+
f" - Environment name {build_input.build_env_name!r}, validation-type {build_input.config.environment.validation_type!r}.\n"
|
|
105
|
+
f" - Config '{build_input.config.filepath!s}'",
|
|
96
106
|
expand=False,
|
|
97
107
|
)
|
|
98
108
|
)
|
|
99
109
|
|
|
100
|
-
def _prepare_target_directory(self,
|
|
110
|
+
def _prepare_target_directory(self, build_dir: Path, clean: bool = False) -> IssueList:
|
|
101
111
|
"""
|
|
102
112
|
Directory logistics
|
|
103
113
|
"""
|
|
104
|
-
issues =
|
|
105
|
-
if
|
|
114
|
+
issues = IssueList()
|
|
115
|
+
if build_dir.exists() and any(build_dir.iterdir()):
|
|
106
116
|
if not clean:
|
|
107
117
|
raise ToolkitError("Build directory is not empty. Run without --no-clean to remove existing files.")
|
|
108
118
|
|
|
109
119
|
if self.verbose:
|
|
110
|
-
issues.append(
|
|
111
|
-
safe_rmtree(
|
|
112
|
-
|
|
120
|
+
issues.append(Issue(code="BUILD_001"))
|
|
121
|
+
safe_rmtree(build_dir)
|
|
122
|
+
build_dir.mkdir(parents=True, exist_ok=True)
|
|
113
123
|
return issues
|
|
114
124
|
|
|
115
|
-
def
|
|
116
|
-
issues =
|
|
117
|
-
#
|
|
118
|
-
# and at least one is selected
|
|
119
|
-
verify_module_directory(input.organization_dir, input.build_env_name)
|
|
120
|
-
|
|
121
|
-
# Validate module selection
|
|
122
|
-
user_selected_modules = input.config.environment.get_selected_modules({})
|
|
123
|
-
module_warnings = validate_module_selection(
|
|
124
|
-
modules=input.modules,
|
|
125
|
-
config=input.config,
|
|
126
|
-
packages={},
|
|
127
|
-
selected_modules=user_selected_modules,
|
|
128
|
-
organization_dir=input.organization_dir,
|
|
129
|
-
)
|
|
130
|
-
if module_warnings:
|
|
131
|
-
issues.extend(BuildIssueList.from_warning_list(module_warnings))
|
|
132
|
-
|
|
133
|
-
# Validate variables. Note: this looks for non-replaced template
|
|
134
|
-
# variables <.*?> and can be improved in the future.
|
|
135
|
-
# Keeping for reference.
|
|
136
|
-
variables_warnings = validate_modules_variables(input.variables, input.config.filepath)
|
|
137
|
-
if variables_warnings:
|
|
138
|
-
issues.extend(BuildIssueList.from_warning_list(variables_warnings))
|
|
139
|
-
|
|
140
|
-
# Track LOC of managed configuration
|
|
141
|
-
# Note: _track is not implemented yet, so we skip it for now
|
|
142
|
-
# self._track(input)
|
|
143
|
-
|
|
144
|
-
return issues
|
|
145
|
-
|
|
146
|
-
def _build_configuration(self, input: BuildInput) -> tuple[BuiltModuleList, BuildIssueList]:
|
|
147
|
-
issues = BuildIssueList()
|
|
148
|
-
# Use input.modules.selected directly (it's already a ModuleDirectories)
|
|
149
|
-
if not input.modules.selected:
|
|
150
|
-
return BuiltModuleList(), issues
|
|
151
|
-
|
|
152
|
-
# first collect variables into practical lookup
|
|
153
|
-
# TODO: parallelism is not implemented yet. I'm sure there are optimizations to be had here, but we'll focus on process parallelism since we believe loading yaml and file i/O are the biggest bottlenecks.
|
|
125
|
+
def _build_configuration(self, build_input: BuildParameters) -> tuple[BuiltModuleList, IssueList]:
|
|
126
|
+
issues = IssueList()
|
|
127
|
+
# Use build_input.modules directly (it is already filtered by selection)
|
|
154
128
|
|
|
155
129
|
old_build_command = OldBuildCommand(print_warning=False, skip_tracking=False)
|
|
156
130
|
built_modules = old_build_command.build_config(
|
|
157
|
-
build_dir=
|
|
158
|
-
organization_dir=
|
|
159
|
-
config=
|
|
131
|
+
build_dir=build_input.build_dir,
|
|
132
|
+
organization_dir=build_input.organization_dir,
|
|
133
|
+
config=build_input.config,
|
|
160
134
|
packages={},
|
|
161
135
|
clean=False,
|
|
162
136
|
verbose=self.verbose,
|
|
163
|
-
client=
|
|
137
|
+
client=build_input.client,
|
|
164
138
|
progress_bar=False,
|
|
165
139
|
on_error=self.on_error,
|
|
166
140
|
)
|
|
@@ -172,29 +146,42 @@ class BuildCommand(ToolkitCommand):
|
|
|
172
146
|
# Always convert warnings to issues, even if the list appears empty
|
|
173
147
|
# (WarningList might have custom __bool__ behavior)
|
|
174
148
|
if old_build_command.warning_list:
|
|
175
|
-
converted_issues =
|
|
149
|
+
converted_issues = IssueList.from_warning_list(old_build_command.warning_list)
|
|
176
150
|
issues.extend(converted_issues)
|
|
177
151
|
return built_modules, issues
|
|
178
152
|
|
|
179
|
-
def _verify_build_quality(self, built_modules: BuiltModuleList) ->
|
|
180
|
-
issues =
|
|
153
|
+
def _verify_build_quality(self, built_modules: BuiltModuleList) -> IssueList:
|
|
154
|
+
issues = IssueList()
|
|
181
155
|
return issues
|
|
182
156
|
|
|
183
|
-
def _write(self,
|
|
157
|
+
def _write(self, build_input: BuildParameters) -> None:
|
|
184
158
|
# Write the build to the build directory.
|
|
185
159
|
# Track lines of code built.
|
|
186
160
|
raise NotImplementedError()
|
|
187
161
|
|
|
188
|
-
def _track(self,
|
|
162
|
+
def _track(self, build_input: BuildParameters) -> None:
|
|
189
163
|
raise NotImplementedError()
|
|
190
164
|
|
|
191
|
-
def
|
|
192
|
-
|
|
165
|
+
def _print_or_log_issues_by_category(self, issues: IssueList) -> None:
|
|
166
|
+
issues_sorted = sorted(issues, key=self._issue_sort_key)
|
|
167
|
+
for code, grouped_issues in groupby(issues_sorted, key=lambda issue: issue.code or ""):
|
|
168
|
+
print(f"[bold]{code}[/]")
|
|
169
|
+
for issue in grouped_issues:
|
|
170
|
+
message = issue.message or ""
|
|
171
|
+
print(f" - {message}")
|
|
172
|
+
|
|
173
|
+
def _issue_sort_key(self, issue: Issue) -> tuple[str, str]:
|
|
174
|
+
code = issue.code or ""
|
|
175
|
+
if not issue.message:
|
|
176
|
+
return code, ""
|
|
177
|
+
match = re.search(r"'([^']+)'", issue.message)
|
|
178
|
+
path = match.group(1) if match else issue.message
|
|
179
|
+
return code, path
|
|
193
180
|
|
|
194
181
|
# Delegate to old BuildCommand for backward compatibility with tests
|
|
195
182
|
def build_modules(
|
|
196
183
|
self,
|
|
197
|
-
modules:
|
|
184
|
+
modules: list[Module],
|
|
198
185
|
build_dir: Path,
|
|
199
186
|
variables: BuildVariables,
|
|
200
187
|
verbose: bool = False,
|
|
@@ -204,10 +191,10 @@ class BuildCommand(ToolkitCommand):
|
|
|
204
191
|
"""Delegate to old BuildCommand for backward compatibility."""
|
|
205
192
|
old_cmd = OldBuildCommand()
|
|
206
193
|
|
|
207
|
-
built_modules = old_cmd.build_modules(modules, build_dir, variables, verbose, progress_bar, on_error)
|
|
194
|
+
built_modules = old_cmd.build_modules(modules, build_dir, variables, verbose, progress_bar, on_error) # type: ignore[arg-type]
|
|
208
195
|
self._additional_tracking_info.package_ids.update(old_cmd._additional_tracking_info.package_ids)
|
|
209
196
|
self._additional_tracking_info.module_ids.update(old_cmd._additional_tracking_info.module_ids)
|
|
210
|
-
self.issues.extend(
|
|
197
|
+
self.issues.extend(IssueList.from_warning_list(old_cmd.warning_list or WarningList[ToolkitWarning]()))
|
|
211
198
|
return built_modules
|
|
212
199
|
|
|
213
200
|
def build_config(
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import sys
|
|
2
|
-
from functools import cached_property
|
|
3
2
|
from pathlib import Path
|
|
4
3
|
|
|
5
4
|
if sys.version_info >= (3, 11):
|
|
@@ -13,14 +12,12 @@ from cognite_toolkit._cdf_tk.client import ToolkitClient
|
|
|
13
12
|
from cognite_toolkit._cdf_tk.constants import DEFAULT_ENV
|
|
14
13
|
from cognite_toolkit._cdf_tk.data_classes import (
|
|
15
14
|
BuildConfigYAML,
|
|
16
|
-
BuildVariables,
|
|
17
|
-
ModuleDirectories,
|
|
18
15
|
)
|
|
19
16
|
from cognite_toolkit._cdf_tk.tk_warnings import ToolkitWarning, WarningList
|
|
20
17
|
from cognite_toolkit._cdf_tk.utils.modules import parse_user_selected_modules
|
|
21
18
|
|
|
22
19
|
|
|
23
|
-
class
|
|
20
|
+
class BuildParameters(BaseModel):
|
|
24
21
|
"""Input to the build process."""
|
|
25
22
|
|
|
26
23
|
# need this until we turn BuildConfigYaml and ToolkitClient into Pydantic models
|
|
@@ -31,8 +28,8 @@ class BuildInput(BaseModel):
|
|
|
31
28
|
build_env_name: str
|
|
32
29
|
config: BuildConfigYAML
|
|
33
30
|
client: ToolkitClient | None = None
|
|
34
|
-
selected: list[str | Path] | None = None
|
|
35
31
|
warnings: WarningList[ToolkitWarning] | None = None
|
|
32
|
+
user_selected: list[str | Path] | None = None
|
|
36
33
|
|
|
37
34
|
@classmethod
|
|
38
35
|
def load(
|
|
@@ -41,24 +38,24 @@ class BuildInput(BaseModel):
|
|
|
41
38
|
build_dir: Path,
|
|
42
39
|
build_env_name: str | None,
|
|
43
40
|
client: ToolkitClient | None,
|
|
44
|
-
|
|
41
|
+
user_selected: list[str | Path] | None = None,
|
|
45
42
|
) -> Self:
|
|
46
43
|
resolved_org_dir = Path.cwd() if organization_dir in {Path("."), Path("./")} else organization_dir
|
|
47
44
|
resolved_env = build_env_name or DEFAULT_ENV
|
|
48
|
-
config, warnings = cls._load_config(resolved_org_dir, resolved_env,
|
|
45
|
+
config, warnings = cls._load_config(resolved_org_dir, resolved_env, user_selected)
|
|
49
46
|
return cls(
|
|
50
47
|
organization_dir=resolved_org_dir,
|
|
51
48
|
build_dir=build_dir,
|
|
52
49
|
build_env_name=resolved_env,
|
|
53
50
|
config=config,
|
|
54
51
|
client=client,
|
|
55
|
-
selected=selected,
|
|
56
52
|
warnings=warnings,
|
|
53
|
+
user_selected=user_selected,
|
|
57
54
|
)
|
|
58
55
|
|
|
59
56
|
@classmethod
|
|
60
57
|
def _load_config(
|
|
61
|
-
cls, organization_dir: Path, build_env_name: str,
|
|
58
|
+
cls, organization_dir: Path, build_env_name: str, user_selected: list[str | Path] | None
|
|
62
59
|
) -> tuple[BuildConfigYAML, WarningList[ToolkitWarning]]:
|
|
63
60
|
warnings: WarningList[ToolkitWarning] = WarningList[ToolkitWarning]()
|
|
64
61
|
if (organization_dir / BuildConfigYAML.get_filename(build_env_name or DEFAULT_ENV)).exists():
|
|
@@ -66,20 +63,9 @@ class BuildInput(BaseModel):
|
|
|
66
63
|
else:
|
|
67
64
|
# Loads the default environment
|
|
68
65
|
config = BuildConfigYAML.load_default(organization_dir)
|
|
69
|
-
if
|
|
70
|
-
config.environment.selected = parse_user_selected_modules(
|
|
66
|
+
if user_selected:
|
|
67
|
+
config.environment.selected = list(set(parse_user_selected_modules(list(user_selected), organization_dir)))
|
|
71
68
|
config.set_environment_variables()
|
|
72
69
|
if environment_warning := config.validate_environment():
|
|
73
70
|
warnings.append(environment_warning)
|
|
74
71
|
return config, warnings
|
|
75
|
-
|
|
76
|
-
@cached_property
|
|
77
|
-
def modules(self) -> ModuleDirectories:
|
|
78
|
-
user_selected_modules = self.config.environment.get_selected_modules({})
|
|
79
|
-
return ModuleDirectories.load(self.organization_dir, user_selected_modules)
|
|
80
|
-
|
|
81
|
-
@cached_property
|
|
82
|
-
def variables(self) -> BuildVariables:
|
|
83
|
-
return BuildVariables.load_raw(
|
|
84
|
-
self.config.variables, self.modules.available_paths, self.modules.selected.available_paths
|
|
85
|
-
)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, ConfigDict
|
|
5
|
+
|
|
6
|
+
from cognite_toolkit._cdf_tk.data_classes._module_toml import ModuleToml
|
|
7
|
+
|
|
8
|
+
if sys.version_info >= (3, 11):
|
|
9
|
+
from typing import Self
|
|
10
|
+
else:
|
|
11
|
+
from typing_extensions import Self
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Module(BaseModel):
|
|
15
|
+
model_config = ConfigDict(
|
|
16
|
+
frozen=True,
|
|
17
|
+
validate_assignment=True,
|
|
18
|
+
arbitrary_types_allowed=True,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
path: Path
|
|
22
|
+
definition: ModuleToml | None = None
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def load(cls, path: Path) -> Self:
|
|
26
|
+
definition = ModuleToml.load(path / ModuleToml.filename) if (path / ModuleToml.filename).exists() else None
|
|
27
|
+
return cls(path=path, definition=definition)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, ConfigDict
|
|
5
|
+
|
|
6
|
+
if sys.version_info >= (3, 11):
|
|
7
|
+
from typing import Self
|
|
8
|
+
else:
|
|
9
|
+
from typing_extensions import Self
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Resource(BaseModel):
|
|
13
|
+
model_config = ConfigDict(
|
|
14
|
+
frozen=True,
|
|
15
|
+
validate_assignment=True,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
path: Path
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def load(cls, path: Path) -> Self:
|
|
22
|
+
return cls(path=path)
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
import itertools
|
|
15
|
+
from collections import defaultdict
|
|
15
16
|
from typing import Literal, TypeAlias
|
|
16
17
|
|
|
17
18
|
from cognite_toolkit._cdf_tk.feature_flags import FeatureFlag, Flags
|
|
@@ -90,24 +91,28 @@ if not FeatureFlag.is_enabled(Flags.STREAMS):
|
|
|
90
91
|
if not FeatureFlag.is_enabled(Flags.SIMULATORS):
|
|
91
92
|
_EXCLUDED_CRUDS.add(SimulatorModelCRUD)
|
|
92
93
|
|
|
93
|
-
|
|
94
|
+
CRUDS_BY_FOLDER_NAME_INCLUDE_ALPHA: defaultdict[str, list[type[Loader]]] = defaultdict(list)
|
|
95
|
+
CRUDS_BY_FOLDER_NAME: defaultdict[str, list[type[Loader]]] = defaultdict(list)
|
|
94
96
|
for _loader in itertools.chain(
|
|
95
97
|
ResourceCRUD.__subclasses__(),
|
|
96
98
|
ResourceContainerCRUD.__subclasses__(),
|
|
97
99
|
DataCRUD.__subclasses__(),
|
|
98
100
|
GroupCRUD.__subclasses__(),
|
|
99
101
|
):
|
|
100
|
-
if _loader in [ResourceCRUD, ResourceContainerCRUD, DataCRUD, GroupCRUD]
|
|
102
|
+
if _loader in [ResourceCRUD, ResourceContainerCRUD, DataCRUD, GroupCRUD]:
|
|
101
103
|
# Skipping base classes
|
|
102
104
|
continue
|
|
103
|
-
if _loader.folder_name not in CRUDS_BY_FOLDER_NAME: # type: ignore[attr-defined]
|
|
104
|
-
CRUDS_BY_FOLDER_NAME[_loader.folder_name] = [] # type: ignore[attr-defined]
|
|
105
105
|
# MyPy bug: https://github.com/python/mypy/issues/4717
|
|
106
|
-
|
|
106
|
+
CRUDS_BY_FOLDER_NAME_INCLUDE_ALPHA[_loader.folder_name].append(_loader) # type: ignore[arg-type, attr-defined]
|
|
107
|
+
|
|
108
|
+
if _loader not in _EXCLUDED_CRUDS:
|
|
109
|
+
CRUDS_BY_FOLDER_NAME[_loader.folder_name].append(_loader) # type: ignore[arg-type, attr-defined]
|
|
107
110
|
del _loader # cleanup module namespace
|
|
108
111
|
|
|
112
|
+
|
|
109
113
|
# For backwards compatibility
|
|
110
114
|
CRUDS_BY_FOLDER_NAME["data_models"] = CRUDS_BY_FOLDER_NAME["data_modeling"] # Todo: Remove in v1.0
|
|
115
|
+
CRUDS_BY_FOLDER_NAME_INCLUDE_ALPHA["data_models"] = CRUDS_BY_FOLDER_NAME_INCLUDE_ALPHA["data_modeling"]
|
|
111
116
|
RESOURCE_CRUD_BY_FOLDER_NAME = {
|
|
112
117
|
folder_name: cruds
|
|
113
118
|
for folder_name, loaders in CRUDS_BY_FOLDER_NAME.items()
|
|
@@ -166,6 +171,7 @@ __all__ = [
|
|
|
166
171
|
"RESOURCE_CRUD_CONTAINER_LIST",
|
|
167
172
|
"RESOURCE_CRUD_LIST",
|
|
168
173
|
"RESOURCE_DATA_CRUD_LIST",
|
|
174
|
+
"_EXCLUDED_CRUDS",
|
|
169
175
|
"AgentCRUD",
|
|
170
176
|
"AssetCRUD",
|
|
171
177
|
"CogniteFileCRUD",
|
|
@@ -4,11 +4,10 @@ from typing import Any, final
|
|
|
4
4
|
from cognite.client.data_classes.capabilities import Capability, StreamsAcl
|
|
5
5
|
from cognite.client.utils.useful_types import SequenceNotStr
|
|
6
6
|
|
|
7
|
-
from cognite_toolkit._cdf_tk.client.
|
|
7
|
+
from cognite_toolkit._cdf_tk.client.resource_classes.identifiers import ExternalId
|
|
8
8
|
from cognite_toolkit._cdf_tk.client.resource_classes.streams import (
|
|
9
9
|
StreamRequest,
|
|
10
10
|
StreamResponse,
|
|
11
|
-
StreamResponseList,
|
|
12
11
|
)
|
|
13
12
|
from cognite_toolkit._cdf_tk.cruds._base_cruds import ResourceCRUD
|
|
14
13
|
from cognite_toolkit._cdf_tk.resource_classes import StreamYAML
|
|
@@ -17,7 +16,7 @@ from .datamodel import ContainerCRUD
|
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
@final
|
|
20
|
-
class StreamCRUD(ResourceCRUD[
|
|
19
|
+
class StreamCRUD(ResourceCRUD[ExternalId, StreamRequest, StreamResponse]):
|
|
21
20
|
folder_name = "streams"
|
|
22
21
|
resource_cls = StreamResponse
|
|
23
22
|
resource_write_cls = StreamRequest
|
|
@@ -32,14 +31,14 @@ class StreamCRUD(ResourceCRUD[str, StreamRequest, StreamResponse]):
|
|
|
32
31
|
return "streams"
|
|
33
32
|
|
|
34
33
|
@classmethod
|
|
35
|
-
def get_id(cls, item: StreamRequest | StreamResponse | dict) ->
|
|
34
|
+
def get_id(cls, item: StreamRequest | StreamResponse | dict) -> ExternalId:
|
|
36
35
|
if isinstance(item, dict):
|
|
37
|
-
return item["externalId"]
|
|
38
|
-
return item.external_id
|
|
36
|
+
return ExternalId(external_id=item["externalId"])
|
|
37
|
+
return ExternalId(external_id=item.external_id)
|
|
39
38
|
|
|
40
39
|
@classmethod
|
|
41
|
-
def dump_id(cls, id:
|
|
42
|
-
return
|
|
40
|
+
def dump_id(cls, id: ExternalId) -> dict[str, Any]:
|
|
41
|
+
return id.dump()
|
|
43
42
|
|
|
44
43
|
@classmethod
|
|
45
44
|
def get_required_capability(
|
|
@@ -55,30 +54,15 @@ class StreamCRUD(ResourceCRUD[str, StreamRequest, StreamResponse]):
|
|
|
55
54
|
)
|
|
56
55
|
return StreamsAcl(actions, StreamsAcl.Scope.All())
|
|
57
56
|
|
|
58
|
-
def create(self, items: Sequence[StreamRequest]) ->
|
|
59
|
-
|
|
60
|
-
return StreamResponseList(created)
|
|
57
|
+
def create(self, items: Sequence[StreamRequest]) -> list[StreamResponse]:
|
|
58
|
+
return self.client.streams.create(items)
|
|
61
59
|
|
|
62
|
-
def retrieve(self, ids: SequenceNotStr[
|
|
63
|
-
|
|
64
|
-
for _id in ids:
|
|
65
|
-
try:
|
|
66
|
-
_resp = self.client.streams.retrieve(_id)
|
|
67
|
-
except ToolkitAPIError:
|
|
68
|
-
continue
|
|
69
|
-
if _resp is not None:
|
|
70
|
-
retrieved.append(_resp)
|
|
71
|
-
return StreamResponseList(retrieved)
|
|
60
|
+
def retrieve(self, ids: SequenceNotStr[ExternalId]) -> list[StreamResponse]:
|
|
61
|
+
return self.client.streams.retrieve(list(ids), ignore_unknown_ids=True)
|
|
72
62
|
|
|
73
|
-
def delete(self, ids: SequenceNotStr[
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
try:
|
|
77
|
-
self.client.streams.delete(_id)
|
|
78
|
-
except ToolkitAPIError:
|
|
79
|
-
continue
|
|
80
|
-
count += 1
|
|
81
|
-
return count
|
|
63
|
+
def delete(self, ids: SequenceNotStr[ExternalId]) -> int:
|
|
64
|
+
self.client.streams.delete(list(ids), ignore_unknown_ids=True)
|
|
65
|
+
return len(ids)
|
|
82
66
|
|
|
83
67
|
def _iterate(
|
|
84
68
|
self,
|
|
@@ -29,6 +29,7 @@ from ._deploy_results import (
|
|
|
29
29
|
ResourceDeployResult,
|
|
30
30
|
UploadDeployResult,
|
|
31
31
|
)
|
|
32
|
+
from ._issues import Issue, IssueList
|
|
32
33
|
from ._module_directories import ModuleDirectories, ModuleLocation
|
|
33
34
|
from ._module_resources import ModuleResources
|
|
34
35
|
from ._packages import Package, Packages
|
|
@@ -56,6 +57,8 @@ __all__ = [
|
|
|
56
57
|
"DeployResults",
|
|
57
58
|
"Environment",
|
|
58
59
|
"InitConfigYAML",
|
|
60
|
+
"Issue",
|
|
61
|
+
"IssueList",
|
|
59
62
|
"ModuleDirectories",
|
|
60
63
|
"ModuleLocation",
|
|
61
64
|
"ModuleResources",
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from collections import UserList
|
|
3
|
+
|
|
4
|
+
if sys.version_info >= (3, 11):
|
|
5
|
+
from typing import Self
|
|
6
|
+
else:
|
|
7
|
+
from typing_extensions import Self
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
10
|
+
|
|
11
|
+
from cognite_toolkit._cdf_tk.tk_warnings import ToolkitWarning, WarningList
|
|
12
|
+
|
|
13
|
+
MODULE_ISSUE_CODE = "MOD"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Issue(BaseModel):
|
|
17
|
+
"""Base class for all issues"""
|
|
18
|
+
|
|
19
|
+
code: str
|
|
20
|
+
message: str | None = Field(default=None)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# temporary adapter to manage existing warnings
|
|
24
|
+
class IssueList(UserList[Issue]):
|
|
25
|
+
"""List of build issues."""
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
def from_warning_list(cls, warning_list: WarningList[ToolkitWarning]) -> Self:
|
|
29
|
+
"""Create a IssueList from a WarningList."""
|
|
30
|
+
return cls([Issue(code="WARN", message=warning.get_message()) for warning in warning_list])
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ModuleLoadingIssue(Issue):
|
|
34
|
+
"""Issue with the loading of a module folder."""
|
|
35
|
+
|
|
36
|
+
code: str = "MOD_001"
|
|
@@ -8,7 +8,8 @@ from pathlib import Path
|
|
|
8
8
|
from typing import Any, SupportsIndex, overload
|
|
9
9
|
|
|
10
10
|
from cognite_toolkit._cdf_tk.constants import INDEX_PATTERN
|
|
11
|
-
from cognite_toolkit._cdf_tk.utils import calculate_directory_hash
|
|
11
|
+
from cognite_toolkit._cdf_tk.utils.hashing import calculate_directory_hash
|
|
12
|
+
from cognite_toolkit._cdf_tk.utils.modules import iterate_modules, resource_folder_from_path
|
|
12
13
|
|
|
13
14
|
from ._module_toml import ModuleToml
|
|
14
15
|
|
|
@@ -11,6 +11,7 @@ from cognite_toolkit._cdf_tk.utils.collection import chunker
|
|
|
11
11
|
from cognite_toolkit._cdf_tk.utils.fileio import MultiFileReader, SchemaColumn
|
|
12
12
|
from cognite_toolkit._cdf_tk.utils.useful_types import JsonVal
|
|
13
13
|
|
|
14
|
+
from .logger import DataLogger, NoOpLogger
|
|
14
15
|
from .selectors import DataSelector
|
|
15
16
|
|
|
16
17
|
|
|
@@ -76,6 +77,7 @@ class StorageIO(ABC, Generic[T_Selector, T_ResourceResponse]):
|
|
|
76
77
|
|
|
77
78
|
def __init__(self, client: ToolkitClient) -> None:
|
|
78
79
|
self.client = client
|
|
80
|
+
self.logger: DataLogger = NoOpLogger()
|
|
79
81
|
|
|
80
82
|
@abstractmethod
|
|
81
83
|
def as_id(self, item: T_ResourceResponse) -> str:
|