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.
- cognite_toolkit/_cdf_tk/client/_toolkit_client.py +6 -0
- cognite_toolkit/_cdf_tk/client/api/filemetadata.py +145 -0
- cognite_toolkit/_cdf_tk/client/api/raw.py +174 -0
- cognite_toolkit/_cdf_tk/client/api/simulator_models.py +118 -0
- cognite_toolkit/_cdf_tk/client/api/simulators.py +8 -0
- cognite_toolkit/_cdf_tk/client/cdf_client/__init__.py +2 -1
- cognite_toolkit/_cdf_tk/client/cdf_client/api.py +40 -6
- cognite_toolkit/_cdf_tk/client/data_classes/annotation.py +79 -0
- cognite_toolkit/_cdf_tk/client/data_classes/base.py +13 -3
- cognite_toolkit/_cdf_tk/client/data_classes/data_modeling/__init__.py +16 -0
- cognite_toolkit/_cdf_tk/client/data_classes/data_modeling/_instance.py +143 -0
- cognite_toolkit/_cdf_tk/client/data_classes/data_modeling/_references.py +8 -0
- cognite_toolkit/_cdf_tk/client/data_classes/dataset.py +35 -0
- cognite_toolkit/_cdf_tk/client/data_classes/extraction_pipeline.py +59 -0
- cognite_toolkit/_cdf_tk/client/data_classes/filemetadata.py +7 -1
- cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_destination.py +34 -0
- cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_job.py +134 -0
- cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_mapping.py +72 -0
- cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/__init__.py +63 -0
- cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_auth.py +63 -0
- cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_base.py +26 -0
- cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_certificate.py +20 -0
- cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_eventhub.py +31 -0
- cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_kafka.py +53 -0
- cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_mqtt.py +36 -0
- cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_rest.py +49 -0
- cognite_toolkit/_cdf_tk/client/data_classes/identifiers.py +8 -0
- cognite_toolkit/_cdf_tk/client/data_classes/label.py +27 -0
- cognite_toolkit/_cdf_tk/client/data_classes/raw.py +3 -2
- cognite_toolkit/_cdf_tk/client/data_classes/securitycategory.py +24 -0
- cognite_toolkit/_cdf_tk/client/data_classes/sequence.py +45 -0
- cognite_toolkit/_cdf_tk/client/data_classes/transformation.py +140 -0
- cognite_toolkit/_cdf_tk/client/data_classes/workflow.py +27 -0
- cognite_toolkit/_cdf_tk/client/data_classes/workflow_trigger.py +63 -0
- cognite_toolkit/_cdf_tk/client/data_classes/workflow_version.py +155 -0
- cognite_toolkit/_cdf_tk/client/testing.py +5 -0
- cognite_toolkit/_cdf_tk/commands/_migrate/conversion.py +4 -3
- cognite_toolkit/_cdf_tk/cruds/_data_cruds.py +7 -3
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/file.py +56 -59
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/relationship.py +1 -1
- cognite_toolkit/_cdf_tk/storageio/_asset_centric.py +34 -29
- cognite_toolkit/_cdf_tk/storageio/_file_content.py +22 -19
- 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.43.dist-info → cognite_toolkit-0.7.44.dist-info}/METADATA +11 -1
- {cognite_toolkit-0.7.43.dist-info → cognite_toolkit-0.7.44.dist-info}/RECORD +50 -24
- {cognite_toolkit-0.7.43.dist-info → cognite_toolkit-0.7.44.dist-info}/WHEEL +1 -1
- {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
|
|
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,
|
|
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,
|
|
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}={
|
|
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:
|
|
126
|
-
yield f" Uploaded file '{datafile!s}' to file with {id_name}={
|
|
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,
|
|
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.
|
|
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[
|
|
54
|
+
class FileMetadataCRUD(ResourceContainerCRUD[ExternalId, FileMetadataRequest, FileMetadataResponse]):
|
|
60
55
|
item_name = "file contents"
|
|
61
56
|
folder_name = "files"
|
|
62
|
-
resource_cls =
|
|
63
|
-
resource_write_cls =
|
|
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[
|
|
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:
|
|
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:
|
|
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:
|
|
106
|
-
return
|
|
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) ->
|
|
125
|
-
if resource.
|
|
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
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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[
|
|
146
|
-
|
|
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[
|
|
156
|
-
return self.client.
|
|
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[
|
|
159
|
-
return self.client.
|
|
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:
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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[
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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[
|
|
182
|
-
existing = self.client.
|
|
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(
|
|
186
|
-
self.create(
|
|
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]
|
|
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 |
|
|
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 |
|
|
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[
|
|
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[
|
|
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[
|
|
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:
|
|
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(
|
|
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
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
self._collect_dependencies(
|
|
449
|
-
yield Page(worker_id="main", items=
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
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[
|
|
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
|