cognite-toolkit 0.7.34__py3-none-any.whl → 0.7.36__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cognite_toolkit/_cdf_tk/apps/_download_app.py +2 -2
- cognite_toolkit/_cdf_tk/apps/_dump_app.py +1 -1
- cognite_toolkit/_cdf_tk/apps/_migrate_app.py +101 -0
- cognite_toolkit/_cdf_tk/builders/_raw.py +1 -1
- cognite_toolkit/_cdf_tk/client/_toolkit_client.py +9 -9
- cognite_toolkit/_cdf_tk/client/api/infield.py +16 -17
- cognite_toolkit/_cdf_tk/client/api/legacy/__init__.py +0 -0
- cognite_toolkit/_cdf_tk/client/api/{canvas.py → legacy/canvas.py} +3 -4
- cognite_toolkit/_cdf_tk/client/api/{charts.py → legacy/charts.py} +1 -1
- cognite_toolkit/_cdf_tk/client/api/{extended_data_modeling.py → legacy/extended_data_modeling.py} +1 -1
- cognite_toolkit/_cdf_tk/client/api/{extended_files.py → legacy/extended_files.py} +2 -2
- cognite_toolkit/_cdf_tk/client/api/{extended_raw.py → legacy/extended_raw.py} +1 -1
- cognite_toolkit/_cdf_tk/client/api/{extended_timeseries.py → legacy/extended_timeseries.py} +5 -2
- cognite_toolkit/_cdf_tk/client/api/{location_filters.py → legacy/location_filters.py} +1 -1
- cognite_toolkit/_cdf_tk/client/api/legacy/robotics/__init__.py +8 -0
- cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/capabilities.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/data_postprocessing.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/frames.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/locations.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/maps.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/robots.py +2 -2
- cognite_toolkit/_cdf_tk/client/api/{search_config.py → legacy/search_config.py} +5 -1
- cognite_toolkit/_cdf_tk/client/api/migration.py +2 -3
- cognite_toolkit/_cdf_tk/client/api/project.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/search.py +2 -2
- cognite_toolkit/_cdf_tk/client/api/streams.py +3 -4
- cognite_toolkit/_cdf_tk/client/api/three_d.py +266 -13
- cognite_toolkit/_cdf_tk/client/data_classes/api_classes.py +13 -0
- cognite_toolkit/_cdf_tk/client/data_classes/base.py +6 -10
- cognite_toolkit/_cdf_tk/client/data_classes/instance_api.py +7 -7
- cognite_toolkit/_cdf_tk/client/data_classes/legacy/__init__.py +0 -0
- cognite_toolkit/_cdf_tk/client/data_classes/{canvas.py → legacy/canvas.py} +1 -1
- cognite_toolkit/_cdf_tk/client/data_classes/three_d.py +59 -0
- cognite_toolkit/_cdf_tk/client/testing.py +18 -16
- cognite_toolkit/_cdf_tk/commands/_migrate/conversion.py +1 -1
- cognite_toolkit/_cdf_tk/commands/_migrate/creators.py +1 -1
- cognite_toolkit/_cdf_tk/commands/_migrate/data_classes.py +3 -3
- cognite_toolkit/_cdf_tk/commands/_migrate/data_mapper.py +60 -12
- cognite_toolkit/_cdf_tk/commands/_migrate/default_mappings.py +1 -1
- cognite_toolkit/_cdf_tk/commands/_migrate/issues.py +1 -1
- cognite_toolkit/_cdf_tk/commands/_migrate/migration_io.py +120 -9
- cognite_toolkit/_cdf_tk/commands/_profile.py +1 -1
- cognite_toolkit/_cdf_tk/commands/_purge.py +9 -11
- cognite_toolkit/_cdf_tk/commands/build_cmd.py +1 -1
- cognite_toolkit/_cdf_tk/commands/dump_resource.py +4 -4
- cognite_toolkit/_cdf_tk/commands/run.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_data_cruds.py +2 -2
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/auth.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/classic.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/configuration.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/datamodel.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/extraction_pipeline.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/fieldops.py +22 -20
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/file.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/function.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/industrial_tool.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/location.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/migration.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/raw.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/robotics.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/transformation.py +1 -1
- cognite_toolkit/_cdf_tk/resource_classes/search_config.py +1 -1
- cognite_toolkit/_cdf_tk/storageio/_applications.py +2 -2
- cognite_toolkit/_cdf_tk/storageio/_file_content.py +1 -2
- cognite_toolkit/_cdf_tk/storageio/_instances.py +1 -1
- cognite_toolkit/_cdf_tk/utils/cdf.py +1 -1
- cognite_toolkit/_cdf_tk/utils/http_client/_data_classes.py +6 -0
- cognite_toolkit/_cdf_tk/utils/http_client/_data_classes2.py +1 -3
- cognite_toolkit/_cdf_tk/utils/interactive_select.py +4 -4
- cognite_toolkit/_repo_files/GitHub/.github/workflows/deploy.yaml +1 -1
- cognite_toolkit/_repo_files/GitHub/.github/workflows/dry-run.yaml +1 -1
- cognite_toolkit/_resources/cdf.toml +1 -1
- cognite_toolkit/_version.py +1 -1
- {cognite_toolkit-0.7.34.dist-info → cognite_toolkit-0.7.36.dist-info}/METADATA +1 -1
- {cognite_toolkit-0.7.34.dist-info → cognite_toolkit-0.7.36.dist-info}/RECORD +100 -98
- cognite_toolkit/_cdf_tk/client/api/robotics/__init__.py +0 -3
- /cognite_toolkit/_cdf_tk/client/api/{dml.py → legacy/dml.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/api/{extended_functions.py → legacy/extended_functions.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/api/{fixed_transformations.py → legacy/fixed_transformations.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/api.py +0 -0
- /cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/utlis.py +0 -0
- /cognite_toolkit/_cdf_tk/client/data_classes/{apm_config_v1.py → legacy/apm_config_v1.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/data_classes/{charts.py → legacy/charts.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/data_classes/{extendable_cognite_file.py → legacy/extendable_cognite_file.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/data_classes/{extended_filemetadata.py → legacy/extended_filemetadata.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/data_classes/{extended_filemetdata.py → legacy/extended_filemetdata.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/data_classes/{extended_timeseries.py → legacy/extended_timeseries.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/data_classes/{functions.py → legacy/functions.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/data_classes/{graphql_data_models.py → legacy/graphql_data_models.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/data_classes/{instances.py → legacy/instances.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/data_classes/{location_filters.py → legacy/location_filters.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/data_classes/{migration.py → legacy/migration.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/data_classes/{pending_instances_ids.py → legacy/pending_instances_ids.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/data_classes/{project.py → legacy/project.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/data_classes/{raw.py → legacy/raw.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/data_classes/{robotics.py → legacy/robotics.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/data_classes/{search_config.py → legacy/search_config.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/data_classes/{sequences.py → legacy/sequences.py} +0 -0
- /cognite_toolkit/_cdf_tk/client/data_classes/{streamlit_.py → legacy/streamlit_.py} +0 -0
- {cognite_toolkit-0.7.34.dist-info → cognite_toolkit-0.7.36.dist-info}/WHEEL +0 -0
- {cognite_toolkit-0.7.34.dist-info → cognite_toolkit-0.7.36.dist-info}/entry_points.txt +0 -0
|
@@ -1,14 +1,23 @@
|
|
|
1
|
-
from collections
|
|
1
|
+
from collections import defaultdict
|
|
2
|
+
from collections.abc import Iterable, Sequence
|
|
3
|
+
from typing import Any, TypeVar
|
|
2
4
|
|
|
5
|
+
from pydantic import TypeAdapter
|
|
3
6
|
from rich.console import Console
|
|
4
7
|
|
|
5
|
-
from cognite_toolkit._cdf_tk.client.data_classes.api_classes import PagedResponse
|
|
6
|
-
from cognite_toolkit._cdf_tk.client.data_classes.three_d import
|
|
8
|
+
from cognite_toolkit._cdf_tk.client.data_classes.api_classes import InternalIdRequest, PagedResponse
|
|
9
|
+
from cognite_toolkit._cdf_tk.client.data_classes.three_d import (
|
|
10
|
+
AssetMappingClassicRequest,
|
|
11
|
+
AssetMappingDMRequest,
|
|
12
|
+
AssetMappingResponse,
|
|
13
|
+
ThreeDModelClassicRequest,
|
|
14
|
+
ThreeDModelResponse,
|
|
15
|
+
)
|
|
16
|
+
from cognite_toolkit._cdf_tk.utils.collection import chunker_sequence
|
|
7
17
|
from cognite_toolkit._cdf_tk.utils.http_client import (
|
|
8
18
|
HTTPClient,
|
|
9
|
-
|
|
19
|
+
ItemsRequest2,
|
|
10
20
|
RequestMessage2,
|
|
11
|
-
SimpleBodyRequest,
|
|
12
21
|
)
|
|
13
22
|
from cognite_toolkit._cdf_tk.utils.useful_types import PrimitiveType
|
|
14
23
|
|
|
@@ -37,16 +46,15 @@ class ThreeDModelAPI:
|
|
|
37
46
|
return []
|
|
38
47
|
if len(models) > self.MAX_CLASSIC_MODELS_PER_CREATE_REQUEST:
|
|
39
48
|
raise ValueError("Cannot create more than 1000 3D models in a single request.")
|
|
40
|
-
responses = self._http_client.
|
|
41
|
-
|
|
49
|
+
responses = self._http_client.request_items_retries(
|
|
50
|
+
ItemsRequest2(
|
|
42
51
|
endpoint_url=self._config.create_api_url(self.ENDPOINT),
|
|
43
52
|
method="POST",
|
|
44
|
-
items=
|
|
53
|
+
items=models,
|
|
45
54
|
)
|
|
46
55
|
)
|
|
47
56
|
responses.raise_for_status()
|
|
48
|
-
|
|
49
|
-
return PagedResponse[ThreeDModelResponse].model_validate(body).items
|
|
57
|
+
return TypeAdapter(list[ThreeDModelResponse]).validate_python(responses.get_items())
|
|
50
58
|
|
|
51
59
|
def delete(self, ids: Sequence[int]) -> None:
|
|
52
60
|
"""Delete 3D models by their IDs.
|
|
@@ -58,11 +66,11 @@ class ThreeDModelAPI:
|
|
|
58
66
|
return None
|
|
59
67
|
if len(ids) > self.MAX_MODELS_PER_DELETE_REQUEST:
|
|
60
68
|
raise ValueError("Cannot delete more than 1000 3D models in a single request.")
|
|
61
|
-
responses = self._http_client.
|
|
62
|
-
|
|
69
|
+
responses = self._http_client.request_items_retries(
|
|
70
|
+
ItemsRequest2(
|
|
63
71
|
endpoint_url=self._config.create_api_url(self.ENDPOINT + "/delete"),
|
|
64
72
|
method="POST",
|
|
65
|
-
|
|
73
|
+
items=InternalIdRequest.from_ids(list(ids)),
|
|
66
74
|
)
|
|
67
75
|
)
|
|
68
76
|
responses.raise_for_status()
|
|
@@ -126,6 +134,251 @@ class ThreeDModelAPI:
|
|
|
126
134
|
return results
|
|
127
135
|
|
|
128
136
|
|
|
137
|
+
T_RequestMapping = TypeVar("T_RequestMapping", bound=AssetMappingClassicRequest | AssetMappingDMRequest)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class ThreeDAssetMappingAPI:
|
|
141
|
+
ENDPOINT = "/3d/models/{modelId}/revisions/{revisionId}/mappings"
|
|
142
|
+
CREATE_CLASSIC_MAX_MAPPINGS_PER_REQUEST = 1000
|
|
143
|
+
CREATE_DM_MAX_MAPPINGS_PER_REQUEST = 100
|
|
144
|
+
DELETE_CLASSIC_MAX_MAPPINGS_PER_REQUEST = 1000
|
|
145
|
+
DELETE_DM_MAX_MAPPINGS_PER_REQUEST = 100
|
|
146
|
+
LIST_REQUEST_MAX_LIMIT = 1000
|
|
147
|
+
|
|
148
|
+
def __init__(self, http_client: HTTPClient, console: Console) -> None:
|
|
149
|
+
self._http_client = http_client
|
|
150
|
+
self._console = console
|
|
151
|
+
self._config = http_client.config
|
|
152
|
+
|
|
153
|
+
def create(self, mappings: Sequence[AssetMappingClassicRequest]) -> list[AssetMappingResponse]:
|
|
154
|
+
"""Create 3D asset mappings.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
mappings (Sequence[AssetMappingClassicRequest]):
|
|
158
|
+
The 3D asset mapping(s) to create.
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
list[AssetMappingResponse]: The created 3D asset mapping(s).
|
|
162
|
+
"""
|
|
163
|
+
results: list[AssetMappingResponse] = []
|
|
164
|
+
for endpoint, model_id, revision_id, revision_mappings in self._chunk_mappings_by_endpoint(
|
|
165
|
+
mappings, self.CREATE_CLASSIC_MAX_MAPPINGS_PER_REQUEST
|
|
166
|
+
):
|
|
167
|
+
responses = self._http_client.request_items_retries(
|
|
168
|
+
ItemsRequest2(
|
|
169
|
+
endpoint_url=self._config.create_api_url(endpoint),
|
|
170
|
+
method="POST",
|
|
171
|
+
items=revision_mappings,
|
|
172
|
+
)
|
|
173
|
+
)
|
|
174
|
+
responses.raise_for_status()
|
|
175
|
+
items = responses.get_items()
|
|
176
|
+
for item in items:
|
|
177
|
+
# We append modelId and revisionId to each item since the API does not return them
|
|
178
|
+
# this is needed to fully populate the AssetMappingResponse data class
|
|
179
|
+
item["modelId"] = model_id
|
|
180
|
+
item["revisionId"] = revision_id
|
|
181
|
+
results.extend(TypeAdapter(list[AssetMappingResponse]).validate_python(items))
|
|
182
|
+
return results
|
|
183
|
+
|
|
184
|
+
def create_dm(
|
|
185
|
+
self, mappings: Sequence[AssetMappingDMRequest], object_3d_space: str, cad_node_space: str
|
|
186
|
+
) -> list[AssetMappingResponse]:
|
|
187
|
+
"""Create 3D asset mappings in Data Modeling format.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
mappings (Sequence[AssetMappingDMRequest]):
|
|
191
|
+
The 3D asset mapping(s) to create
|
|
192
|
+
object_3d_space (str):
|
|
193
|
+
The instance space where the Cognite3DObject are located.
|
|
194
|
+
cad_node_space (str):
|
|
195
|
+
The instance space where the CogniteCADNode are located.
|
|
196
|
+
Returns:
|
|
197
|
+
list[AssetMappingResponse]: The created 3D asset mapping(s).
|
|
198
|
+
"""
|
|
199
|
+
results: list[AssetMappingResponse] = []
|
|
200
|
+
for endpoint, model_id, revision_id, revision_mappings in self._chunk_mappings_by_endpoint(
|
|
201
|
+
mappings, self.CREATE_DM_MAX_MAPPINGS_PER_REQUEST
|
|
202
|
+
):
|
|
203
|
+
responses = self._http_client.request_items_retries(
|
|
204
|
+
ItemsRequest2(
|
|
205
|
+
endpoint_url=self._config.create_api_url(endpoint),
|
|
206
|
+
method="POST",
|
|
207
|
+
items=revision_mappings,
|
|
208
|
+
extra_body_fields={
|
|
209
|
+
"dmsContextualizationConfig": {
|
|
210
|
+
"object3DSpace": object_3d_space,
|
|
211
|
+
"cadNodeSpace": cad_node_space,
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
)
|
|
215
|
+
)
|
|
216
|
+
responses.raise_for_status()
|
|
217
|
+
items = responses.get_items()
|
|
218
|
+
for item in items:
|
|
219
|
+
# We append modelId and revisionId to each item since the API does not return them
|
|
220
|
+
# this is needed to fully populate the AssetMappingResponse data class
|
|
221
|
+
item["modelId"] = model_id
|
|
222
|
+
item["revisionId"] = revision_id
|
|
223
|
+
results.extend(TypeAdapter(list[AssetMappingResponse]).validate_python(items))
|
|
224
|
+
return results
|
|
225
|
+
|
|
226
|
+
@classmethod
|
|
227
|
+
def _chunk_mappings_by_endpoint(
|
|
228
|
+
cls, mappings: Sequence[T_RequestMapping], chunk_size: int
|
|
229
|
+
) -> Iterable[tuple[str, int, int, list[T_RequestMapping]]]:
|
|
230
|
+
chunked_mappings: dict[tuple[int, int], list[T_RequestMapping]] = defaultdict(list)
|
|
231
|
+
for mapping in mappings:
|
|
232
|
+
key = mapping.model_id, mapping.revision_id
|
|
233
|
+
chunked_mappings[key].append(mapping)
|
|
234
|
+
for (model_id, revision_id), revision_mappings in chunked_mappings.items():
|
|
235
|
+
endpoint = cls.ENDPOINT.format(modelId=model_id, revisionId=revision_id)
|
|
236
|
+
for chunk in chunker_sequence(revision_mappings, chunk_size):
|
|
237
|
+
yield endpoint, model_id, revision_id, chunk
|
|
238
|
+
|
|
239
|
+
def delete(self, mappings: Sequence[AssetMappingClassicRequest]) -> None:
|
|
240
|
+
"""Delete 3D asset mappings.
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
mappings (Sequence[AssetMappingClassicRequest]):
|
|
244
|
+
The 3D asset mapping(s) to delete.
|
|
245
|
+
"""
|
|
246
|
+
for endpoint, *_, revision_mappings in self._chunk_mappings_by_endpoint(
|
|
247
|
+
mappings, self.DELETE_CLASSIC_MAX_MAPPINGS_PER_REQUEST
|
|
248
|
+
):
|
|
249
|
+
responses = self._http_client.request_items_retries(
|
|
250
|
+
ItemsRequest2(
|
|
251
|
+
endpoint_url=self._config.create_api_url(f"{endpoint}/delete"),
|
|
252
|
+
method="DELETE",
|
|
253
|
+
items=revision_mappings,
|
|
254
|
+
)
|
|
255
|
+
)
|
|
256
|
+
responses.raise_for_status()
|
|
257
|
+
return None
|
|
258
|
+
|
|
259
|
+
def delete_dm(self, mappings: Sequence[AssetMappingDMRequest], object_3d_space: str, cad_node_space: str) -> None:
|
|
260
|
+
"""Delete 3D asset mappings in Data Modeling format.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
mappings (Sequence[AssetMappingDMRequest]):
|
|
264
|
+
The 3D asset mapping(s) to delete.
|
|
265
|
+
object_3d_space (str):
|
|
266
|
+
The instance space where the Cognite3DObject are located.
|
|
267
|
+
cad_node_space (str):
|
|
268
|
+
The instance space where the CogniteCADNode are located.
|
|
269
|
+
"""
|
|
270
|
+
for endpoint, *_, revision_mappings in self._chunk_mappings_by_endpoint(
|
|
271
|
+
mappings, self.DELETE_DM_MAX_MAPPINGS_PER_REQUEST
|
|
272
|
+
):
|
|
273
|
+
responses = self._http_client.request_items_retries(
|
|
274
|
+
ItemsRequest2(
|
|
275
|
+
endpoint_url=self._config.create_api_url(f"{endpoint}/delete"),
|
|
276
|
+
method="DELETE",
|
|
277
|
+
items=revision_mappings,
|
|
278
|
+
extra_body_fields={
|
|
279
|
+
"dmsContextualizationConfig": {
|
|
280
|
+
"object3DSpace": object_3d_space,
|
|
281
|
+
"cadNodeSpace": cad_node_space,
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
)
|
|
285
|
+
)
|
|
286
|
+
responses.raise_for_status()
|
|
287
|
+
return None
|
|
288
|
+
|
|
289
|
+
def iterate(
|
|
290
|
+
self,
|
|
291
|
+
model_id: int,
|
|
292
|
+
revision_id: int,
|
|
293
|
+
asset_ids: list[int] | None = None,
|
|
294
|
+
asset_instance_ids: list[str] | None = None,
|
|
295
|
+
node_ids: list[int] | None = None,
|
|
296
|
+
tree_indexes: list[int] | None = None,
|
|
297
|
+
get_dms_instances: bool = False,
|
|
298
|
+
limit: int = 100,
|
|
299
|
+
cursor: str | None = None,
|
|
300
|
+
) -> PagedResponse[AssetMappingResponse]:
|
|
301
|
+
if not (0 < limit <= self.LIST_REQUEST_MAX_LIMIT):
|
|
302
|
+
raise ValueError(f"Limit must be between 1 and {self.LIST_REQUEST_MAX_LIMIT}, got {limit}.")
|
|
303
|
+
if sum(param is not None for param in [asset_ids, asset_instance_ids, node_ids, tree_indexes]) > 1:
|
|
304
|
+
raise ValueError("Only one of asset_ids, asset_instance_ids, node_ids, or tree_indexes can be provided.")
|
|
305
|
+
body: dict[str, Any] = {
|
|
306
|
+
"getDmsInstances": get_dms_instances,
|
|
307
|
+
"limit": limit,
|
|
308
|
+
}
|
|
309
|
+
if asset_ids is not None:
|
|
310
|
+
if not (0 < len(asset_ids) <= 100):
|
|
311
|
+
raise ValueError("asset_ids must contain between 1 and 100 IDs.")
|
|
312
|
+
body["filter"] = {"assetIds": asset_ids}
|
|
313
|
+
elif asset_instance_ids is not None:
|
|
314
|
+
if not (0 < len(asset_instance_ids) <= 100):
|
|
315
|
+
raise ValueError("asset_instance_ids must contain between 1 and 100 IDs.")
|
|
316
|
+
body["filter"] = {"assetInstanceIds": asset_instance_ids}
|
|
317
|
+
elif node_ids is not None:
|
|
318
|
+
if not (0 < len(node_ids) <= 100):
|
|
319
|
+
raise ValueError("node_ids must contain between 1 and 100 IDs.")
|
|
320
|
+
body["filter"] = {"nodeIds": node_ids}
|
|
321
|
+
elif tree_indexes is not None:
|
|
322
|
+
if not (0 < len(tree_indexes) <= 100):
|
|
323
|
+
raise ValueError("tree_indexes must contain between 1 and 100 indexes.")
|
|
324
|
+
body["filter"] = {"treeIndexes": tree_indexes}
|
|
325
|
+
if cursor is not None:
|
|
326
|
+
body["cursor"] = cursor
|
|
327
|
+
|
|
328
|
+
endpoint = self.ENDPOINT.format(modelId=model_id, revisionId=revision_id)
|
|
329
|
+
responses = self._http_client.request_single_retries(
|
|
330
|
+
RequestMessage2(
|
|
331
|
+
endpoint_url=self._config.create_api_url(f"{endpoint}/list"),
|
|
332
|
+
method="POST",
|
|
333
|
+
body_content=body,
|
|
334
|
+
)
|
|
335
|
+
)
|
|
336
|
+
success_response = responses.get_success_or_raise()
|
|
337
|
+
body_json = success_response.body_json
|
|
338
|
+
# Add modelId and revisionId to items since the API does not return them
|
|
339
|
+
for item in body_json.get("items", []):
|
|
340
|
+
item["modelId"] = model_id
|
|
341
|
+
item["revisionId"] = revision_id
|
|
342
|
+
return PagedResponse[AssetMappingResponse].model_validate(body_json)
|
|
343
|
+
|
|
344
|
+
def list(
|
|
345
|
+
self,
|
|
346
|
+
model_id: int,
|
|
347
|
+
revision_id: int,
|
|
348
|
+
asset_ids: list[int] | None = None,
|
|
349
|
+
asset_instance_ids: list[str] | None = None,
|
|
350
|
+
node_ids: list[int] | None = None,
|
|
351
|
+
tree_indexes: list[int] | None = None,
|
|
352
|
+
get_dms_instances: bool = False,
|
|
353
|
+
limit: int | None = 100,
|
|
354
|
+
) -> list[AssetMappingResponse]:
|
|
355
|
+
results: list[AssetMappingResponse] = []
|
|
356
|
+
cursor: str | None = None
|
|
357
|
+
while True:
|
|
358
|
+
request_limit = (
|
|
359
|
+
self.LIST_REQUEST_MAX_LIMIT if limit is None else min(limit - len(results), self.LIST_REQUEST_MAX_LIMIT)
|
|
360
|
+
)
|
|
361
|
+
if request_limit <= 0:
|
|
362
|
+
break
|
|
363
|
+
page = self.iterate(
|
|
364
|
+
model_id=model_id,
|
|
365
|
+
revision_id=revision_id,
|
|
366
|
+
asset_ids=asset_ids,
|
|
367
|
+
asset_instance_ids=asset_instance_ids,
|
|
368
|
+
node_ids=node_ids,
|
|
369
|
+
tree_indexes=tree_indexes,
|
|
370
|
+
get_dms_instances=get_dms_instances,
|
|
371
|
+
limit=request_limit,
|
|
372
|
+
cursor=cursor,
|
|
373
|
+
)
|
|
374
|
+
results.extend(page.items)
|
|
375
|
+
if page.next_cursor is None:
|
|
376
|
+
break
|
|
377
|
+
cursor = page.next_cursor
|
|
378
|
+
return results
|
|
379
|
+
|
|
380
|
+
|
|
129
381
|
class ThreeDAPI:
|
|
130
382
|
def __init__(self, http_client: HTTPClient, console: Console) -> None:
|
|
131
383
|
self.models = ThreeDModelAPI(http_client, console)
|
|
384
|
+
self.asset_mappings = ThreeDAssetMappingAPI(http_client, console)
|
|
@@ -2,6 +2,8 @@ from typing import Generic, TypeVar
|
|
|
2
2
|
|
|
3
3
|
from pydantic import BaseModel, Field, JsonValue
|
|
4
4
|
|
|
5
|
+
from cognite_toolkit._cdf_tk.utils.http_client._data_classes2 import RequestResource
|
|
6
|
+
|
|
5
7
|
T = TypeVar("T", bound=BaseModel)
|
|
6
8
|
|
|
7
9
|
|
|
@@ -15,3 +17,14 @@ class QueryResponse(BaseModel, Generic[T]):
|
|
|
15
17
|
typing: dict[str, JsonValue] | None = None
|
|
16
18
|
next_cursor: dict[str, str] = Field(alias="nextCursor")
|
|
17
19
|
debug: dict[str, JsonValue] | None = None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class InternalIdRequest(RequestResource):
|
|
23
|
+
id: int
|
|
24
|
+
|
|
25
|
+
def as_id(self) -> int:
|
|
26
|
+
return self.id
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def from_ids(cls, ids: list[int]) -> list["InternalIdRequest"]:
|
|
30
|
+
return [cls(id=id_) for id_ in ids]
|
|
@@ -3,7 +3,7 @@ from abc import ABC, abstractmethod
|
|
|
3
3
|
from collections import UserList
|
|
4
4
|
from typing import TYPE_CHECKING, Any, Generic, TypeVar
|
|
5
5
|
|
|
6
|
-
from pydantic import
|
|
6
|
+
from pydantic import ConfigDict
|
|
7
7
|
from pydantic.alias_generators import to_camel
|
|
8
8
|
|
|
9
9
|
from cognite_toolkit._cdf_tk.utils.http_client._data_classes2 import BaseModelObject, RequestResource
|
|
@@ -31,21 +31,17 @@ class ResponseResource(BaseModelObject, Generic[T_RequestResource], ABC):
|
|
|
31
31
|
return self.as_request_resource()
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
class Identifier(
|
|
34
|
+
class Identifier(RequestResource, ABC):
|
|
35
35
|
"""Base class for all identifier classes."""
|
|
36
36
|
|
|
37
37
|
model_config = ConfigDict(alias_generator=to_camel, extra="ignore", populate_by_name=True, frozen=True)
|
|
38
38
|
|
|
39
|
-
def dump(self, include_type: bool = True) -> dict[str, Any]:
|
|
40
|
-
"""Dump the
|
|
39
|
+
def dump(self, camel_case: bool = True, include_type: bool = True) -> dict[str, Any]:
|
|
40
|
+
"""Dump the resource to a dictionary.
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
include_type (bool): Whether to include the type of the identifier in the output.
|
|
44
|
-
|
|
45
|
-
Returns:
|
|
46
|
-
dict[str, Any]: The dumped identifier.
|
|
42
|
+
This is the default serialization method for request resources.
|
|
47
43
|
"""
|
|
48
|
-
return self.model_dump(mode="json", by_alias=
|
|
44
|
+
return self.model_dump(mode="json", by_alias=camel_case, exclude_unset=not include_type)
|
|
49
45
|
|
|
50
46
|
def as_id(self) -> Self:
|
|
51
47
|
return self
|
|
@@ -15,19 +15,19 @@ class TypedInstanceIdentifier(Identifier):
|
|
|
15
15
|
external_id: str
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
class
|
|
19
|
-
space: str
|
|
20
|
-
external_id: str
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class NodeIdentifier(TypedInstanceIdentifier):
|
|
18
|
+
class TypedNodeIdentifier(TypedInstanceIdentifier):
|
|
24
19
|
instance_type: Literal["node"] = "node"
|
|
25
20
|
|
|
26
21
|
|
|
27
|
-
class
|
|
22
|
+
class TypedEdgeIdentifier(TypedInstanceIdentifier):
|
|
28
23
|
instance_type: Literal["edge"] = "edge"
|
|
29
24
|
|
|
30
25
|
|
|
26
|
+
class InstanceIdentifier(Identifier):
|
|
27
|
+
space: str
|
|
28
|
+
external_id: str
|
|
29
|
+
|
|
30
|
+
|
|
31
31
|
class InstanceResult(BaseModelObject):
|
|
32
32
|
instance_type: InstanceType
|
|
33
33
|
version: int
|
|
File without changes
|
|
@@ -30,7 +30,7 @@ from cognite.client.data_classes.data_modeling.instances import (
|
|
|
30
30
|
TypedNodeApply,
|
|
31
31
|
)
|
|
32
32
|
|
|
33
|
-
from cognite_toolkit._cdf_tk.client.data_classes.migration import AssetCentricId
|
|
33
|
+
from cognite_toolkit._cdf_tk.client.data_classes.legacy.migration import AssetCentricId
|
|
34
34
|
from cognite_toolkit._cdf_tk.utils.useful_types import JsonVal
|
|
35
35
|
|
|
36
36
|
if sys.version_info >= (3, 11):
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
from collections.abc import Hashable
|
|
1
2
|
from typing import Literal
|
|
2
3
|
|
|
4
|
+
from pydantic import Field
|
|
5
|
+
|
|
3
6
|
from .base import BaseModelObject, RequestResource, ResponseResource
|
|
4
7
|
|
|
5
8
|
|
|
@@ -51,3 +54,59 @@ class ThreeDModelResponse(ResponseResource[ThreeDModelRequest]):
|
|
|
51
54
|
return ThreeDModelClassicRequest._load(self.dump())
|
|
52
55
|
else:
|
|
53
56
|
return ThreeDModelDMSRequest._load(self.dump())
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class AssetMappingDMRequest(RequestResource):
|
|
60
|
+
node_id: int
|
|
61
|
+
asset_instance_id: NodeReference
|
|
62
|
+
# These fields are part of the path request and not the body schema.
|
|
63
|
+
model_id: int = Field(exclude=True)
|
|
64
|
+
revision_id: int = Field(exclude=True)
|
|
65
|
+
|
|
66
|
+
def as_id(self) -> Hashable:
|
|
67
|
+
return (
|
|
68
|
+
self.model_id,
|
|
69
|
+
self.revision_id,
|
|
70
|
+
self.node_id,
|
|
71
|
+
self.asset_instance_id.space,
|
|
72
|
+
self.asset_instance_id.external_id,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class AssetMappingClassicRequest(RequestResource):
|
|
77
|
+
node_id: int
|
|
78
|
+
asset_id: int | None = None
|
|
79
|
+
asset_instance_id: NodeReference | None = None
|
|
80
|
+
# These fields are part of the path request and not the body schema.
|
|
81
|
+
model_id: int = Field(exclude=True)
|
|
82
|
+
revision_id: int = Field(exclude=True)
|
|
83
|
+
|
|
84
|
+
def as_id(self) -> Hashable:
|
|
85
|
+
if self.asset_id:
|
|
86
|
+
return self.model_id, self.revision_id, self.node_id, self.asset_id
|
|
87
|
+
elif self.asset_instance_id:
|
|
88
|
+
return (
|
|
89
|
+
self.model_id,
|
|
90
|
+
self.revision_id,
|
|
91
|
+
self.node_id,
|
|
92
|
+
self.asset_instance_id.space,
|
|
93
|
+
self.asset_instance_id.external_id,
|
|
94
|
+
)
|
|
95
|
+
else:
|
|
96
|
+
raise AttributeError("asset_id or asset_instance_id is required")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class AssetMappingResponse(ResponseResource[AssetMappingClassicRequest]):
|
|
100
|
+
node_id: int
|
|
101
|
+
asset_id: int | None = None
|
|
102
|
+
asset_instance_id: NodeReference | None = None
|
|
103
|
+
tree_index: int | None = None
|
|
104
|
+
subtree_size: int | None = None
|
|
105
|
+
# These fields are part of the path request and response, but they are included here for convenience.
|
|
106
|
+
model_id: int = Field(exclude=True)
|
|
107
|
+
revision_id: int = Field(exclude=True)
|
|
108
|
+
|
|
109
|
+
def as_request_resource(self) -> AssetMappingClassicRequest:
|
|
110
|
+
return AssetMappingClassicRequest.model_validate(
|
|
111
|
+
{**self.dump(), "modelId": self.model_id, "revisionId": self.revision_id}
|
|
112
|
+
)
|
|
@@ -12,18 +12,27 @@ from cognite.client.testing import CogniteClientMock
|
|
|
12
12
|
from rich.console import Console
|
|
13
13
|
|
|
14
14
|
from cognite_toolkit._cdf_tk.client._toolkit_client import ToolkitClient
|
|
15
|
+
from cognite_toolkit._cdf_tk.client.api.legacy.canvas import CanvasAPI, IndustrialCanvasAPI
|
|
16
|
+
from cognite_toolkit._cdf_tk.client.api.legacy.charts import ChartsAPI
|
|
17
|
+
from cognite_toolkit._cdf_tk.client.api.legacy.dml import DMLAPI
|
|
18
|
+
from cognite_toolkit._cdf_tk.client.api.legacy.extended_data_modeling import ExtendedInstancesAPI
|
|
19
|
+
from cognite_toolkit._cdf_tk.client.api.legacy.extended_files import ExtendedFileMetadataAPI
|
|
20
|
+
from cognite_toolkit._cdf_tk.client.api.legacy.extended_functions import ExtendedFunctionsAPI
|
|
21
|
+
from cognite_toolkit._cdf_tk.client.api.legacy.extended_raw import ExtendedRawAPI
|
|
22
|
+
from cognite_toolkit._cdf_tk.client.api.legacy.extended_timeseries import ExtendedTimeSeriesAPI
|
|
23
|
+
from cognite_toolkit._cdf_tk.client.api.legacy.location_filters import LocationFiltersAPI
|
|
24
|
+
from cognite_toolkit._cdf_tk.client.api.legacy.robotics import (
|
|
25
|
+
CapabilitiesAPI,
|
|
26
|
+
DataPostProcessingAPI,
|
|
27
|
+
FramesAPI,
|
|
28
|
+
MapsAPI,
|
|
29
|
+
RoboticsAPI,
|
|
30
|
+
)
|
|
31
|
+
from cognite_toolkit._cdf_tk.client.api.legacy.robotics import LocationsAPI as RoboticsLocationsAPI
|
|
32
|
+
from cognite_toolkit._cdf_tk.client.api.legacy.search_config import SearchConfigurationsAPI
|
|
15
33
|
|
|
16
34
|
from ._toolkit_client import ToolAPI
|
|
17
|
-
from .api.canvas import CanvasAPI, IndustrialCanvasAPI
|
|
18
|
-
from .api.charts import ChartsAPI
|
|
19
|
-
from .api.dml import DMLAPI
|
|
20
|
-
from .api.extended_data_modeling import ExtendedInstancesAPI
|
|
21
|
-
from .api.extended_files import ExtendedFileMetadataAPI
|
|
22
|
-
from .api.extended_functions import ExtendedFunctionsAPI
|
|
23
|
-
from .api.extended_raw import ExtendedRawAPI
|
|
24
|
-
from .api.extended_timeseries import ExtendedTimeSeriesAPI
|
|
25
35
|
from .api.infield import InfieldAPI, InFieldCDMConfigAPI, InfieldConfigAPI
|
|
26
|
-
from .api.location_filters import LocationFiltersAPI
|
|
27
36
|
from .api.lookup import (
|
|
28
37
|
AssetLookUpAPI,
|
|
29
38
|
DataSetLookUpAPI,
|
|
@@ -45,14 +54,7 @@ from .api.migration import (
|
|
|
45
54
|
ResourceViewMappingAPI,
|
|
46
55
|
)
|
|
47
56
|
from .api.project import ProjectAPI
|
|
48
|
-
from .api.robotics import RoboticsAPI
|
|
49
|
-
from .api.robotics.capabilities import CapabilitiesAPI
|
|
50
|
-
from .api.robotics.data_postprocessing import DataPostProcessingAPI
|
|
51
|
-
from .api.robotics.frames import FramesAPI
|
|
52
|
-
from .api.robotics.locations import LocationsAPI as RoboticsLocationsAPI
|
|
53
|
-
from .api.robotics.maps import MapsAPI
|
|
54
57
|
from .api.search import SearchAPI
|
|
55
|
-
from .api.search_config import SearchConfigurationsAPI
|
|
56
58
|
from .api.streams import StreamsAPI
|
|
57
59
|
from .api.three_d import ThreeDAPI, ThreeDModelAPI
|
|
58
60
|
from .api.token import TokenAPI
|
|
@@ -15,7 +15,7 @@ from cognite.client.data_classes.data_modeling.views import ViewProperty
|
|
|
15
15
|
from cognite.client.utils._identifier import InstanceId
|
|
16
16
|
|
|
17
17
|
from cognite_toolkit._cdf_tk.client import ToolkitClient
|
|
18
|
-
from cognite_toolkit._cdf_tk.client.data_classes.migration import (
|
|
18
|
+
from cognite_toolkit._cdf_tk.client.data_classes.legacy.migration import (
|
|
19
19
|
AssetCentricId,
|
|
20
20
|
ResourceViewMappingApply,
|
|
21
21
|
)
|
|
@@ -20,7 +20,7 @@ from cognite.client.data_classes.documents import SourceFileProperty
|
|
|
20
20
|
from cognite.client.data_classes.events import EventProperty
|
|
21
21
|
|
|
22
22
|
from cognite_toolkit._cdf_tk.client import ToolkitClient
|
|
23
|
-
from cognite_toolkit._cdf_tk.client.data_classes.apm_config_v1 import APMConfig, APMConfigList
|
|
23
|
+
from cognite_toolkit._cdf_tk.client.data_classes.legacy.apm_config_v1 import APMConfig, APMConfigList
|
|
24
24
|
from cognite_toolkit._cdf_tk.cruds import NodeCRUD, ResourceCRUD, SpaceCRUD
|
|
25
25
|
from cognite_toolkit._cdf_tk.exceptions import ToolkitMissingResourceError, ToolkitRequiredValueError
|
|
26
26
|
from cognite_toolkit._cdf_tk.utils import humanize_collection
|
|
@@ -13,9 +13,9 @@ from pydantic import BaseModel, BeforeValidator, Field, field_validator, model_v
|
|
|
13
13
|
|
|
14
14
|
from cognite_toolkit._cdf_tk.client.data_classes.base import BaseModelObject, RequestResource
|
|
15
15
|
from cognite_toolkit._cdf_tk.client.data_classes.instance_api import InstanceIdentifier
|
|
16
|
-
from cognite_toolkit._cdf_tk.client.data_classes.instances import InstanceApplyList
|
|
17
|
-
from cognite_toolkit._cdf_tk.client.data_classes.migration import AssetCentricId
|
|
18
|
-
from cognite_toolkit._cdf_tk.client.data_classes.pending_instances_ids import PendingInstanceId
|
|
16
|
+
from cognite_toolkit._cdf_tk.client.data_classes.legacy.instances import InstanceApplyList
|
|
17
|
+
from cognite_toolkit._cdf_tk.client.data_classes.legacy.migration import AssetCentricId
|
|
18
|
+
from cognite_toolkit._cdf_tk.client.data_classes.legacy.pending_instances_ids import PendingInstanceId
|
|
19
19
|
from cognite_toolkit._cdf_tk.commands._migrate.default_mappings import (
|
|
20
20
|
ASSET_ANNOTATIONS_ID,
|
|
21
21
|
FILE_ANNOTATIONS_ID,
|
|
@@ -15,21 +15,27 @@ from cognite.client.data_classes.data_modeling import (
|
|
|
15
15
|
from cognite.client.exceptions import CogniteException
|
|
16
16
|
|
|
17
17
|
from cognite_toolkit._cdf_tk.client import ToolkitClient
|
|
18
|
-
from cognite_toolkit._cdf_tk.client.data_classes.canvas import (
|
|
19
|
-
ContainerReferenceApply,
|
|
20
|
-
FdmInstanceContainerReferenceApply,
|
|
21
|
-
IndustrialCanvas,
|
|
22
|
-
IndustrialCanvasApply,
|
|
23
|
-
)
|
|
24
|
-
from cognite_toolkit._cdf_tk.client.data_classes.charts import Chart, ChartWrite
|
|
25
18
|
from cognite_toolkit._cdf_tk.client.data_classes.charts_data import (
|
|
26
19
|
ChartCoreTimeseries,
|
|
27
20
|
ChartSource,
|
|
28
21
|
ChartTimeseries,
|
|
29
22
|
)
|
|
30
23
|
from cognite_toolkit._cdf_tk.client.data_classes.instance_api import InstanceIdentifier
|
|
31
|
-
from cognite_toolkit._cdf_tk.client.data_classes.
|
|
32
|
-
|
|
24
|
+
from cognite_toolkit._cdf_tk.client.data_classes.legacy.canvas import (
|
|
25
|
+
ContainerReferenceApply,
|
|
26
|
+
FdmInstanceContainerReferenceApply,
|
|
27
|
+
IndustrialCanvas,
|
|
28
|
+
IndustrialCanvasApply,
|
|
29
|
+
)
|
|
30
|
+
from cognite_toolkit._cdf_tk.client.data_classes.legacy.charts import Chart, ChartWrite
|
|
31
|
+
from cognite_toolkit._cdf_tk.client.data_classes.legacy.migration import ResourceViewMappingApply
|
|
32
|
+
from cognite_toolkit._cdf_tk.client.data_classes.three_d import (
|
|
33
|
+
AssetMappingDMRequest,
|
|
34
|
+
AssetMappingResponse,
|
|
35
|
+
NodeReference,
|
|
36
|
+
RevisionStatus,
|
|
37
|
+
ThreeDModelResponse,
|
|
38
|
+
)
|
|
33
39
|
from cognite_toolkit._cdf_tk.commands._migrate.conversion import DirectRelationCache, asset_centric_to_dm
|
|
34
40
|
from cognite_toolkit._cdf_tk.commands._migrate.data_classes import (
|
|
35
41
|
Model,
|
|
@@ -443,15 +449,15 @@ class ThreeDMapper(DataMapper[ThreeDSelector, ThreeDModelResponse, ThreeDMigrati
|
|
|
443
449
|
return None, issue
|
|
444
450
|
|
|
445
451
|
mapped_request = ThreeDMigrationRequest(
|
|
446
|
-
|
|
452
|
+
modelId=item.id,
|
|
447
453
|
type=model_type,
|
|
448
454
|
space=instance_space,
|
|
449
455
|
revision=ThreeDRevisionMigrationRequest(
|
|
450
456
|
space=instance_space,
|
|
451
457
|
type=model_type,
|
|
452
|
-
|
|
458
|
+
revisionId=last_revision_id,
|
|
453
459
|
model=Model(
|
|
454
|
-
|
|
460
|
+
instanceId=InstanceIdentifier(
|
|
455
461
|
space=instance_space,
|
|
456
462
|
external_id=f"cog_3d_model_{item.id!s}",
|
|
457
463
|
)
|
|
@@ -469,3 +475,45 @@ class ThreeDMapper(DataMapper[ThreeDSelector, ThreeDModelResponse, ThreeDMigrati
|
|
|
469
475
|
return "PointCloud"
|
|
470
476
|
else:
|
|
471
477
|
return None
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
class ThreeDAssetMapper(DataMapper[ThreeDSelector, AssetMappingResponse, AssetMappingDMRequest]):
|
|
481
|
+
def __init__(self, client: ToolkitClient) -> None:
|
|
482
|
+
self.client = client
|
|
483
|
+
|
|
484
|
+
def map(
|
|
485
|
+
self, source: Sequence[AssetMappingResponse]
|
|
486
|
+
) -> Sequence[tuple[AssetMappingDMRequest | None, MigrationIssue]]:
|
|
487
|
+
output: list[tuple[AssetMappingDMRequest | None, MigrationIssue]] = []
|
|
488
|
+
self._populate_cache(source)
|
|
489
|
+
for item in source:
|
|
490
|
+
mapped_item, issue = self._map_single_item(item)
|
|
491
|
+
output.append((mapped_item, issue))
|
|
492
|
+
return output
|
|
493
|
+
|
|
494
|
+
def _populate_cache(self, source: Sequence[AssetMappingResponse]) -> None:
|
|
495
|
+
asset_ids: set[int] = set()
|
|
496
|
+
for mapping in source:
|
|
497
|
+
if mapping.asset_id is not None:
|
|
498
|
+
asset_ids.add(mapping.asset_id)
|
|
499
|
+
self.client.migration.lookup.assets(list(asset_ids))
|
|
500
|
+
|
|
501
|
+
def _map_single_item(
|
|
502
|
+
self, item: AssetMappingResponse
|
|
503
|
+
) -> tuple[AssetMappingDMRequest | None, ThreeDModelMigrationIssue]:
|
|
504
|
+
issue = ThreeDModelMigrationIssue(model_name=f"AssetMapping_{item.model_id}", model_id=item.model_id)
|
|
505
|
+
asset_instance_id = item.asset_instance_id
|
|
506
|
+
if item.asset_id and asset_instance_id is None:
|
|
507
|
+
asset_node_id = self.client.migration.lookup.assets(item.asset_id)
|
|
508
|
+
if asset_node_id is None:
|
|
509
|
+
issue.error_message.append(f"Missing asset instance for asset ID {item.asset_id!r}")
|
|
510
|
+
return None, issue
|
|
511
|
+
asset_instance_id = NodeReference(space=asset_node_id.space, externalId=asset_node_id.external_id)
|
|
512
|
+
|
|
513
|
+
if asset_instance_id is None:
|
|
514
|
+
issue.error_message.append("Neither assetInstanceId nor assetId provided for mapping.")
|
|
515
|
+
return None, issue
|
|
516
|
+
mapped_request = AssetMappingDMRequest(
|
|
517
|
+
modelId=item.model_id, revisionId=item.revision_id, nodeId=item.node_id, assetInstanceId=asset_instance_id
|
|
518
|
+
)
|
|
519
|
+
return mapped_request, issue
|