cognite-toolkit 0.7.32__py3-none-any.whl → 0.7.33__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.
@@ -15,10 +15,16 @@ from cognite_toolkit._cdf_tk.commands._migrate.creators import (
15
15
  InstanceSpaceCreator,
16
16
  SourceSystemCreator,
17
17
  )
18
- from cognite_toolkit._cdf_tk.commands._migrate.data_mapper import AssetCentricMapper, CanvasMapper, ChartMapper
18
+ from cognite_toolkit._cdf_tk.commands._migrate.data_mapper import (
19
+ AssetCentricMapper,
20
+ CanvasMapper,
21
+ ChartMapper,
22
+ ThreeDMapper,
23
+ )
19
24
  from cognite_toolkit._cdf_tk.commands._migrate.migration_io import (
20
25
  AnnotationMigrationIO,
21
26
  AssetCentricMigrationIO,
27
+ ThreeDMigrationIO,
22
28
  )
23
29
  from cognite_toolkit._cdf_tk.commands._migrate.selectors import (
24
30
  AssetCentricMigrationSelector,
@@ -26,7 +32,11 @@ from cognite_toolkit._cdf_tk.commands._migrate.selectors import (
26
32
  MigrationCSVFileSelector,
27
33
  )
28
34
  from cognite_toolkit._cdf_tk.storageio import CanvasIO, ChartIO
29
- from cognite_toolkit._cdf_tk.storageio.selectors import CanvasExternalIdSelector, ChartExternalIdSelector
35
+ from cognite_toolkit._cdf_tk.storageio.selectors import (
36
+ CanvasExternalIdSelector,
37
+ ChartExternalIdSelector,
38
+ ThreeDModelIdSelector,
39
+ )
30
40
  from cognite_toolkit._cdf_tk.utils.auth import EnvironmentVariables
31
41
  from cognite_toolkit._cdf_tk.utils.cli_args import parse_view_str
32
42
  from cognite_toolkit._cdf_tk.utils.interactive_select import (
@@ -36,6 +46,7 @@ from cognite_toolkit._cdf_tk.utils.interactive_select import (
36
46
  InteractiveCanvasSelect,
37
47
  InteractiveChartSelect,
38
48
  ResourceViewMappingInteractiveSelect,
49
+ ThreeDInteractiveSelect,
39
50
  )
40
51
  from cognite_toolkit._cdf_tk.utils.useful_types import AssetCentricKind
41
52
 
@@ -56,6 +67,7 @@ class MigrateApp(typer.Typer):
56
67
  self.command("annotations")(self.annotations)
57
68
  self.command("canvas")(self.canvas)
58
69
  self.command("charts")(self.charts)
70
+ self.command("3d")(self.three_d)
59
71
  # Uncomment when infield v2 config migration is ready
60
72
  # self.command("infield-configs")(self.infield_configs)
61
73
 
@@ -980,6 +992,68 @@ class MigrateApp(typer.Typer):
980
992
  )
981
993
  )
982
994
 
995
+ @staticmethod
996
+ def three_d(
997
+ ctx: typer.Context,
998
+ id: Annotated[
999
+ list[int] | None,
1000
+ typer.Argument(
1001
+ help="The ID of the 3D Model to migrate. If not provided, an interactive selection will be "
1002
+ "performed to select the 3D Models to migrate."
1003
+ ),
1004
+ ] = None,
1005
+ log_dir: Annotated[
1006
+ Path,
1007
+ typer.Option(
1008
+ "--log-dir",
1009
+ "-l",
1010
+ help="Path to the directory where migration logs will be stored.",
1011
+ ),
1012
+ ] = Path(f"migration_logs_{TODAY}"),
1013
+ dry_run: Annotated[
1014
+ bool,
1015
+ typer.Option(
1016
+ "--dry-run",
1017
+ "-d",
1018
+ help="If set, the migration will not be executed, but only a report of "
1019
+ "what would be done is printed. This is useful for checking that all resources referenced by the 3D Models "
1020
+ "have been migrated to the new data modeling resources in CDF.",
1021
+ ),
1022
+ ] = False,
1023
+ verbose: Annotated[
1024
+ bool,
1025
+ typer.Option(
1026
+ "--verbose",
1027
+ "-v",
1028
+ help="Turn on to get more verbose output when running the command",
1029
+ ),
1030
+ ] = False,
1031
+ ) -> None:
1032
+ """Migrate 3D Models from Asset-Centric to data modeling in CDF.
1033
+
1034
+ This command expects that the CogniteMigration data model is already deployed, and that the Mapping view
1035
+ is populated with the mapping from Asset-Centric resources to the new data modeling resources.
1036
+ """
1037
+ client = EnvironmentVariables.create_from_environment().get_client()
1038
+ selected_ids: list[int]
1039
+ if id:
1040
+ selected_ids = id
1041
+ else:
1042
+ selected_models = ThreeDInteractiveSelect(client, "migrate").select_three_d_models("classic")
1043
+ selected_ids = [model.id for model in selected_models]
1044
+
1045
+ cmd = MigrationCommand()
1046
+ cmd.run(
1047
+ lambda: cmd.migrate(
1048
+ selected=ThreeDModelIdSelector(ids=tuple(selected_ids)),
1049
+ data=ThreeDMigrationIO(client),
1050
+ mapper=ThreeDMapper(client),
1051
+ log_dir=log_dir,
1052
+ dry_run=dry_run,
1053
+ verbose=verbose,
1054
+ )
1055
+ )
1056
+
983
1057
  @staticmethod
984
1058
  def infield_configs(
985
1059
  ctx: typer.Context,
@@ -1,19 +1,72 @@
1
+ from collections.abc import Sequence
2
+
1
3
  from rich.console import Console
2
4
 
3
5
  from cognite_toolkit._cdf_tk.client.data_classes.api_classes import PagedResponse
4
- from cognite_toolkit._cdf_tk.client.data_classes.three_d import ThreeDModelResponse
5
- from cognite_toolkit._cdf_tk.utils.http_client import HTTPClient, RequestMessage2
6
+ from cognite_toolkit._cdf_tk.client.data_classes.three_d import ThreeDModelClassicRequest, ThreeDModelResponse
7
+ from cognite_toolkit._cdf_tk.utils.http_client import (
8
+ HTTPClient,
9
+ ItemsRequest,
10
+ RequestMessage2,
11
+ SimpleBodyRequest,
12
+ )
6
13
  from cognite_toolkit._cdf_tk.utils.useful_types import PrimitiveType
7
14
 
8
15
 
9
16
  class ThreeDModelAPI:
10
17
  ENDPOINT = "/3d/models"
18
+ MAX_CLASSIC_MODELS_PER_CREATE_REQUEST = 1000
19
+ MAX_MODELS_PER_DELETE_REQUEST = 1000
20
+ _LIST_REQUEST_MAX_LIMIT = 1000
11
21
 
12
22
  def __init__(self, http_client: HTTPClient, console: Console) -> None:
13
23
  self._http_client = http_client
14
24
  self._console = console
15
25
  self._config = http_client.config
16
26
 
27
+ def create(self, models: Sequence[ThreeDModelClassicRequest]) -> list[ThreeDModelResponse]:
28
+ """Create 3D models in classic format.
29
+
30
+ Args:
31
+ models (Sequence[ThreeDModelClassicRequest]): The 3D model(s) to create.
32
+
33
+ Returns:
34
+ list[ThreeDModelResponse]: The created 3D model(s).
35
+ """
36
+ if not models:
37
+ return []
38
+ if len(models) > self.MAX_CLASSIC_MODELS_PER_CREATE_REQUEST:
39
+ raise ValueError("Cannot create more than 1000 3D models in a single request.")
40
+ responses = self._http_client.request_with_retries(
41
+ ItemsRequest(
42
+ endpoint_url=self._config.create_api_url(self.ENDPOINT),
43
+ method="POST",
44
+ items=list(models),
45
+ )
46
+ )
47
+ responses.raise_for_status()
48
+ body = responses.get_first_body()
49
+ return PagedResponse[ThreeDModelResponse].model_validate(body).items
50
+
51
+ def delete(self, ids: Sequence[int]) -> None:
52
+ """Delete 3D models by their IDs.
53
+
54
+ Args:
55
+ ids (Sequence[int]): The IDs of the 3D models to delete.
56
+ """
57
+ if not ids:
58
+ return None
59
+ if len(ids) > self.MAX_MODELS_PER_DELETE_REQUEST:
60
+ raise ValueError("Cannot delete more than 1000 3D models in a single request.")
61
+ responses = self._http_client.request_with_retries(
62
+ SimpleBodyRequest(
63
+ endpoint_url=self._config.create_api_url(self.ENDPOINT + "/delete"),
64
+ method="POST",
65
+ body_content={"items": [{"id": id_} for id_ in ids]},
66
+ )
67
+ )
68
+ responses.raise_for_status()
69
+
17
70
  def iterate(
18
71
  self,
19
72
  published: bool | None = None,
@@ -21,8 +74,8 @@ class ThreeDModelAPI:
21
74
  limit: int = 100,
22
75
  cursor: str | None = None,
23
76
  ) -> PagedResponse[ThreeDModelResponse]:
24
- if not (0 < limit <= 1000):
25
- raise ValueError("Limit must be between 1 and 1000.")
77
+ if not (0 < limit <= self._LIST_REQUEST_MAX_LIMIT):
78
+ raise ValueError(f"Limit must be between 1 and {self._LIST_REQUEST_MAX_LIMIT}, got {limit}.")
26
79
  parameters: dict[str, PrimitiveType] = {
27
80
  # There is a bug in the API. The parameter includeRevisionInfo is expected to be lower case and not
28
81
  # camel case as documented. You get error message: Unrecognized query parameter includeRevisionInfo,
@@ -44,6 +97,34 @@ class ThreeDModelAPI:
44
97
  success_response = responses.get_success_or_raise()
45
98
  return PagedResponse[ThreeDModelResponse].model_validate(success_response.body_json)
46
99
 
100
+ def list(
101
+ self,
102
+ published: bool | None = None,
103
+ include_revision_info: bool = False,
104
+ limit: int | None = 100,
105
+ cursor: str | None = None,
106
+ ) -> list[ThreeDModelResponse]:
107
+ results: list[ThreeDModelResponse] = []
108
+ while True:
109
+ request_limit = (
110
+ self._LIST_REQUEST_MAX_LIMIT
111
+ if limit is None
112
+ else min(limit - len(results), self._LIST_REQUEST_MAX_LIMIT)
113
+ )
114
+ if request_limit <= 0:
115
+ break
116
+ page = self.iterate(
117
+ published=published,
118
+ include_revision_info=include_revision_info,
119
+ limit=request_limit,
120
+ cursor=cursor,
121
+ )
122
+ results.extend(page.items)
123
+ if page.next_cursor is None:
124
+ break
125
+ cursor = page.next_cursor
126
+ return results
127
+
47
128
 
48
129
  class ThreeDAPI:
49
130
  def __init__(self, http_client: HTTPClient, console: Console) -> None:
@@ -26,6 +26,10 @@ class ResponseResource(BaseModelObject, Generic[T_RequestResource], ABC):
26
26
  """Convert the response resource to a request resource."""
27
27
  ...
28
28
 
29
+ def as_write(self) -> T_RequestResource:
30
+ """Alias for as_request_resource to match protocol signature."""
31
+ return self.as_request_resource()
32
+
29
33
 
30
34
  class Identifier(BaseModel):
31
35
  """Base class for all identifier classes."""
@@ -7,7 +7,7 @@ from .base import BaseModelObject, Identifier, RequestResource
7
7
  InstanceType: TypeAlias = Literal["node", "edge"]
8
8
 
9
9
 
10
- class InstanceIdentifier(Identifier):
10
+ class TypedInstanceIdentifier(Identifier):
11
11
  """Identifier for an Instance instance."""
12
12
 
13
13
  instance_type: InstanceType
@@ -15,11 +15,16 @@ class InstanceIdentifier(Identifier):
15
15
  external_id: str
16
16
 
17
17
 
18
- class NodeIdentifier(InstanceIdentifier):
18
+ class InstanceIdentifier(Identifier):
19
+ space: str
20
+ external_id: str
21
+
22
+
23
+ class NodeIdentifier(TypedInstanceIdentifier):
19
24
  instance_type: Literal["node"] = "node"
20
25
 
21
26
 
22
- class EdgeIdentifier(InstanceIdentifier):
27
+ class EdgeIdentifier(TypedInstanceIdentifier):
23
28
  instance_type: Literal["edge"] = "edge"
24
29
 
25
30
 
@@ -32,8 +37,8 @@ class InstanceResult(BaseModelObject):
32
37
  created_time: int
33
38
  last_updated_time: int
34
39
 
35
- def as_id(self) -> InstanceIdentifier:
36
- return InstanceIdentifier(
40
+ def as_id(self) -> TypedInstanceIdentifier:
41
+ return TypedInstanceIdentifier(
37
42
  instance_type=self.instance_type,
38
43
  space=self.space,
39
44
  external_id=self.external_id,
@@ -62,8 +67,8 @@ class InstanceRequestResource(RequestResource):
62
67
  space: str
63
68
  external_id: str
64
69
 
65
- def as_id(self) -> InstanceIdentifier:
66
- return InstanceIdentifier(
70
+ def as_id(self) -> TypedInstanceIdentifier:
71
+ return TypedInstanceIdentifier(
67
72
  instance_type=self.instance_type,
68
73
  space=self.space,
69
74
  external_id=self.external_id,
@@ -115,8 +120,8 @@ class InstanceRequestItem(RequestResource):
115
120
  existing_version: int | None = None
116
121
  sources: list[InstanceSource] | None = None
117
122
 
118
- def as_id(self) -> InstanceIdentifier:
119
- return InstanceIdentifier(
123
+ def as_id(self) -> TypedInstanceIdentifier:
124
+ return TypedInstanceIdentifier(
120
125
  instance_type=self.instance_type,
121
126
  space=self.space,
122
127
  external_id=self.external_id,
@@ -128,7 +133,7 @@ class InstanceResponseItem(BaseModelObject):
128
133
  space: str
129
134
  external_id: str
130
135
  version: int
131
- type: InstanceIdentifier | None = None
136
+ type: TypedInstanceIdentifier | None = None
132
137
  created_time: int
133
138
  last_updated_time: int
134
139
  deleted_time: int | None = None
@@ -149,8 +154,8 @@ class InstanceResponseItem(BaseModelObject):
149
154
  output.update(space_properties.get(view_version, {}))
150
155
  return output
151
156
 
152
- def as_id(self) -> InstanceIdentifier:
153
- return InstanceIdentifier(
157
+ def as_id(self) -> TypedInstanceIdentifier:
158
+ return TypedInstanceIdentifier(
154
159
  instance_type=self.instance_type,
155
160
  space=self.space,
156
161
  external_id=self.external_id,
@@ -27,6 +27,9 @@ class ThreeDModelClassicRequest(ThreeDModelRequest):
27
27
  data_set_id: int | None = None
28
28
  metadata: dict[str, str] | None = None
29
29
 
30
+ def as_id(self) -> str:
31
+ return self.name
32
+
30
33
 
31
34
  class ThreeDModelDMSRequest(ThreeDModelRequest):
32
35
  space: str
@@ -13,6 +13,7 @@ from rich.console import Console
13
13
 
14
14
  from cognite_toolkit._cdf_tk.client._toolkit_client import ToolkitClient
15
15
 
16
+ from ._toolkit_client import ToolAPI
16
17
  from .api.canvas import CanvasAPI, IndustrialCanvasAPI
17
18
  from .api.charts import ChartsAPI
18
19
  from .api.dml import DMLAPI
@@ -53,6 +54,7 @@ from .api.robotics.maps import MapsAPI
53
54
  from .api.search import SearchAPI
54
55
  from .api.search_config import SearchConfigurationsAPI
55
56
  from .api.streams import StreamsAPI
57
+ from .api.three_d import ThreeDAPI, ThreeDModelAPI
56
58
  from .api.token import TokenAPI
57
59
  from .api.verify import VerifyAPI
58
60
 
@@ -131,6 +133,10 @@ class ToolkitClientMock(CogniteClientMock):
131
133
  self.time_series.data.synthetic = MagicMock(spec_set=SyntheticDatapointsAPI)
132
134
  self.time_series.subscriptions = MagicMock(spec_set=DatapointsSubscriptionAPI)
133
135
 
136
+ self.tool = MagicMock(spec=ToolAPI)
137
+ self.tool.three_d = MagicMock(spec=ThreeDAPI)
138
+ self.tool.three_d.models = MagicMock(spec_set=ThreeDModelAPI)
139
+
134
140
  self.streams = MagicMock(spec=StreamsAPI)
135
141
 
136
142
  # This is a helper API, not a real API.
@@ -9,8 +9,10 @@ from cognite.client.data_classes._base import (
9
9
  from cognite.client.data_classes.data_modeling import EdgeId, InstanceApply, NodeId, ViewId
10
10
  from cognite.client.utils._identifier import InstanceId
11
11
  from cognite.client.utils._text import to_camel_case
12
- from pydantic import BaseModel, BeforeValidator, field_validator, model_validator
12
+ from pydantic import BaseModel, BeforeValidator, Field, field_validator, model_validator
13
13
 
14
+ from cognite_toolkit._cdf_tk.client.data_classes.base import BaseModelObject, RequestResource
15
+ from cognite_toolkit._cdf_tk.client.data_classes.instance_api import InstanceIdentifier
14
16
  from cognite_toolkit._cdf_tk.client.data_classes.instances import InstanceApplyList
15
17
  from cognite_toolkit._cdf_tk.client.data_classes.migration import AssetCentricId
16
18
  from cognite_toolkit._cdf_tk.client.data_classes.pending_instances_ids import PendingInstanceId
@@ -261,3 +263,32 @@ class AssetCentricMappingList(
261
263
 
262
264
  def as_write(self) -> InstanceApplyList:
263
265
  return InstanceApplyList([item.as_write() for item in self])
266
+
267
+
268
+ class Model(BaseModelObject):
269
+ instance_id: InstanceIdentifier
270
+
271
+
272
+ class Thumbnail(BaseModelObject):
273
+ instance_id: InstanceIdentifier
274
+
275
+
276
+ class ThreeDRevisionMigrationRequest(RequestResource):
277
+ space: str
278
+ type: Literal["CAD", "PointCloud", "Image360"]
279
+ revision_id: int
280
+ model: Model
281
+
282
+ def as_id(self) -> int:
283
+ return self.revision_id
284
+
285
+
286
+ class ThreeDMigrationRequest(RequestResource):
287
+ model_id: int
288
+ type: Literal["CAD", "PointCloud", "Image360"]
289
+ space: str
290
+ thumbnail: Thumbnail | None = None
291
+ revision: ThreeDRevisionMigrationRequest = Field(exclude=True)
292
+
293
+ def as_id(self) -> int:
294
+ return self.model_id
@@ -1,7 +1,7 @@
1
1
  from abc import ABC, abstractmethod
2
2
  from collections import defaultdict
3
3
  from collections.abc import Callable, Sequence
4
- from typing import Generic, cast
4
+ from typing import Generic, Literal, cast
5
5
  from uuid import uuid4
6
6
 
7
7
  from cognite.client.data_classes.data_modeling import (
@@ -27,26 +27,33 @@ from cognite_toolkit._cdf_tk.client.data_classes.charts_data import (
27
27
  ChartSource,
28
28
  ChartTimeseries,
29
29
  )
30
+ from cognite_toolkit._cdf_tk.client.data_classes.instance_api import InstanceIdentifier
30
31
  from cognite_toolkit._cdf_tk.client.data_classes.migration import ResourceViewMappingApply
32
+ from cognite_toolkit._cdf_tk.client.data_classes.three_d import RevisionStatus, ThreeDModelResponse
31
33
  from cognite_toolkit._cdf_tk.commands._migrate.conversion import DirectRelationCache, asset_centric_to_dm
32
- from cognite_toolkit._cdf_tk.commands._migrate.data_classes import AssetCentricMapping
34
+ from cognite_toolkit._cdf_tk.commands._migrate.data_classes import (
35
+ Model,
36
+ ThreeDMigrationRequest,
37
+ ThreeDRevisionMigrationRequest,
38
+ )
33
39
  from cognite_toolkit._cdf_tk.commands._migrate.default_mappings import create_default_mappings
34
40
  from cognite_toolkit._cdf_tk.commands._migrate.issues import (
35
41
  CanvasMigrationIssue,
36
42
  ChartMigrationIssue,
37
43
  ConversionIssue,
38
44
  MigrationIssue,
45
+ ThreeDModelMigrationIssue,
39
46
  )
40
- from cognite_toolkit._cdf_tk.commands._migrate.selectors import AssetCentricMigrationSelector
41
47
  from cognite_toolkit._cdf_tk.constants import MISSING_INSTANCE_SPACE
42
48
  from cognite_toolkit._cdf_tk.exceptions import ToolkitMigrationError, ToolkitValueError
43
49
  from cognite_toolkit._cdf_tk.protocols import T_ResourceRequest, T_ResourceResponse
44
50
  from cognite_toolkit._cdf_tk.storageio._base import T_Selector
45
- from cognite_toolkit._cdf_tk.storageio.selectors import CanvasSelector, ChartSelector
51
+ from cognite_toolkit._cdf_tk.storageio.selectors import CanvasSelector, ChartSelector, ThreeDSelector
46
52
  from cognite_toolkit._cdf_tk.utils import humanize_collection
47
- from cognite_toolkit._cdf_tk.utils.useful_types import (
48
- T_AssetCentricResourceExtended,
49
- )
53
+ from cognite_toolkit._cdf_tk.utils.useful_types import T_AssetCentricResourceExtended
54
+
55
+ from .data_classes import AssetCentricMapping
56
+ from .selectors import AssetCentricMigrationSelector
50
57
 
51
58
 
52
59
  class DataMapper(Generic[T_Selector, T_ResourceResponse, T_ResourceRequest], ABC):
@@ -383,3 +390,82 @@ class CanvasMapper(DataMapper[CanvasSelector, IndustrialCanvas, IndustrialCanvas
383
390
  max_width=reference.max_width,
384
391
  max_height=reference.max_height,
385
392
  )
393
+
394
+
395
+ class ThreeDMapper(DataMapper[ThreeDSelector, ThreeDModelResponse, ThreeDMigrationRequest]):
396
+ def __init__(self, client: ToolkitClient) -> None:
397
+ self.client = client
398
+
399
+ def map(
400
+ self, source: Sequence[ThreeDModelResponse]
401
+ ) -> Sequence[tuple[ThreeDMigrationRequest | None, MigrationIssue]]:
402
+ self._populate_cache(source)
403
+ output: list[tuple[ThreeDMigrationRequest | None, MigrationIssue]] = []
404
+ for item in source:
405
+ mapped_item, issue = self._map_single_item(item)
406
+ output.append((mapped_item, issue))
407
+ return output
408
+
409
+ def _populate_cache(self, source: Sequence[ThreeDModelResponse]) -> None:
410
+ dataset_ids: set[int] = set()
411
+ for model in source:
412
+ if model.data_set_id is not None:
413
+ dataset_ids.add(model.data_set_id)
414
+ self.client.migration.space_source.retrieve(list(dataset_ids))
415
+
416
+ def _map_single_item(
417
+ self, item: ThreeDModelResponse
418
+ ) -> tuple[ThreeDMigrationRequest | None, ThreeDModelMigrationIssue]:
419
+ issue = ThreeDModelMigrationIssue(model_name=item.name, model_id=item.id)
420
+ instance_space: str | None = None
421
+ last_revision_id: int | None = None
422
+ model_type: Literal["CAD", "PointCloud", "Image360"] | None = None
423
+ if item.data_set_id is None:
424
+ issue.error_message.append("3D model is not associated with any dataset.")
425
+ else:
426
+ space_source = self.client.migration.space_source.retrieve(item.data_set_id)
427
+ if space_source is not None:
428
+ instance_space = space_source.instance_space
429
+ if instance_space is None and item.data_set_id is not None:
430
+ issue.error_message.append(f"Missing instance space for dataset ID {item.data_set_id!r}")
431
+ if item.last_revision_info is None:
432
+ issue.error_message.append("3D model has no revisions.")
433
+ else:
434
+ model_type = self._get_type(item.last_revision_info)
435
+ last_revision_id = item.last_revision_info.revision_id
436
+ if last_revision_id is None:
437
+ issue.error_message.append("3D model's last revision has no revision ID.")
438
+
439
+ if model_type is None:
440
+ issue.error_message.append("3D model's last revision has no recognized type.")
441
+
442
+ if instance_space is None or last_revision_id is None or model_type is None or issue.has_issues:
443
+ return None, issue
444
+
445
+ mapped_request = ThreeDMigrationRequest(
446
+ model_id=item.id,
447
+ type=model_type,
448
+ space=instance_space,
449
+ revision=ThreeDRevisionMigrationRequest(
450
+ space=instance_space,
451
+ type=model_type,
452
+ revision_id=last_revision_id,
453
+ model=Model(
454
+ instance_id=InstanceIdentifier(
455
+ space=instance_space,
456
+ external_id=f"cog_3d_model_{item.id!s}",
457
+ )
458
+ ),
459
+ ),
460
+ )
461
+ return mapped_request, issue
462
+
463
+ @staticmethod
464
+ def _get_type(revision: RevisionStatus) -> Literal["CAD", "PointCloud", "Image360"] | None:
465
+ types = revision.types or []
466
+ if any("gltf-directory" in t for t in types):
467
+ return "CAD"
468
+ elif any("ept-pointcloud" in t for t in types):
469
+ return "PointCloud"
470
+ else:
471
+ return None
@@ -30,6 +30,24 @@ class MigrationIssue(MigrationObject):
30
30
  return True
31
31
 
32
32
 
33
+ class ThreeDModelMigrationIssue(MigrationIssue):
34
+ """Represents a 3D model migration issue encountered during migration.
35
+
36
+ Attributes:
37
+ model_external_id (str): The external ID of the 3D model that could not be migrated.
38
+ """
39
+
40
+ type: ClassVar[str] = "threeDModelMigration"
41
+ model_name: str
42
+ model_id: int
43
+ error_message: list[str] = Field(default_factory=list)
44
+
45
+ @property
46
+ def has_issues(self) -> bool:
47
+ """Check if there are any issues recorded in this ThreeDModelMigrationIssue."""
48
+ return bool(self.error_message)
49
+
50
+
33
51
  class ChartMigrationIssue(MigrationIssue):
34
52
  """Represents a chart migration issue encountered during migration.
35
53
 
@@ -6,6 +6,8 @@ from cognite.client.data_classes.data_modeling import EdgeId, InstanceApply, Nod
6
6
 
7
7
  from cognite_toolkit._cdf_tk.client import ToolkitClient
8
8
  from cognite_toolkit._cdf_tk.client.data_classes.pending_instances_ids import PendingInstanceId
9
+ from cognite_toolkit._cdf_tk.client.data_classes.three_d import ThreeDModelResponse
10
+ from cognite_toolkit._cdf_tk.commands._migrate.data_classes import ThreeDMigrationRequest
9
11
  from cognite_toolkit._cdf_tk.constants import MISSING_EXTERNAL_ID, MISSING_INSTANCE_SPACE
10
12
  from cognite_toolkit._cdf_tk.exceptions import ToolkitNotImplementedError, ToolkitValueError
11
13
  from cognite_toolkit._cdf_tk.storageio import (
@@ -15,9 +17,22 @@ from cognite_toolkit._cdf_tk.storageio import (
15
17
  UploadableStorageIO,
16
18
  )
17
19
  from cognite_toolkit._cdf_tk.storageio._base import Page, UploadItem
20
+ from cognite_toolkit._cdf_tk.storageio.selectors import (
21
+ ThreeDModelFilteredSelector,
22
+ ThreeDModelIdSelector,
23
+ ThreeDSelector,
24
+ )
18
25
  from cognite_toolkit._cdf_tk.tk_warnings import MediumSeverityWarning
19
26
  from cognite_toolkit._cdf_tk.utils.collection import chunker_sequence
20
- from cognite_toolkit._cdf_tk.utils.http_client import HTTPClient, HTTPMessage, ItemsRequest, SuccessResponseItems
27
+ from cognite_toolkit._cdf_tk.utils.http_client import (
28
+ FailedResponse,
29
+ HTTPClient,
30
+ HTTPMessage,
31
+ ItemsRequest,
32
+ SimpleBodyRequest,
33
+ SuccessResponseItems,
34
+ ToolkitAPIError,
35
+ )
21
36
  from cognite_toolkit._cdf_tk.utils.useful_types import (
22
37
  AssetCentricKindExtended,
23
38
  AssetCentricType,
@@ -348,3 +363,94 @@ class AnnotationMigrationIO(
348
363
  selector: AssetCentricMigrationSelector | None = None,
349
364
  ) -> list[dict[str, JsonVal]]:
350
365
  raise NotImplementedError("Serializing Annotation Migrations to JSON is not supported.")
366
+
367
+
368
+ class ThreeDMigrationIO(UploadableStorageIO[ThreeDSelector, ThreeDModelResponse, ThreeDMigrationRequest]):
369
+ KIND = "3DMigration"
370
+ SUPPORTED_DOWNLOAD_FORMATS = frozenset({".ndjson"})
371
+ SUPPORTED_COMPRESSIONS = frozenset({".gz"})
372
+ SUPPORTED_READ_FORMATS = frozenset({".ndjson"})
373
+ DOWNLOAD_LIMIT = 1000
374
+ CHUNK_SIZE = 1
375
+ UPLOAD_ENDPOINT = "/3d/migrate/models"
376
+ REVISION_ENDPOINT = "/3d/migrate/revisions"
377
+
378
+ def as_id(self, item: ThreeDModelResponse) -> str:
379
+ return f"{item.name}_{item.id!s}"
380
+
381
+ def stream_data(self, selector: ThreeDSelector, limit: int | None = None) -> Iterable[Page[ThreeDModelResponse]]:
382
+ published: bool | None = None
383
+ if isinstance(selector, ThreeDModelFilteredSelector):
384
+ published = selector.published
385
+ included_models: set[int] | None = None
386
+ if isinstance(selector, ThreeDModelIdSelector):
387
+ included_models = set(selector.ids)
388
+ cursor: str | None = None
389
+ total = 0
390
+ while True:
391
+ request_limit = min(self.DOWNLOAD_LIMIT, limit - total) if limit is not None else self.DOWNLOAD_LIMIT
392
+ response = self.client.tool.three_d.models.iterate(
393
+ published=published, include_revision_info=True, limit=request_limit, cursor=cursor
394
+ )
395
+ # Only include asset-centric 3D models
396
+ items = [
397
+ item
398
+ for item in response.items
399
+ if item.space is None and (included_models is None or item.id in included_models)
400
+ ]
401
+ total += len(items)
402
+ if items:
403
+ yield Page(worker_id="main", items=items, next_cursor=response.next_cursor)
404
+ if response.next_cursor is None:
405
+ break
406
+ cursor = response.next_cursor
407
+
408
+ def count(self, selector: ThreeDSelector) -> int | None:
409
+ # There is no efficient way to count 3D models in CDF.
410
+ return None
411
+
412
+ def data_to_json_chunk(
413
+ self, data_chunk: Sequence[ThreeDModelResponse], selector: ThreeDSelector | None = None
414
+ ) -> list[dict[str, JsonVal]]:
415
+ raise NotImplementedError("Deserializing Annotation Migrations from JSON is not supported.")
416
+
417
+ def json_to_resource(self, item_json: dict[str, JsonVal]) -> ThreeDMigrationRequest:
418
+ raise NotImplementedError("Deserializing ThreeD Migrations from JSON is not supported.")
419
+
420
+ def upload_items(
421
+ self,
422
+ data_chunk: Sequence[UploadItem[ThreeDMigrationRequest]],
423
+ http_client: HTTPClient,
424
+ selector: ThreeDSelector | None = None,
425
+ ) -> Sequence[HTTPMessage]:
426
+ """Migrate 3D models by uploading them to the migrate/models endpoint."""
427
+ if len(data_chunk) > self.CHUNK_SIZE:
428
+ raise RuntimeError(f"Uploading more than {self.CHUNK_SIZE} 3D models at a time is not supported.")
429
+
430
+ results: list[HTTPMessage] = []
431
+ responses = http_client.request_with_retries(
432
+ message=ItemsRequest(
433
+ endpoint_url=self.client.config.create_api_url(self.UPLOAD_ENDPOINT),
434
+ method="POST",
435
+ items=list(data_chunk),
436
+ )
437
+ )
438
+ if (
439
+ failed_response := next((res for res in responses if isinstance(res, FailedResponse)), None)
440
+ ) and failed_response.status_code == 400:
441
+ raise ToolkitAPIError("3D model migration failed. You need to enable the 3D migration alpha feature flag.")
442
+
443
+ results.extend(responses)
444
+ success_ids = {id for res in responses if isinstance(res, SuccessResponseItems) for id in res.ids}
445
+ for data in data_chunk:
446
+ if data.source_id not in success_ids:
447
+ continue
448
+ revision = http_client.request_with_retries(
449
+ message=SimpleBodyRequest(
450
+ endpoint_url=self.client.config.create_api_url(self.REVISION_ENDPOINT),
451
+ method="POST",
452
+ body_content={"items": [data.item.revision.dump(camel_case=True)]},
453
+ )
454
+ )
455
+ results.extend(revision.as_item_responses(data.source_id))
456
+ return results
@@ -38,9 +38,12 @@ from ._instances import (
38
38
  SelectedView,
39
39
  )
40
40
  from ._raw import RawTableSelector, SelectedTable
41
+ from ._three_d import ThreeDModelFilteredSelector, ThreeDModelIdSelector, ThreeDSelector
41
42
 
42
43
  Selector = Annotated[
43
44
  RawTableSelector
45
+ | ThreeDModelIdSelector
46
+ | ThreeDModelFilteredSelector
44
47
  | InstanceViewSelector
45
48
  | InstanceFileSelector
46
49
  | InstanceSpaceSelector
@@ -60,7 +63,7 @@ Selector = Annotated[
60
63
  ]
61
64
 
62
65
  ALPHA_SELECTORS = {FileIdentifierSelector}
63
-
66
+ INTERNAL = {ThreeDModelIdSelector, ThreeDModelFilteredSelector}
64
67
  SelectorAdapter: TypeAdapter[Selector] = TypeAdapter(Selector)
65
68
 
66
69
 
@@ -83,6 +86,10 @@ def load_selector(manifest_file: Path) -> Selector | ToolkitWarning:
83
86
  return MediumSeverityWarning(
84
87
  f"Selector type '{type(selector).__name__}' in file '{manifest_file}' is in alpha. To enable it set the alpha flag 'extend-upload = true' in your CDF.toml file."
85
88
  )
89
+ elif type(selector) in INTERNAL:
90
+ return MediumSeverityWarning(
91
+ f"Selector type '{type(selector).__name__}' in file '{manifest_file}' is for internal use only and cannot be used."
92
+ )
86
93
  return selector
87
94
 
88
95
 
@@ -119,6 +126,8 @@ __all__ = [
119
126
  "SelectedView",
120
127
  "Selector",
121
128
  "SelectorAdapter",
129
+ "ThreeDModelIdSelector",
130
+ "ThreeDSelector",
122
131
  "TimeSeriesColumn",
123
132
  "load_selector",
124
133
  ]
@@ -0,0 +1,34 @@
1
+ import hashlib
2
+ from abc import ABC
3
+ from typing import Literal
4
+
5
+ from ._base import DataSelector
6
+
7
+
8
+ class ThreeDSelector(DataSelector, ABC):
9
+ kind: Literal["3D"] = "3D"
10
+
11
+ @property
12
+ def group(self) -> str:
13
+ return "3DModels"
14
+
15
+
16
+ class ThreeDModelFilteredSelector(ThreeDSelector):
17
+ type: Literal["3DFiltered"] = "3DFiltered"
18
+ model_type: Literal["Classic", "DataModel"] = "Classic"
19
+ published: bool | None = None
20
+
21
+ def __str__(self) -> str:
22
+ suffix = f"3DModels_{self.model_type}"
23
+ if self.published is not None:
24
+ return f"{suffix}_published_{self.published}"
25
+ return suffix
26
+
27
+
28
+ class ThreeDModelIdSelector(ThreeDSelector):
29
+ type: Literal["3DId"] = "3DId"
30
+ ids: tuple[int, ...]
31
+
32
+ def __str__(self) -> str:
33
+ hash_ = hashlib.md5(",".join(sorted(map(str, self.ids))).encode()).hexdigest()[:8]
34
+ return f"3DModels_ids_count_{len(self.ids)}_hash_{hash_}"
@@ -25,6 +25,7 @@ from cognite_toolkit._cdf_tk.client.data_classes.canvas import Canvas
25
25
  from cognite_toolkit._cdf_tk.client.data_classes.charts import Chart, ChartList, Visibility
26
26
  from cognite_toolkit._cdf_tk.client.data_classes.migration import ResourceViewMapping
27
27
  from cognite_toolkit._cdf_tk.client.data_classes.raw import RawTable
28
+ from cognite_toolkit._cdf_tk.client.data_classes.three_d import ThreeDModelResponse
28
29
  from cognite_toolkit._cdf_tk.exceptions import ToolkitMissingResourceError, ToolkitValueError
29
30
 
30
31
  from . import humanize_collection
@@ -823,3 +824,49 @@ class ResourceViewMappingInteractiveSelect:
823
824
  f"Selected Resource View Mapping is not a valid ResourceViewMapping object: {selected_mapping!r}"
824
825
  )
825
826
  return selected_mapping
827
+
828
+
829
+ class ThreeDInteractiveSelect:
830
+ def __init__(self, client: ToolkitClient, operation: str) -> None:
831
+ self.client = client
832
+ self.operation = operation
833
+
834
+ def select_three_d_models(self, model_type: Literal["classic", "dm"] | None = None) -> list[ThreeDModelResponse]:
835
+ """Select multiple 3D models interactively."""
836
+ if model_type is None:
837
+ model_type = questionary.select(
838
+ f"What type of 3D models do you want to {self.operation}?",
839
+ choices=[
840
+ Choice(title="Classic models", value="classic"),
841
+ Choice(title="Data modeling 3D", value="dm"),
842
+ ],
843
+ ).ask()
844
+ if model_type is None:
845
+ raise ToolkitValueError("No 3D model type selected.")
846
+ published = questionary.select(
847
+ f"Do you want to {self.operation} published or unpublished 3D models?",
848
+ choices=[
849
+ Choice(title="Published models", value=True),
850
+ Choice(title="Unpublished models", value=False),
851
+ Choice(title="Both published and unpublished models", value=None),
852
+ ],
853
+ ).ask()
854
+
855
+ models = self.client.tool.three_d.models.list(published=published, include_revision_info=True, limit=None)
856
+ if model_type == "classic":
857
+ models = [model for model in models if model.space is None]
858
+ else:
859
+ models = [model for model in models if model.space is not None]
860
+ if not models:
861
+ raise ToolkitMissingResourceError(
862
+ f"No 3D models found for type {model_type!r} with published={published!r}."
863
+ )
864
+
865
+ choices = [Choice(title=f"{model.name} ({model.id})", value=model) for model in models]
866
+ selected_models = questionary.checkbox(
867
+ f"Select 3D models to {self.operation}:",
868
+ choices=choices,
869
+ ).ask()
870
+ if selected_models is None or len(selected_models) == 0:
871
+ raise ToolkitValueError("No 3D models selected.")
872
+ return selected_models
@@ -12,7 +12,7 @@ jobs:
12
12
  environment: dev
13
13
  name: Deploy
14
14
  container:
15
- image: cognite/toolkit:0.7.32
15
+ image: cognite/toolkit:0.7.33
16
16
  env:
17
17
  CDF_CLUSTER: ${{ vars.CDF_CLUSTER }}
18
18
  CDF_PROJECT: ${{ vars.CDF_PROJECT }}
@@ -10,7 +10,7 @@ jobs:
10
10
  environment: dev
11
11
  name: Deploy Dry Run
12
12
  container:
13
- image: cognite/toolkit:0.7.32
13
+ image: cognite/toolkit:0.7.33
14
14
  env:
15
15
  CDF_CLUSTER: ${{ vars.CDF_CLUSTER }}
16
16
  CDF_PROJECT: ${{ vars.CDF_PROJECT }}
@@ -4,7 +4,7 @@ default_env = "<DEFAULT_ENV_PLACEHOLDER>"
4
4
  [modules]
5
5
  # This is the version of the modules. It should not be changed manually.
6
6
  # It will be updated by the 'cdf modules upgrade' command.
7
- version = "0.7.32"
7
+ version = "0.7.33"
8
8
 
9
9
 
10
10
  [plugins]
@@ -1 +1 @@
1
- __version__ = "0.7.32"
1
+ __version__ = "0.7.33"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cognite_toolkit
3
- Version: 0.7.32
3
+ Version: 0.7.33
4
4
  Summary: Official Cognite Data Fusion tool for project templates and configuration deployment
5
5
  Author: Cognite AS
6
6
  Author-email: Cognite AS <support@cognite.com>
@@ -10,7 +10,7 @@ cognite_toolkit/_cdf_tk/apps/_download_app.py,sha256=2nPn9P_9br9poynSpKKSZF7WYTY
10
10
  cognite_toolkit/_cdf_tk/apps/_dump_app.py,sha256=EPq6fWSaScj9ncKfRY253rRJ37er47PIM60IFgkQK_k,37127
11
11
  cognite_toolkit/_cdf_tk/apps/_import_app.py,sha256=5n5AF40HJ0Q_3LENCknG0MxH4pMUS8OwsqvtCYj_t7w,2086
12
12
  cognite_toolkit/_cdf_tk/apps/_landing_app.py,sha256=YR9z83OY7PhhgBVC5gmRLgo9iTXoGoZfRhOU3gd_r2o,888
13
- cognite_toolkit/_cdf_tk/apps/_migrate_app.py,sha256=_woM0D2j6VzuYC0LJKteALbQ4U8vGj0B1LSBj_WszKQ,41198
13
+ cognite_toolkit/_cdf_tk/apps/_migrate_app.py,sha256=R7BsckVnPe59Z26mY06NsWSGjq21DwobPBJ3tMfqRhs,43707
14
14
  cognite_toolkit/_cdf_tk/apps/_modules_app.py,sha256=t0SPvulgbgkF_OO2E68mQ_ZUcJ6HoaurYe0IkmXie0o,7449
15
15
  cognite_toolkit/_cdf_tk/apps/_profile_app.py,sha256=vSRJW54bEvIul8_4rOqyOYA7ztXx7TFOvZRZWZTxMbg,7007
16
16
  cognite_toolkit/_cdf_tk/apps/_purge.py,sha256=KYI1wFy7yHFEM1qJnTYc4_8E2FVGu4QhPsWsxop1sZA,14242
@@ -57,7 +57,7 @@ cognite_toolkit/_cdf_tk/client/api/robotics/utlis.py,sha256=EMwyrIb9CfM1q6HAfPe6
57
57
  cognite_toolkit/_cdf_tk/client/api/search.py,sha256=L4cDPip7pJVP7bEgAiSOjqINIHg8AULNBtR29G5khEQ,612
58
58
  cognite_toolkit/_cdf_tk/client/api/search_config.py,sha256=31rPCSOnzfiLv8FKU6F3tF9ZesEV8moSlbnkFPNh13g,1824
59
59
  cognite_toolkit/_cdf_tk/client/api/streams.py,sha256=qOUFHdpz75PSlfImIizVCtschLLHttR8AUV0Jw3DTRM,3055
60
- cognite_toolkit/_cdf_tk/client/api/three_d.py,sha256=zY71RGEBkH5b8R8WOb2CKHUsxFcDWTb5kPaxBa8wuAY,2053
60
+ cognite_toolkit/_cdf_tk/client/api/three_d.py,sha256=zvzyeeAz8P2h0_yC-i-PAqe-kl8ocyOAZbQ3Y3_O3Wo,4949
61
61
  cognite_toolkit/_cdf_tk/client/api/token.py,sha256=8SiA44Dwsx0j_X8lgIxl2rdNCQSdEiSfoD_4ybxMtFA,5131
62
62
  cognite_toolkit/_cdf_tk/client/api/verify.py,sha256=-x6z6lMaOZG91adi0m9NtJ4wIQgoZURbzluPALXM-ps,3730
63
63
  cognite_toolkit/_cdf_tk/client/api_client.py,sha256=CQdD_gfDqQkz5OYHrTnKvBvEvzHPdHDB1BkZPWRoahg,440
@@ -65,7 +65,7 @@ cognite_toolkit/_cdf_tk/client/config.py,sha256=weMR43z-gqHMn-Jqvfmh_nJ0HbgEdyeC
65
65
  cognite_toolkit/_cdf_tk/client/data_classes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
66
  cognite_toolkit/_cdf_tk/client/data_classes/api_classes.py,sha256=X-aGFnYzSxXYDxlFP2rqJ8P10Um7bcRRUZxVVzblYBw,477
67
67
  cognite_toolkit/_cdf_tk/client/data_classes/apm_config_v1.py,sha256=0bPq7R0qvdf8SMFS06kX7TXHIClDcJNHwdTBweQB-GU,20150
68
- cognite_toolkit/_cdf_tk/client/data_classes/base.py,sha256=CQ64XroKpH7pODOZ3NPZ_GBkdsH7evFAxYKQ8-ywmYI,2142
68
+ cognite_toolkit/_cdf_tk/client/data_classes/base.py,sha256=VtqQv2xVV5J81Ls8Y-tvsITKnUCOfjhQwFijwqNIIuU,2303
69
69
  cognite_toolkit/_cdf_tk/client/data_classes/canvas.py,sha256=DrE-7HOLnk1ELhydySsEhw-VOjriUqB_zzon5qb7CDk,50721
70
70
  cognite_toolkit/_cdf_tk/client/data_classes/capabilities.py,sha256=muqpAC2JLCFcEpRPzuh_3sS3o_q42WFyfsGzl-LfB_U,8773
71
71
  cognite_toolkit/_cdf_tk/client/data_classes/charts.py,sha256=4ZSZDJhDP8uNubXfzphuLJzKJhL1F01grB4UesxtSbQ,3745
@@ -77,7 +77,7 @@ cognite_toolkit/_cdf_tk/client/data_classes/extended_timeseries.py,sha256=yAvJCH
77
77
  cognite_toolkit/_cdf_tk/client/data_classes/functions.py,sha256=r9vhkS7sJ-wCiwvtD9CDKKthAktDMS6FJWDsLzq6iJ8,378
78
78
  cognite_toolkit/_cdf_tk/client/data_classes/graphql_data_models.py,sha256=N_1dfXSdsLlhw5uXreNfmSCo5bA4XeiZneMdnHWDgJI,4313
79
79
  cognite_toolkit/_cdf_tk/client/data_classes/infield.py,sha256=xZDpHw190FgX2vK6zk_r8dUJA7J6UzdS8227VOu74ms,4298
80
- cognite_toolkit/_cdf_tk/client/data_classes/instance_api.py,sha256=Ihi2Q1GKL3uBDReudtMI-T8XL8wxuNYmvrY3PD0feQs,4929
80
+ cognite_toolkit/_cdf_tk/client/data_classes/instance_api.py,sha256=ajOCEzRf9OrwR3JyGKNvBkru_Nfpe4PxmcPc8mYB8PE,5065
81
81
  cognite_toolkit/_cdf_tk/client/data_classes/instances.py,sha256=aGV3XtBGwG1ELks3kqFkScO-MGC5zvcSZtYXOVWL2BE,2501
82
82
  cognite_toolkit/_cdf_tk/client/data_classes/location_filters.py,sha256=IgHU7Hto0Zz3Bk_QW17JC3vUw0yN1oaTeJ3ZPKOGFAE,12112
83
83
  cognite_toolkit/_cdf_tk/client/data_classes/migration.py,sha256=AoYgqwSoYn1ok_ksG9Lljb270J4zPF_qyJSu5ZHtD_Q,18632
@@ -89,8 +89,8 @@ cognite_toolkit/_cdf_tk/client/data_classes/search_config.py,sha256=Reo_rcFrwk_s
89
89
  cognite_toolkit/_cdf_tk/client/data_classes/sequences.py,sha256=02d34fPcJ1H7U5ZnCCfOi36z5WJ4WnRfCWwkp99mW2E,6234
90
90
  cognite_toolkit/_cdf_tk/client/data_classes/streamlit_.py,sha256=nEk00FH3i-px2r6ql4kk1VVL4sytjUn0_sTkEdDSHVc,6746
91
91
  cognite_toolkit/_cdf_tk/client/data_classes/streams.py,sha256=DHSDrBax81fUzneIikn9hUMVgQVbdaiQ9aY-bRaTK38,2459
92
- cognite_toolkit/_cdf_tk/client/data_classes/three_d.py,sha256=afPfgZtsYs7OhBo7lJXb-7xInTdYK8wWg1a_hQJNOcE,1352
93
- cognite_toolkit/_cdf_tk/client/testing.py,sha256=mXqEXPMZcbETrXBn6D-SiAcjD7xAkuuxCNYJMW0IO0Y,6815
92
+ cognite_toolkit/_cdf_tk/client/data_classes/three_d.py,sha256=9NvZNkbdkHlfzZqV_Kr43eHjpfyfOOxcL9ry7Y_zZ0I,1406
93
+ cognite_toolkit/_cdf_tk/client/testing.py,sha256=V6JcS-fVlpilAt5wE_ygPiLEEdgzTArhiGODMR0yDVw,7072
94
94
  cognite_toolkit/_cdf_tk/client/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
95
95
  cognite_toolkit/_cdf_tk/client/utils/_concurrency.py,sha256=3GtQbKDaosyKHEt-KzxKK9Yie4TvZPdoou2vUk6dUa8,2298
96
96
  cognite_toolkit/_cdf_tk/client/utils/_http_client.py,sha256=oXNKrIaizG4WiSAhL_kSCHAuL4aaaEhCU4pOJGxh6Xs,483
@@ -104,12 +104,12 @@ cognite_toolkit/_cdf_tk/commands/_migrate/__init__.py,sha256=8ki04tJGH1dHdF2NtVF
104
104
  cognite_toolkit/_cdf_tk/commands/_migrate/command.py,sha256=l2P0Em05aEJvNZH4WkEIm-QfO3TAjG1rc_YxELuQIQM,14214
105
105
  cognite_toolkit/_cdf_tk/commands/_migrate/conversion.py,sha256=Ew9JRYrd-Ol9G9csTzpnhXAgCFnX67MwDYOTsdJLP3E,16803
106
106
  cognite_toolkit/_cdf_tk/commands/_migrate/creators.py,sha256=FTu7w3G8KyPY8pagG3KdPpOmpLcjehaAg2auEy6iM7A,9605
107
- cognite_toolkit/_cdf_tk/commands/_migrate/data_classes.py,sha256=_vMS_qAPj4yup1VnmmojPVigAZtyPQH7PM0Raby5tao,10619
108
- cognite_toolkit/_cdf_tk/commands/_migrate/data_mapper.py,sha256=b_6_yYibtzWiBFrYq5pB8NZUi1TRuf-DIy_GRroj4wg,18551
107
+ cognite_toolkit/_cdf_tk/commands/_migrate/data_classes.py,sha256=uVPO58QtiWvXXlZt8xERFaG9lE0FX1zym8X1yjt_l-Q,11467
108
+ cognite_toolkit/_cdf_tk/commands/_migrate/data_mapper.py,sha256=Y3x02BwhAlv6x2LEkCHAvONOtE2zKotzmdQkkfMS2eA,22258
109
109
  cognite_toolkit/_cdf_tk/commands/_migrate/data_model.py,sha256=i1eUsNX6Dueol9STIEwyksBnBsWUk13O8qHIjW964pM,7860
110
110
  cognite_toolkit/_cdf_tk/commands/_migrate/default_mappings.py,sha256=ERn3qFrJFXdtXaMjHq3Gk7MxH03MGFk3FrtWCOBJQts,5544
111
- cognite_toolkit/_cdf_tk/commands/_migrate/issues.py,sha256=n8en744-r7GL9eUyxEojFes1yk69V04SnlpVXHrdPOQ,6972
112
- cognite_toolkit/_cdf_tk/commands/_migrate/migration_io.py,sha256=nc77Eu1a2sGS8Pb0bkMgqWebYmWlLbQe8xPCay5aoNo,17208
111
+ cognite_toolkit/_cdf_tk/commands/_migrate/issues.py,sha256=FAgZj0iWydwgXfseUySfiiU1YeGIM9myVr-TijAUm-s,7540
112
+ cognite_toolkit/_cdf_tk/commands/_migrate/migration_io.py,sha256=NwJIzSTNJAu1HsqXfMn-VwGr99QFczaHvxKbT3UV4kc,21749
113
113
  cognite_toolkit/_cdf_tk/commands/_migrate/prepare.py,sha256=RfqaNoso5CyBwc-p6ckwcYqBfZXKhdJgdGIyd0TATaI,2635
114
114
  cognite_toolkit/_cdf_tk/commands/_migrate/selectors.py,sha256=N1H_-rBpPUD6pbrlcofn1uEK1bA694EUXEe1zIXeqyo,2489
115
115
  cognite_toolkit/_cdf_tk/commands/_profile.py,sha256=_4iX3AHAI6eLmRVUlWXCSvVHx1BZW2yDr_i2i9ECg6U,43120
@@ -250,7 +250,7 @@ cognite_toolkit/_cdf_tk/storageio/_datapoints.py,sha256=xE1YgoP98-mJjIeF5536KwCh
250
250
  cognite_toolkit/_cdf_tk/storageio/_file_content.py,sha256=4b1Lr8ZROLZg7MjT7IiCsRhyVAl1KCWtr0fcDtyzk1o,19062
251
251
  cognite_toolkit/_cdf_tk/storageio/_instances.py,sha256=t9fNpHnT6kCk8LDoPj3qZXmHpyDbPF5BZ6pI8ziTyFw,10810
252
252
  cognite_toolkit/_cdf_tk/storageio/_raw.py,sha256=pgZN5MbqDwMZl9Ow1KouDJUO2Ngga8_b6hwv7H31SVQ,5161
253
- cognite_toolkit/_cdf_tk/storageio/selectors/__init__.py,sha256=zPLiF5iCzvKF1fyAOAnTUS2YqHCDzNHaPg3hobvwDuw,3916
253
+ cognite_toolkit/_cdf_tk/storageio/selectors/__init__.py,sha256=5qqgeCrsmMLVsrRuYKxCKq1bNnvJkWeAsATpTKN1eC4,4394
254
254
  cognite_toolkit/_cdf_tk/storageio/selectors/_asset_centric.py,sha256=7Iv_ccVX6Vzt3ZLFZ0Er3hN92iEsFTm9wgF-yermOWE,1467
255
255
  cognite_toolkit/_cdf_tk/storageio/selectors/_base.py,sha256=hjFkbmNGsK3QIW-jnJV_8YNmvVROERxzG82qIZhU7SM,3065
256
256
  cognite_toolkit/_cdf_tk/storageio/selectors/_canvas.py,sha256=E9S-wr-JUqRosI_2cSCfR0tF8MdIFTrMxDItuWRcuO4,597
@@ -259,6 +259,7 @@ cognite_toolkit/_cdf_tk/storageio/selectors/_datapoints.py,sha256=qdR9wttPUoHZIR
259
259
  cognite_toolkit/_cdf_tk/storageio/selectors/_file_content.py,sha256=e7riknOinuhJszkROHeg7iv3foiVz7mIJmva6lMTiOs,5116
260
260
  cognite_toolkit/_cdf_tk/storageio/selectors/_instances.py,sha256=NCFSJrAw52bNX6UTfOali8PvNjlqHnvxzL0hYBr7ZmA,4934
261
261
  cognite_toolkit/_cdf_tk/storageio/selectors/_raw.py,sha256=sZq9C4G9DMe3S46_usKet0FphQ6ow7cWM_PfXrEAakk,503
262
+ cognite_toolkit/_cdf_tk/storageio/selectors/_three_d.py,sha256=0dT1vVG6EIyo0OJK3t_vwtE63i0dZvH8nZT7ebl1Ku0,924
262
263
  cognite_toolkit/_cdf_tk/tk_warnings/__init__.py,sha256=U9bT-G2xKrX6mmtZ7nZ1FfQeCjNKfKP_p7pev90dwOE,2316
263
264
  cognite_toolkit/_cdf_tk/tk_warnings/base.py,sha256=cX8TCmb56gqx3lc7dankXuqpm5HGASJ4wTb07-MCJWs,4401
264
265
  cognite_toolkit/_cdf_tk/tk_warnings/fileread.py,sha256=d2Kx6YyLmCkyFNjK8MO6eKGceCIEaFLZ4LYcG-EjnuM,8947
@@ -289,7 +290,7 @@ cognite_toolkit/_cdf_tk/utils/http_client/_data_classes.py,sha256=8KEDyRRaOLhwN2
289
290
  cognite_toolkit/_cdf_tk/utils/http_client/_data_classes2.py,sha256=Qqy7OEg8MGF9EksDUcn39fq6GpC_SrbWbyt-UGqD80Q,8811
290
291
  cognite_toolkit/_cdf_tk/utils/http_client/_exception.py,sha256=fC9oW6BN0HbUe2AkYABMP7Kj0-9dNYXVFBY5RQztq2c,126
291
292
  cognite_toolkit/_cdf_tk/utils/http_client/_tracker.py,sha256=EBBnd-JZ7nc_jYNFJokCHN2UZ9sx0McFLZvlceUYYic,1215
292
- cognite_toolkit/_cdf_tk/utils/interactive_select.py,sha256=dP_ZFHvzQRPQxRt6EzURY3Z3Ld_otJtCz-nGqUNtt1k,35725
293
+ cognite_toolkit/_cdf_tk/utils/interactive_select.py,sha256=v3O3vLc1HhHG_StLn8VtrRueREZ_Zag6EFqgfZXc2WU,37879
293
294
  cognite_toolkit/_cdf_tk/utils/modules.py,sha256=9RvOGUaGEi_-A7Qrq0E1tCx82QK8GbvEZXB7r1RnD_U,5974
294
295
  cognite_toolkit/_cdf_tk/utils/producer_worker.py,sha256=1l77HIehkq1ARCBH6SlZ_V-jd6QKijYKeWetcUmAXg0,14216
295
296
  cognite_toolkit/_cdf_tk/utils/progress_tracker.py,sha256=LGpC22iSTTlo6FWi38kqBu_E4XouTvZU_N953WAzZWA,3865
@@ -306,14 +307,14 @@ cognite_toolkit/_repo_files/.gitignore,sha256=ip9kf9tcC5OguF4YF4JFEApnKYw0nG0vPi
306
307
  cognite_toolkit/_repo_files/AzureDevOps/.devops/README.md,sha256=OLA0D7yCX2tACpzvkA0IfkgQ4_swSd-OlJ1tYcTBpsA,240
307
308
  cognite_toolkit/_repo_files/AzureDevOps/.devops/deploy-pipeline.yml,sha256=brULcs8joAeBC_w_aoWjDDUHs3JheLMIR9ajPUK96nc,693
308
309
  cognite_toolkit/_repo_files/AzureDevOps/.devops/dry-run-pipeline.yml,sha256=OBFDhFWK1mlT4Dc6mDUE2Es834l8sAlYG50-5RxRtHk,723
309
- cognite_toolkit/_repo_files/GitHub/.github/workflows/deploy.yaml,sha256=SJrUHATry3OVNdwVmG33hrleUAMRoGWh39OwuxJEAt8,667
310
- cognite_toolkit/_repo_files/GitHub/.github/workflows/dry-run.yaml,sha256=WvlVo-pbKtDRwAk9gZwD4aQxRKhd10OI3dY1AVgXbvc,2430
311
- cognite_toolkit/_resources/cdf.toml,sha256=hmcpZvF4m-Ii4jhmVnuxrTp5Juk0kV4LQQHRpO_Dp9g,475
312
- cognite_toolkit/_version.py,sha256=1XUohj6Z0TqUfrazUNkieWrPdQbTTSPaX1bSiD_w2V0,23
310
+ cognite_toolkit/_repo_files/GitHub/.github/workflows/deploy.yaml,sha256=RIV-MDRX1qH0MizvAq4038NFQyux2jnjgQoG8H0Xbj8,667
311
+ cognite_toolkit/_repo_files/GitHub/.github/workflows/dry-run.yaml,sha256=FDRUWleXR81HUHROCib7RbLqkBnI9J6JlSURiKkYvk0,2430
312
+ cognite_toolkit/_resources/cdf.toml,sha256=2epVBQo_m2z8GY9outwcZ9cXX7fHEIYYxqxxnn69RGU,475
313
+ cognite_toolkit/_version.py,sha256=HbFp4k5nhcLL9U3SdQuIdWAUBPETOj1k7h6vrI5evXw,23
313
314
  cognite_toolkit/config.dev.yaml,sha256=M33FiIKdS3XKif-9vXniQ444GTZ-bLXV8aFH86u9iUQ,332
314
315
  cognite_toolkit/demo/__init__.py,sha256=-m1JoUiwRhNCL18eJ6t7fZOL7RPfowhCuqhYFtLgrss,72
315
316
  cognite_toolkit/demo/_base.py,sha256=6xKBUQpXZXGQ3fJ5f7nj7oT0s2n7OTAGIa17ZlKHZ5U,8052
316
- cognite_toolkit-0.7.32.dist-info/WHEEL,sha256=xDCZ-UyfvkGuEHPeI7BcJzYKIZzdqN8A8o1M5Om8IyA,79
317
- cognite_toolkit-0.7.32.dist-info/entry_points.txt,sha256=EtZ17K2mUjh-AY0QNU1CPIB_aDSSOdmtNI_4Fj967mA,84
318
- cognite_toolkit-0.7.32.dist-info/METADATA,sha256=AINvh-AoKJNaRlhP7RO_AaPoBItlW2tt4cxrDhFNxvc,4507
319
- cognite_toolkit-0.7.32.dist-info/RECORD,,
317
+ cognite_toolkit-0.7.33.dist-info/WHEEL,sha256=xDCZ-UyfvkGuEHPeI7BcJzYKIZzdqN8A8o1M5Om8IyA,79
318
+ cognite_toolkit-0.7.33.dist-info/entry_points.txt,sha256=EtZ17K2mUjh-AY0QNU1CPIB_aDSSOdmtNI_4Fj967mA,84
319
+ cognite_toolkit-0.7.33.dist-info/METADATA,sha256=q6zuIsvjFmMnRbtcHQwBzLkkB-Vn7jMLumZVV1kTASs,4507
320
+ cognite_toolkit-0.7.33.dist-info/RECORD,,