cognite-toolkit 0.6.97__py3-none-any.whl → 0.7.39__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cognite_toolkit/_cdf.py +21 -23
- cognite_toolkit/_cdf_tk/apps/__init__.py +4 -0
- cognite_toolkit/_cdf_tk/apps/_core_app.py +19 -5
- cognite_toolkit/_cdf_tk/apps/_data_app.py +1 -1
- cognite_toolkit/_cdf_tk/apps/_dev_app.py +86 -0
- cognite_toolkit/_cdf_tk/apps/_download_app.py +693 -25
- cognite_toolkit/_cdf_tk/apps/_dump_app.py +44 -102
- cognite_toolkit/_cdf_tk/apps/_import_app.py +41 -0
- cognite_toolkit/_cdf_tk/apps/_landing_app.py +18 -4
- cognite_toolkit/_cdf_tk/apps/_migrate_app.py +424 -9
- cognite_toolkit/_cdf_tk/apps/_modules_app.py +0 -3
- cognite_toolkit/_cdf_tk/apps/_purge.py +15 -43
- cognite_toolkit/_cdf_tk/apps/_run.py +11 -0
- cognite_toolkit/_cdf_tk/apps/_upload_app.py +45 -6
- cognite_toolkit/_cdf_tk/builders/__init__.py +2 -2
- cognite_toolkit/_cdf_tk/builders/_base.py +28 -42
- cognite_toolkit/_cdf_tk/builders/_raw.py +1 -1
- cognite_toolkit/_cdf_tk/cdf_toml.py +20 -1
- cognite_toolkit/_cdf_tk/client/_toolkit_client.py +32 -12
- cognite_toolkit/_cdf_tk/client/api/infield.py +114 -17
- cognite_toolkit/_cdf_tk/client/api/{canvas.py → legacy/canvas.py} +15 -7
- 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_functions.py → legacy/extended_functions.py} +15 -18
- 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 +177 -4
- cognite_toolkit/_cdf_tk/client/api/project.py +9 -8
- cognite_toolkit/_cdf_tk/client/api/search.py +2 -2
- cognite_toolkit/_cdf_tk/client/api/streams.py +88 -0
- cognite_toolkit/_cdf_tk/client/api/three_d.py +384 -0
- cognite_toolkit/_cdf_tk/client/data_classes/api_classes.py +13 -0
- cognite_toolkit/_cdf_tk/client/data_classes/base.py +37 -33
- cognite_toolkit/_cdf_tk/client/data_classes/charts_data.py +95 -213
- cognite_toolkit/_cdf_tk/client/data_classes/infield.py +32 -18
- cognite_toolkit/_cdf_tk/client/data_classes/instance_api.py +18 -13
- cognite_toolkit/_cdf_tk/client/data_classes/legacy/__init__.py +0 -0
- cognite_toolkit/_cdf_tk/client/data_classes/{canvas.py → legacy/canvas.py} +47 -4
- cognite_toolkit/_cdf_tk/client/data_classes/{charts.py → legacy/charts.py} +3 -3
- cognite_toolkit/_cdf_tk/client/data_classes/{migration.py → legacy/migration.py} +10 -2
- cognite_toolkit/_cdf_tk/client/data_classes/streams.py +90 -0
- cognite_toolkit/_cdf_tk/client/data_classes/three_d.py +112 -0
- cognite_toolkit/_cdf_tk/client/testing.py +42 -18
- cognite_toolkit/_cdf_tk/commands/__init__.py +7 -6
- cognite_toolkit/_cdf_tk/commands/_changes.py +3 -42
- cognite_toolkit/_cdf_tk/commands/_download.py +21 -11
- cognite_toolkit/_cdf_tk/commands/_migrate/__init__.py +0 -2
- cognite_toolkit/_cdf_tk/commands/_migrate/command.py +22 -20
- cognite_toolkit/_cdf_tk/commands/_migrate/conversion.py +140 -92
- cognite_toolkit/_cdf_tk/commands/_migrate/creators.py +1 -1
- cognite_toolkit/_cdf_tk/commands/_migrate/data_classes.py +108 -26
- cognite_toolkit/_cdf_tk/commands/_migrate/data_mapper.py +448 -45
- cognite_toolkit/_cdf_tk/commands/_migrate/data_model.py +1 -0
- cognite_toolkit/_cdf_tk/commands/_migrate/default_mappings.py +6 -6
- cognite_toolkit/_cdf_tk/commands/_migrate/issues.py +52 -1
- cognite_toolkit/_cdf_tk/commands/_migrate/migration_io.py +377 -11
- cognite_toolkit/_cdf_tk/commands/_migrate/selectors.py +9 -4
- cognite_toolkit/_cdf_tk/commands/_profile.py +1 -1
- cognite_toolkit/_cdf_tk/commands/_purge.py +36 -39
- cognite_toolkit/_cdf_tk/commands/_questionary_style.py +16 -0
- cognite_toolkit/_cdf_tk/commands/_upload.py +109 -86
- cognite_toolkit/_cdf_tk/commands/about.py +221 -0
- cognite_toolkit/_cdf_tk/commands/auth.py +19 -12
- cognite_toolkit/_cdf_tk/commands/build_cmd.py +16 -62
- cognite_toolkit/_cdf_tk/commands/build_v2/__init__.py +0 -0
- cognite_toolkit/_cdf_tk/commands/build_v2/build_cmd.py +241 -0
- cognite_toolkit/_cdf_tk/commands/build_v2/build_input.py +85 -0
- cognite_toolkit/_cdf_tk/commands/build_v2/build_issues.py +27 -0
- cognite_toolkit/_cdf_tk/commands/clean.py +63 -16
- cognite_toolkit/_cdf_tk/commands/deploy.py +20 -17
- cognite_toolkit/_cdf_tk/commands/dump_resource.py +10 -8
- cognite_toolkit/_cdf_tk/commands/init.py +225 -3
- cognite_toolkit/_cdf_tk/commands/modules.py +20 -44
- cognite_toolkit/_cdf_tk/commands/pull.py +6 -19
- cognite_toolkit/_cdf_tk/commands/resources.py +179 -0
- cognite_toolkit/_cdf_tk/commands/run.py +1 -1
- cognite_toolkit/_cdf_tk/constants.py +20 -1
- cognite_toolkit/_cdf_tk/cruds/__init__.py +19 -5
- cognite_toolkit/_cdf_tk/cruds/_base_cruds.py +14 -70
- cognite_toolkit/_cdf_tk/cruds/_data_cruds.py +10 -19
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/__init__.py +4 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/agent.py +11 -9
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/auth.py +5 -15
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/classic.py +45 -44
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/configuration.py +5 -12
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/data_organization.py +4 -13
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/datamodel.py +206 -67
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/extraction_pipeline.py +6 -18
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/fieldops.py +126 -35
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/file.py +7 -28
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/function.py +23 -30
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/hosted_extractors.py +12 -30
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/industrial_tool.py +4 -8
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/location.py +4 -16
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/migration.py +5 -13
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/raw.py +5 -11
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/relationship.py +3 -8
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/robotics.py +16 -45
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/streams.py +94 -0
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/three_d_model.py +3 -7
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/timeseries.py +5 -15
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/transformation.py +75 -32
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/workflow.py +20 -40
- cognite_toolkit/_cdf_tk/cruds/_worker.py +24 -36
- cognite_toolkit/_cdf_tk/data_classes/_module_toml.py +1 -0
- cognite_toolkit/_cdf_tk/feature_flags.py +16 -36
- cognite_toolkit/_cdf_tk/plugins.py +2 -1
- cognite_toolkit/_cdf_tk/resource_classes/__init__.py +4 -0
- cognite_toolkit/_cdf_tk/resource_classes/capabilities.py +12 -0
- cognite_toolkit/_cdf_tk/resource_classes/functions.py +3 -1
- cognite_toolkit/_cdf_tk/resource_classes/infield_cdm_location_config.py +109 -0
- cognite_toolkit/_cdf_tk/resource_classes/migration.py +8 -17
- cognite_toolkit/_cdf_tk/resource_classes/search_config.py +1 -1
- cognite_toolkit/_cdf_tk/resource_classes/streams.py +29 -0
- cognite_toolkit/_cdf_tk/resource_classes/workflow_version.py +164 -5
- cognite_toolkit/_cdf_tk/storageio/__init__.py +9 -21
- cognite_toolkit/_cdf_tk/storageio/_annotations.py +19 -16
- cognite_toolkit/_cdf_tk/storageio/_applications.py +340 -28
- cognite_toolkit/_cdf_tk/storageio/_asset_centric.py +67 -104
- cognite_toolkit/_cdf_tk/storageio/_base.py +61 -29
- cognite_toolkit/_cdf_tk/storageio/_datapoints.py +276 -20
- cognite_toolkit/_cdf_tk/storageio/_file_content.py +435 -0
- cognite_toolkit/_cdf_tk/storageio/_instances.py +35 -3
- cognite_toolkit/_cdf_tk/storageio/_raw.py +26 -0
- cognite_toolkit/_cdf_tk/storageio/selectors/__init__.py +71 -4
- cognite_toolkit/_cdf_tk/storageio/selectors/_base.py +14 -2
- cognite_toolkit/_cdf_tk/storageio/selectors/_canvas.py +14 -0
- cognite_toolkit/_cdf_tk/storageio/selectors/_charts.py +14 -0
- cognite_toolkit/_cdf_tk/storageio/selectors/_datapoints.py +23 -3
- cognite_toolkit/_cdf_tk/storageio/selectors/_file_content.py +164 -0
- cognite_toolkit/_cdf_tk/storageio/selectors/_three_d.py +34 -0
- cognite_toolkit/_cdf_tk/tk_warnings/other.py +4 -0
- cognite_toolkit/_cdf_tk/tracker.py +2 -2
- cognite_toolkit/_cdf_tk/utils/cdf.py +1 -1
- cognite_toolkit/_cdf_tk/utils/dtype_conversion.py +9 -3
- cognite_toolkit/_cdf_tk/utils/fileio/__init__.py +2 -0
- cognite_toolkit/_cdf_tk/utils/fileio/_base.py +5 -1
- cognite_toolkit/_cdf_tk/utils/fileio/_readers.py +112 -20
- cognite_toolkit/_cdf_tk/utils/fileio/_writers.py +15 -15
- cognite_toolkit/_cdf_tk/utils/http_client/__init__.py +28 -0
- cognite_toolkit/_cdf_tk/utils/http_client/_client.py +285 -18
- cognite_toolkit/_cdf_tk/utils/http_client/_data_classes.py +56 -4
- cognite_toolkit/_cdf_tk/utils/http_client/_data_classes2.py +247 -0
- cognite_toolkit/_cdf_tk/utils/http_client/_tracker.py +5 -2
- cognite_toolkit/_cdf_tk/utils/interactive_select.py +60 -18
- cognite_toolkit/_cdf_tk/utils/sql_parser.py +2 -3
- cognite_toolkit/_cdf_tk/utils/useful_types.py +6 -2
- cognite_toolkit/_cdf_tk/validation.py +83 -1
- 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 +5 -4
- cognite_toolkit/_version.py +1 -1
- cognite_toolkit/config.dev.yaml +13 -0
- {cognite_toolkit-0.6.97.dist-info → cognite_toolkit-0.7.39.dist-info}/METADATA +24 -24
- cognite_toolkit-0.7.39.dist-info/RECORD +322 -0
- cognite_toolkit-0.7.39.dist-info/WHEEL +4 -0
- {cognite_toolkit-0.6.97.dist-info → cognite_toolkit-0.7.39.dist-info}/entry_points.txt +1 -0
- cognite_toolkit/_cdf_tk/client/api/robotics/__init__.py +0 -3
- cognite_toolkit/_cdf_tk/commands/_migrate/canvas.py +0 -201
- cognite_toolkit/_cdf_tk/commands/dump_data.py +0 -489
- cognite_toolkit/_cdf_tk/commands/featureflag.py +0 -27
- cognite_toolkit/_cdf_tk/prototypes/import_app.py +0 -41
- cognite_toolkit/_cdf_tk/utils/table_writers.py +0 -434
- cognite_toolkit-0.6.97.dist-info/RECORD +0 -306
- cognite_toolkit-0.6.97.dist-info/WHEEL +0 -4
- cognite_toolkit-0.6.97.dist-info/licenses/LICENSE +0 -18
- /cognite_toolkit/_cdf_tk/{prototypes/commands → client/api/legacy}/__init__.py +0 -0
- /cognite_toolkit/_cdf_tk/client/api/{dml.py → legacy/dml.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/{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/{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/_cdf_tk/{prototypes/commands/import_.py → commands/_import_cmd.py} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
from collections import defaultdict
|
|
3
|
-
from collections.abc import Iterable,
|
|
3
|
+
from collections.abc import Iterable, Sequence
|
|
4
4
|
from typing import Any, ClassVar, Generic
|
|
5
5
|
|
|
6
6
|
from cognite.client.data_classes import (
|
|
@@ -8,26 +8,16 @@ from cognite.client.data_classes import (
|
|
|
8
8
|
Asset,
|
|
9
9
|
AssetList,
|
|
10
10
|
AssetWrite,
|
|
11
|
-
AssetWriteList,
|
|
12
11
|
Event,
|
|
13
12
|
EventList,
|
|
14
13
|
EventWrite,
|
|
15
|
-
EventWriteList,
|
|
16
14
|
FileMetadata,
|
|
17
15
|
FileMetadataList,
|
|
18
|
-
FileMetadataWrite,
|
|
19
|
-
FileMetadataWriteList,
|
|
20
16
|
Label,
|
|
21
17
|
LabelDefinition,
|
|
22
18
|
TimeSeries,
|
|
23
19
|
TimeSeriesList,
|
|
24
20
|
TimeSeriesWrite,
|
|
25
|
-
TimeSeriesWriteList,
|
|
26
|
-
)
|
|
27
|
-
from cognite.client.data_classes._base import (
|
|
28
|
-
T_CogniteResourceList,
|
|
29
|
-
T_WritableCogniteResource,
|
|
30
|
-
T_WriteClass,
|
|
31
21
|
)
|
|
32
22
|
|
|
33
23
|
from cognite_toolkit._cdf_tk.client import ToolkitClient
|
|
@@ -40,6 +30,7 @@ from cognite_toolkit._cdf_tk.cruds import (
|
|
|
40
30
|
TimeSeriesCRUD,
|
|
41
31
|
)
|
|
42
32
|
from cognite_toolkit._cdf_tk.exceptions import ToolkitMissingResourceError, ToolkitNotImplementedError
|
|
33
|
+
from cognite_toolkit._cdf_tk.protocols import T_ResourceRequest, T_ResourceResponse
|
|
43
34
|
from cognite_toolkit._cdf_tk.utils.aggregators import (
|
|
44
35
|
AssetAggregator,
|
|
45
36
|
AssetCentricAggregator,
|
|
@@ -50,23 +41,10 @@ from cognite_toolkit._cdf_tk.utils.aggregators import (
|
|
|
50
41
|
from cognite_toolkit._cdf_tk.utils.cdf import metadata_key_counts
|
|
51
42
|
from cognite_toolkit._cdf_tk.utils.fileio import FileReader, SchemaColumn
|
|
52
43
|
from cognite_toolkit._cdf_tk.utils.fileio._readers import TableReader
|
|
53
|
-
from cognite_toolkit._cdf_tk.utils.http_client import (
|
|
54
|
-
FailedRequestItems,
|
|
55
|
-
FailedRequestMessage,
|
|
56
|
-
FailedResponse,
|
|
57
|
-
FailedResponseItems,
|
|
58
|
-
HTTPClient,
|
|
59
|
-
HTTPMessage,
|
|
60
|
-
SimpleBodyRequest,
|
|
61
|
-
SuccessResponse,
|
|
62
|
-
SuccessResponseItems,
|
|
63
|
-
)
|
|
64
44
|
from cognite_toolkit._cdf_tk.utils.useful_types import (
|
|
65
|
-
T_ID,
|
|
66
45
|
AssetCentricResource,
|
|
67
46
|
AssetCentricType,
|
|
68
47
|
JsonVal,
|
|
69
|
-
T_WritableCogniteResourceList,
|
|
70
48
|
)
|
|
71
49
|
|
|
72
50
|
from ._base import (
|
|
@@ -80,11 +58,10 @@ from ._base import (
|
|
|
80
58
|
from .selectors import AssetCentricSelector, AssetSubtreeSelector, DataSetSelector
|
|
81
59
|
|
|
82
60
|
|
|
83
|
-
class
|
|
84
|
-
Generic[
|
|
85
|
-
TableStorageIO[AssetCentricSelector,
|
|
86
|
-
ConfigurableStorageIO[AssetCentricSelector,
|
|
87
|
-
TableUploadableStorageIO[AssetCentricSelector, T_WritableCogniteResource, T_WriteClass],
|
|
61
|
+
class AssetCentricIO(
|
|
62
|
+
Generic[T_ResourceResponse],
|
|
63
|
+
TableStorageIO[AssetCentricSelector, T_ResourceResponse],
|
|
64
|
+
ConfigurableStorageIO[AssetCentricSelector, T_ResourceResponse],
|
|
88
65
|
ABC,
|
|
89
66
|
):
|
|
90
67
|
RESOURCE_TYPE: ClassVar[AssetCentricType]
|
|
@@ -102,7 +79,7 @@ class BaseAssetCentricIO(
|
|
|
102
79
|
raise NotImplementedError()
|
|
103
80
|
|
|
104
81
|
@abstractmethod
|
|
105
|
-
def retrieve(self, ids: Sequence[int]) ->
|
|
82
|
+
def retrieve(self, ids: Sequence[int]) -> Sequence[T_ResourceResponse]:
|
|
106
83
|
raise NotImplementedError()
|
|
107
84
|
|
|
108
85
|
def count(self, selector: AssetCentricSelector) -> int | None:
|
|
@@ -188,6 +165,26 @@ class BaseAssetCentricIO(
|
|
|
188
165
|
asset_ids.update(item.asset_ids or [])
|
|
189
166
|
self.client.lookup.assets.external_id(list(asset_ids))
|
|
190
167
|
|
|
168
|
+
def data_to_row(
|
|
169
|
+
self, data_chunk: Sequence[T_ResourceResponse], selector: AssetCentricSelector | None = None
|
|
170
|
+
) -> list[dict[str, JsonVal]]:
|
|
171
|
+
rows: list[dict[str, JsonVal]] = []
|
|
172
|
+
for chunk in self.data_to_json_chunk(data_chunk, selector):
|
|
173
|
+
if "metadata" in chunk and isinstance(chunk["metadata"], dict):
|
|
174
|
+
metadata = chunk.pop("metadata")
|
|
175
|
+
# MyPy does understand that metadata is a dict here due to the check above.
|
|
176
|
+
for key, value in metadata.items(): # type: ignore[union-attr]
|
|
177
|
+
chunk[f"metadata.{key}"] = value
|
|
178
|
+
rows.append(chunk)
|
|
179
|
+
return rows
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class UploadableAssetCentricIO(
|
|
183
|
+
Generic[T_ResourceResponse, T_ResourceRequest],
|
|
184
|
+
AssetCentricIO[T_ResourceResponse],
|
|
185
|
+
TableUploadableStorageIO[AssetCentricSelector, T_ResourceResponse, T_ResourceRequest],
|
|
186
|
+
ABC,
|
|
187
|
+
):
|
|
191
188
|
def _populate_data_set_external_id_cache(self, chunk: Sequence[dict[str, Any]]) -> None:
|
|
192
189
|
data_set_external_ids: set[str] = set()
|
|
193
190
|
for item in chunk:
|
|
@@ -222,22 +219,16 @@ class BaseAssetCentricIO(
|
|
|
222
219
|
security_category_names.add(security_category_external_id)
|
|
223
220
|
self.client.lookup.security_categories.id(list(security_category_names))
|
|
224
221
|
|
|
225
|
-
def
|
|
226
|
-
self,
|
|
227
|
-
) ->
|
|
228
|
-
rows
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
# MyPy does understand that metadata is a dict here due to the check above.
|
|
233
|
-
for key, value in metadata.items(): # type: ignore[union-attr]
|
|
234
|
-
chunk[f"metadata.{key}"] = value
|
|
235
|
-
rows.append(chunk)
|
|
236
|
-
return rows
|
|
222
|
+
def rows_to_data(
|
|
223
|
+
self, rows: list[tuple[str, dict[str, JsonVal]]], selector: AssetCentricSelector | None = None
|
|
224
|
+
) -> Sequence[UploadItem[T_ResourceRequest]]:
|
|
225
|
+
# We need to populate caches for any external IDs used in the rows before converting to resources.
|
|
226
|
+
# Thus, we override this method instead of row_to_resource, and reuse the json_to_resource method that
|
|
227
|
+
# does the cache population.
|
|
228
|
+
return self.json_chunk_to_data([(source_id, self.row_to_json(row)) for source_id, row in rows])
|
|
237
229
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
) -> T_WriteClass:
|
|
230
|
+
@classmethod
|
|
231
|
+
def row_to_json(cls, row: dict[str, JsonVal]) -> dict[str, JsonVal]:
|
|
241
232
|
metadata: dict[str, JsonVal] = {}
|
|
242
233
|
cleaned_row: dict[str, JsonVal] = {}
|
|
243
234
|
for key, value in row.items():
|
|
@@ -248,10 +239,17 @@ class BaseAssetCentricIO(
|
|
|
248
239
|
cleaned_row[key] = value
|
|
249
240
|
if metadata:
|
|
250
241
|
cleaned_row["metadata"] = metadata
|
|
251
|
-
return
|
|
242
|
+
return cleaned_row
|
|
243
|
+
|
|
244
|
+
def row_to_resource(
|
|
245
|
+
self, source_id: str, row: dict[str, JsonVal], selector: AssetCentricSelector | None = None
|
|
246
|
+
) -> T_ResourceRequest:
|
|
247
|
+
raise NotImplementedError(
|
|
248
|
+
f"This method should not be called. {type(self).__name__} overrides rows_to_data instead."
|
|
249
|
+
)
|
|
252
250
|
|
|
253
251
|
|
|
254
|
-
class AssetIO(
|
|
252
|
+
class AssetIO(UploadableAssetCentricIO[Asset, AssetWrite]):
|
|
255
253
|
KIND = "Assets"
|
|
256
254
|
RESOURCE_TYPE = "asset"
|
|
257
255
|
SUPPORTED_DOWNLOAD_FORMATS = frozenset({".parquet", ".csv", ".ndjson"})
|
|
@@ -319,6 +317,9 @@ class AssetIO(BaseAssetCentricIO[str, AssetWrite, Asset, AssetWriteList, AssetLi
|
|
|
319
317
|
asset_subtree_external_ids=asset_subtree_external_ids,
|
|
320
318
|
data_set_external_ids=data_set_external_ids,
|
|
321
319
|
aggregated_properties=["child_count", "path", "depth"],
|
|
320
|
+
# We cannot use partitions here as it is not thread safe. This spawn multiple threads
|
|
321
|
+
# that are not shut down until all data is downloaded. We need to be able to abort.
|
|
322
|
+
partitions=None,
|
|
322
323
|
):
|
|
323
324
|
self._collect_dependencies(asset_list, selector)
|
|
324
325
|
yield Page(worker_id="main", items=asset_list)
|
|
@@ -347,7 +348,9 @@ class AssetIO(BaseAssetCentricIO[str, AssetWrite, Asset, AssetWriteList, AssetLi
|
|
|
347
348
|
return self.client.assets.retrieve_multiple(ids)
|
|
348
349
|
|
|
349
350
|
@classmethod
|
|
350
|
-
def read_chunks(
|
|
351
|
+
def read_chunks(
|
|
352
|
+
cls, reader: FileReader, selector: AssetCentricSelector
|
|
353
|
+
) -> Iterable[list[tuple[str, dict[str, JsonVal]]]]:
|
|
351
354
|
"""Assets require special handling when reading data to ensure parent assets are created first."""
|
|
352
355
|
current_depth = max_depth = 0
|
|
353
356
|
data_name = "row" if isinstance(reader, TableReader) else "line"
|
|
@@ -375,7 +378,7 @@ class AssetIO(BaseAssetCentricIO[str, AssetWrite, Asset, AssetWriteList, AssetLi
|
|
|
375
378
|
current_depth += 1
|
|
376
379
|
|
|
377
380
|
|
|
378
|
-
class FileMetadataIO(
|
|
381
|
+
class FileMetadataIO(AssetCentricIO[FileMetadata]):
|
|
379
382
|
KIND = "FileMetadata"
|
|
380
383
|
RESOURCE_TYPE = "file"
|
|
381
384
|
SUPPORTED_DOWNLOAD_FORMATS = frozenset({".parquet", ".csv", ".ndjson"})
|
|
@@ -430,54 +433,20 @@ class FileMetadataIO(BaseAssetCentricIO[str, FileMetadataWrite, FileMetadata, Fi
|
|
|
430
433
|
]
|
|
431
434
|
return file_schema + metadata_schema
|
|
432
435
|
|
|
433
|
-
def stream_data(self, selector: AssetCentricSelector, limit: int | None = None) -> Iterable[Page]:
|
|
436
|
+
def stream_data(self, selector: AssetCentricSelector, limit: int | None = None) -> Iterable[Page[FileMetadata]]:
|
|
434
437
|
asset_subtree_external_ids, data_set_external_ids = self._get_hierarchy_dataset_pair(selector)
|
|
435
438
|
for file_list in self.client.files(
|
|
436
439
|
chunk_size=self.CHUNK_SIZE,
|
|
437
440
|
limit=limit,
|
|
438
441
|
asset_subtree_external_ids=asset_subtree_external_ids,
|
|
439
442
|
data_set_external_ids=data_set_external_ids,
|
|
443
|
+
# We cannot use partitions here as it is not thread safe. This spawn multiple threads
|
|
444
|
+
# that are not shut down until all data is downloaded. We need to be able to abort.
|
|
445
|
+
partitions=None,
|
|
440
446
|
):
|
|
441
447
|
self._collect_dependencies(file_list, selector)
|
|
442
448
|
yield Page(worker_id="main", items=file_list)
|
|
443
449
|
|
|
444
|
-
def upload_items(
|
|
445
|
-
self,
|
|
446
|
-
data_chunk: Sequence[UploadItem[FileMetadataWrite]],
|
|
447
|
-
http_client: HTTPClient,
|
|
448
|
-
selector: AssetCentricSelector | None = None,
|
|
449
|
-
) -> Sequence[HTTPMessage]:
|
|
450
|
-
# The /files endpoint only supports creating one file at a time, so we override the default chunked
|
|
451
|
-
# upload behavior to upload one by one.
|
|
452
|
-
config = http_client.config
|
|
453
|
-
results: MutableSequence[HTTPMessage] = []
|
|
454
|
-
for item in data_chunk:
|
|
455
|
-
responses = http_client.request_with_retries(
|
|
456
|
-
message=SimpleBodyRequest(
|
|
457
|
-
endpoint_url=config.create_api_url(self.UPLOAD_ENDPOINT),
|
|
458
|
-
method="POST",
|
|
459
|
-
# MyPy does not understand that .dump is valid json
|
|
460
|
-
body_content=item.dump(), # type: ignore[arg-type]
|
|
461
|
-
)
|
|
462
|
-
)
|
|
463
|
-
# Convert the responses to per-item responses
|
|
464
|
-
for message in responses:
|
|
465
|
-
if isinstance(message, SuccessResponse):
|
|
466
|
-
results.append(
|
|
467
|
-
SuccessResponseItems(status_code=message.status_code, ids=[item.as_id()], body=message.body)
|
|
468
|
-
)
|
|
469
|
-
elif isinstance(message, FailedResponse):
|
|
470
|
-
results.append(
|
|
471
|
-
FailedResponseItems(
|
|
472
|
-
status_code=message.status_code, ids=[item.as_id()], body=message.body, error=message.error
|
|
473
|
-
)
|
|
474
|
-
)
|
|
475
|
-
elif isinstance(message, FailedRequestMessage):
|
|
476
|
-
results.append(FailedRequestItems(ids=[item.as_id()], error=message.error))
|
|
477
|
-
else:
|
|
478
|
-
results.append(message)
|
|
479
|
-
return results
|
|
480
|
-
|
|
481
450
|
def retrieve(self, ids: Sequence[int]) -> FileMetadataList:
|
|
482
451
|
return self.client.files.retrieve_multiple(ids)
|
|
483
452
|
|
|
@@ -492,20 +461,8 @@ class FileMetadataIO(BaseAssetCentricIO[str, FileMetadataWrite, FileMetadata, Fi
|
|
|
492
461
|
|
|
493
462
|
return [self._crud.dump_resource(item) for item in data_chunk]
|
|
494
463
|
|
|
495
|
-
def json_chunk_to_data(
|
|
496
|
-
self, data_chunk: list[tuple[str, dict[str, JsonVal]]]
|
|
497
|
-
) -> Sequence[UploadItem[FileMetadataWrite]]:
|
|
498
|
-
chunks = [item_json for _, item_json in data_chunk]
|
|
499
|
-
self._populate_asset_external_ids_cache(chunks)
|
|
500
|
-
self._populate_data_set_external_id_cache(chunks)
|
|
501
|
-
self._populate_security_category_name_cache(chunks)
|
|
502
|
-
return super().json_chunk_to_data(data_chunk)
|
|
503
|
-
|
|
504
|
-
def json_to_resource(self, item_json: dict[str, JsonVal]) -> FileMetadataWrite:
|
|
505
|
-
return self._crud.load_resource(item_json)
|
|
506
|
-
|
|
507
464
|
|
|
508
|
-
class TimeSeriesIO(
|
|
465
|
+
class TimeSeriesIO(UploadableAssetCentricIO[TimeSeries, TimeSeriesWrite]):
|
|
509
466
|
KIND = "TimeSeries"
|
|
510
467
|
SUPPORTED_DOWNLOAD_FORMATS = frozenset({".parquet", ".csv", ".ndjson"})
|
|
511
468
|
SUPPORTED_COMPRESSIONS = frozenset({".gz"})
|
|
@@ -533,6 +490,9 @@ class TimeSeriesIO(BaseAssetCentricIO[str, TimeSeriesWrite, TimeSeries, TimeSeri
|
|
|
533
490
|
limit=limit,
|
|
534
491
|
asset_subtree_external_ids=asset_subtree_external_ids,
|
|
535
492
|
data_set_external_ids=data_set_external_ids,
|
|
493
|
+
# We cannot use partitions here as it is not thread safe. This spawn multiple threads
|
|
494
|
+
# that are not shut down until all data is downloaded. We need to be able to abort.
|
|
495
|
+
partitions=None,
|
|
536
496
|
):
|
|
537
497
|
self._collect_dependencies(ts_list, selector)
|
|
538
498
|
yield Page(worker_id="main", items=ts_list)
|
|
@@ -598,7 +558,7 @@ class TimeSeriesIO(BaseAssetCentricIO[str, TimeSeriesWrite, TimeSeries, TimeSeri
|
|
|
598
558
|
return ts_schema + metadata_schema
|
|
599
559
|
|
|
600
560
|
|
|
601
|
-
class EventIO(
|
|
561
|
+
class EventIO(UploadableAssetCentricIO[Event, EventWrite]):
|
|
602
562
|
KIND = "Events"
|
|
603
563
|
SUPPORTED_DOWNLOAD_FORMATS = frozenset({".parquet", ".csv", ".ndjson"})
|
|
604
564
|
SUPPORTED_COMPRESSIONS = frozenset({".gz"})
|
|
@@ -660,6 +620,9 @@ class EventIO(BaseAssetCentricIO[str, EventWrite, Event, EventWriteList, EventLi
|
|
|
660
620
|
limit=limit,
|
|
661
621
|
asset_subtree_external_ids=asset_subtree_external_ids,
|
|
662
622
|
data_set_external_ids=data_set_external_ids,
|
|
623
|
+
# We cannot use partitions here as it is not thread safe. This spawn multiple threads
|
|
624
|
+
# that are not shut down until all data is downloaded. We need to be able to abort.
|
|
625
|
+
partitions=None,
|
|
663
626
|
):
|
|
664
627
|
self._collect_dependencies(event_list, selector)
|
|
665
628
|
yield Page(worker_id="main", items=event_list)
|
|
@@ -698,7 +661,7 @@ class HierarchyIO(ConfigurableStorageIO[AssetCentricSelector, AssetCentricResour
|
|
|
698
661
|
self._file_io = FileMetadataIO(client)
|
|
699
662
|
self._timeseries_io = TimeSeriesIO(client)
|
|
700
663
|
self._event_io = EventIO(client)
|
|
701
|
-
self._io_by_kind: dict[str,
|
|
664
|
+
self._io_by_kind: dict[str, AssetCentricIO] = {
|
|
702
665
|
self._asset_io.KIND: self._asset_io,
|
|
703
666
|
self._file_io.KIND: self._file_io,
|
|
704
667
|
self._timeseries_io.KIND: self._timeseries_io,
|
|
@@ -706,7 +669,7 @@ class HierarchyIO(ConfigurableStorageIO[AssetCentricSelector, AssetCentricResour
|
|
|
706
669
|
}
|
|
707
670
|
|
|
708
671
|
def as_id(self, item: AssetCentricResource) -> str:
|
|
709
|
-
return item.external_id or
|
|
672
|
+
return item.external_id or AssetCentricIO.create_internal_identifier(item.id, self.client.config.project)
|
|
710
673
|
|
|
711
674
|
def stream_data(
|
|
712
675
|
self, selector: AssetCentricSelector, limit: int | None = None
|
|
@@ -726,5 +689,5 @@ class HierarchyIO(ConfigurableStorageIO[AssetCentricSelector, AssetCentricResour
|
|
|
726
689
|
def configurations(self, selector: AssetCentricSelector) -> Iterable[StorageIOConfig]:
|
|
727
690
|
yield from self.get_resource_io(selector.kind).configurations(selector)
|
|
728
691
|
|
|
729
|
-
def get_resource_io(self, kind: str) ->
|
|
692
|
+
def get_resource_io(self, kind: str) -> AssetCentricIO:
|
|
730
693
|
return self._io_by_kind[kind]
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
from collections.abc import Iterable, Mapping, Sequence, Sized
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import ClassVar, Generic, TypeVar
|
|
5
|
-
|
|
6
|
-
from cognite.client.data_classes._base import T_CogniteResource
|
|
4
|
+
from typing import ClassVar, Generic, Literal, TypeVar
|
|
7
5
|
|
|
8
6
|
from cognite_toolkit._cdf_tk.client import ToolkitClient
|
|
9
7
|
from cognite_toolkit._cdf_tk.exceptions import ToolkitNotImplementedError
|
|
8
|
+
from cognite_toolkit._cdf_tk.protocols import T_ResourceRequest, T_ResourceResponse
|
|
10
9
|
from cognite_toolkit._cdf_tk.utils.collection import chunker
|
|
11
|
-
from cognite_toolkit._cdf_tk.utils.fileio import
|
|
12
|
-
from cognite_toolkit._cdf_tk.utils.fileio._readers import TableReader
|
|
10
|
+
from cognite_toolkit._cdf_tk.utils.fileio import MultiFileReader, SchemaColumn
|
|
13
11
|
from cognite_toolkit._cdf_tk.utils.http_client import HTTPClient, HTTPMessage, ItemsRequest
|
|
14
|
-
from cognite_toolkit._cdf_tk.utils.useful_types import JsonVal
|
|
12
|
+
from cognite_toolkit._cdf_tk.utils.useful_types import JsonVal
|
|
15
13
|
|
|
16
14
|
from .selectors import DataSelector
|
|
17
15
|
|
|
@@ -28,9 +26,9 @@ T_Selector = TypeVar("T_Selector", bound=DataSelector)
|
|
|
28
26
|
|
|
29
27
|
|
|
30
28
|
@dataclass
|
|
31
|
-
class Page(Generic[
|
|
29
|
+
class Page(Generic[T_ResourceResponse], Sized):
|
|
32
30
|
worker_id: str
|
|
33
|
-
items: Sequence[
|
|
31
|
+
items: Sequence[T_ResourceResponse]
|
|
34
32
|
next_cursor: str | None = None
|
|
35
33
|
|
|
36
34
|
def __len__(self) -> int:
|
|
@@ -38,7 +36,7 @@ class Page(Generic[T_CogniteResource], Sized):
|
|
|
38
36
|
|
|
39
37
|
|
|
40
38
|
@dataclass
|
|
41
|
-
class UploadItem(Generic[
|
|
39
|
+
class UploadItem(Generic[T_ResourceRequest]):
|
|
42
40
|
"""An item to be uploaded to CDF, consisting of a source ID and the writable Cognite resource.
|
|
43
41
|
|
|
44
42
|
Attributes:
|
|
@@ -47,7 +45,7 @@ class UploadItem(Generic[T_WriteCogniteResource]):
|
|
|
47
45
|
"""
|
|
48
46
|
|
|
49
47
|
source_id: str
|
|
50
|
-
item:
|
|
48
|
+
item: T_ResourceRequest
|
|
51
49
|
|
|
52
50
|
def as_id(self) -> str:
|
|
53
51
|
return self.source_id
|
|
@@ -56,7 +54,7 @@ class UploadItem(Generic[T_WriteCogniteResource]):
|
|
|
56
54
|
return self.item.dump(camel_case=True)
|
|
57
55
|
|
|
58
56
|
|
|
59
|
-
class StorageIO(ABC, Generic[T_Selector,
|
|
57
|
+
class StorageIO(ABC, Generic[T_Selector, T_ResourceResponse]):
|
|
60
58
|
"""This is a base class for all storage classes in Cognite Toolkit
|
|
61
59
|
|
|
62
60
|
It defines the interface for downloading data from CDF. Note this can also be used for multiple
|
|
@@ -80,7 +78,7 @@ class StorageIO(ABC, Generic[T_Selector, T_CogniteResource]):
|
|
|
80
78
|
self.client = client
|
|
81
79
|
|
|
82
80
|
@abstractmethod
|
|
83
|
-
def as_id(self, item:
|
|
81
|
+
def as_id(self, item: T_ResourceResponse) -> str:
|
|
84
82
|
"""Convert an item to its corresponding ID.
|
|
85
83
|
Args:
|
|
86
84
|
item: The item to convert.
|
|
@@ -116,7 +114,7 @@ class StorageIO(ABC, Generic[T_Selector, T_CogniteResource]):
|
|
|
116
114
|
|
|
117
115
|
@abstractmethod
|
|
118
116
|
def data_to_json_chunk(
|
|
119
|
-
self, data_chunk: Sequence[
|
|
117
|
+
self, data_chunk: Sequence[T_ResourceResponse], selector: T_Selector | None = None
|
|
120
118
|
) -> list[dict[str, JsonVal]]:
|
|
121
119
|
"""Convert a chunk of data to a JSON-compatible format.
|
|
122
120
|
|
|
@@ -132,7 +130,7 @@ class StorageIO(ABC, Generic[T_Selector, T_CogniteResource]):
|
|
|
132
130
|
|
|
133
131
|
|
|
134
132
|
class UploadableStorageIO(
|
|
135
|
-
Generic[T_Selector,
|
|
133
|
+
Generic[T_Selector, T_ResourceResponse, T_ResourceRequest], StorageIO[T_Selector, T_ResourceResponse], ABC
|
|
136
134
|
):
|
|
137
135
|
"""A base class for storage items that support uploading data to CDF.
|
|
138
136
|
|
|
@@ -145,12 +143,14 @@ class UploadableStorageIO(
|
|
|
145
143
|
|
|
146
144
|
KIND: ClassVar[str]
|
|
147
145
|
SUPPORTED_READ_FORMATS: ClassVar[frozenset[str]]
|
|
146
|
+
UPLOAD_ENDPOINT_TYPE: Literal["app", "api"] = "api"
|
|
147
|
+
UPLOAD_ENDPOINT_METHOD: Literal["GET", "POST", "PATCH", "DELETE", "PUT"] = "POST"
|
|
148
148
|
UPLOAD_ENDPOINT: ClassVar[str]
|
|
149
149
|
UPLOAD_EXTRA_ARGS: ClassVar[Mapping[str, JsonVal] | None] = None
|
|
150
150
|
|
|
151
151
|
def upload_items(
|
|
152
152
|
self,
|
|
153
|
-
data_chunk: Sequence[UploadItem[
|
|
153
|
+
data_chunk: Sequence[UploadItem[T_ResourceRequest]],
|
|
154
154
|
http_client: HTTPClient,
|
|
155
155
|
selector: T_Selector | None = None,
|
|
156
156
|
) -> Sequence[HTTPMessage]:
|
|
@@ -170,10 +170,17 @@ class UploadableStorageIO(
|
|
|
170
170
|
raise ValueError(f"Data chunk size {len(data_chunk)} exceeds the maximum CHUNK_SIZE of {self.CHUNK_SIZE}.")
|
|
171
171
|
|
|
172
172
|
config = http_client.config
|
|
173
|
+
if self.UPLOAD_ENDPOINT_TYPE == "api":
|
|
174
|
+
url = config.create_api_url(self.UPLOAD_ENDPOINT)
|
|
175
|
+
elif self.UPLOAD_ENDPOINT_TYPE == "app":
|
|
176
|
+
url = config.create_app_url(self.UPLOAD_ENDPOINT)
|
|
177
|
+
else:
|
|
178
|
+
raise ToolkitNotImplementedError(f"Unsupported UPLOAD_ENDPOINT_TYPE {self.UPLOAD_ENDPOINT_TYPE!r}.")
|
|
179
|
+
|
|
173
180
|
return http_client.request_with_retries(
|
|
174
181
|
message=ItemsRequest(
|
|
175
|
-
endpoint_url=
|
|
176
|
-
method=
|
|
182
|
+
endpoint_url=url,
|
|
183
|
+
method=self.UPLOAD_ENDPOINT_METHOD,
|
|
177
184
|
items=list(data_chunk),
|
|
178
185
|
extra_body_fields=dict(self.UPLOAD_EXTRA_ARGS or {}),
|
|
179
186
|
)
|
|
@@ -181,7 +188,7 @@ class UploadableStorageIO(
|
|
|
181
188
|
|
|
182
189
|
def json_chunk_to_data(
|
|
183
190
|
self, data_chunk: list[tuple[str, dict[str, JsonVal]]]
|
|
184
|
-
) -> Sequence[UploadItem[
|
|
191
|
+
) -> Sequence[UploadItem[T_ResourceRequest]]:
|
|
185
192
|
"""Convert a JSON-compatible chunk of data back to a writable Cognite resource list.
|
|
186
193
|
|
|
187
194
|
Args:
|
|
@@ -190,14 +197,14 @@ class UploadableStorageIO(
|
|
|
190
197
|
Returns:
|
|
191
198
|
A writable Cognite resource list representing the data.
|
|
192
199
|
"""
|
|
193
|
-
result: list[UploadItem[
|
|
200
|
+
result: list[UploadItem[T_ResourceRequest]] = []
|
|
194
201
|
for source_id, item_json in data_chunk:
|
|
195
202
|
item = self.json_to_resource(item_json)
|
|
196
203
|
result.append(UploadItem(source_id=source_id, item=item))
|
|
197
204
|
return result
|
|
198
205
|
|
|
199
206
|
@abstractmethod
|
|
200
|
-
def json_to_resource(self, item_json: dict[str, JsonVal]) ->
|
|
207
|
+
def json_to_resource(self, item_json: dict[str, JsonVal]) -> T_ResourceRequest:
|
|
201
208
|
"""Convert a JSON-compatible dictionary back to a writable Cognite resource.
|
|
202
209
|
|
|
203
210
|
Args:
|
|
@@ -208,20 +215,45 @@ class UploadableStorageIO(
|
|
|
208
215
|
raise NotImplementedError()
|
|
209
216
|
|
|
210
217
|
@classmethod
|
|
211
|
-
def read_chunks(
|
|
212
|
-
|
|
218
|
+
def read_chunks(
|
|
219
|
+
cls, reader: MultiFileReader, selector: T_Selector
|
|
220
|
+
) -> Iterable[list[tuple[str, dict[str, JsonVal]]]]:
|
|
221
|
+
"""Read data from a MultiFileReader in chunks.
|
|
222
|
+
|
|
223
|
+
This method yields chunks of data, where each chunk is a list of tuples. Each tuple contains a source ID
|
|
224
|
+
(e.g., line number or row identifier) and a dictionary representing the data in a JSON-compatible format.
|
|
225
|
+
|
|
226
|
+
This method can be overridden by subclasses to customize how data is read and chunked.
|
|
227
|
+
Args:
|
|
228
|
+
reader: An instance of MultiFileReader to read data from.
|
|
229
|
+
selector: The selection criteria to identify the data.
|
|
230
|
+
"""
|
|
231
|
+
data_name = "row" if reader.is_table else "line"
|
|
213
232
|
# Include name of line for better error messages
|
|
214
233
|
iterable = ((f"{data_name} {line_no}", item) for line_no, item in reader.read_chunks_with_line_numbers())
|
|
215
234
|
|
|
216
235
|
yield from chunker(iterable, cls.CHUNK_SIZE)
|
|
217
236
|
|
|
237
|
+
@classmethod
|
|
238
|
+
def count_chunks(cls, reader: MultiFileReader) -> int:
|
|
239
|
+
"""Count the number of items in a MultiFileReader.
|
|
240
|
+
|
|
241
|
+
This method can be overridden by subclasses to customize how items are counted.
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
reader: An instance of MultiFileReader to count items from.
|
|
245
|
+
Returns:
|
|
246
|
+
The number of items in the reader.
|
|
247
|
+
"""
|
|
248
|
+
return reader.count()
|
|
249
|
+
|
|
218
250
|
|
|
219
|
-
class TableUploadableStorageIO(UploadableStorageIO[T_Selector,
|
|
251
|
+
class TableUploadableStorageIO(UploadableStorageIO[T_Selector, T_ResourceResponse, T_ResourceRequest], ABC):
|
|
220
252
|
"""A base class for storage items that support uploading data with table schemas."""
|
|
221
253
|
|
|
222
254
|
def rows_to_data(
|
|
223
255
|
self, rows: list[tuple[str, dict[str, JsonVal]]], selector: T_Selector | None = None
|
|
224
|
-
) -> Sequence[UploadItem[
|
|
256
|
+
) -> Sequence[UploadItem[T_ResourceRequest]]:
|
|
225
257
|
"""Convert a row-based JSON-compatible chunk of data back to a writable Cognite resource list.
|
|
226
258
|
|
|
227
259
|
Args:
|
|
@@ -232,7 +264,7 @@ class TableUploadableStorageIO(UploadableStorageIO[T_Selector, T_CogniteResource
|
|
|
232
264
|
Returns:
|
|
233
265
|
A writable Cognite resource list representing the data.
|
|
234
266
|
"""
|
|
235
|
-
result: list[UploadItem[
|
|
267
|
+
result: list[UploadItem[T_ResourceRequest]] = []
|
|
236
268
|
for source_id, row in rows:
|
|
237
269
|
item = self.row_to_resource(source_id, row, selector=selector)
|
|
238
270
|
result.append(UploadItem(source_id=source_id, item=item))
|
|
@@ -241,7 +273,7 @@ class TableUploadableStorageIO(UploadableStorageIO[T_Selector, T_CogniteResource
|
|
|
241
273
|
@abstractmethod
|
|
242
274
|
def row_to_resource(
|
|
243
275
|
self, source_id: str, row: dict[str, JsonVal], selector: T_Selector | None = None
|
|
244
|
-
) ->
|
|
276
|
+
) -> T_ResourceRequest:
|
|
245
277
|
"""Convert a row-based JSON-compatible dictionary back to a writable Cognite resource.
|
|
246
278
|
|
|
247
279
|
Args:
|
|
@@ -254,7 +286,7 @@ class TableUploadableStorageIO(UploadableStorageIO[T_Selector, T_CogniteResource
|
|
|
254
286
|
raise NotImplementedError()
|
|
255
287
|
|
|
256
288
|
|
|
257
|
-
class ConfigurableStorageIO(StorageIO[T_Selector,
|
|
289
|
+
class ConfigurableStorageIO(StorageIO[T_Selector, T_ResourceResponse], ABC):
|
|
258
290
|
"""A base class for storage items that support configurations for different storage items."""
|
|
259
291
|
|
|
260
292
|
@abstractmethod
|
|
@@ -263,7 +295,7 @@ class ConfigurableStorageIO(StorageIO[T_Selector, T_CogniteResource], ABC):
|
|
|
263
295
|
raise NotImplementedError()
|
|
264
296
|
|
|
265
297
|
|
|
266
|
-
class TableStorageIO(StorageIO[T_Selector,
|
|
298
|
+
class TableStorageIO(StorageIO[T_Selector, T_ResourceResponse], ABC):
|
|
267
299
|
"""A base class for storage items that support table schemas."""
|
|
268
300
|
|
|
269
301
|
@abstractmethod
|
|
@@ -281,7 +313,7 @@ class TableStorageIO(StorageIO[T_Selector, T_CogniteResource], ABC):
|
|
|
281
313
|
|
|
282
314
|
@abstractmethod
|
|
283
315
|
def data_to_row(
|
|
284
|
-
self, data_chunk: Sequence[
|
|
316
|
+
self, data_chunk: Sequence[T_ResourceResponse], selector: T_Selector | None = None
|
|
285
317
|
) -> list[dict[str, JsonVal]]:
|
|
286
318
|
"""Convert a chunk of data to a row-based JSON-compatible format.
|
|
287
319
|
|