cognite-toolkit 0.6.97__py3-none-any.whl → 0.7.39__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 (198) hide show
  1. cognite_toolkit/_cdf.py +21 -23
  2. cognite_toolkit/_cdf_tk/apps/__init__.py +4 -0
  3. cognite_toolkit/_cdf_tk/apps/_core_app.py +19 -5
  4. cognite_toolkit/_cdf_tk/apps/_data_app.py +1 -1
  5. cognite_toolkit/_cdf_tk/apps/_dev_app.py +86 -0
  6. cognite_toolkit/_cdf_tk/apps/_download_app.py +693 -25
  7. cognite_toolkit/_cdf_tk/apps/_dump_app.py +44 -102
  8. cognite_toolkit/_cdf_tk/apps/_import_app.py +41 -0
  9. cognite_toolkit/_cdf_tk/apps/_landing_app.py +18 -4
  10. cognite_toolkit/_cdf_tk/apps/_migrate_app.py +424 -9
  11. cognite_toolkit/_cdf_tk/apps/_modules_app.py +0 -3
  12. cognite_toolkit/_cdf_tk/apps/_purge.py +15 -43
  13. cognite_toolkit/_cdf_tk/apps/_run.py +11 -0
  14. cognite_toolkit/_cdf_tk/apps/_upload_app.py +45 -6
  15. cognite_toolkit/_cdf_tk/builders/__init__.py +2 -2
  16. cognite_toolkit/_cdf_tk/builders/_base.py +28 -42
  17. cognite_toolkit/_cdf_tk/builders/_raw.py +1 -1
  18. cognite_toolkit/_cdf_tk/cdf_toml.py +20 -1
  19. cognite_toolkit/_cdf_tk/client/_toolkit_client.py +32 -12
  20. cognite_toolkit/_cdf_tk/client/api/infield.py +114 -17
  21. cognite_toolkit/_cdf_tk/client/api/{canvas.py → legacy/canvas.py} +15 -7
  22. cognite_toolkit/_cdf_tk/client/api/{charts.py → legacy/charts.py} +1 -1
  23. cognite_toolkit/_cdf_tk/client/api/{extended_data_modeling.py → legacy/extended_data_modeling.py} +1 -1
  24. cognite_toolkit/_cdf_tk/client/api/{extended_files.py → legacy/extended_files.py} +2 -2
  25. cognite_toolkit/_cdf_tk/client/api/{extended_functions.py → legacy/extended_functions.py} +15 -18
  26. cognite_toolkit/_cdf_tk/client/api/{extended_raw.py → legacy/extended_raw.py} +1 -1
  27. cognite_toolkit/_cdf_tk/client/api/{extended_timeseries.py → legacy/extended_timeseries.py} +5 -2
  28. cognite_toolkit/_cdf_tk/client/api/{location_filters.py → legacy/location_filters.py} +1 -1
  29. cognite_toolkit/_cdf_tk/client/api/legacy/robotics/__init__.py +8 -0
  30. cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/capabilities.py +1 -1
  31. cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/data_postprocessing.py +1 -1
  32. cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/frames.py +1 -1
  33. cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/locations.py +1 -1
  34. cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/maps.py +1 -1
  35. cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/robots.py +2 -2
  36. cognite_toolkit/_cdf_tk/client/api/{search_config.py → legacy/search_config.py} +5 -1
  37. cognite_toolkit/_cdf_tk/client/api/migration.py +177 -4
  38. cognite_toolkit/_cdf_tk/client/api/project.py +9 -8
  39. cognite_toolkit/_cdf_tk/client/api/search.py +2 -2
  40. cognite_toolkit/_cdf_tk/client/api/streams.py +88 -0
  41. cognite_toolkit/_cdf_tk/client/api/three_d.py +384 -0
  42. cognite_toolkit/_cdf_tk/client/data_classes/api_classes.py +13 -0
  43. cognite_toolkit/_cdf_tk/client/data_classes/base.py +37 -33
  44. cognite_toolkit/_cdf_tk/client/data_classes/charts_data.py +95 -213
  45. cognite_toolkit/_cdf_tk/client/data_classes/infield.py +32 -18
  46. cognite_toolkit/_cdf_tk/client/data_classes/instance_api.py +18 -13
  47. cognite_toolkit/_cdf_tk/client/data_classes/legacy/__init__.py +0 -0
  48. cognite_toolkit/_cdf_tk/client/data_classes/{canvas.py → legacy/canvas.py} +47 -4
  49. cognite_toolkit/_cdf_tk/client/data_classes/{charts.py → legacy/charts.py} +3 -3
  50. cognite_toolkit/_cdf_tk/client/data_classes/{migration.py → legacy/migration.py} +10 -2
  51. cognite_toolkit/_cdf_tk/client/data_classes/streams.py +90 -0
  52. cognite_toolkit/_cdf_tk/client/data_classes/three_d.py +112 -0
  53. cognite_toolkit/_cdf_tk/client/testing.py +42 -18
  54. cognite_toolkit/_cdf_tk/commands/__init__.py +7 -6
  55. cognite_toolkit/_cdf_tk/commands/_changes.py +3 -42
  56. cognite_toolkit/_cdf_tk/commands/_download.py +21 -11
  57. cognite_toolkit/_cdf_tk/commands/_migrate/__init__.py +0 -2
  58. cognite_toolkit/_cdf_tk/commands/_migrate/command.py +22 -20
  59. cognite_toolkit/_cdf_tk/commands/_migrate/conversion.py +140 -92
  60. cognite_toolkit/_cdf_tk/commands/_migrate/creators.py +1 -1
  61. cognite_toolkit/_cdf_tk/commands/_migrate/data_classes.py +108 -26
  62. cognite_toolkit/_cdf_tk/commands/_migrate/data_mapper.py +448 -45
  63. cognite_toolkit/_cdf_tk/commands/_migrate/data_model.py +1 -0
  64. cognite_toolkit/_cdf_tk/commands/_migrate/default_mappings.py +6 -6
  65. cognite_toolkit/_cdf_tk/commands/_migrate/issues.py +52 -1
  66. cognite_toolkit/_cdf_tk/commands/_migrate/migration_io.py +377 -11
  67. cognite_toolkit/_cdf_tk/commands/_migrate/selectors.py +9 -4
  68. cognite_toolkit/_cdf_tk/commands/_profile.py +1 -1
  69. cognite_toolkit/_cdf_tk/commands/_purge.py +36 -39
  70. cognite_toolkit/_cdf_tk/commands/_questionary_style.py +16 -0
  71. cognite_toolkit/_cdf_tk/commands/_upload.py +109 -86
  72. cognite_toolkit/_cdf_tk/commands/about.py +221 -0
  73. cognite_toolkit/_cdf_tk/commands/auth.py +19 -12
  74. cognite_toolkit/_cdf_tk/commands/build_cmd.py +16 -62
  75. cognite_toolkit/_cdf_tk/commands/build_v2/__init__.py +0 -0
  76. cognite_toolkit/_cdf_tk/commands/build_v2/build_cmd.py +241 -0
  77. cognite_toolkit/_cdf_tk/commands/build_v2/build_input.py +85 -0
  78. cognite_toolkit/_cdf_tk/commands/build_v2/build_issues.py +27 -0
  79. cognite_toolkit/_cdf_tk/commands/clean.py +63 -16
  80. cognite_toolkit/_cdf_tk/commands/deploy.py +20 -17
  81. cognite_toolkit/_cdf_tk/commands/dump_resource.py +10 -8
  82. cognite_toolkit/_cdf_tk/commands/init.py +225 -3
  83. cognite_toolkit/_cdf_tk/commands/modules.py +20 -44
  84. cognite_toolkit/_cdf_tk/commands/pull.py +6 -19
  85. cognite_toolkit/_cdf_tk/commands/resources.py +179 -0
  86. cognite_toolkit/_cdf_tk/commands/run.py +1 -1
  87. cognite_toolkit/_cdf_tk/constants.py +20 -1
  88. cognite_toolkit/_cdf_tk/cruds/__init__.py +19 -5
  89. cognite_toolkit/_cdf_tk/cruds/_base_cruds.py +14 -70
  90. cognite_toolkit/_cdf_tk/cruds/_data_cruds.py +10 -19
  91. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/__init__.py +4 -1
  92. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/agent.py +11 -9
  93. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/auth.py +5 -15
  94. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/classic.py +45 -44
  95. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/configuration.py +5 -12
  96. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/data_organization.py +4 -13
  97. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/datamodel.py +206 -67
  98. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/extraction_pipeline.py +6 -18
  99. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/fieldops.py +126 -35
  100. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/file.py +7 -28
  101. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/function.py +23 -30
  102. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/hosted_extractors.py +12 -30
  103. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/industrial_tool.py +4 -8
  104. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/location.py +4 -16
  105. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/migration.py +5 -13
  106. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/raw.py +5 -11
  107. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/relationship.py +3 -8
  108. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/robotics.py +16 -45
  109. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/streams.py +94 -0
  110. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/three_d_model.py +3 -7
  111. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/timeseries.py +5 -15
  112. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/transformation.py +75 -32
  113. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/workflow.py +20 -40
  114. cognite_toolkit/_cdf_tk/cruds/_worker.py +24 -36
  115. cognite_toolkit/_cdf_tk/data_classes/_module_toml.py +1 -0
  116. cognite_toolkit/_cdf_tk/feature_flags.py +16 -36
  117. cognite_toolkit/_cdf_tk/plugins.py +2 -1
  118. cognite_toolkit/_cdf_tk/resource_classes/__init__.py +4 -0
  119. cognite_toolkit/_cdf_tk/resource_classes/capabilities.py +12 -0
  120. cognite_toolkit/_cdf_tk/resource_classes/functions.py +3 -1
  121. cognite_toolkit/_cdf_tk/resource_classes/infield_cdm_location_config.py +109 -0
  122. cognite_toolkit/_cdf_tk/resource_classes/migration.py +8 -17
  123. cognite_toolkit/_cdf_tk/resource_classes/search_config.py +1 -1
  124. cognite_toolkit/_cdf_tk/resource_classes/streams.py +29 -0
  125. cognite_toolkit/_cdf_tk/resource_classes/workflow_version.py +164 -5
  126. cognite_toolkit/_cdf_tk/storageio/__init__.py +9 -21
  127. cognite_toolkit/_cdf_tk/storageio/_annotations.py +19 -16
  128. cognite_toolkit/_cdf_tk/storageio/_applications.py +340 -28
  129. cognite_toolkit/_cdf_tk/storageio/_asset_centric.py +67 -104
  130. cognite_toolkit/_cdf_tk/storageio/_base.py +61 -29
  131. cognite_toolkit/_cdf_tk/storageio/_datapoints.py +276 -20
  132. cognite_toolkit/_cdf_tk/storageio/_file_content.py +435 -0
  133. cognite_toolkit/_cdf_tk/storageio/_instances.py +35 -3
  134. cognite_toolkit/_cdf_tk/storageio/_raw.py +26 -0
  135. cognite_toolkit/_cdf_tk/storageio/selectors/__init__.py +71 -4
  136. cognite_toolkit/_cdf_tk/storageio/selectors/_base.py +14 -2
  137. cognite_toolkit/_cdf_tk/storageio/selectors/_canvas.py +14 -0
  138. cognite_toolkit/_cdf_tk/storageio/selectors/_charts.py +14 -0
  139. cognite_toolkit/_cdf_tk/storageio/selectors/_datapoints.py +23 -3
  140. cognite_toolkit/_cdf_tk/storageio/selectors/_file_content.py +164 -0
  141. cognite_toolkit/_cdf_tk/storageio/selectors/_three_d.py +34 -0
  142. cognite_toolkit/_cdf_tk/tk_warnings/other.py +4 -0
  143. cognite_toolkit/_cdf_tk/tracker.py +2 -2
  144. cognite_toolkit/_cdf_tk/utils/cdf.py +1 -1
  145. cognite_toolkit/_cdf_tk/utils/dtype_conversion.py +9 -3
  146. cognite_toolkit/_cdf_tk/utils/fileio/__init__.py +2 -0
  147. cognite_toolkit/_cdf_tk/utils/fileio/_base.py +5 -1
  148. cognite_toolkit/_cdf_tk/utils/fileio/_readers.py +112 -20
  149. cognite_toolkit/_cdf_tk/utils/fileio/_writers.py +15 -15
  150. cognite_toolkit/_cdf_tk/utils/http_client/__init__.py +28 -0
  151. cognite_toolkit/_cdf_tk/utils/http_client/_client.py +285 -18
  152. cognite_toolkit/_cdf_tk/utils/http_client/_data_classes.py +56 -4
  153. cognite_toolkit/_cdf_tk/utils/http_client/_data_classes2.py +247 -0
  154. cognite_toolkit/_cdf_tk/utils/http_client/_tracker.py +5 -2
  155. cognite_toolkit/_cdf_tk/utils/interactive_select.py +60 -18
  156. cognite_toolkit/_cdf_tk/utils/sql_parser.py +2 -3
  157. cognite_toolkit/_cdf_tk/utils/useful_types.py +6 -2
  158. cognite_toolkit/_cdf_tk/validation.py +83 -1
  159. cognite_toolkit/_repo_files/GitHub/.github/workflows/deploy.yaml +1 -1
  160. cognite_toolkit/_repo_files/GitHub/.github/workflows/dry-run.yaml +1 -1
  161. cognite_toolkit/_resources/cdf.toml +5 -4
  162. cognite_toolkit/_version.py +1 -1
  163. cognite_toolkit/config.dev.yaml +13 -0
  164. {cognite_toolkit-0.6.97.dist-info → cognite_toolkit-0.7.39.dist-info}/METADATA +24 -24
  165. cognite_toolkit-0.7.39.dist-info/RECORD +322 -0
  166. cognite_toolkit-0.7.39.dist-info/WHEEL +4 -0
  167. {cognite_toolkit-0.6.97.dist-info → cognite_toolkit-0.7.39.dist-info}/entry_points.txt +1 -0
  168. cognite_toolkit/_cdf_tk/client/api/robotics/__init__.py +0 -3
  169. cognite_toolkit/_cdf_tk/commands/_migrate/canvas.py +0 -201
  170. cognite_toolkit/_cdf_tk/commands/dump_data.py +0 -489
  171. cognite_toolkit/_cdf_tk/commands/featureflag.py +0 -27
  172. cognite_toolkit/_cdf_tk/prototypes/import_app.py +0 -41
  173. cognite_toolkit/_cdf_tk/utils/table_writers.py +0 -434
  174. cognite_toolkit-0.6.97.dist-info/RECORD +0 -306
  175. cognite_toolkit-0.6.97.dist-info/WHEEL +0 -4
  176. cognite_toolkit-0.6.97.dist-info/licenses/LICENSE +0 -18
  177. /cognite_toolkit/_cdf_tk/{prototypes/commands → client/api/legacy}/__init__.py +0 -0
  178. /cognite_toolkit/_cdf_tk/client/api/{dml.py → legacy/dml.py} +0 -0
  179. /cognite_toolkit/_cdf_tk/client/api/{fixed_transformations.py → legacy/fixed_transformations.py} +0 -0
  180. /cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/api.py +0 -0
  181. /cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/utlis.py +0 -0
  182. /cognite_toolkit/_cdf_tk/client/data_classes/{apm_config_v1.py → legacy/apm_config_v1.py} +0 -0
  183. /cognite_toolkit/_cdf_tk/client/data_classes/{extendable_cognite_file.py → legacy/extendable_cognite_file.py} +0 -0
  184. /cognite_toolkit/_cdf_tk/client/data_classes/{extended_filemetadata.py → legacy/extended_filemetadata.py} +0 -0
  185. /cognite_toolkit/_cdf_tk/client/data_classes/{extended_filemetdata.py → legacy/extended_filemetdata.py} +0 -0
  186. /cognite_toolkit/_cdf_tk/client/data_classes/{extended_timeseries.py → legacy/extended_timeseries.py} +0 -0
  187. /cognite_toolkit/_cdf_tk/client/data_classes/{functions.py → legacy/functions.py} +0 -0
  188. /cognite_toolkit/_cdf_tk/client/data_classes/{graphql_data_models.py → legacy/graphql_data_models.py} +0 -0
  189. /cognite_toolkit/_cdf_tk/client/data_classes/{instances.py → legacy/instances.py} +0 -0
  190. /cognite_toolkit/_cdf_tk/client/data_classes/{location_filters.py → legacy/location_filters.py} +0 -0
  191. /cognite_toolkit/_cdf_tk/client/data_classes/{pending_instances_ids.py → legacy/pending_instances_ids.py} +0 -0
  192. /cognite_toolkit/_cdf_tk/client/data_classes/{project.py → legacy/project.py} +0 -0
  193. /cognite_toolkit/_cdf_tk/client/data_classes/{raw.py → legacy/raw.py} +0 -0
  194. /cognite_toolkit/_cdf_tk/client/data_classes/{robotics.py → legacy/robotics.py} +0 -0
  195. /cognite_toolkit/_cdf_tk/client/data_classes/{search_config.py → legacy/search_config.py} +0 -0
  196. /cognite_toolkit/_cdf_tk/client/data_classes/{sequences.py → legacy/sequences.py} +0 -0
  197. /cognite_toolkit/_cdf_tk/client/data_classes/{streamlit_.py → legacy/streamlit_.py} +0 -0
  198. /cognite_toolkit/_cdf_tk/{prototypes/commands/import_.py → commands/_import_cmd.py} +0 -0
@@ -1,29 +1,59 @@
1
- from collections.abc import Iterator, Mapping, Sequence
2
- from typing import ClassVar, cast
1
+ from collections.abc import Iterable, Iterator, Mapping, Sequence
2
+ from typing import ClassVar, Literal, cast
3
3
 
4
- from cognite.client.data_classes.data_modeling import InstanceApply, NodeId
4
+ from cognite.client.data_classes import Annotation
5
+ from cognite.client.data_classes.data_modeling import EdgeId, InstanceApply, NodeId
5
6
 
6
7
  from cognite_toolkit._cdf_tk.client import ToolkitClient
7
- from cognite_toolkit._cdf_tk.client.data_classes.pending_instances_ids import PendingInstanceId
8
+ from cognite_toolkit._cdf_tk.client.data_classes.legacy.pending_instances_ids import PendingInstanceId
9
+ from cognite_toolkit._cdf_tk.client.data_classes.three_d import (
10
+ AssetMappingDMRequest,
11
+ AssetMappingResponse,
12
+ ThreeDModelResponse,
13
+ )
14
+ from cognite_toolkit._cdf_tk.commands._migrate.data_classes import ThreeDMigrationRequest
8
15
  from cognite_toolkit._cdf_tk.constants import MISSING_EXTERNAL_ID, MISSING_INSTANCE_SPACE
9
- from cognite_toolkit._cdf_tk.exceptions import ToolkitNotImplementedError
16
+ from cognite_toolkit._cdf_tk.exceptions import ToolkitNotImplementedError, ToolkitValueError
10
17
  from cognite_toolkit._cdf_tk.storageio import (
18
+ AnnotationIO,
11
19
  HierarchyIO,
12
20
  InstanceIO,
21
+ T_Selector,
13
22
  UploadableStorageIO,
14
23
  )
15
24
  from cognite_toolkit._cdf_tk.storageio._base import Page, UploadItem
25
+ from cognite_toolkit._cdf_tk.storageio.selectors import (
26
+ ThreeDModelFilteredSelector,
27
+ ThreeDModelIdSelector,
28
+ ThreeDSelector,
29
+ )
30
+ from cognite_toolkit._cdf_tk.tk_warnings import MediumSeverityWarning
16
31
  from cognite_toolkit._cdf_tk.utils.collection import chunker_sequence
17
- from cognite_toolkit._cdf_tk.utils.http_client import HTTPClient, HTTPMessage, ItemsRequest, SuccessResponseItems
32
+ from cognite_toolkit._cdf_tk.utils.http_client import (
33
+ FailedResponse,
34
+ HTTPClient,
35
+ HTTPMessage,
36
+ ItemsRequest,
37
+ SimpleBodyRequest,
38
+ SuccessResponseItems,
39
+ ToolkitAPIError,
40
+ )
18
41
  from cognite_toolkit._cdf_tk.utils.useful_types import (
19
- AssetCentricKind,
42
+ AssetCentricKindExtended,
20
43
  AssetCentricType,
21
44
  JsonVal,
22
45
  T_AssetCentricResource,
23
46
  )
24
47
 
25
- from .data_classes import AssetCentricMapping, AssetCentricMappingList, MigrationMapping, MigrationMappingList
48
+ from .data_classes import (
49
+ AnnotationMapping,
50
+ AssetCentricMapping,
51
+ AssetCentricMappingList,
52
+ MigrationMapping,
53
+ MigrationMappingList,
54
+ )
26
55
  from .data_model import INSTANCE_SOURCE_VIEW_ID
56
+ from .default_mappings import ASSET_ANNOTATIONS_ID, FILE_ANNOTATIONS_ID
27
57
  from .selectors import AssetCentricMigrationSelector, MigrateDataSetSelector, MigrationCSVFileSelector
28
58
 
29
59
 
@@ -37,7 +67,7 @@ class AssetCentricMigrationIO(
37
67
  CHUNK_SIZE = 1000
38
68
  UPLOAD_ENDPOINT = InstanceIO.UPLOAD_ENDPOINT
39
69
 
40
- PENDING_INSTANCE_ID_ENDPOINT_BY_KIND: ClassVar[Mapping[AssetCentricKind, str]] = {
70
+ PENDING_INSTANCE_ID_ENDPOINT_BY_KIND: ClassVar[Mapping[AssetCentricKindExtended, str]] = {
41
71
  "TimeSeries": "/timeseries/set-pending-instance-ids",
42
72
  "FileMetadata": "/files/set-pending-instance-ids",
43
73
  }
@@ -113,8 +143,8 @@ class AssetCentricMigrationIO(
113
143
  yield mapping_list
114
144
 
115
145
  @staticmethod
116
- def _kind_to_resource_type(kind: AssetCentricKind) -> AssetCentricType:
117
- mapping: dict[AssetCentricKind, AssetCentricType] = {
146
+ def _kind_to_resource_type(kind: AssetCentricKindExtended) -> AssetCentricType:
147
+ mapping: dict[AssetCentricKindExtended, AssetCentricType] = {
118
148
  "Assets": "asset",
119
149
  "Events": "event",
120
150
  "TimeSeries": "timeseries",
@@ -199,3 +229,339 @@ class AssetCentricMigrationIO(
199
229
  pending_instance_id=NodeId(item.space, item.external_id),
200
230
  id=id_,
201
231
  )
232
+
233
+
234
+ class AnnotationMigrationIO(
235
+ UploadableStorageIO[AssetCentricMigrationSelector, AssetCentricMapping[Annotation], InstanceApply]
236
+ ):
237
+ """IO class for migrating Annotations.
238
+
239
+ Args:
240
+ client: The ToolkitClient to use for CDF interactions.
241
+ instance_space: The instance space to use for the migrated annotations.
242
+ default_asset_annotation_mapping: The default ingestion mapping to use for asset-linked annotations.
243
+ default_file_annotation_mapping: The default ingestion mappingto use for file-linked annotations.
244
+
245
+ """
246
+
247
+ KIND = "AnnotationMigration"
248
+ SUPPORTED_DOWNLOAD_FORMATS = frozenset({".parquet", ".csv", ".ndjson"})
249
+ SUPPORTED_COMPRESSIONS = frozenset({".gz"})
250
+ SUPPORTED_READ_FORMATS = frozenset({".parquet", ".csv", ".ndjson", ".yaml", ".yml"})
251
+ CHUNK_SIZE = 1000
252
+ UPLOAD_ENDPOINT = InstanceIO.UPLOAD_ENDPOINT
253
+
254
+ SUPPORTED_ANNOTATION_TYPES = frozenset({"diagrams.AssetLink", "diagrams.FileLink"})
255
+
256
+ def __init__(
257
+ self,
258
+ client: ToolkitClient,
259
+ instance_space: str | None = None,
260
+ default_asset_annotation_mapping: str | None = None,
261
+ default_file_annotation_mapping: str | None = None,
262
+ ) -> None:
263
+ super().__init__(client)
264
+ self.annotation_io = AnnotationIO(client)
265
+ self.instance_space = instance_space
266
+ self.default_asset_annotation_mapping = default_asset_annotation_mapping or ASSET_ANNOTATIONS_ID
267
+ self.default_file_annotation_mapping = default_file_annotation_mapping or FILE_ANNOTATIONS_ID
268
+
269
+ def as_id(self, item: AssetCentricMapping[Annotation]) -> str:
270
+ return f"Annotation_{item.mapping.id}"
271
+
272
+ def count(self, selector: AssetCentricMigrationSelector) -> int | None:
273
+ if isinstance(selector, MigrationCSVFileSelector):
274
+ return len(selector.items)
275
+ else:
276
+ # There is no efficient way to count annotations in CDF.
277
+ return None
278
+
279
+ def stream_data(self, selector: AssetCentricMigrationSelector, limit: int | None = None) -> Iterable[Page]:
280
+ if isinstance(selector, MigrateDataSetSelector):
281
+ iterator = self._stream_from_dataset(selector, limit)
282
+ elif isinstance(selector, MigrationCSVFileSelector):
283
+ iterator = self._stream_from_csv(selector, limit)
284
+ else:
285
+ raise ToolkitNotImplementedError(f"Selector {type(selector)} is not supported for stream_data")
286
+ yield from (Page(worker_id="main", items=items) for items in iterator)
287
+
288
+ def _stream_from_dataset(
289
+ self, selector: MigrateDataSetSelector, limit: int | None = None
290
+ ) -> Iterator[Sequence[AssetCentricMapping[Annotation]]]:
291
+ if self.instance_space is None:
292
+ raise ToolkitValueError("Instance space must be provided for dataset-based annotation migration.")
293
+ asset_centric_selector = selector.as_asset_centric_selector()
294
+ for data_chunk in self.annotation_io.stream_data(asset_centric_selector, limit):
295
+ mapping_list = AssetCentricMappingList[Annotation]([])
296
+ for resource in data_chunk.items:
297
+ if resource.annotation_type not in self.SUPPORTED_ANNOTATION_TYPES:
298
+ # This should not happen, as the annotation_io should already filter these out.
299
+ # This is just in case.
300
+ continue
301
+ mapping = AnnotationMapping(
302
+ instance_id=EdgeId(space=self.instance_space, external_id=f"annotation_{resource.id!r}"),
303
+ id=resource.id,
304
+ ingestion_view=self._get_mapping(selector.ingestion_mapping, resource),
305
+ preferred_consumer_view=selector.preferred_consumer_view,
306
+ # The PySDK is poorly typed.
307
+ annotation_type=resource.annotation_type, # type: ignore[arg-type]
308
+ )
309
+ mapping_list.append(AssetCentricMapping(mapping=mapping, resource=resource))
310
+ yield mapping_list
311
+
312
+ def _stream_from_csv(
313
+ self, selector: MigrationCSVFileSelector, limit: int | None = None
314
+ ) -> Iterator[Sequence[AssetCentricMapping[Annotation]]]:
315
+ items = selector.items
316
+ if limit is not None:
317
+ items = MigrationMappingList(items[:limit])
318
+ chunk: list[AssetCentricMapping[Annotation]] = []
319
+ for current_batch in chunker_sequence(items, self.CHUNK_SIZE):
320
+ resources = self.client.annotations.retrieve_multiple(current_batch.get_ids())
321
+ resources_by_id = {resource.id: resource for resource in resources}
322
+ not_found = 0
323
+ incorrect_type_count = 0
324
+ for mapping in current_batch:
325
+ resource = resources_by_id.get(mapping.id)
326
+ if resource is None:
327
+ not_found += 1
328
+ continue
329
+ if resource.annotation_type not in self.SUPPORTED_ANNOTATION_TYPES:
330
+ incorrect_type_count += 1
331
+ continue
332
+ mapping.ingestion_view = self._get_mapping(mapping.ingestion_view, resource)
333
+ chunk.append(AssetCentricMapping(mapping=mapping, resource=resource))
334
+ if chunk:
335
+ yield chunk
336
+ chunk = []
337
+ if not_found:
338
+ MediumSeverityWarning(
339
+ f"Could not find {not_found} annotations referenced in the CSV file. They will be skipped during migration."
340
+ ).print_warning(include_timestamp=True, console=self.client.console)
341
+ if incorrect_type_count:
342
+ MediumSeverityWarning(
343
+ f"Found {incorrect_type_count} annotations with unsupported types. Only 'diagrams.AssetLink' and "
344
+ "'diagrams.FileLink' are supported. These annotations will be skipped during migration."
345
+ ).print_warning(include_timestamp=True, console=self.client.console)
346
+
347
+ def _get_mapping(self, current_mapping: str | None, resource: Annotation) -> str:
348
+ try:
349
+ return (
350
+ current_mapping
351
+ or {
352
+ "diagrams.AssetLink": self.default_asset_annotation_mapping,
353
+ "diagrams.FileLink": self.default_file_annotation_mapping,
354
+ }[resource.annotation_type]
355
+ )
356
+ except KeyError as e:
357
+ raise ToolkitValueError(
358
+ f"Could not determine default ingestion view for annotation type '{resource.annotation_type}'. "
359
+ "Please specify the ingestion view explicitly in the CSV file."
360
+ ) from e
361
+
362
+ def json_to_resource(self, item_json: dict[str, JsonVal]) -> InstanceApply:
363
+ raise NotImplementedError("Deserializing Annotation Migrations from JSON is not supported.")
364
+
365
+ def data_to_json_chunk(
366
+ self,
367
+ data_chunk: Sequence[AssetCentricMapping[Annotation]],
368
+ selector: AssetCentricMigrationSelector | None = None,
369
+ ) -> list[dict[str, JsonVal]]:
370
+ raise NotImplementedError("Serializing Annotation Migrations to JSON is not supported.")
371
+
372
+
373
+ class ThreeDMigrationIO(UploadableStorageIO[ThreeDSelector, ThreeDModelResponse, ThreeDMigrationRequest]):
374
+ """IO class for downloading and migrating 3D models.
375
+
376
+ Args:
377
+ client: The ToolkitClient to use for CDF interactions.
378
+ data_model_type: The type of 3D data model to download. Either "classic" or "DM".
379
+
380
+ """
381
+
382
+ KIND = "3DMigration"
383
+ SUPPORTED_DOWNLOAD_FORMATS = frozenset({".ndjson"})
384
+ SUPPORTED_COMPRESSIONS = frozenset({".gz"})
385
+ SUPPORTED_READ_FORMATS = frozenset({".ndjson"})
386
+ DOWNLOAD_LIMIT = 1000
387
+ CHUNK_SIZE = 1
388
+ UPLOAD_ENDPOINT = "/3d/migrate/models"
389
+ REVISION_ENDPOINT = "/3d/migrate/revisions"
390
+
391
+ def __init__(self, client: ToolkitClient, data_model_type: Literal["classic", "data modeling"] = "classic") -> None:
392
+ super().__init__(client)
393
+ self.data_model_type = data_model_type
394
+
395
+ def as_id(self, item: ThreeDModelResponse) -> str:
396
+ return f"{item.name}_{item.id!s}"
397
+
398
+ def _is_selected(self, item: ThreeDModelResponse, included_models: set[int] | None) -> bool:
399
+ return self._is_correct_type(item) and (included_models is None or item.id in included_models)
400
+
401
+ def _is_correct_type(self, item: ThreeDModelResponse) -> bool:
402
+ if self.data_model_type == "classic":
403
+ return item.space is None
404
+ else:
405
+ return item.space is not None
406
+
407
+ def stream_data(self, selector: ThreeDSelector, limit: int | None = None) -> Iterable[Page[ThreeDModelResponse]]:
408
+ published: bool | None = None
409
+ if isinstance(selector, ThreeDModelFilteredSelector):
410
+ published = selector.published
411
+ included_models: set[int] | None = None
412
+ if isinstance(selector, ThreeDModelIdSelector):
413
+ included_models = set(selector.ids)
414
+ cursor: str | None = None
415
+ total = 0
416
+ while True:
417
+ request_limit = min(self.DOWNLOAD_LIMIT, limit - total) if limit is not None else self.DOWNLOAD_LIMIT
418
+ response = self.client.tool.three_d.models.iterate(
419
+ published=published, include_revision_info=True, limit=request_limit, cursor=cursor
420
+ )
421
+ items = [item for item in response.items if self._is_selected(item, included_models)]
422
+ total += len(items)
423
+ if items:
424
+ yield Page(worker_id="main", items=items, next_cursor=response.next_cursor)
425
+ if response.next_cursor is None:
426
+ break
427
+ cursor = response.next_cursor
428
+
429
+ def count(self, selector: ThreeDSelector) -> int | None:
430
+ # There is no efficient way to count 3D models in CDF.
431
+ return None
432
+
433
+ def data_to_json_chunk(
434
+ self, data_chunk: Sequence[ThreeDModelResponse], selector: ThreeDSelector | None = None
435
+ ) -> list[dict[str, JsonVal]]:
436
+ raise NotImplementedError("Deserializing Annotation Migrations from JSON is not supported.")
437
+
438
+ def json_to_resource(self, item_json: dict[str, JsonVal]) -> ThreeDMigrationRequest:
439
+ raise NotImplementedError("Deserializing ThreeD Migrations from JSON is not supported.")
440
+
441
+ def upload_items(
442
+ self,
443
+ data_chunk: Sequence[UploadItem[ThreeDMigrationRequest]],
444
+ http_client: HTTPClient,
445
+ selector: ThreeDSelector | None = None,
446
+ ) -> Sequence[HTTPMessage]:
447
+ """Migrate 3D models by uploading them to the migrate/models endpoint."""
448
+ if len(data_chunk) > self.CHUNK_SIZE:
449
+ raise RuntimeError(f"Uploading more than {self.CHUNK_SIZE} 3D models at a time is not supported.")
450
+
451
+ results: list[HTTPMessage] = []
452
+ responses = http_client.request_with_retries(
453
+ message=ItemsRequest(
454
+ endpoint_url=self.client.config.create_api_url(self.UPLOAD_ENDPOINT),
455
+ method="POST",
456
+ items=list(data_chunk),
457
+ )
458
+ )
459
+ if (
460
+ failed_response := next((res for res in responses if isinstance(res, FailedResponse)), None)
461
+ ) and failed_response.status_code == 400:
462
+ raise ToolkitAPIError("3D model migration failed. You need to enable the 3D migration alpha feature flag.")
463
+
464
+ results.extend(responses)
465
+ success_ids = {id for res in responses if isinstance(res, SuccessResponseItems) for id in res.ids}
466
+ for data in data_chunk:
467
+ if data.source_id not in success_ids:
468
+ continue
469
+ revision = http_client.request_with_retries(
470
+ message=SimpleBodyRequest(
471
+ endpoint_url=self.client.config.create_api_url(self.REVISION_ENDPOINT),
472
+ method="POST",
473
+ body_content={"items": [data.item.revision.dump(camel_case=True)]},
474
+ )
475
+ )
476
+ results.extend(revision.as_item_responses(data.source_id))
477
+ return results
478
+
479
+
480
+ class ThreeDAssetMappingMigrationIO(UploadableStorageIO[ThreeDSelector, AssetMappingResponse, AssetMappingDMRequest]):
481
+ KIND = "3DMigrationAssetMapping"
482
+ SUPPORTED_DOWNLOAD_FORMATS = frozenset({".ndjson"})
483
+ SUPPORTED_COMPRESSIONS = frozenset({".gz"})
484
+ SUPPORTED_READ_FORMATS = frozenset({".ndjson"})
485
+ DOWNLOAD_LIMIT = 1000
486
+ CHUNK_SIZE = 100
487
+ UPLOAD_ENDPOINT = "/3d/models/{modelId}/revisions/{revisionId}/mappings"
488
+
489
+ def __init__(self, client: ToolkitClient, object_3D_space: str, cad_node_space: str) -> None:
490
+ super().__init__(client)
491
+ self.object_3D_space = object_3D_space
492
+ self.cad_node_space = cad_node_space
493
+ # We can only migrate asset mappings for 3D models that are already migrated to data modeling.
494
+ self._3D_io = ThreeDMigrationIO(client, data_model_type="data modeling")
495
+
496
+ def as_id(self, item: AssetMappingResponse) -> str:
497
+ return f"AssetMapping_{item.model_id!s}_{item.revision_id!s}_{item.asset_id!s}"
498
+
499
+ def stream_data(self, selector: ThreeDSelector, limit: int | None = None) -> Iterable[Page[AssetMappingResponse]]:
500
+ total = 0
501
+ for three_d_page in self._3D_io.stream_data(selector, None):
502
+ for model in three_d_page.items:
503
+ if model.last_revision_info is None or model.last_revision_info.revision_id is None:
504
+ # No revisions, so no asset mappings to
505
+ continue
506
+ cursor: str | None = None
507
+ while True:
508
+ request_limit = (
509
+ min(self.DOWNLOAD_LIMIT, limit - total) if limit is not None else self.DOWNLOAD_LIMIT
510
+ )
511
+ if limit is not None and total >= limit:
512
+ return
513
+ response = self.client.tool.three_d.asset_mappings.iterate(
514
+ model_id=model.id,
515
+ revision_id=model.last_revision_info.revision_id,
516
+ cursor=cursor,
517
+ limit=request_limit,
518
+ )
519
+ items = response.items
520
+ total += len(items)
521
+ if items:
522
+ yield Page(worker_id="main", items=items, next_cursor=response.next_cursor)
523
+ if response.next_cursor is None:
524
+ break
525
+ cursor = response.next_cursor
526
+
527
+ def count(self, selector: ThreeDSelector) -> int | None:
528
+ # There is no efficient way to count 3D asset mappings in CDF.
529
+ return None
530
+
531
+ def upload_items(
532
+ self,
533
+ data_chunk: Sequence[UploadItem[AssetMappingDMRequest]],
534
+ http_client: HTTPClient,
535
+ selector: T_Selector | None = None,
536
+ ) -> Sequence[HTTPMessage]:
537
+ """Migrate 3D asset mappings by uploading them to the migrate/asset-mappings endpoint."""
538
+ if not data_chunk:
539
+ return []
540
+ # Assume all items in the chunk belong to the same model and revision, they should
541
+ # if the .stream_data method is used for downloading.
542
+ first = data_chunk[0]
543
+ model_id = first.item.model_id
544
+ revision_id = first.item.revision_id
545
+ endpoint = self.UPLOAD_ENDPOINT.format(modelId=model_id, revisionId=revision_id)
546
+ responses = http_client.request_with_retries(
547
+ ItemsRequest(
548
+ endpoint_url=self.client.config.create_api_url(endpoint),
549
+ method="POST",
550
+ items=list(data_chunk),
551
+ extra_body_fields={
552
+ "dmsContextualizationConfig": {
553
+ "object3DSpace": self.object_3D_space,
554
+ "cadNodeSpace": self.cad_node_space,
555
+ }
556
+ },
557
+ )
558
+ )
559
+ return responses
560
+
561
+ def json_to_resource(self, item_json: dict[str, JsonVal]) -> AssetMappingDMRequest:
562
+ raise NotImplementedError("Deserializing 3D Asset Mappings from JSON is not supported.")
563
+
564
+ def data_to_json_chunk(
565
+ self, data_chunk: Sequence[AssetMappingResponse], selector: ThreeDSelector | None = None
566
+ ) -> list[dict[str, JsonVal]]:
567
+ raise NotImplementedError("Serializing 3D Asset Mappings to JSON is not supported.")
@@ -8,11 +8,11 @@ from cognite.client.data_classes.data_modeling import ViewId
8
8
  from cognite_toolkit._cdf_tk.commands._migrate.data_classes import MigrationMappingList
9
9
  from cognite_toolkit._cdf_tk.storageio import DataSelector
10
10
  from cognite_toolkit._cdf_tk.storageio.selectors import DataSetSelector
11
- from cognite_toolkit._cdf_tk.utils.useful_types import AssetCentricKind
11
+ from cognite_toolkit._cdf_tk.utils.useful_types import AssetCentricKindExtended
12
12
 
13
13
 
14
14
  class AssetCentricMigrationSelector(DataSelector, ABC):
15
- kind: AssetCentricKind
15
+ kind: AssetCentricKindExtended
16
16
 
17
17
  @abstractmethod
18
18
  def get_ingestion_mappings(self) -> list[str]:
@@ -41,7 +41,7 @@ class MigrationCSVFileSelector(AssetCentricMigrationSelector):
41
41
 
42
42
  class MigrateDataSetSelector(AssetCentricMigrationSelector):
43
43
  type: Literal["migrateDataSet"] = "migrateDataSet"
44
- kind: AssetCentricKind
44
+ kind: AssetCentricKindExtended
45
45
  data_set_external_id: str
46
46
  ingestion_mapping: str | None = None
47
47
  preferred_consumer_view: ViewId | None = None
@@ -63,4 +63,9 @@ class MigrateDataSetSelector(AssetCentricMigrationSelector):
63
63
  return [self.ingestion_mapping] if self.ingestion_mapping else []
64
64
 
65
65
  def as_asset_centric_selector(self) -> DataSetSelector:
66
- return DataSetSelector(data_set_external_id=self.data_set_external_id, kind=self.kind)
66
+ if self.kind == "Annotations":
67
+ # Annotations are connected to file metadata, so we need to download the file metadata
68
+ # and look up the annotations connected to each file metadata.
69
+ return DataSetSelector(data_set_external_id=self.data_set_external_id, kind="FileMetadata")
70
+ else:
71
+ return DataSetSelector(data_set_external_id=self.data_set_external_id, kind=self.kind)
@@ -21,7 +21,7 @@ from rich.spinner import Spinner
21
21
  from rich.table import Table
22
22
 
23
23
  from cognite_toolkit._cdf_tk.client import ToolkitClient
24
- from cognite_toolkit._cdf_tk.client.data_classes.raw import RawProfileResults, RawTable
24
+ from cognite_toolkit._cdf_tk.client.data_classes.legacy.raw import RawProfileResults, RawTable
25
25
  from cognite_toolkit._cdf_tk.constants import MAX_ROW_ITERATION_RUN_QUERY
26
26
  from cognite_toolkit._cdf_tk.exceptions import ToolkitMissingDependencyError, ToolkitThrottledError, ToolkitValueError
27
27
  from cognite_toolkit._cdf_tk.utils.aggregators import (
@@ -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
@@ -21,6 +16,7 @@ from rich.console import Console
21
16
  from rich.panel import Panel
22
17
 
23
18
  from cognite_toolkit._cdf_tk.client import ToolkitClient
19
+ from cognite_toolkit._cdf_tk.client.data_classes.instance_api import TypedInstanceIdentifier
24
20
  from cognite_toolkit._cdf_tk.cruds import (
25
21
  AssetCRUD,
26
22
  ContainerCRUD,
@@ -46,6 +42,7 @@ from cognite_toolkit._cdf_tk.exceptions import (
46
42
  AuthorizationError,
47
43
  ToolkitMissingResourceError,
48
44
  )
45
+ from cognite_toolkit._cdf_tk.protocols import ResourceResponseProtocol
49
46
  from cognite_toolkit._cdf_tk.storageio import InstanceIO
50
47
  from cognite_toolkit._cdf_tk.storageio.selectors import InstanceSelector
51
48
  from cognite_toolkit._cdf_tk.tk_warnings import (
@@ -63,10 +60,10 @@ from cognite_toolkit._cdf_tk.utils.aggregators import (
63
60
  TimeSeriesAggregator,
64
61
  )
65
62
  from cognite_toolkit._cdf_tk.utils.http_client import (
66
- FailedRequestItems,
67
- FailedResponseItems,
68
63
  HTTPClient,
69
64
  ItemsRequest,
65
+ ItemsRequest2,
66
+ ItemsSuccessResponse2,
70
67
  SuccessResponseItems,
71
68
  )
72
69
  from cognite_toolkit._cdf_tk.utils.producer_worker import ProducerWorkerExecutor
@@ -107,7 +104,7 @@ class ToDelete(ABC):
107
104
  @abstractmethod
108
105
  def get_process_function(
109
106
  self, client: ToolkitClient, console: Console, verbose: bool, process_results: ResourceDeployResult
110
- ) -> Callable[[CogniteResourceList], list[JsonVal]]:
107
+ ) -> Callable[[list[ResourceResponseProtocol]], list[JsonVal]]:
111
108
  raise NotImplementedError()
112
109
 
113
110
  def get_extra_fields(self) -> dict[str, JsonVal]:
@@ -118,9 +115,10 @@ class ToDelete(ABC):
118
115
  class DataModelingToDelete(ToDelete):
119
116
  def get_process_function(
120
117
  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]
118
+ ) -> Callable[[list[ResourceResponseProtocol]], list[JsonVal]]:
119
+ def as_id(chunk: list[ResourceResponseProtocol]) -> list[JsonVal]:
120
+ # We know that all data modeling resources implement as_id
121
+ return [item.as_id().dump(include_type=False) for item in chunk] # type: ignore[attr-defined]
124
122
 
125
123
  return as_id
126
124
 
@@ -129,11 +127,11 @@ class DataModelingToDelete(ToDelete):
129
127
  class EdgeToDelete(ToDelete):
130
128
  def get_process_function(
131
129
  self, client: ToolkitClient, console: Console, verbose: bool, process_results: ResourceDeployResult
132
- ) -> Callable[[CogniteResourceList], list[JsonVal]]:
133
- def as_id(chunk: CogniteResourceList) -> list[JsonVal]:
130
+ ) -> Callable[[list[ResourceResponseProtocol]], list[JsonVal]]:
131
+ def as_id(chunk: list[ResourceResponseProtocol]) -> list[JsonVal]:
134
132
  return [
135
133
  {"space": item.space, "externalId": item.external_id, "instanceType": "edge"}
136
- for item in cast(EdgeList, chunk)
134
+ for item in cast(list[Edge], chunk)
137
135
  ]
138
136
 
139
137
  return as_id
@@ -146,9 +144,10 @@ class NodesToDelete(ToDelete):
146
144
 
147
145
  def get_process_function(
148
146
  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()
147
+ ) -> Callable[[list[ResourceResponseProtocol]], list[JsonVal]]:
148
+ def check_for_data(chunk: list[ResourceResponseProtocol]) -> list[JsonVal]:
149
+ # We know that all node resources implement as_id
150
+ node_ids = [item.as_id() for item in chunk] # type: ignore[attr-defined]
152
151
  found_ids: set[InstanceId] = set()
153
152
  if not self.delete_datapoints:
154
153
  timeseries = client.time_series.retrieve_multiple(instance_ids=node_ids, ignore_unknown_ids=True)
@@ -164,8 +163,7 @@ class NodesToDelete(ToDelete):
164
163
  dumped = node_id.dump(include_instance_type=True)
165
164
  # The delete endpoint expects "instanceType" instead of "type"
166
165
  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]
166
+ result.append(dumped)
169
167
  return result
170
168
 
171
169
  return check_for_data
@@ -175,9 +173,10 @@ class NodesToDelete(ToDelete):
175
173
  class IdResourceToDelete(ToDelete):
176
174
  def get_process_function(
177
175
  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]
176
+ ) -> Callable[[list[ResourceResponseProtocol]], list[JsonVal]]:
177
+ def as_id(chunk: list[ResourceResponseProtocol]) -> list[JsonVal]:
178
+ # We know that all id resources have an id attribute
179
+ return [{"id": item.id} for item in chunk] # type: ignore[attr-defined]
181
180
 
182
181
  return as_id
183
182
 
@@ -186,9 +185,10 @@ class IdResourceToDelete(ToDelete):
186
185
  class ExternalIdToDelete(ToDelete):
187
186
  def get_process_function(
188
187
  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]
188
+ ) -> Callable[[list[ResourceResponseProtocol]], list[JsonVal]]:
189
+ def as_external_id(chunk: list[ResourceResponseProtocol]) -> list[JsonVal]:
190
+ # We know that all external id resources have an external_id attribute
191
+ return [{"externalId": item.external_id} for item in chunk] # type: ignore[attr-defined]
192
192
 
193
193
  return as_external_id
194
194
 
@@ -321,7 +321,7 @@ class PurgeCommand(ToolkitCommand):
321
321
  iteration_count = item.total // self.BATCH_SIZE_DM + (
322
322
  1 if item.total % self.BATCH_SIZE_DM > 0 else 0
323
323
  )
324
- executor = ProducerWorkerExecutor[CogniteResourceList, list[JsonVal]](
324
+ executor = ProducerWorkerExecutor[list[ResourceResponseProtocol], list[JsonVal]](
325
325
  download_iterable=self._iterate_batch(
326
326
  item.crud, space, data_set_external_id, batch_size=self.BATCH_SIZE_DM
327
327
  ),
@@ -348,13 +348,13 @@ class PurgeCommand(ToolkitCommand):
348
348
  @staticmethod
349
349
  def _iterate_batch(
350
350
  crud: ResourceCRUD, selected_space: str | None, data_set_external_id: str | None, batch_size: int
351
- ) -> Iterable[CogniteResourceList]:
352
- batch = crud.list_cls([])
351
+ ) -> Iterable[list[ResourceResponseProtocol]]:
352
+ batch: list[ResourceResponseProtocol] = []
353
353
  for resource in crud.iterate(space=selected_space, data_set_external_id=data_set_external_id):
354
354
  batch.append(resource)
355
355
  if len(batch) >= batch_size:
356
356
  yield batch
357
- batch = crud.list_cls([])
357
+ batch = []
358
358
  if batch:
359
359
  yield batch
360
360
 
@@ -715,21 +715,18 @@ class PurgeCommand(ToolkitCommand):
715
715
  results.deleted += len(items)
716
716
  return
717
717
 
718
- responses = delete_client.request_with_retries(
719
- ItemsRequest(
720
- delete_client.config.create_api_url("/models/instances/delete"),
718
+ responses = delete_client.request_items_retries(
719
+ ItemsRequest2(
720
+ endpoint_url=delete_client.config.create_api_url("/models/instances/delete"),
721
721
  method="POST",
722
- # MyPy does not understand that InstanceId.load handles dict[str, JsonVal]
723
- items=[DeleteItem(item=item, as_id_fun=InstanceId.load) for item in items], # type: ignore[arg-type]
722
+ items=[TypedInstanceIdentifier._load(item) for item in items],
724
723
  )
725
724
  )
726
725
  for response in responses:
727
- if isinstance(response, SuccessResponseItems):
726
+ if isinstance(response, ItemsSuccessResponse2):
728
727
  results.deleted += len(response.ids)
729
- elif isinstance(response, FailedResponseItems | FailedRequestItems):
730
- results.failed += len(response.ids)
731
728
  else:
732
- results.failed += len(items)
729
+ results.failed += len(response.ids)
733
730
 
734
731
  @staticmethod
735
732
  def _unlink_timeseries(
@@ -0,0 +1,16 @@
1
+ import questionary
2
+
3
+ custom_style_fancy = questionary.Style(
4
+ [
5
+ ("qmark", "fg:#673ab7"), # token in front of the question
6
+ ("question", "bold"), # question text
7
+ ("answer", "fg:#f44336 bold"), # submitted answer text behind the question
8
+ ("pointer", "fg:#673ab7 bold"), # pointer used in select and checkbox prompts
9
+ ("highlighted", "fg:#673ab7 bold"), # pointed-at choice in select and checkbox prompts
10
+ ("selected", "fg:#673ab7"), # style for a selected item of a checkbox
11
+ ("separator", "fg:#cc5454"), # separator in lists
12
+ ("instruction", ""), # user instructions for select, rawselect, checkbox
13
+ ("text", ""), # plain text
14
+ ("disabled", "fg:#858585 italic"), # disabled choices for select and checkbox prompts
15
+ ]
16
+ )