cognite-toolkit 0.7.9__py3-none-any.whl → 0.7.11__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.
Files changed (45) hide show
  1. cognite_toolkit/_cdf_tk/commands/_purge.py +27 -28
  2. cognite_toolkit/_cdf_tk/commands/_upload.py +6 -2
  3. cognite_toolkit/_cdf_tk/commands/clean.py +11 -13
  4. cognite_toolkit/_cdf_tk/commands/deploy.py +9 -17
  5. cognite_toolkit/_cdf_tk/commands/dump_resource.py +6 -4
  6. cognite_toolkit/_cdf_tk/commands/pull.py +6 -19
  7. cognite_toolkit/_cdf_tk/cruds/_base_cruds.py +7 -25
  8. cognite_toolkit/_cdf_tk/cruds/_data_cruds.py +3 -6
  9. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/agent.py +4 -6
  10. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/auth.py +4 -12
  11. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/classic.py +19 -36
  12. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/configuration.py +4 -10
  13. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/data_organization.py +4 -12
  14. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/datamodel.py +16 -41
  15. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/extraction_pipeline.py +5 -15
  16. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/fieldops.py +8 -21
  17. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/file.py +6 -22
  18. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/function.py +5 -15
  19. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/hosted_extractors.py +12 -26
  20. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/industrial_tool.py +3 -6
  21. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/location.py +3 -14
  22. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/migration.py +4 -8
  23. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/raw.py +4 -8
  24. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/relationship.py +3 -6
  25. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/robotics.py +15 -34
  26. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/streams.py +2 -5
  27. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/three_d_model.py +3 -6
  28. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/timeseries.py +5 -13
  29. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/transformation.py +4 -19
  30. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/workflow.py +20 -37
  31. cognite_toolkit/_cdf_tk/cruds/_worker.py +13 -30
  32. cognite_toolkit/_cdf_tk/storageio/__init__.py +3 -3
  33. cognite_toolkit/_cdf_tk/storageio/_base.py +23 -0
  34. cognite_toolkit/_cdf_tk/storageio/_file_content.py +4 -0
  35. cognite_toolkit/_cdf_tk/storageio/selectors/_datapoints.py +1 -1
  36. cognite_toolkit/_cdf_tk/utils/fileio/_readers.py +42 -1
  37. cognite_toolkit/_repo_files/GitHub/.github/workflows/deploy.yaml +1 -1
  38. cognite_toolkit/_repo_files/GitHub/.github/workflows/dry-run.yaml +1 -1
  39. cognite_toolkit/_resources/cdf.toml +1 -1
  40. cognite_toolkit/_version.py +1 -1
  41. {cognite_toolkit-0.7.9.dist-info → cognite_toolkit-0.7.11.dist-info}/METADATA +1 -1
  42. {cognite_toolkit-0.7.9.dist-info → cognite_toolkit-0.7.11.dist-info}/RECORD +45 -45
  43. {cognite_toolkit-0.7.9.dist-info → cognite_toolkit-0.7.11.dist-info}/WHEEL +0 -0
  44. {cognite_toolkit-0.7.9.dist-info → cognite_toolkit-0.7.11.dist-info}/entry_points.txt +0 -0
  45. {cognite_toolkit-0.7.9.dist-info → cognite_toolkit-0.7.11.dist-info}/licenses/LICENSE +0 -0
@@ -7,12 +7,7 @@ from typing import Literal, cast
7
7
 
8
8
  import questionary
9
9
  from cognite.client.data_classes import DataSetUpdate
10
- from cognite.client.data_classes._base import CogniteResourceList
11
- from cognite.client.data_classes.data_modeling import (
12
- EdgeList,
13
- NodeId,
14
- NodeList,
15
- )
10
+ from cognite.client.data_classes.data_modeling import Edge, NodeId
16
11
  from cognite.client.data_classes.data_modeling.statistics import SpaceStatistics
17
12
  from cognite.client.exceptions import CogniteAPIError
18
13
  from cognite.client.utils._identifier import InstanceId
@@ -46,6 +41,7 @@ from cognite_toolkit._cdf_tk.exceptions import (
46
41
  AuthorizationError,
47
42
  ToolkitMissingResourceError,
48
43
  )
44
+ from cognite_toolkit._cdf_tk.protocols import ResourceResponseProtocol
49
45
  from cognite_toolkit._cdf_tk.storageio import InstanceIO
50
46
  from cognite_toolkit._cdf_tk.storageio.selectors import InstanceSelector
51
47
  from cognite_toolkit._cdf_tk.tk_warnings import (
@@ -107,7 +103,7 @@ class ToDelete(ABC):
107
103
  @abstractmethod
108
104
  def get_process_function(
109
105
  self, client: ToolkitClient, console: Console, verbose: bool, process_results: ResourceDeployResult
110
- ) -> Callable[[CogniteResourceList], list[JsonVal]]:
106
+ ) -> Callable[[list[ResourceResponseProtocol]], list[JsonVal]]:
111
107
  raise NotImplementedError()
112
108
 
113
109
  def get_extra_fields(self) -> dict[str, JsonVal]:
@@ -118,9 +114,10 @@ class ToDelete(ABC):
118
114
  class DataModelingToDelete(ToDelete):
119
115
  def get_process_function(
120
116
  self, client: ToolkitClient, console: Console, verbose: bool, process_results: ResourceDeployResult
121
- ) -> Callable[[CogniteResourceList], list[JsonVal]]:
122
- def as_id(chunk: CogniteResourceList) -> list[JsonVal]:
123
- return [item.as_id().dump(include_type=False) for item in chunk]
117
+ ) -> Callable[[list[ResourceResponseProtocol]], list[JsonVal]]:
118
+ def as_id(chunk: list[ResourceResponseProtocol]) -> list[JsonVal]:
119
+ # We know that all data modeling resources implement as_id
120
+ return [item.as_id().dump(include_type=False) for item in chunk] # type: ignore[attr-defined]
124
121
 
125
122
  return as_id
126
123
 
@@ -129,11 +126,11 @@ class DataModelingToDelete(ToDelete):
129
126
  class EdgeToDelete(ToDelete):
130
127
  def get_process_function(
131
128
  self, client: ToolkitClient, console: Console, verbose: bool, process_results: ResourceDeployResult
132
- ) -> Callable[[CogniteResourceList], list[JsonVal]]:
133
- def as_id(chunk: CogniteResourceList) -> list[JsonVal]:
129
+ ) -> Callable[[list[ResourceResponseProtocol]], list[JsonVal]]:
130
+ def as_id(chunk: list[ResourceResponseProtocol]) -> list[JsonVal]:
134
131
  return [
135
132
  {"space": item.space, "externalId": item.external_id, "instanceType": "edge"}
136
- for item in cast(EdgeList, chunk)
133
+ for item in cast(list[Edge], chunk)
137
134
  ]
138
135
 
139
136
  return as_id
@@ -146,9 +143,10 @@ class NodesToDelete(ToDelete):
146
143
 
147
144
  def get_process_function(
148
145
  self, client: ToolkitClient, console: Console, verbose: bool, process_results: ResourceDeployResult
149
- ) -> Callable[[CogniteResourceList], list[JsonVal]]:
150
- def check_for_data(chunk: CogniteResourceList) -> list[JsonVal]:
151
- node_ids = cast(NodeList, chunk).as_ids()
146
+ ) -> Callable[[list[ResourceResponseProtocol]], list[JsonVal]]:
147
+ def check_for_data(chunk: list[ResourceResponseProtocol]) -> list[JsonVal]:
148
+ # We know that all node resources implement as_id
149
+ node_ids = [item.as_id() for item in chunk] # type: ignore[attr-defined]
152
150
  found_ids: set[InstanceId] = set()
153
151
  if not self.delete_datapoints:
154
152
  timeseries = client.time_series.retrieve_multiple(instance_ids=node_ids, ignore_unknown_ids=True)
@@ -164,8 +162,7 @@ class NodesToDelete(ToDelete):
164
162
  dumped = node_id.dump(include_instance_type=True)
165
163
  # The delete endpoint expects "instanceType" instead of "type"
166
164
  dumped["instanceType"] = dumped.pop("type")
167
- # MyPy think complains about invariant here, even though dict[str, str] is a type of JsonVal
168
- result.append(dumped) # type: ignore[arg-type]
165
+ result.append(dumped)
169
166
  return result
170
167
 
171
168
  return check_for_data
@@ -175,9 +172,10 @@ class NodesToDelete(ToDelete):
175
172
  class IdResourceToDelete(ToDelete):
176
173
  def get_process_function(
177
174
  self, client: ToolkitClient, console: Console, verbose: bool, process_results: ResourceDeployResult
178
- ) -> Callable[[CogniteResourceList], list[JsonVal]]:
179
- def as_id(chunk: CogniteResourceList) -> list[JsonVal]:
180
- return [{"id": item.id} for item in chunk]
175
+ ) -> Callable[[list[ResourceResponseProtocol]], list[JsonVal]]:
176
+ def as_id(chunk: list[ResourceResponseProtocol]) -> list[JsonVal]:
177
+ # We know that all id resources have an id attribute
178
+ return [{"id": item.id} for item in chunk] # type: ignore[attr-defined]
181
179
 
182
180
  return as_id
183
181
 
@@ -186,9 +184,10 @@ class IdResourceToDelete(ToDelete):
186
184
  class ExternalIdToDelete(ToDelete):
187
185
  def get_process_function(
188
186
  self, client: ToolkitClient, console: Console, verbose: bool, process_results: ResourceDeployResult
189
- ) -> Callable[[CogniteResourceList], list[JsonVal]]:
190
- def as_external_id(chunk: CogniteResourceList) -> list[JsonVal]:
191
- return [{"externalId": item.external_id} for item in chunk]
187
+ ) -> Callable[[list[ResourceResponseProtocol]], list[JsonVal]]:
188
+ def as_external_id(chunk: list[ResourceResponseProtocol]) -> list[JsonVal]:
189
+ # We know that all external id resources have an external_id attribute
190
+ return [{"externalId": item.external_id} for item in chunk] # type: ignore[attr-defined]
192
191
 
193
192
  return as_external_id
194
193
 
@@ -321,7 +320,7 @@ class PurgeCommand(ToolkitCommand):
321
320
  iteration_count = item.total // self.BATCH_SIZE_DM + (
322
321
  1 if item.total % self.BATCH_SIZE_DM > 0 else 0
323
322
  )
324
- executor = ProducerWorkerExecutor[CogniteResourceList, list[JsonVal]](
323
+ executor = ProducerWorkerExecutor[list[ResourceResponseProtocol], list[JsonVal]](
325
324
  download_iterable=self._iterate_batch(
326
325
  item.crud, space, data_set_external_id, batch_size=self.BATCH_SIZE_DM
327
326
  ),
@@ -348,13 +347,13 @@ class PurgeCommand(ToolkitCommand):
348
347
  @staticmethod
349
348
  def _iterate_batch(
350
349
  crud: ResourceCRUD, selected_space: str | None, data_set_external_id: str | None, batch_size: int
351
- ) -> Iterable[CogniteResourceList]:
352
- batch = crud.list_cls([])
350
+ ) -> Iterable[list[ResourceResponseProtocol]]:
351
+ batch: list[ResourceResponseProtocol] = []
353
352
  for resource in crud.iterate(space=selected_space, data_set_external_id=data_set_external_id):
354
353
  batch.append(resource)
355
354
  if len(batch) >= batch_size:
356
355
  yield batch
357
- batch = crud.list_cls([])
356
+ batch = []
358
357
  if batch:
359
358
  yield batch
360
359
 
@@ -215,6 +215,10 @@ class UploadCommand(ToolkitCommand):
215
215
  reader = MultiFileReader(datafiles)
216
216
  if reader.is_table and not isinstance(io, TableUploadableStorageIO):
217
217
  raise ToolkitValueError(f"{selector.display_name} does not support {reader.format!r} files.")
218
+
219
+ chunk_count = io.count_chunks(reader)
220
+ iteration_count = chunk_count // io.CHUNK_SIZE + (1 if chunk_count % io.CHUNK_SIZE > 0 else 0)
221
+
218
222
  tracker = ProgressTracker[str]([self._UPLOAD])
219
223
  executor = ProducerWorkerExecutor[list[tuple[str, dict[str, JsonVal]]], Sequence[UploadItem]](
220
224
  download_iterable=io.read_chunks(reader, selector),
@@ -230,7 +234,7 @@ class UploadCommand(ToolkitCommand):
230
234
  tracker=tracker,
231
235
  console=console,
232
236
  ),
233
- iteration_count=None,
237
+ iteration_count=iteration_count,
234
238
  max_queue_size=self._MAX_QUEUE_SIZE,
235
239
  download_description=f"Reading {selector.display_name!r} files",
236
240
  process_description="Processing",
@@ -262,7 +266,7 @@ class UploadCommand(ToolkitCommand):
262
266
  self, selector: Selector, data_file: Path, client: ToolkitClient
263
267
  ) -> UploadableStorageIO | None:
264
268
  try:
265
- io_cls = get_upload_io(type(selector))
269
+ io_cls = get_upload_io(selector)
266
270
  except ValueError as e:
267
271
  self.warn(HighSeverityWarning(f"Could not find StorageIO for selector {selector}: {e}"))
268
272
  return None
@@ -1,4 +1,5 @@
1
1
  import traceback
2
+ from collections.abc import Sequence
2
3
  from graphlib import TopologicalSorter
3
4
  from pathlib import Path
4
5
 
@@ -24,14 +25,7 @@ from cognite_toolkit._cdf_tk.cruds import (
24
25
  ResourceCRUD,
25
26
  ResourceWorker,
26
27
  )
27
- from cognite_toolkit._cdf_tk.cruds._base_cruds import (
28
- T_ID,
29
- Loader,
30
- T_ResourceRequest,
31
- T_ResourceRequestList,
32
- T_ResourceResponse,
33
- T_ResourceResponseList,
34
- )
28
+ from cognite_toolkit._cdf_tk.cruds._base_cruds import Loader
35
29
  from cognite_toolkit._cdf_tk.data_classes import (
36
30
  BuildEnvironment,
37
31
  DeployResults,
@@ -46,6 +40,7 @@ from cognite_toolkit._cdf_tk.exceptions import (
46
40
  ToolkitValidationError,
47
41
  ToolkitValueError,
48
42
  )
43
+ from cognite_toolkit._cdf_tk.protocols import T_ResourceRequest, T_ResourceResponse
49
44
  from cognite_toolkit._cdf_tk.tk_warnings import (
50
45
  LowSeverityWarning,
51
46
  MediumSeverityWarning,
@@ -57,6 +52,7 @@ from cognite_toolkit._cdf_tk.utils import (
57
52
  read_yaml_file,
58
53
  )
59
54
  from cognite_toolkit._cdf_tk.utils.auth import EnvironmentVariables
55
+ from cognite_toolkit._cdf_tk.utils.useful_types import T_ID
60
56
 
61
57
  from ._utils import _print_ids_or_length
62
58
 
@@ -66,9 +62,7 @@ AVAILABLE_DATA_TYPES: tuple[str, ...] = tuple(CRUDS_BY_FOLDER_NAME)
66
62
  class CleanCommand(ToolkitCommand):
67
63
  def clean_resources(
68
64
  self,
69
- loader: ResourceCRUD[
70
- T_ID, T_ResourceRequest, T_ResourceResponse, T_ResourceRequestList, T_ResourceResponseList
71
- ],
65
+ loader: ResourceCRUD[T_ID, T_ResourceRequest, T_ResourceResponse],
72
66
  env_vars: EnvironmentVariables,
73
67
  read_modules: list[ReadModule],
74
68
  dry_run: bool = False,
@@ -139,7 +133,7 @@ class CleanCommand(ToolkitCommand):
139
133
  return ResourceDeployResult(name=loader.display_name)
140
134
 
141
135
  def _delete_resources(
142
- self, loaded_resources: T_ResourceResponseList, loader: ResourceCRUD, dry_run: bool, verbose: bool
136
+ self, loaded_resources: Sequence[T_ResourceResponse], loader: ResourceCRUD, dry_run: bool, verbose: bool
143
137
  ) -> int:
144
138
  nr_of_deleted = 0
145
139
  resource_ids = loader.get_ids(loaded_resources)
@@ -164,7 +158,11 @@ class CleanCommand(ToolkitCommand):
164
158
  return nr_of_deleted
165
159
 
166
160
  def _drop_data(
167
- self, loaded_resources: T_ResourceResponseList, loader: ResourceContainerCRUD, dry_run: bool, verbose: bool
161
+ self,
162
+ loaded_resources: Sequence[T_ResourceResponse],
163
+ loader: ResourceContainerCRUD,
164
+ dry_run: bool,
165
+ verbose: bool,
168
166
  ) -> int:
169
167
  nr_of_dropped = 0
170
168
  resource_ids = loader.get_ids(loaded_resources)
@@ -1,4 +1,4 @@
1
- from collections.abc import Hashable
1
+ from collections.abc import Hashable, Sequence
2
2
  from graphlib import TopologicalSorter
3
3
  from pathlib import Path
4
4
  from typing import overload
@@ -46,9 +46,7 @@ from cognite_toolkit._cdf_tk.exceptions import (
46
46
  )
47
47
  from cognite_toolkit._cdf_tk.protocols import (
48
48
  T_ResourceRequest,
49
- T_ResourceRequestList,
50
49
  T_ResourceResponse,
51
- T_ResourceResponseList,
52
50
  )
53
51
  from cognite_toolkit._cdf_tk.tk_warnings import EnvironmentVariableMissingWarning
54
52
  from cognite_toolkit._cdf_tk.tk_warnings.base import WarningList, catch_warnings
@@ -338,9 +336,7 @@ class DeployCommand(ToolkitCommand):
338
336
 
339
337
  def deploy_resource_type(
340
338
  self,
341
- loader: ResourceCRUD[
342
- T_ID, T_ResourceRequest, T_ResourceResponse, T_ResourceRequestList, T_ResourceResponseList
343
- ],
339
+ loader: ResourceCRUD[T_ID, T_ResourceRequest, T_ResourceResponse],
344
340
  env_vars: EnvironmentVariables,
345
341
  read_modules: list[ReadModule] | None = None,
346
342
  dry_run: bool = False,
@@ -402,10 +398,8 @@ class DeployCommand(ToolkitCommand):
402
398
 
403
399
  def actual_deploy(
404
400
  self,
405
- resources: CategorizedResources[T_ID, T_ResourceResponseList],
406
- loader: ResourceCRUD[
407
- T_ID, T_ResourceRequest, T_ResourceResponse, T_ResourceRequestList, T_ResourceResponseList
408
- ],
401
+ resources: CategorizedResources[T_ID, T_ResourceRequest],
402
+ loader: ResourceCRUD[T_ID, T_ResourceRequest, T_ResourceResponse],
409
403
  env_var_warnings: WarningList | None = None,
410
404
  ) -> ResourceDeployResult:
411
405
  environment_variable_warning_by_id = {
@@ -436,10 +430,8 @@ class DeployCommand(ToolkitCommand):
436
430
 
437
431
  @staticmethod
438
432
  def dry_run_deploy(
439
- resources: CategorizedResources[T_ID, T_ResourceResponseList],
440
- loader: ResourceCRUD[
441
- T_ID, T_ResourceRequest, T_ResourceResponse, T_ResourceRequestList, T_ResourceResponseList
442
- ],
433
+ resources: CategorizedResources[T_ID, T_ResourceRequest],
434
+ loader: ResourceCRUD[T_ID, T_ResourceRequest, T_ResourceResponse],
443
435
  has_done_drop: bool,
444
436
  has_dropped_data: bool,
445
437
  ) -> ResourceDeployResult:
@@ -470,7 +462,7 @@ class DeployCommand(ToolkitCommand):
470
462
 
471
463
  @staticmethod
472
464
  def _verbose_print(
473
- resources: CategorizedResources[T_ID, T_ResourceResponseList],
465
+ resources: CategorizedResources[T_ID, T_ResourceRequest],
474
466
  loader: ResourceCRUD,
475
467
  dry_run: bool,
476
468
  ) -> None:
@@ -494,7 +486,7 @@ class DeployCommand(ToolkitCommand):
494
486
 
495
487
  def _create_resources(
496
488
  self,
497
- resources: T_ResourceResponseList,
489
+ resources: Sequence[T_ResourceRequest],
498
490
  loader: ResourceCRUD,
499
491
  environment_variable_warning_by_id: dict[Hashable, EnvironmentVariableMissingWarning],
500
492
  ) -> int:
@@ -517,7 +509,7 @@ class DeployCommand(ToolkitCommand):
517
509
 
518
510
  def _update_resources(
519
511
  self,
520
- resources: T_ResourceResponseList,
512
+ resources: Sequence[T_ResourceRequest],
521
513
  loader: ResourceCRUD,
522
514
  environment_variable_warning_by_id: dict[Hashable, EnvironmentVariableMissingWarning],
523
515
  ) -> int:
@@ -3,7 +3,7 @@ import json
3
3
  import zipfile
4
4
  from abc import ABC, abstractmethod
5
5
  from collections import defaultdict
6
- from collections.abc import Hashable, Iterable, Iterator
6
+ from collections.abc import Hashable, Iterable, Iterator, Sequence
7
7
  from functools import cached_property
8
8
  from pathlib import Path
9
9
  from typing import Generic, cast
@@ -22,6 +22,7 @@ from cognite.client.data_classes import (
22
22
  filters,
23
23
  )
24
24
  from cognite.client.data_classes._base import (
25
+ CogniteResource,
25
26
  CogniteResourceList,
26
27
  )
27
28
  from cognite.client.data_classes.agents import (
@@ -113,7 +114,7 @@ class ResourceFinder(Iterable, ABC, Generic[T_ID]):
113
114
  raise NotImplementedError
114
115
 
115
116
  # Can be implemented in subclasses
116
- def update(self, resources: CogniteResourceList) -> None: ...
117
+ def update(self, resources: Sequence[CogniteResource]) -> None: ...
117
118
 
118
119
 
119
120
  class DataModelFinder(ResourceFinder[DataModelId]):
@@ -178,7 +179,7 @@ class DataModelFinder(ResourceFinder[DataModelId]):
178
179
  self.data_model = models_by_version[selected_model]
179
180
  return self.data_model.as_id()
180
181
 
181
- def update(self, resources: CogniteResourceList) -> None:
182
+ def update(self, resources: Sequence[CogniteResource]) -> None:
182
183
  if isinstance(resources, dm.DataModelList):
183
184
  self.view_ids |= {
184
185
  view.as_id() if isinstance(view, dm.View) else view for item in resources for view in item.views
@@ -187,7 +188,7 @@ class DataModelFinder(ResourceFinder[DataModelId]):
187
188
  self.container_ids |= resources.referenced_containers()
188
189
  elif isinstance(resources, dm.SpaceList):
189
190
  return
190
- self.space_ids |= {item.space for item in resources}
191
+ self.space_ids |= {item.space for item in resources if hasattr(item, "space")}
191
192
 
192
193
  def __iter__(self) -> Iterator[tuple[list[Hashable], CogniteResourceList | None, ResourceCRUD, None | str]]:
193
194
  self.identifier = self._selected()
@@ -804,6 +805,7 @@ class DumpResourceCommand(ToolkitCommand):
804
805
  output_dir.mkdir(exist_ok=True)
805
806
 
806
807
  dumped_ids: list[Hashable] = []
808
+ resources: Sequence[CogniteResource] | None = None
807
809
  for identifiers, resources, loader, subfolder in finder:
808
810
  if not identifiers and not resources:
809
811
  # No resources to dump
@@ -29,13 +29,6 @@ from cognite_toolkit._cdf_tk.cruds import (
29
29
  ResourceCRUD,
30
30
  StreamlitCRUD,
31
31
  )
32
- from cognite_toolkit._cdf_tk.cruds._base_cruds import (
33
- T_ID,
34
- T_ResourceRequest,
35
- T_ResourceRequestList,
36
- T_ResourceResponse,
37
- T_ResourceResponseList,
38
- )
39
32
  from cognite_toolkit._cdf_tk.data_classes import (
40
33
  BuildEnvironment,
41
34
  BuildVariable,
@@ -49,6 +42,7 @@ from cognite_toolkit._cdf_tk.data_classes import (
49
42
  YAMLComments,
50
43
  )
51
44
  from cognite_toolkit._cdf_tk.exceptions import ToolkitError, ToolkitMissingResourceError, ToolkitValueError
45
+ from cognite_toolkit._cdf_tk.protocols import T_ResourceRequest, T_ResourceResponse
52
46
  from cognite_toolkit._cdf_tk.tk_warnings import LowSeverityWarning, MediumSeverityWarning
53
47
  from cognite_toolkit._cdf_tk.utils import (
54
48
  YAMLComment,
@@ -64,6 +58,7 @@ from cognite_toolkit._cdf_tk.utils.modules import (
64
58
  module_directory_from_path,
65
59
  parse_user_selected_modules,
66
60
  )
61
+ from cognite_toolkit._cdf_tk.utils.useful_types import T_ID
67
62
 
68
63
  from ._base import ToolkitCommand
69
64
  from .build_cmd import BuildCommand
@@ -547,9 +542,7 @@ class PullCommand(ToolkitCommand):
547
542
 
548
543
  def _pull_resources(
549
544
  self,
550
- loader: ResourceCRUD[
551
- T_ID, T_ResourceRequest, T_ResourceResponse, T_ResourceRequestList, T_ResourceResponseList
552
- ],
545
+ loader: ResourceCRUD[T_ID, T_ResourceRequest, T_ResourceResponse],
553
546
  resources: BuiltFullResourceList[T_ID],
554
547
  dry_run: bool,
555
548
  environment_variables: dict[str, str | None],
@@ -581,9 +574,7 @@ class PullCommand(ToolkitCommand):
581
574
  local_resource_by_id: dict[T_ID, dict[str, Any]],
582
575
  cdf_resource_by_id: dict[T_ID, T_ResourceResponse],
583
576
  file_results: ResourceDeployResult,
584
- loader: ResourceCRUD[
585
- T_ID, T_ResourceRequest, T_ResourceResponse, T_ResourceRequestList, T_ResourceResponseList
586
- ],
577
+ loader: ResourceCRUD[T_ID, T_ResourceRequest, T_ResourceResponse],
587
578
  ) -> tuple[bool, dict[T_ID, dict[str, Any]]]:
588
579
  to_write: dict[T_ID, dict[str, Any]] = {}
589
580
  has_changes = False
@@ -612,9 +603,7 @@ class PullCommand(ToolkitCommand):
612
603
  @staticmethod
613
604
  def _get_local_resource_dict_by_id(
614
605
  resources: BuiltFullResourceList[T_ID],
615
- loader: ResourceCRUD[
616
- T_ID, T_ResourceRequest, T_ResourceResponse, T_ResourceRequestList, T_ResourceResponseList
617
- ],
606
+ loader: ResourceCRUD[T_ID, T_ResourceRequest, T_ResourceResponse],
618
607
  environment_variables: dict[str, str | None],
619
608
  ) -> dict[T_ID, dict[str, Any]]:
620
609
  unique_destinations = {r.destination for r in resources if r.destination}
@@ -651,9 +640,7 @@ class PullCommand(ToolkitCommand):
651
640
  to_write: dict[T_ID, dict[str, Any]],
652
641
  resources: BuiltFullResourceList[T_ID],
653
642
  environment_variables: dict[str, str | None],
654
- loader: ResourceCRUD[
655
- T_ID, T_ResourceRequest, T_ResourceResponse, T_ResourceRequestList, T_ResourceResponseList
656
- ],
643
+ loader: ResourceCRUD[T_ID, T_ResourceRequest, T_ResourceResponse],
657
644
  source_file: Path,
658
645
  ) -> tuple[str, dict[Path, str]]:
659
646
  # 1. Replace all variables with placeholders
@@ -10,12 +10,7 @@ from rich.console import Console
10
10
 
11
11
  from cognite_toolkit._cdf_tk.client import ToolkitClient
12
12
  from cognite_toolkit._cdf_tk.constants import BUILD_FOLDER_ENCODING, EXCL_FILES
13
- from cognite_toolkit._cdf_tk.protocols import (
14
- T_ResourceRequest,
15
- T_ResourceRequestList,
16
- T_ResourceResponse,
17
- T_ResourceResponseList,
18
- )
13
+ from cognite_toolkit._cdf_tk.protocols import T_ResourceRequest, T_ResourceResponse
19
14
  from cognite_toolkit._cdf_tk.resource_classes import ToolkitResource
20
15
  from cognite_toolkit._cdf_tk.tk_warnings import ToolkitWarning
21
16
  from cognite_toolkit._cdf_tk.utils import load_yaml_inject_variables, safe_read, sanitize_filename
@@ -133,11 +128,7 @@ class Loader(ABC):
133
128
  T_Loader = TypeVar("T_Loader", bound=Loader)
134
129
 
135
130
 
136
- class ResourceCRUD(
137
- Loader,
138
- ABC,
139
- Generic[T_ID, T_ResourceRequest, T_ResourceResponse, T_ResourceRequestList, T_ResourceResponseList],
140
- ):
131
+ class ResourceCRUD(Loader, ABC, Generic[T_ID, T_ResourceRequest, T_ResourceResponse]):
141
132
  """This is the base class for all resource CRUD.
142
133
 
143
134
  A resource loader consists of the following
@@ -150,8 +141,6 @@ class ResourceCRUD(
150
141
  Class attributes:
151
142
  resource_write_cls: The API write data class for the resource.
152
143
  resource_cls: The API read data class for the resource.
153
- list_cls: The API read list format for this resource.
154
- list_write_cls: The API write list format for this resource.
155
144
  yaml_cls: The File format for this resource. This is used to validate the user input.
156
145
  support_drop: Whether the resource supports the drop flag.
157
146
  support_update: Whether the resource supports the update operation.
@@ -165,8 +154,6 @@ class ResourceCRUD(
165
154
  # Must be set in the subclass
166
155
  resource_write_cls: type[T_ResourceRequest]
167
156
  resource_cls: type[T_ResourceResponse]
168
- list_cls: type[T_ResourceResponseList]
169
- list_write_cls: type[T_ResourceRequestList]
170
157
  yaml_cls: type[ToolkitResource]
171
158
  # Optional to set in the subclass
172
159
  support_drop = True
@@ -197,14 +184,14 @@ class ResourceCRUD(
197
184
  raise NotImplementedError(f"get_required_capability must be implemented for {cls.__name__}.")
198
185
 
199
186
  @abstractmethod
200
- def create(self, items: T_ResourceRequestList) -> Sized:
187
+ def create(self, items: Sequence[T_ResourceRequest]) -> Sized:
201
188
  raise NotImplementedError
202
189
 
203
190
  @abstractmethod
204
- def retrieve(self, ids: SequenceNotStr[T_ID]) -> T_ResourceResponseList:
191
+ def retrieve(self, ids: SequenceNotStr[T_ID]) -> Sequence[T_ResourceResponse]:
205
192
  raise NotImplementedError
206
193
 
207
- def update(self, items: T_ResourceRequestList) -> Sized:
194
+ def update(self, items: Sequence[T_ResourceRequest]) -> Sized:
208
195
  raise NotImplementedError(f"Update is not supported for {type(self).__name__}.")
209
196
 
210
197
  @abstractmethod
@@ -390,9 +377,7 @@ class ResourceCRUD(
390
377
 
391
378
  # Helper methods
392
379
  @classmethod
393
- def get_ids(
394
- cls, items: Sequence[T_ResourceRequest | T_ResourceResponse | dict] | T_ResourceResponseList
395
- ) -> list[T_ID]:
380
+ def get_ids(cls, items: Sequence[T_ResourceRequest | T_ResourceResponse | dict]) -> list[T_ID]:
396
381
  return [cls.get_id(item) for item in items]
397
382
 
398
383
  @classmethod
@@ -404,10 +389,7 @@ class ResourceCRUD(
404
389
  )
405
390
 
406
391
 
407
- class ResourceContainerCRUD(
408
- ResourceCRUD[T_ID, T_ResourceRequest, T_ResourceResponse, T_ResourceRequestList, T_ResourceResponseList],
409
- ABC,
410
- ):
392
+ class ResourceContainerCRUD(ResourceCRUD[T_ID, T_ResourceRequest, T_ResourceResponse], ABC):
411
393
  """This is the base class for all resource CRUD' containers.
412
394
 
413
395
  A resource container CRUD is a resource that contains data. For example, Timeseries contains datapoints, and another
@@ -11,9 +11,7 @@ from cognite_toolkit._cdf_tk.client.data_classes.raw import RawTable
11
11
  from cognite_toolkit._cdf_tk.constants import BUILD_FOLDER_ENCODING
12
12
  from cognite_toolkit._cdf_tk.protocols import (
13
13
  T_ResourceRequest,
14
- T_ResourceRequestList,
15
14
  T_ResourceResponse,
16
- T_ResourceResponseList,
17
15
  )
18
16
  from cognite_toolkit._cdf_tk.utils import read_yaml_content, safe_read
19
17
  from cognite_toolkit._cdf_tk.utils.file import read_csv
@@ -131,17 +129,16 @@ class FileCRUD(DataCRUD):
131
129
  @staticmethod
132
130
  def _read_metadata(
133
131
  destination: Path,
134
- loader: type[
135
- ResourceCRUD[T_ID, T_ResourceRequest, T_ResourceResponse, T_ResourceRequestList, T_ResourceResponseList]
136
- ],
132
+ loader: type[ResourceCRUD[T_ID, T_ResourceRequest, T_ResourceResponse]],
137
133
  identifier: T_ID,
138
134
  ) -> T_ResourceRequest:
139
135
  built_content = read_yaml_content(safe_read(destination, encoding=BUILD_FOLDER_ENCODING))
140
136
  if isinstance(built_content, dict):
141
137
  return loader.resource_write_cls._load(built_content)
142
138
  elif isinstance(built_content, list):
139
+ write_resources = (loader.resource_write_cls._load(content) for content in built_content)
143
140
  try:
144
- return next(m for m in loader.list_write_cls.load(built_content) if loader.get_id(m) == identifier)
141
+ return next(m for m in write_resources if loader.get_id(m) == identifier)
145
142
  except StopIteration:
146
143
  raise RuntimeError(f"Missing metadata for {destination.as_posix()}")
147
144
 
@@ -1,7 +1,7 @@
1
1
  from collections.abc import Hashable, Iterable, Sequence
2
2
  from typing import Any
3
3
 
4
- from cognite.client.data_classes.agents import Agent, AgentList, AgentUpsert, AgentUpsertList
4
+ from cognite.client.data_classes.agents import Agent, AgentList, AgentUpsert
5
5
  from cognite.client.data_classes.capabilities import AgentsAcl, Capability
6
6
  from cognite.client.exceptions import CogniteAPIError
7
7
  from cognite.client.utils.useful_types import SequenceNotStr
@@ -11,12 +11,10 @@ from cognite_toolkit._cdf_tk.resource_classes import AgentYAML
11
11
  from cognite_toolkit._cdf_tk.utils.diff_list import diff_list_hashable, diff_list_identifiable
12
12
 
13
13
 
14
- class AgentCRUD(ResourceCRUD[str, AgentUpsert, Agent, AgentUpsertList, AgentList]):
14
+ class AgentCRUD(ResourceCRUD[str, AgentUpsert, Agent]):
15
15
  folder_name = "agents"
16
16
  resource_cls = Agent
17
17
  resource_write_cls = AgentUpsert
18
- list_cls = AgentList
19
- list_write_cls = AgentUpsertList
20
18
  kind = "Agent"
21
19
  yaml_cls = AgentYAML
22
20
  _doc_base_url = ""
@@ -43,13 +41,13 @@ class AgentCRUD(ResourceCRUD[str, AgentUpsert, Agent, AgentUpsertList, AgentList
43
41
 
44
42
  return AgentsAcl(actions, AgentsAcl.Scope.All())
45
43
 
46
- def create(self, items: AgentUpsertList) -> AgentList:
44
+ def create(self, items: Sequence[AgentUpsert]) -> AgentList:
47
45
  return self.client.agents.upsert(items)
48
46
 
49
47
  def retrieve(self, ids: SequenceNotStr[str]) -> AgentList:
50
48
  return self.client.agents.retrieve(ids, ignore_unknown_ids=True)
51
49
 
52
- def update(self, items: AgentUpsertList) -> AgentList:
50
+ def update(self, items: Sequence[AgentUpsert]) -> AgentList:
53
51
  return self.client.agents.upsert(items)
54
52
 
55
53
  def delete(self, ids: SequenceNotStr[str]) -> int:
@@ -30,11 +30,9 @@ from cognite.client.data_classes.iam import (
30
30
  Group,
31
31
  GroupList,
32
32
  GroupWrite,
33
- GroupWriteList,
34
33
  SecurityCategory,
35
34
  SecurityCategoryList,
36
35
  SecurityCategoryWrite,
37
- SecurityCategoryWriteList,
38
36
  )
39
37
  from cognite.client.exceptions import CogniteAPIError, CogniteNotFoundError
40
38
  from cognite.client.utils.useful_types import SequenceNotStr
@@ -65,13 +63,11 @@ class _ReplaceMethod:
65
63
  id_name: str
66
64
 
67
65
 
68
- class GroupCRUD(ResourceCRUD[str, GroupWrite, Group, GroupWriteList, GroupList]):
66
+ class GroupCRUD(ResourceCRUD[str, GroupWrite, Group]):
69
67
  folder_name = "auth"
70
68
  kind = "Group"
71
69
  resource_cls = Group
72
70
  resource_write_cls = GroupWrite
73
- list_cls = GroupList
74
- list_write_cls = GroupWriteList
75
71
  yaml_cls = GroupYAML
76
72
  resource_scopes = frozenset(
77
73
  {
@@ -478,13 +474,9 @@ class GroupAllScopedCRUD(GroupCRUD):
478
474
 
479
475
 
480
476
  @final
481
- class SecurityCategoryCRUD(
482
- ResourceCRUD[str, SecurityCategoryWrite, SecurityCategory, SecurityCategoryWriteList, SecurityCategoryList]
483
- ):
477
+ class SecurityCategoryCRUD(ResourceCRUD[str, SecurityCategoryWrite, SecurityCategory]):
484
478
  resource_cls = SecurityCategory
485
479
  resource_write_cls = SecurityCategoryWrite
486
- list_cls = SecurityCategoryList
487
- list_write_cls = SecurityCategoryWriteList
488
480
  kind = "SecurityCategory"
489
481
  yaml_cls = SecurityCategoriesYAML
490
482
  folder_name = "auth"
@@ -532,7 +524,7 @@ class SecurityCategoryCRUD(
532
524
  SecurityCategoriesAcl.Scope.All(),
533
525
  )
534
526
 
535
- def create(self, items: SecurityCategoryWriteList) -> SecurityCategoryList:
527
+ def create(self, items: Sequence[SecurityCategoryWrite]) -> SecurityCategoryList:
536
528
  return self.client.iam.security_categories.create(items)
537
529
 
538
530
  def retrieve(self, ids: SequenceNotStr[str]) -> SecurityCategoryList:
@@ -540,7 +532,7 @@ class SecurityCategoryCRUD(
540
532
  categories = self.client.iam.security_categories.list(limit=-1)
541
533
  return SecurityCategoryList([c for c in categories if c.name in names])
542
534
 
543
- def update(self, items: SecurityCategoryWriteList) -> SecurityCategoryList:
535
+ def update(self, items: Sequence[SecurityCategoryWrite]) -> SecurityCategoryList:
544
536
  items_by_name = {item.name: item for item in items}
545
537
  retrieved = self.retrieve(list(items_by_name.keys()))
546
538
  retrieved_by_name = {item.name: item for item in retrieved}