cognite-toolkit 0.7.43__py3-none-any.whl → 0.7.44__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 (50) hide show
  1. cognite_toolkit/_cdf_tk/client/_toolkit_client.py +6 -0
  2. cognite_toolkit/_cdf_tk/client/api/filemetadata.py +145 -0
  3. cognite_toolkit/_cdf_tk/client/api/raw.py +174 -0
  4. cognite_toolkit/_cdf_tk/client/api/simulator_models.py +118 -0
  5. cognite_toolkit/_cdf_tk/client/api/simulators.py +8 -0
  6. cognite_toolkit/_cdf_tk/client/cdf_client/__init__.py +2 -1
  7. cognite_toolkit/_cdf_tk/client/cdf_client/api.py +40 -6
  8. cognite_toolkit/_cdf_tk/client/data_classes/annotation.py +79 -0
  9. cognite_toolkit/_cdf_tk/client/data_classes/base.py +13 -3
  10. cognite_toolkit/_cdf_tk/client/data_classes/data_modeling/__init__.py +16 -0
  11. cognite_toolkit/_cdf_tk/client/data_classes/data_modeling/_instance.py +143 -0
  12. cognite_toolkit/_cdf_tk/client/data_classes/data_modeling/_references.py +8 -0
  13. cognite_toolkit/_cdf_tk/client/data_classes/dataset.py +35 -0
  14. cognite_toolkit/_cdf_tk/client/data_classes/extraction_pipeline.py +59 -0
  15. cognite_toolkit/_cdf_tk/client/data_classes/filemetadata.py +7 -1
  16. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_destination.py +34 -0
  17. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_job.py +134 -0
  18. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_mapping.py +72 -0
  19. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/__init__.py +63 -0
  20. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_auth.py +63 -0
  21. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_base.py +26 -0
  22. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_certificate.py +20 -0
  23. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_eventhub.py +31 -0
  24. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_kafka.py +53 -0
  25. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_mqtt.py +36 -0
  26. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_rest.py +49 -0
  27. cognite_toolkit/_cdf_tk/client/data_classes/identifiers.py +8 -0
  28. cognite_toolkit/_cdf_tk/client/data_classes/label.py +27 -0
  29. cognite_toolkit/_cdf_tk/client/data_classes/raw.py +3 -2
  30. cognite_toolkit/_cdf_tk/client/data_classes/securitycategory.py +24 -0
  31. cognite_toolkit/_cdf_tk/client/data_classes/sequence.py +45 -0
  32. cognite_toolkit/_cdf_tk/client/data_classes/transformation.py +140 -0
  33. cognite_toolkit/_cdf_tk/client/data_classes/workflow.py +27 -0
  34. cognite_toolkit/_cdf_tk/client/data_classes/workflow_trigger.py +63 -0
  35. cognite_toolkit/_cdf_tk/client/data_classes/workflow_version.py +155 -0
  36. cognite_toolkit/_cdf_tk/client/testing.py +5 -0
  37. cognite_toolkit/_cdf_tk/commands/_migrate/conversion.py +4 -3
  38. cognite_toolkit/_cdf_tk/cruds/_data_cruds.py +7 -3
  39. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/file.py +56 -59
  40. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/relationship.py +1 -1
  41. cognite_toolkit/_cdf_tk/storageio/_asset_centric.py +34 -29
  42. cognite_toolkit/_cdf_tk/storageio/_file_content.py +22 -19
  43. cognite_toolkit/_repo_files/GitHub/.github/workflows/deploy.yaml +1 -1
  44. cognite_toolkit/_repo_files/GitHub/.github/workflows/dry-run.yaml +1 -1
  45. cognite_toolkit/_resources/cdf.toml +1 -1
  46. cognite_toolkit/_version.py +1 -1
  47. {cognite_toolkit-0.7.43.dist-info → cognite_toolkit-0.7.44.dist-info}/METADATA +11 -1
  48. {cognite_toolkit-0.7.43.dist-info → cognite_toolkit-0.7.44.dist-info}/RECORD +50 -24
  49. {cognite_toolkit-0.7.43.dist-info → cognite_toolkit-0.7.44.dist-info}/WHEEL +1 -1
  50. {cognite_toolkit-0.7.43.dist-info → cognite_toolkit-0.7.44.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,63 @@
1
+ from typing import Annotated, Literal
2
+
3
+ from pydantic import Field, JsonValue
4
+
5
+ from cognite_toolkit._cdf_tk.client.data_classes.base import (
6
+ BaseModelObject,
7
+ RequestResource,
8
+ ResponseResource,
9
+ )
10
+
11
+ from .identifiers import ExternalId
12
+
13
+
14
+ class TriggerRuleDefinition(BaseModelObject):
15
+ trigger_type: str
16
+
17
+
18
+ class ScheduleTriggerRule(BaseModelObject):
19
+ trigger_type: Literal["schedule"] = "schedule"
20
+ cron_expression: str
21
+ timezone: str | None = None
22
+
23
+
24
+ class DataModelingTriggerRule(BaseModelObject):
25
+ trigger_type: Literal["dataModeling"] = "dataModeling"
26
+ data_modeling_query: JsonValue
27
+ batch_size: int
28
+ batch_timeout: int
29
+
30
+
31
+ TriggerRule = Annotated[
32
+ ScheduleTriggerRule | DataModelingTriggerRule,
33
+ Field(discriminator="trigger_type"),
34
+ ]
35
+
36
+
37
+ class NonceCredentials(BaseModelObject):
38
+ nonce: str
39
+
40
+
41
+ class WorkflowTrigger(BaseModelObject):
42
+ external_id: str
43
+ trigger_rule: TriggerRule
44
+ workflow_external_id: str
45
+ workflow_version: str
46
+ input: JsonValue | None = None
47
+ metadata: dict[str, str] | None = None
48
+
49
+ def as_id(self) -> ExternalId:
50
+ return ExternalId(external_id=self.external_id)
51
+
52
+
53
+ class WorkflowTriggerRequest(WorkflowTrigger, RequestResource):
54
+ authentication: NonceCredentials
55
+
56
+
57
+ class WorkflowTriggerResponse(WorkflowTrigger, ResponseResource[WorkflowTriggerRequest]):
58
+ created_time: int
59
+ last_updated_time: int
60
+ is_paused: bool
61
+
62
+ def as_request_resource(self) -> WorkflowTriggerRequest:
63
+ return WorkflowTriggerRequest.model_validate(self.dump(), extra="ignore")
@@ -0,0 +1,155 @@
1
+ from typing import Annotated, Any, Literal
2
+
3
+ from pydantic import Field, JsonValue, field_validator
4
+ from pydantic_core.core_schema import ValidationInfo
5
+
6
+ from cognite_toolkit._cdf_tk.client.data_classes.base import (
7
+ BaseModelObject,
8
+ RequestResource,
9
+ ResponseResource,
10
+ )
11
+
12
+ from .identifiers import Identifier, WorkflowVersionId
13
+
14
+
15
+ class TaskId(Identifier):
16
+ external_id: str
17
+
18
+ def __str__(self) -> str:
19
+ return f"externalId='{self.external_id}'"
20
+
21
+
22
+ class TaskParameterDefinition(BaseModelObject):
23
+ type: str
24
+
25
+
26
+ class CogniteFunctionRef(BaseModelObject):
27
+ external_id: str
28
+ data: JsonValue | str | None = None
29
+
30
+
31
+ class FunctionTaskParameters(TaskParameterDefinition):
32
+ type: Literal["function"] = Field("function", exclude=True)
33
+ function: CogniteFunctionRef
34
+ is_async_complete: bool | None = None
35
+
36
+
37
+ class TransformationRef(BaseModelObject):
38
+ external_id: str
39
+ concurrency_policy: Literal["fail", "waitForCurrent", "restartAfterCurrent"] | None = None
40
+ use_transformation_credentials: bool | None = None
41
+
42
+
43
+ class TransformationTaskParameters(TaskParameterDefinition):
44
+ type: Literal["transformation"] = Field("transformation", exclude=True)
45
+ transformation: TransformationRef
46
+
47
+
48
+ class CDFRequest(BaseModelObject):
49
+ resource_path: str
50
+ method: str
51
+ query_parameters: JsonValue | str | None = None
52
+ body: JsonValue | str | None = None
53
+ request_timeout_in_millis: float | str | None = None
54
+ cdf_version_header: str | None = None
55
+
56
+
57
+ class CDFTaskParameters(TaskParameterDefinition):
58
+ type: Literal["cdf"] = Field("cdf", exclude=True)
59
+ cdf_request: CDFRequest
60
+
61
+
62
+ class DynamicRef(BaseModelObject):
63
+ tasks: str
64
+
65
+
66
+ class DynamicTaskParameters(TaskParameterDefinition):
67
+ type: Literal["dynamic"] = Field("dynamic", exclude=True)
68
+ dynamic: DynamicRef
69
+
70
+
71
+ class SubworkflowRef(BaseModelObject):
72
+ tasks: "list[Task]"
73
+
74
+
75
+ class SubworkflowTaskParameters(TaskParameterDefinition):
76
+ type: Literal["subworkflow"] = Field("subworkflow", exclude=True)
77
+ subworkflow: WorkflowVersionId | SubworkflowRef
78
+
79
+
80
+ class SimulatorInputUnit(BaseModelObject):
81
+ name: str
82
+
83
+
84
+ class SimulatorInput(BaseModelObject):
85
+ reference_id: str
86
+ value: str | int | float | list[str] | list[int] | list[float]
87
+ unit: SimulatorInputUnit | None = None
88
+
89
+
90
+ class SimulationRef(BaseModelObject):
91
+ routine_external_id: str
92
+ run_time: int | None = None
93
+ inputs: list[SimulatorInput] | None = None
94
+
95
+
96
+ class SimulationTaskParameters(TaskParameterDefinition):
97
+ type: Literal["simulation"] = Field("simulation", exclude=True)
98
+ simulation: SimulationRef
99
+
100
+
101
+ Parameter = Annotated[
102
+ FunctionTaskParameters
103
+ | TransformationTaskParameters
104
+ | CDFTaskParameters
105
+ | DynamicTaskParameters
106
+ | SubworkflowTaskParameters
107
+ | SimulationTaskParameters,
108
+ Field(discriminator="type"),
109
+ ]
110
+
111
+
112
+ class Task(BaseModelObject):
113
+ external_id: str
114
+ type: str
115
+ name: str | None = None
116
+ description: str | None = None
117
+ retries: int | None = None
118
+ timeout: int | None = None
119
+ on_failure: Literal["abortWorkflow", "skipTask"] = "abortWorkflow"
120
+ depends_on: list[TaskId] | None = None
121
+ parameters: Parameter | None = None
122
+
123
+ @field_validator("parameters", mode="before")
124
+ @classmethod
125
+ def move_type_to_field(cls, value: Any, info: ValidationInfo) -> Any:
126
+ if not isinstance(value, dict) or "type" not in info.data:
127
+ return value
128
+ value = dict(value)
129
+ value["type"] = info.data["type"]
130
+ return value
131
+
132
+
133
+ class WorkflowDefinition(BaseModelObject):
134
+ description: str | None = None
135
+ tasks: list[Task]
136
+
137
+
138
+ class WorkflowVersion(BaseModelObject):
139
+ workflow_external_id: str
140
+ version: str
141
+ workflow_definition: WorkflowDefinition
142
+
143
+ def as_id(self) -> WorkflowVersionId:
144
+ return WorkflowVersionId(workflow_external_id=self.workflow_external_id, version=self.version)
145
+
146
+
147
+ class WorkflowVersionRequest(WorkflowVersion, RequestResource): ...
148
+
149
+
150
+ class WorkflowVersionResponse(WorkflowVersion, ResponseResource[WorkflowVersionRequest]):
151
+ created_time: int
152
+ last_updated_time: int
153
+
154
+ def as_request_resource(self) -> WorkflowVersionRequest:
155
+ return WorkflowVersionRequest.model_validate(self.dump(), extra="ignore")
@@ -7,12 +7,14 @@ from cognite.client._api.datapoints import DatapointsAPI
7
7
  from cognite.client._api.datapoints_subscriptions import DatapointsSubscriptionAPI
8
8
  from cognite.client._api.functions import FunctionCallsAPI, FunctionSchedulesAPI
9
9
  from cognite.client._api.raw import RawDatabasesAPI, RawRowsAPI, RawTablesAPI
10
+ from cognite.client._api.simulators import SimulatorModelsAPI, SimulatorsAPI
10
11
  from cognite.client._api.synthetic_time_series import SyntheticDatapointsAPI
11
12
  from cognite.client.testing import CogniteClientMock
12
13
  from rich.console import Console
13
14
 
14
15
  from cognite_toolkit._cdf_tk.client._toolkit_client import ToolkitClient
15
16
  from cognite_toolkit._cdf_tk.client.api.assets import AssetsAPI
17
+ from cognite_toolkit._cdf_tk.client.api.filemetadata import FileMetadataAPI
16
18
  from cognite_toolkit._cdf_tk.client.api.legacy.canvas import CanvasAPI, IndustrialCanvasAPI
17
19
  from cognite_toolkit._cdf_tk.client.api.legacy.charts import ChartsAPI
18
20
  from cognite_toolkit._cdf_tk.client.api.legacy.dml import DMLAPI
@@ -143,7 +145,10 @@ class ToolkitClientMock(CogniteClientMock):
143
145
  self.tool.three_d.models = MagicMock(spec_set=ThreeDModelAPI)
144
146
  self.tool.assets = MagicMock(spec_set=AssetsAPI)
145
147
  self.tool.timeseries = MagicMock(spec_set=TimeSeriesAPI)
148
+ self.tool.filemetadata = MagicMock(spec_set=FileMetadataAPI)
146
149
  self.tool.events = MagicMock(spec_set=EventsAPI)
150
+ self.tool.simulators = MagicMock(spec=SimulatorsAPI)
151
+ self.tool.simulators.models = MagicMock(spec_set=SimulatorModelsAPI)
147
152
 
148
153
  self.streams = MagicMock(spec=StreamsAPI)
149
154
 
@@ -1,7 +1,7 @@
1
1
  from collections.abc import Iterable, Mapping, Set
2
2
  from typing import Any, ClassVar, cast
3
3
 
4
- from cognite.client.data_classes import Annotation, FileMetadata
4
+ from cognite.client.data_classes import Annotation
5
5
  from cognite.client.data_classes.data_modeling import (
6
6
  DirectRelation,
7
7
  DirectRelationReference,
@@ -18,6 +18,7 @@ from cognite.client.utils._identifier import InstanceId
18
18
  from cognite_toolkit._cdf_tk.client import ToolkitClient
19
19
  from cognite_toolkit._cdf_tk.client.data_classes.asset import AssetResponse
20
20
  from cognite_toolkit._cdf_tk.client.data_classes.event import EventResponse
21
+ from cognite_toolkit._cdf_tk.client.data_classes.filemetadata import FileMetadataResponse
21
22
  from cognite_toolkit._cdf_tk.client.data_classes.legacy.migration import (
22
23
  AssetCentricId,
23
24
  ResourceViewMappingApply,
@@ -117,7 +118,7 @@ class DirectRelationCache:
117
118
  source_ids.add(resource.source)
118
119
  if resource.parent_id is not None:
119
120
  asset_ids.add(resource.parent_id)
120
- elif isinstance(resource, FileMetadata):
121
+ elif isinstance(resource, FileMetadataResponse):
121
122
  if resource.source:
122
123
  source_ids.add(resource.source)
123
124
  if resource.asset_ids:
@@ -248,7 +249,7 @@ def asset_centric_to_dm(
248
249
  def _lookup_resource_type(resource_type: AssetCentricResourceExtended) -> AssetCentricTypeExtended:
249
250
  if isinstance(resource_type, AssetResponse):
250
251
  return "asset"
251
- elif isinstance(resource_type, FileMetadata):
252
+ elif isinstance(resource_type, FileMetadataResponse):
252
253
  return "file"
253
254
  elif isinstance(resource_type, EventResponse):
254
255
  return "event"
@@ -6,6 +6,7 @@ from typing import TYPE_CHECKING, cast, final
6
6
  import pandas as pd
7
7
  from cognite.client.data_classes import FileMetadataWrite
8
8
 
9
+ from cognite_toolkit._cdf_tk.client.data_classes.identifiers import ExternalId
9
10
  from cognite_toolkit._cdf_tk.client.data_classes.legacy.extendable_cognite_file import ExtendableCogniteFileApply
10
11
  from cognite_toolkit._cdf_tk.client.data_classes.legacy.raw import RawTable
11
12
  from cognite_toolkit._cdf_tk.constants import BUILD_FOLDER_ENCODING
@@ -119,11 +120,14 @@ class FileCRUD(DataCRUD):
119
120
  if not datafile.exists():
120
121
  continue
121
122
 
123
+ identifier = resource.identifier
124
+ if isinstance(identifier, ExternalId):
125
+ identifier = identifier.external_id
122
126
  if dry_run:
123
- yield f" Would upload file '{datafile!s}' to file with {id_name}={resource.identifier!r}", 1
127
+ yield f" Would upload file '{datafile!s}' to file with {id_name}={identifier!r}", 1
124
128
  else:
125
- self.client.files.upload_content(path=str(datafile), **{id_name: resource.identifier})
126
- yield f" Uploaded file '{datafile!s}' to file with {id_name}={resource.identifier!r}", 1
129
+ self.client.files.upload_content(path=str(datafile), **{id_name: identifier})
130
+ yield f" Uploaded file '{datafile!s}' to file with {id_name}={identifier!r}", 1
127
131
 
128
132
  @staticmethod
129
133
  def _read_metadata(
@@ -15,13 +15,8 @@
15
15
 
16
16
  from collections.abc import Hashable, Iterable, Sequence
17
17
  from datetime import date, datetime
18
- from typing import Any, cast, final
18
+ from typing import Any, final
19
19
 
20
- from cognite.client.data_classes import (
21
- FileMetadata,
22
- FileMetadataList,
23
- FileMetadataWrite,
24
- )
25
20
  from cognite.client.data_classes.capabilities import (
26
21
  Capability,
27
22
  DataModelInstancesAcl,
@@ -31,9 +26,9 @@ from cognite.client.data_classes.data_modeling import NodeApplyResultList, NodeI
31
26
  from cognite.client.exceptions import CogniteAPIError
32
27
  from cognite.client.utils._time import convert_data_modelling_timestamp
33
28
  from cognite.client.utils.useful_types import SequenceNotStr
34
- from rich import print
35
29
 
36
- from cognite_toolkit._cdf_tk.client.data_classes.identifiers import ExternalId
30
+ from cognite_toolkit._cdf_tk.client.data_classes.filemetadata import FileMetadataRequest, FileMetadataResponse
31
+ from cognite_toolkit._cdf_tk.client.data_classes.identifiers import ExternalId, InternalOrExternalId
37
32
  from cognite_toolkit._cdf_tk.client.data_classes.legacy.extendable_cognite_file import (
38
33
  ExtendableCogniteFile,
39
34
  ExtendableCogniteFileApply,
@@ -56,11 +51,11 @@ from .datamodel import SpaceCRUD, ViewCRUD
56
51
 
57
52
 
58
53
  @final
59
- class FileMetadataCRUD(ResourceContainerCRUD[str, FileMetadataWrite, FileMetadata]):
54
+ class FileMetadataCRUD(ResourceContainerCRUD[ExternalId, FileMetadataRequest, FileMetadataResponse]):
60
55
  item_name = "file contents"
61
56
  folder_name = "files"
62
- resource_cls = FileMetadata
63
- resource_write_cls = FileMetadataWrite
57
+ resource_cls = FileMetadataResponse
58
+ resource_write_cls = FileMetadataRequest
64
59
  yaml_cls = FileMetadataYAML
65
60
  kind = "FileMetadata"
66
61
  dependencies = frozenset({DataSetsCRUD, GroupAllScopedCRUD, LabelCRUD, AssetCRUD})
@@ -73,7 +68,7 @@ class FileMetadataCRUD(ResourceContainerCRUD[str, FileMetadataWrite, FileMetadat
73
68
 
74
69
  @classmethod
75
70
  def get_required_capability(
76
- cls, items: Sequence[FileMetadataWrite] | None, read_only: bool
71
+ cls, items: Sequence[FileMetadataRequest] | None, read_only: bool
77
72
  ) -> Capability | list[Capability]:
78
73
  if not items and items is not None:
79
74
  return []
@@ -88,22 +83,22 @@ class FileMetadataCRUD(ResourceContainerCRUD[str, FileMetadataWrite, FileMetadat
88
83
  return FilesAcl(actions, scope)
89
84
 
90
85
  @classmethod
91
- def get_id(cls, item: FileMetadata | FileMetadataWrite | dict) -> str:
86
+ def get_id(cls, item: FileMetadataRequest | FileMetadataResponse | dict) -> ExternalId:
92
87
  if isinstance(item, dict):
93
- return item["externalId"]
88
+ return ExternalId(external_id=item["externalId"])
94
89
  if item.external_id is None:
95
90
  raise ToolkitRequiredValueError("FileMetadata must have external_id set.")
96
- return item.external_id
91
+ return ExternalId(external_id=item.external_id)
97
92
 
98
93
  @classmethod
99
- def get_internal_id(cls, item: FileMetadata | dict) -> int:
94
+ def get_internal_id(cls, item: FileMetadataResponse | dict) -> int:
100
95
  if isinstance(item, dict):
101
96
  return item["id"]
102
97
  return item.id
103
98
 
104
99
  @classmethod
105
- def dump_id(cls, id: str) -> dict[str, Any]:
106
- return {"externalId": id}
100
+ def dump_id(cls, id: ExternalId) -> dict[str, Any]:
101
+ return id.dump()
107
102
 
108
103
  @classmethod
109
104
  def get_dependent_items(cls, item: dict) -> Iterable[tuple[type[ResourceCRUD], Hashable]]:
@@ -121,69 +116,71 @@ class FileMetadataCRUD(ResourceContainerCRUD[str, FileMetadataWrite, FileMetadat
121
116
  for asset_external_id in item.get("assetExternalIds", []):
122
117
  yield AssetCRUD, ExternalId(external_id=asset_external_id)
123
118
 
124
- def load_resource(self, resource: dict[str, Any], is_dry_run: bool = False) -> FileMetadataWrite:
125
- if resource.get("dataSetExternalId") is not None:
126
- ds_external_id = resource.pop("dataSetExternalId")
119
+ def load_resource(self, resource: dict[str, Any], is_dry_run: bool = False) -> FileMetadataRequest:
120
+ if ds_external_id := resource.pop("dataSetExternalId", None):
127
121
  resource["dataSetId"] = self.client.lookup.data_sets.id(ds_external_id, is_dry_run)
128
122
  if security_categories_names := resource.pop("securityCategoryNames", []):
129
- security_categories = self.client.lookup.security_categories.id(security_categories_names, is_dry_run)
130
- resource["securityCategories"] = security_categories
131
- if "assetExternalIds" in resource:
132
- resource["assetIds"] = self.client.lookup.assets.id(resource["assetExternalIds"], is_dry_run)
133
- return FileMetadataWrite._load(resource)
134
-
135
- def dump_resource(self, resource: FileMetadata, local: dict[str, Any] | None = None) -> dict[str, Any]:
136
- dumped = resource.as_write().dump()
137
- if ds_id := dumped.pop("dataSetId", None):
138
- dumped["dataSetExternalId"] = self.client.lookup.data_sets.external_id(ds_id)
123
+ resource["securityCategories"] = self.client.lookup.security_categories.id(
124
+ security_categories_names, is_dry_run
125
+ )
126
+ if asset_external_ids := resource.pop("assetExternalIds", None):
127
+ resource["assetIds"] = self.client.lookup.assets.id(asset_external_ids, is_dry_run)
128
+ return FileMetadataRequest.model_validate(resource)
129
+
130
+ def dump_resource(self, resource: FileMetadataResponse, local: dict[str, Any] | None = None) -> dict[str, Any]:
131
+ dumped = resource.as_request_resource().dump()
132
+ if data_set_id := dumped.pop("dataSetId", None):
133
+ dumped["dataSetExternalId"] = self.client.lookup.data_sets.external_id(data_set_id)
139
134
  if security_categories := dumped.pop("securityCategories", []):
140
135
  dumped["securityCategoryNames"] = self.client.lookup.security_categories.external_id(security_categories)
141
136
  if asset_ids := dumped.pop("assetIds", []):
142
137
  dumped["assetExternalIds"] = self.client.lookup.assets.external_id(asset_ids)
143
138
  return dumped
144
139
 
145
- def create(self, items: Sequence[FileMetadataWrite]) -> FileMetadataList:
146
- created = FileMetadataList([])
147
- for meta in items:
148
- try:
149
- created.append(self.client.files.create(meta))
150
- except CogniteAPIError as e:
151
- if e.code == 409:
152
- print(f" [bold yellow]WARNING:[/] File {meta.external_id} already exists, skipping upload.")
153
- return created
140
+ def create(self, items: Sequence[FileMetadataRequest]) -> list[FileMetadataResponse]:
141
+ return self.client.tool.filemetadata.create(items, overwrite=True)
154
142
 
155
- def retrieve(self, ids: SequenceNotStr[str]) -> FileMetadataList:
156
- return self.client.files.retrieve_multiple(external_ids=ids, ignore_unknown_ids=True)
143
+ def retrieve(self, ids: SequenceNotStr[ExternalId]) -> list[FileMetadataResponse]:
144
+ return self.client.tool.filemetadata.retrieve(list(ids), ignore_unknown_ids=True)
157
145
 
158
- def update(self, items: Sequence[FileMetadataWrite]) -> FileMetadataList:
159
- return self.client.files.update(items, mode="replace")
146
+ def update(self, items: Sequence[FileMetadataRequest]) -> list[FileMetadataResponse]:
147
+ return self.client.tool.filemetadata.update(items, mode="replace")
160
148
 
161
- def delete(self, ids: str | int | SequenceNotStr[str | int] | None) -> int:
162
- internal_ids, external_ids = self._split_ids(ids)
163
- self.client.files.delete(id=internal_ids, external_id=external_ids)
164
- return len(cast(SequenceNotStr[str], ids))
149
+ def delete(self, ids: SequenceNotStr[InternalOrExternalId]) -> int:
150
+ if not ids:
151
+ return 0
152
+ self.client.tool.filemetadata.delete(list(ids), ignore_unknown_ids=True)
153
+ return len(ids)
165
154
 
166
155
  def _iterate(
167
156
  self,
168
157
  data_set_external_id: str | None = None,
169
158
  space: str | None = None,
170
159
  parent_ids: list[Hashable] | None = None,
171
- ) -> Iterable[FileMetadata]:
172
- return iter(self.client.files(data_set_external_ids=[data_set_external_id] if data_set_external_id else None))
173
-
174
- def count(self, ids: SequenceNotStr[str]) -> int:
160
+ ) -> Iterable[FileMetadataResponse]:
161
+ cursor: str | None = None
162
+ while True:
163
+ page = self.client.tool.filemetadata.iterate(
164
+ data_set_external_ids=[data_set_external_id] if data_set_external_id else None,
165
+ limit=1000,
166
+ cursor=cursor,
167
+ )
168
+ yield from page.items
169
+ if not page.next_cursor or not page.items:
170
+ break
171
+ cursor = page.next_cursor
172
+
173
+ def count(self, ids: SequenceNotStr[ExternalId]) -> int:
175
174
  return sum(
176
- 1
177
- for meta in self.client.files.retrieve_multiple(external_ids=list(ids), ignore_unknown_ids=True)
178
- if meta.uploaded
175
+ 1 for meta in self.client.tool.filemetadata.retrieve(list(ids), ignore_unknown_ids=True) if meta.uploaded
179
176
  )
180
177
 
181
- def drop_data(self, ids: SequenceNotStr[str]) -> int:
182
- existing = self.client.files.retrieve_multiple(external_ids=list(ids), ignore_unknown_ids=True)
178
+ def drop_data(self, ids: SequenceNotStr[ExternalId]) -> int:
179
+ existing = self.client.tool.filemetadata.retrieve(list(ids), ignore_unknown_ids=True)
183
180
  # File and FileMetadata is tightly coupled, so we need to delete the metadata and recreate it
184
181
  # without the source set to delete the file.
185
- deleted_files = self.delete(existing.as_external_ids())
186
- self.create(existing.as_write())
182
+ deleted_files = self.delete([meta.as_id() for meta in existing])
183
+ self.create([meta.as_request_resource() for meta in existing])
187
184
  return deleted_files
188
185
 
189
186
 
@@ -130,7 +130,7 @@ class RelationshipCRUD(ResourceCRUD[str, RelationshipWrite, Relationship]):
130
130
  elif type_value == "timeseries":
131
131
  yield TimeSeriesCRUD, ExternalId(external_id=id_value)
132
132
  elif type_value == "file":
133
- yield FileMetadataCRUD, id_value
133
+ yield FileMetadataCRUD, ExternalId(external_id=id_value)
134
134
  elif type_value == "event":
135
135
  yield EventCRUD, ExternalId(external_id=id_value)
136
136
 
@@ -3,16 +3,12 @@ from collections import defaultdict
3
3
  from collections.abc import Iterable, Sequence
4
4
  from typing import Any, ClassVar, Generic
5
5
 
6
- from cognite.client.data_classes import (
7
- FileMetadata,
8
- FileMetadataList,
9
- Label,
10
- LabelDefinition,
11
- )
6
+ from cognite.client.data_classes import Label, LabelDefinition
12
7
 
13
8
  from cognite_toolkit._cdf_tk.client import ToolkitClient
14
9
  from cognite_toolkit._cdf_tk.client.data_classes.asset import AssetAggregateItem, AssetRequest, AssetResponse
15
10
  from cognite_toolkit._cdf_tk.client.data_classes.event import EventRequest, EventResponse
11
+ from cognite_toolkit._cdf_tk.client.data_classes.filemetadata import FileMetadataResponse
16
12
  from cognite_toolkit._cdf_tk.client.data_classes.identifiers import InternalId
17
13
  from cognite_toolkit._cdf_tk.client.data_classes.timeseries import TimeSeriesRequest, TimeSeriesResponse
18
14
  from cognite_toolkit._cdf_tk.cruds import (
@@ -107,13 +103,16 @@ class AssetCentricIO(
107
103
 
108
104
  def _collect_dependencies(
109
105
  self,
110
- resources: Sequence[AssetResponse] | FileMetadataList | Sequence[TimeSeriesResponse] | Sequence[EventResponse],
106
+ resources: Sequence[AssetResponse]
107
+ | Sequence[FileMetadataResponse]
108
+ | Sequence[TimeSeriesResponse]
109
+ | Sequence[EventResponse],
111
110
  selector: AssetCentricSelector,
112
111
  ) -> None:
113
112
  for resource in resources:
114
113
  if resource.data_set_id:
115
114
  self._downloaded_data_sets_by_selector[selector].add(resource.data_set_id)
116
- if isinstance(resource, AssetResponse | FileMetadata):
115
+ if isinstance(resource, AssetResponse | FileMetadataResponse):
117
116
  for label in resource.labels or []:
118
117
  if isinstance(label, str):
119
118
  self._downloaded_labels_by_selector[selector].add(label)
@@ -146,18 +145,18 @@ class AssetCentricIO(
146
145
  return f"INTERNAL_ID_project_{project}_{internal_id!s}"
147
146
 
148
147
  def _populate_data_set_id_cache(
149
- self, chunk: Sequence[AssetResponse | FileMetadata | TimeSeriesResponse | EventResponse]
148
+ self, chunk: Sequence[AssetResponse | FileMetadataResponse | TimeSeriesResponse | EventResponse]
150
149
  ) -> None:
151
150
  data_set_ids = {item.data_set_id for item in chunk if item.data_set_id is not None}
152
151
  self.client.lookup.data_sets.external_id(list(data_set_ids))
153
152
 
154
- def _populate_security_category_cache(self, chunk: Sequence[FileMetadata | TimeSeriesResponse]) -> None:
153
+ def _populate_security_category_cache(self, chunk: Sequence[FileMetadataResponse | TimeSeriesResponse]) -> None:
155
154
  security_category_ids: set[int] = set()
156
155
  for item in chunk:
157
156
  security_category_ids.update(item.security_categories or [])
158
157
  self.client.lookup.security_categories.external_id(list(security_category_ids))
159
158
 
160
- def _populate_asset_id_cache(self, chunk: Sequence[FileMetadata | EventResponse]) -> None:
159
+ def _populate_asset_id_cache(self, chunk: Sequence[FileMetadataResponse | EventResponse]) -> None:
161
160
  asset_ids: set[int] = set()
162
161
  for item in chunk:
163
162
  asset_ids.update(item.asset_ids or [])
@@ -379,7 +378,7 @@ class AssetIO(UploadableAssetCentricIO[AssetResponse, AssetRequest]):
379
378
  current_depth += 1
380
379
 
381
380
 
382
- class FileMetadataIO(AssetCentricIO[FileMetadata]):
381
+ class FileMetadataIO(AssetCentricIO[FileMetadataResponse]):
383
382
  KIND = "FileMetadata"
384
383
  RESOURCE_TYPE = "file"
385
384
  SUPPORTED_DOWNLOAD_FORMATS = frozenset({".parquet", ".csv", ".ndjson"})
@@ -391,7 +390,7 @@ class FileMetadataIO(AssetCentricIO[FileMetadata]):
391
390
  super().__init__(client)
392
391
  self._crud = FileMetadataCRUD.create_loader(self.client)
393
392
 
394
- def as_id(self, item: FileMetadata) -> str:
393
+ def as_id(self, item: FileMetadataResponse) -> str:
395
394
  return item.external_id if item.external_id is not None else self._create_identifier(item.id)
396
395
 
397
396
  def _get_aggregator(self) -> AssetCentricAggregator:
@@ -434,25 +433,31 @@ class FileMetadataIO(AssetCentricIO[FileMetadata]):
434
433
  ]
435
434
  return file_schema + metadata_schema
436
435
 
437
- def stream_data(self, selector: AssetCentricSelector, limit: int | None = None) -> Iterable[Page[FileMetadata]]:
436
+ def stream_data(
437
+ self, selector: AssetCentricSelector, limit: int | None = None
438
+ ) -> Iterable[Page[FileMetadataResponse]]:
438
439
  asset_subtree_external_ids, data_set_external_ids = self._get_hierarchy_dataset_pair(selector)
439
- for file_list in self.client.files(
440
- chunk_size=self.CHUNK_SIZE,
441
- limit=limit,
442
- asset_subtree_external_ids=asset_subtree_external_ids,
443
- data_set_external_ids=data_set_external_ids,
444
- # We cannot use partitions here as it is not thread safe. This spawn multiple threads
445
- # that are not shut down until all data is downloaded. We need to be able to abort.
446
- partitions=None,
447
- ):
448
- self._collect_dependencies(file_list, selector)
449
- yield Page(worker_id="main", items=file_list)
450
-
451
- def retrieve(self, ids: Sequence[int]) -> FileMetadataList:
452
- return self.client.files.retrieve_multiple(ids)
440
+ cursor: str | None = None
441
+ total_count = 0
442
+ while True:
443
+ page = self.client.tool.filemetadata.iterate(
444
+ data_set_external_ids=data_set_external_ids,
445
+ asset_subtree_external_ids=asset_subtree_external_ids,
446
+ limit=self.CHUNK_SIZE,
447
+ cursor=cursor,
448
+ )
449
+ self._collect_dependencies(page.items, selector)
450
+ yield Page(worker_id="main", items=page.items)
451
+ total_count += len(page.items)
452
+ if page.next_cursor is None or (limit is not None and total_count >= limit):
453
+ break
454
+ cursor = page.next_cursor
455
+
456
+ def retrieve(self, ids: Sequence[int]) -> list[FileMetadataResponse]:
457
+ return self.client.tool.filemetadata.retrieve(InternalId.from_ids(ids))
453
458
 
454
459
  def data_to_json_chunk(
455
- self, data_chunk: Sequence[FileMetadata], selector: AssetCentricSelector | None = None
460
+ self, data_chunk: Sequence[FileMetadataResponse], selector: AssetCentricSelector | None = None
456
461
  ) -> list[dict[str, JsonVal]]:
457
462
  # Ensure data sets/assets/security-categories are looked up to populate cache.
458
463
  # This is to avoid looking up each data set id individually in the .dump_resource call