cognite-toolkit 0.6.83__py3-none-any.whl → 0.6.85__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.
Potentially problematic release.
This version of cognite-toolkit might be problematic. Click here for more details.
- cognite_toolkit/_cdf_tk/apps/_purge.py +84 -4
- cognite_toolkit/_cdf_tk/client/_toolkit_client.py +3 -1
- cognite_toolkit/_cdf_tk/client/api/lookup.py +128 -73
- cognite_toolkit/_cdf_tk/client/testing.py +2 -0
- cognite_toolkit/_cdf_tk/commands/_download.py +1 -2
- cognite_toolkit/_cdf_tk/commands/_migrate/creators.py +5 -4
- cognite_toolkit/_cdf_tk/commands/_purge.py +173 -348
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/auth.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/function.py +23 -17
- cognite_toolkit/_cdf_tk/storageio/_asset_centric.py +105 -37
- cognite_toolkit/_cdf_tk/utils/aggregators.py +47 -9
- cognite_toolkit/_cdf_tk/utils/validate_access.py +205 -43
- 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.6.83.dist-info → cognite_toolkit-0.6.85.dist-info}/METADATA +1 -1
- {cognite_toolkit-0.6.83.dist-info → cognite_toolkit-0.6.85.dist-info}/RECORD +21 -21
- {cognite_toolkit-0.6.83.dist-info → cognite_toolkit-0.6.85.dist-info}/WHEEL +0 -0
- {cognite_toolkit-0.6.83.dist-info → cognite_toolkit-0.6.85.dist-info}/entry_points.txt +0 -0
- {cognite_toolkit-0.6.83.dist-info → cognite_toolkit-0.6.85.dist-info}/licenses/LICENSE +0 -0
|
@@ -36,7 +36,6 @@ from cognite_toolkit._cdf_tk.client.data_classes.functions import FunctionSchedu
|
|
|
36
36
|
from cognite_toolkit._cdf_tk.cruds._base_cruds import ResourceCRUD
|
|
37
37
|
from cognite_toolkit._cdf_tk.exceptions import (
|
|
38
38
|
ResourceCreationError,
|
|
39
|
-
ResourceRetrievalError,
|
|
40
39
|
ToolkitRequiredValueError,
|
|
41
40
|
)
|
|
42
41
|
from cognite_toolkit._cdf_tk.feature_flags import Flags
|
|
@@ -565,22 +564,7 @@ class FunctionScheduleCRUD(
|
|
|
565
564
|
|
|
566
565
|
def create(self, items: FunctionScheduleWriteList) -> FunctionSchedulesList:
|
|
567
566
|
created_list = FunctionSchedulesList([], cognite_client=self.client)
|
|
568
|
-
|
|
569
|
-
function_id_by_external_id: dict[str, int] = {}
|
|
570
|
-
if functions_to_lookup:
|
|
571
|
-
try:
|
|
572
|
-
function_ids = self.client.lookup.functions.id(functions_to_lookup)
|
|
573
|
-
except ResourceRetrievalError as e:
|
|
574
|
-
failed_items = self.get_ids(items)
|
|
575
|
-
missing_functions = functions_to_lookup
|
|
576
|
-
if e.resources:
|
|
577
|
-
missing_functions = list(e.resources)
|
|
578
|
-
failed_items = [id_ for id_ in failed_items if id_.function_external_id in set(missing_functions)]
|
|
579
|
-
raise ResourceCreationError(
|
|
580
|
-
f"Failed to create function schedule(s) {humanize_collection(failed_items)}. "
|
|
581
|
-
f"Could not find function(s) {humanize_collection(missing_functions)!r}"
|
|
582
|
-
) from e
|
|
583
|
-
function_id_by_external_id = dict(zip(functions_to_lookup, function_ids))
|
|
567
|
+
function_id_by_external_id = self._get_function_ids_by_external_id(items)
|
|
584
568
|
|
|
585
569
|
for item in items:
|
|
586
570
|
id_ = self.get_id(item)
|
|
@@ -607,6 +591,28 @@ class FunctionScheduleCRUD(
|
|
|
607
591
|
created_list.append(created)
|
|
608
592
|
return created_list
|
|
609
593
|
|
|
594
|
+
def _get_function_ids_by_external_id(self, items: FunctionScheduleWriteList) -> dict[str, int]:
|
|
595
|
+
functions_to_lookup = list({item.function_external_id for item in items if item.function_external_id})
|
|
596
|
+
if not functions_to_lookup:
|
|
597
|
+
return {}
|
|
598
|
+
function_ids = self.client.lookup.functions.id(functions_to_lookup)
|
|
599
|
+
|
|
600
|
+
if len(function_ids) == len(functions_to_lookup):
|
|
601
|
+
return dict(zip(functions_to_lookup, function_ids))
|
|
602
|
+
# The lookup API is cached, so it is cheap to do individual lookups to find the missing ones.
|
|
603
|
+
lookup_pair = (
|
|
604
|
+
(function_external_id, self.client.lookup.functions.id(function_external_id))
|
|
605
|
+
for function_external_id in functions_to_lookup
|
|
606
|
+
)
|
|
607
|
+
missing_functions = {func for func, func_id in lookup_pair if func_id is None}
|
|
608
|
+
failed_schedules = [self.get_id(item) for item in items if item.function_external_id in missing_functions]
|
|
609
|
+
plural_schedules = "s" if len(failed_schedules) > 1 else ""
|
|
610
|
+
plural_fun = "s" if len(missing_functions) > 1 else ""
|
|
611
|
+
raise ResourceCreationError(
|
|
612
|
+
f"Failed to create function schedule{plural_schedules} {humanize_collection(failed_schedules)}. "
|
|
613
|
+
f"Could not find function{plural_fun} {humanize_collection(missing_functions)!r}"
|
|
614
|
+
)
|
|
615
|
+
|
|
610
616
|
def delete(self, ids: SequenceNotStr[FunctionScheduleID]) -> int:
|
|
611
617
|
schedules = self.retrieve(ids)
|
|
612
618
|
count = 0
|
|
@@ -36,10 +36,9 @@ from cognite_toolkit._cdf_tk.cruds import (
|
|
|
36
36
|
EventCRUD,
|
|
37
37
|
FileMetadataCRUD,
|
|
38
38
|
LabelCRUD,
|
|
39
|
-
ResourceCRUD,
|
|
40
39
|
TimeSeriesCRUD,
|
|
41
40
|
)
|
|
42
|
-
from cognite_toolkit._cdf_tk.exceptions import ToolkitNotImplementedError
|
|
41
|
+
from cognite_toolkit._cdf_tk.exceptions import ToolkitMissingResourceError, ToolkitNotImplementedError
|
|
43
42
|
from cognite_toolkit._cdf_tk.utils.aggregators import (
|
|
44
43
|
AssetAggregator,
|
|
45
44
|
AssetCentricAggregator,
|
|
@@ -85,19 +84,10 @@ class BaseAssetCentricIO(
|
|
|
85
84
|
|
|
86
85
|
def __init__(self, client: ToolkitClient) -> None:
|
|
87
86
|
super().__init__(client)
|
|
88
|
-
self._loader = self._get_loader()
|
|
89
87
|
self._aggregator = self._get_aggregator()
|
|
90
88
|
self._downloaded_data_sets_by_selector: dict[AssetCentricSelector, set[int]] = defaultdict(set)
|
|
91
89
|
self._downloaded_labels_by_selector: dict[AssetCentricSelector, set[str]] = defaultdict(set)
|
|
92
90
|
|
|
93
|
-
@abstractmethod
|
|
94
|
-
def _get_loader(
|
|
95
|
-
self,
|
|
96
|
-
) -> ResourceCRUD[
|
|
97
|
-
T_ID, T_WriteClass, T_WritableCogniteResource, T_CogniteResourceList, T_WritableCogniteResourceList
|
|
98
|
-
]:
|
|
99
|
-
raise NotImplementedError()
|
|
100
|
-
|
|
101
91
|
@abstractmethod
|
|
102
92
|
def _get_aggregator(self) -> AssetCentricAggregator:
|
|
103
93
|
raise NotImplementedError()
|
|
@@ -113,11 +103,6 @@ class BaseAssetCentricIO(
|
|
|
113
103
|
return self._aggregator.count(hierarchy=selector.hierarchy)
|
|
114
104
|
return None
|
|
115
105
|
|
|
116
|
-
def data_to_json_chunk(
|
|
117
|
-
self, data_chunk: Sequence[T_WritableCogniteResource], selector: AssetCentricSelector | None = None
|
|
118
|
-
) -> list[dict[str, JsonVal]]:
|
|
119
|
-
return [self._loader.dump_resource(item) for item in data_chunk]
|
|
120
|
-
|
|
121
106
|
def configurations(self, selector: AssetCentricSelector) -> Iterable[StorageIOConfig]:
|
|
122
107
|
data_set_ids = self._downloaded_data_sets_by_selector[selector]
|
|
123
108
|
if data_set_ids:
|
|
@@ -178,6 +163,22 @@ class BaseAssetCentricIO(
|
|
|
178
163
|
def create_internal_identifier(cls, internal_id: int, project: str) -> str:
|
|
179
164
|
return f"INTERNAL_ID_project_{project}_{internal_id!s}"
|
|
180
165
|
|
|
166
|
+
def _populate_data_set_cache(self, chunk: Sequence[Asset | FileMetadata | TimeSeries | Event]) -> None:
|
|
167
|
+
data_set_ids = {item.data_set_id for item in chunk if item.data_set_id is not None}
|
|
168
|
+
self.client.lookup.data_sets.external_id(list(data_set_ids))
|
|
169
|
+
|
|
170
|
+
def _populate_security_category_cache(self, chunk: Sequence[FileMetadata | TimeSeries]) -> None:
|
|
171
|
+
security_category_ids: set[int] = set()
|
|
172
|
+
for item in chunk:
|
|
173
|
+
security_category_ids.update(item.security_categories or [])
|
|
174
|
+
self.client.lookup.security_categories.external_id(list(security_category_ids))
|
|
175
|
+
|
|
176
|
+
def _populate_asset_cache(self, chunk: Sequence[FileMetadata | Event]) -> None:
|
|
177
|
+
asset_ids: set[int] = set()
|
|
178
|
+
for item in chunk:
|
|
179
|
+
asset_ids.update(item.asset_ids or [])
|
|
180
|
+
self.client.lookup.assets.external_id(list(asset_ids))
|
|
181
|
+
|
|
181
182
|
|
|
182
183
|
class AssetIO(BaseAssetCentricIO[str, AssetWrite, Asset, AssetWriteList, AssetList]):
|
|
183
184
|
KIND = "Assets"
|
|
@@ -187,22 +188,31 @@ class AssetIO(BaseAssetCentricIO[str, AssetWrite, Asset, AssetWriteList, AssetLi
|
|
|
187
188
|
SUPPORTED_READ_FORMATS = frozenset({".parquet", ".csv", ".ndjson", ".yaml", ".yml"})
|
|
188
189
|
UPLOAD_ENDPOINT = "/assets"
|
|
189
190
|
|
|
191
|
+
def __init__(self, client: ToolkitClient) -> None:
|
|
192
|
+
super().__init__(client)
|
|
193
|
+
self._crud = AssetCRUD.create_loader(self.client)
|
|
194
|
+
|
|
190
195
|
def as_id(self, item: Asset) -> str:
|
|
191
196
|
return item.external_id if item.external_id is not None else self._create_identifier(item.id)
|
|
192
197
|
|
|
193
|
-
def _get_loader(self) -> AssetCRUD:
|
|
194
|
-
return AssetCRUD.create_loader(self.client)
|
|
195
|
-
|
|
196
198
|
def _get_aggregator(self) -> AssetCentricAggregator:
|
|
197
199
|
return AssetAggregator(self.client)
|
|
198
200
|
|
|
199
201
|
def get_schema(self, selector: AssetCentricSelector) -> list[SchemaColumn]:
|
|
200
202
|
data_set_ids: list[int] = []
|
|
201
203
|
if isinstance(selector, DataSetSelector):
|
|
202
|
-
|
|
204
|
+
data_set_id = self.client.lookup.data_sets.id(selector.data_set_external_id)
|
|
205
|
+
if data_set_id is None:
|
|
206
|
+
raise ToolkitMissingResourceError(
|
|
207
|
+
f"Data set with external ID {selector.data_set_external_id} not found."
|
|
208
|
+
)
|
|
209
|
+
data_set_ids.append(data_set_id)
|
|
203
210
|
hierarchy: list[int] = []
|
|
204
211
|
if isinstance(selector, AssetSubtreeSelector):
|
|
205
|
-
|
|
212
|
+
asset_id = self.client.lookup.assets.id(selector.hierarchy)
|
|
213
|
+
if asset_id is None:
|
|
214
|
+
raise ToolkitMissingResourceError(f"Asset with external ID {selector.hierarchy} not found.")
|
|
215
|
+
hierarchy.append(asset_id)
|
|
206
216
|
|
|
207
217
|
if hierarchy or data_set_ids:
|
|
208
218
|
metadata_keys = metadata_key_counts(
|
|
@@ -238,8 +248,17 @@ class AssetIO(BaseAssetCentricIO[str, AssetWrite, Asset, AssetWriteList, AssetLi
|
|
|
238
248
|
self._collect_dependencies(asset_list, selector)
|
|
239
249
|
yield Page(worker_id="main", items=asset_list)
|
|
240
250
|
|
|
251
|
+
def data_to_json_chunk(
|
|
252
|
+
self, data_chunk: Sequence[Asset], selector: AssetCentricSelector | None = None
|
|
253
|
+
) -> list[dict[str, JsonVal]]:
|
|
254
|
+
# Ensure data sets are looked up to populate cache.
|
|
255
|
+
# This is to avoid looking up each data set id individually in the .dump_resource call.
|
|
256
|
+
self._populate_data_set_cache(data_chunk)
|
|
257
|
+
|
|
258
|
+
return [self._crud.dump_resource(item) for item in data_chunk]
|
|
259
|
+
|
|
241
260
|
def json_to_resource(self, item_json: dict[str, JsonVal]) -> AssetWrite:
|
|
242
|
-
return self.
|
|
261
|
+
return self._crud.load_resource(item_json)
|
|
243
262
|
|
|
244
263
|
def retrieve(self, ids: Sequence[int]) -> AssetList:
|
|
245
264
|
return self.client.assets.retrieve_multiple(ids)
|
|
@@ -253,19 +272,25 @@ class FileMetadataIO(BaseAssetCentricIO[str, FileMetadataWrite, FileMetadata, Fi
|
|
|
253
272
|
SUPPORTED_READ_FORMATS = frozenset({".parquet", ".csv", ".ndjson"})
|
|
254
273
|
UPLOAD_ENDPOINT = "/files"
|
|
255
274
|
|
|
275
|
+
def __init__(self, client: ToolkitClient) -> None:
|
|
276
|
+
super().__init__(client)
|
|
277
|
+
self._crud = FileMetadataCRUD.create_loader(self.client)
|
|
278
|
+
|
|
256
279
|
def as_id(self, item: FileMetadata) -> str:
|
|
257
280
|
return item.external_id if item.external_id is not None else self._create_identifier(item.id)
|
|
258
281
|
|
|
259
|
-
def _get_loader(self) -> FileMetadataCRUD:
|
|
260
|
-
return FileMetadataCRUD.create_loader(self.client)
|
|
261
|
-
|
|
262
282
|
def _get_aggregator(self) -> AssetCentricAggregator:
|
|
263
283
|
return FileAggregator(self.client)
|
|
264
284
|
|
|
265
285
|
def get_schema(self, selector: AssetCentricSelector) -> list[SchemaColumn]:
|
|
266
286
|
data_set_ids: list[int] = []
|
|
267
287
|
if isinstance(selector, DataSetSelector):
|
|
268
|
-
|
|
288
|
+
data_set_id = self.client.lookup.data_sets.id(selector.data_set_external_id)
|
|
289
|
+
if data_set_id is None:
|
|
290
|
+
raise ToolkitMissingResourceError(
|
|
291
|
+
f"Data set with external ID {selector.data_set_external_id} not found."
|
|
292
|
+
)
|
|
293
|
+
data_set_ids.append(data_set_id)
|
|
269
294
|
if isinstance(selector, AssetSubtreeSelector):
|
|
270
295
|
raise ToolkitNotImplementedError(f"Selector type {type(selector)} not supported for FileIO.")
|
|
271
296
|
|
|
@@ -345,8 +370,19 @@ class FileMetadataIO(BaseAssetCentricIO[str, FileMetadataWrite, FileMetadata, Fi
|
|
|
345
370
|
def retrieve(self, ids: Sequence[int]) -> FileMetadataList:
|
|
346
371
|
return self.client.files.retrieve_multiple(ids)
|
|
347
372
|
|
|
373
|
+
def data_to_json_chunk(
|
|
374
|
+
self, data_chunk: Sequence[FileMetadata], selector: AssetCentricSelector | None = None
|
|
375
|
+
) -> list[dict[str, JsonVal]]:
|
|
376
|
+
# Ensure data sets/assets/security-categories are looked up to populate cache.
|
|
377
|
+
# This is to avoid looking up each data set id individually in the .dump_resource call
|
|
378
|
+
self._populate_data_set_cache(data_chunk)
|
|
379
|
+
self._populate_asset_cache(data_chunk)
|
|
380
|
+
self._populate_security_category_cache(data_chunk)
|
|
381
|
+
|
|
382
|
+
return [self._crud.dump_resource(item) for item in data_chunk]
|
|
383
|
+
|
|
348
384
|
def json_to_resource(self, item_json: dict[str, JsonVal]) -> FileMetadataWrite:
|
|
349
|
-
return self.
|
|
385
|
+
return self._crud.load_resource(item_json)
|
|
350
386
|
|
|
351
387
|
|
|
352
388
|
class TimeSeriesIO(BaseAssetCentricIO[str, TimeSeriesWrite, TimeSeries, TimeSeriesWriteList, TimeSeriesList]):
|
|
@@ -357,12 +393,13 @@ class TimeSeriesIO(BaseAssetCentricIO[str, TimeSeriesWrite, TimeSeries, TimeSeri
|
|
|
357
393
|
UPLOAD_ENDPOINT = "/timeseries"
|
|
358
394
|
RESOURCE_TYPE = "timeseries"
|
|
359
395
|
|
|
396
|
+
def __init__(self, client: ToolkitClient) -> None:
|
|
397
|
+
super().__init__(client)
|
|
398
|
+
self._crud = TimeSeriesCRUD.create_loader(self.client)
|
|
399
|
+
|
|
360
400
|
def as_id(self, item: TimeSeries) -> str:
|
|
361
401
|
return item.external_id if item.external_id is not None else self._create_identifier(item.id)
|
|
362
402
|
|
|
363
|
-
def _get_loader(self) -> TimeSeriesCRUD:
|
|
364
|
-
return TimeSeriesCRUD.create_loader(self.client)
|
|
365
|
-
|
|
366
403
|
def _get_aggregator(self) -> AssetCentricAggregator:
|
|
367
404
|
return TimeSeriesAggregator(self.client)
|
|
368
405
|
|
|
@@ -380,13 +417,29 @@ class TimeSeriesIO(BaseAssetCentricIO[str, TimeSeriesWrite, TimeSeries, TimeSeri
|
|
|
380
417
|
self._collect_dependencies(ts_list, selector)
|
|
381
418
|
yield Page(worker_id="main", items=ts_list)
|
|
382
419
|
|
|
420
|
+
def data_to_json_chunk(
|
|
421
|
+
self, data_chunk: Sequence[TimeSeries], selector: AssetCentricSelector | None = None
|
|
422
|
+
) -> list[dict[str, JsonVal]]:
|
|
423
|
+
# Ensure data sets/assets/security categories are looked up to populate cache.
|
|
424
|
+
self._populate_data_set_cache(data_chunk)
|
|
425
|
+
self._populate_security_category_cache(data_chunk)
|
|
426
|
+
asset_ids = {item.asset_id for item in data_chunk if item.asset_id is not None}
|
|
427
|
+
self.client.lookup.assets.external_id(list(asset_ids))
|
|
428
|
+
|
|
429
|
+
return [self._crud.dump_resource(item) for item in data_chunk]
|
|
430
|
+
|
|
383
431
|
def json_to_resource(self, item_json: dict[str, JsonVal]) -> TimeSeriesWrite:
|
|
384
|
-
return self.
|
|
432
|
+
return self._crud.load_resource(item_json)
|
|
385
433
|
|
|
386
434
|
def get_schema(self, selector: AssetCentricSelector) -> list[SchemaColumn]:
|
|
387
435
|
data_set_ids: list[int] = []
|
|
388
436
|
if isinstance(selector, DataSetSelector):
|
|
389
|
-
|
|
437
|
+
data_set_id = self.client.lookup.data_sets.id(selector.data_set_external_id)
|
|
438
|
+
if data_set_id is None:
|
|
439
|
+
raise ToolkitMissingResourceError(
|
|
440
|
+
f"Data set with external ID {selector.data_set_external_id} not found."
|
|
441
|
+
)
|
|
442
|
+
data_set_ids.append(data_set_id)
|
|
390
443
|
elif isinstance(selector, AssetSubtreeSelector):
|
|
391
444
|
raise ToolkitNotImplementedError(f"Selector type {type(selector)} not supported for {type(self).__name__}.")
|
|
392
445
|
|
|
@@ -424,19 +477,25 @@ class EventIO(BaseAssetCentricIO[str, EventWrite, Event, EventWriteList, EventLi
|
|
|
424
477
|
UPLOAD_ENDPOINT = "/events"
|
|
425
478
|
RESOURCE_TYPE = "event"
|
|
426
479
|
|
|
480
|
+
def __init__(self, client: ToolkitClient) -> None:
|
|
481
|
+
super().__init__(client)
|
|
482
|
+
self._crud = EventCRUD.create_loader(self.client)
|
|
483
|
+
|
|
427
484
|
def as_id(self, item: Event) -> str:
|
|
428
485
|
return item.external_id if item.external_id is not None else self._create_identifier(item.id)
|
|
429
486
|
|
|
430
|
-
def _get_loader(self) -> EventCRUD:
|
|
431
|
-
return EventCRUD.create_loader(self.client)
|
|
432
|
-
|
|
433
487
|
def _get_aggregator(self) -> AssetCentricAggregator:
|
|
434
488
|
return EventAggregator(self.client)
|
|
435
489
|
|
|
436
490
|
def get_schema(self, selector: AssetCentricSelector) -> list[SchemaColumn]:
|
|
437
491
|
data_set_ids: list[int] = []
|
|
438
492
|
if isinstance(selector, DataSetSelector):
|
|
439
|
-
|
|
493
|
+
data_set_id = self.client.lookup.data_sets.id(selector.data_set_external_id)
|
|
494
|
+
if data_set_id is None:
|
|
495
|
+
raise ToolkitMissingResourceError(
|
|
496
|
+
f"Data set with external ID {selector.data_set_external_id} not found."
|
|
497
|
+
)
|
|
498
|
+
data_set_ids.append(data_set_id)
|
|
440
499
|
hierarchy: list[int] = []
|
|
441
500
|
if isinstance(selector, AssetSubtreeSelector):
|
|
442
501
|
raise ToolkitNotImplementedError(f"Selector type {type(selector)} not supported for {type(self).__name__}.")
|
|
@@ -476,8 +535,17 @@ class EventIO(BaseAssetCentricIO[str, EventWrite, Event, EventWriteList, EventLi
|
|
|
476
535
|
self._collect_dependencies(event_list, selector)
|
|
477
536
|
yield Page(worker_id="main", items=event_list)
|
|
478
537
|
|
|
538
|
+
def data_to_json_chunk(
|
|
539
|
+
self, data_chunk: Sequence[Event], selector: AssetCentricSelector | None = None
|
|
540
|
+
) -> list[dict[str, JsonVal]]:
|
|
541
|
+
# Ensure data sets/assets are looked up to populate cache.
|
|
542
|
+
self._populate_data_set_cache(data_chunk)
|
|
543
|
+
self._populate_asset_cache(data_chunk)
|
|
544
|
+
|
|
545
|
+
return [self._crud.dump_resource(item) for item in data_chunk]
|
|
546
|
+
|
|
479
547
|
def json_to_resource(self, item_json: dict[str, JsonVal]) -> EventWrite:
|
|
480
|
-
return self.
|
|
548
|
+
return self._crud.load_resource(item_json)
|
|
481
549
|
|
|
482
550
|
def retrieve(self, ids: Sequence[int]) -> EventList:
|
|
483
551
|
return self.client.events.retrieve_multiple(ids)
|
|
@@ -18,6 +18,7 @@ from cognite.client.data_classes.sequences import SequenceProperty
|
|
|
18
18
|
from cognite.client.data_classes.time_series import TimeSeriesProperty
|
|
19
19
|
|
|
20
20
|
from cognite_toolkit._cdf_tk.client import ToolkitClient
|
|
21
|
+
from cognite_toolkit._cdf_tk.exceptions import ToolkitMissingResourceError
|
|
21
22
|
from cognite_toolkit._cdf_tk.utils.cdf import (
|
|
22
23
|
label_aggregate_count,
|
|
23
24
|
label_count,
|
|
@@ -105,6 +106,15 @@ class AssetCentricAggregator(ABC):
|
|
|
105
106
|
seen.add(int_id)
|
|
106
107
|
return ids
|
|
107
108
|
|
|
109
|
+
def _to_dataset_id(self, data_set_external_id: str | list[str] | None) -> list[int] | None:
|
|
110
|
+
"""Converts data set external IDs to data set IDs."""
|
|
111
|
+
dataset_id: list[int] | None = None
|
|
112
|
+
if data_set_external_id is not None:
|
|
113
|
+
if isinstance(data_set_external_id, str):
|
|
114
|
+
data_set_external_id = [data_set_external_id]
|
|
115
|
+
dataset_id = self.client.lookup.data_sets.id(data_set_external_id, allow_empty=False)
|
|
116
|
+
return dataset_id
|
|
117
|
+
|
|
108
118
|
|
|
109
119
|
class MetadataAggregator(AssetCentricAggregator, ABC, Generic[T_CogniteFilter]):
|
|
110
120
|
filter_cls: type[T_CogniteFilter]
|
|
@@ -125,7 +135,9 @@ class MetadataAggregator(AssetCentricAggregator, ABC, Generic[T_CogniteFilter]):
|
|
|
125
135
|
self, hierarchy: str | list[str] | None = None, data_sets: str | list[str] | None = None
|
|
126
136
|
) -> list[tuple[str, int]]:
|
|
127
137
|
"""Returns a list of metadata keys and their counts."""
|
|
128
|
-
hierarchy_ids, data_set_ids = self._lookup_hierarchy_data_set_pair(
|
|
138
|
+
hierarchy_ids, data_set_ids = self._lookup_hierarchy_data_set_pair(
|
|
139
|
+
hierarchy, data_sets, operation="find metadata keys"
|
|
140
|
+
)
|
|
129
141
|
return self._used_metadata_keys(hierarchy=hierarchy_ids, data_sets=data_set_ids)
|
|
130
142
|
|
|
131
143
|
@lru_cache(maxsize=1)
|
|
@@ -140,22 +152,44 @@ class MetadataAggregator(AssetCentricAggregator, ABC, Generic[T_CogniteFilter]):
|
|
|
140
152
|
)
|
|
141
153
|
|
|
142
154
|
def _lookup_hierarchy_data_set_pair(
|
|
143
|
-
self, hierarchy: str | list[str] | None
|
|
155
|
+
self, hierarchy: str | list[str] | None, data_sets: str | list[str] | None, operation: str
|
|
144
156
|
) -> tuple[tuple[int, ...] | None, tuple[int, ...] | None]:
|
|
145
157
|
"""Returns a tuple of hierarchy and data sets."""
|
|
146
158
|
hierarchy_ids: tuple[int, ...] | None = None
|
|
147
159
|
if isinstance(hierarchy, str):
|
|
148
160
|
asset_id = self.client.lookup.assets.id(external_id=hierarchy, allow_empty=False)
|
|
161
|
+
if asset_id is None:
|
|
162
|
+
raise ToolkitMissingResourceError(f"Cannot {operation}. Asset with external ID {hierarchy!r} not found")
|
|
149
163
|
hierarchy_ids = (asset_id,)
|
|
150
164
|
elif isinstance(hierarchy, list) and all(isinstance(item, str) for item in hierarchy):
|
|
151
|
-
|
|
165
|
+
asset_ids = self.client.lookup.assets.id(external_id=hierarchy, allow_empty=False)
|
|
166
|
+
if len(asset_ids) != len(hierarchy):
|
|
167
|
+
missing = set(hierarchy) - set(
|
|
168
|
+
self.client.lookup.assets.external_id([id_ for id_ in asset_ids if id_ is not None])
|
|
169
|
+
)
|
|
170
|
+
raise ToolkitMissingResourceError(
|
|
171
|
+
f"Cannot {operation}. Assets with external IDs {sorted(missing)!r} not found"
|
|
172
|
+
)
|
|
173
|
+
hierarchy_ids = tuple(sorted(asset_ids))
|
|
152
174
|
|
|
153
175
|
data_set_ids: tuple[int, ...] | None = None
|
|
154
176
|
if isinstance(data_sets, str):
|
|
155
177
|
data_set_id = self.client.lookup.data_sets.id(external_id=data_sets, allow_empty=False)
|
|
178
|
+
if data_set_id is None:
|
|
179
|
+
raise ToolkitMissingResourceError(
|
|
180
|
+
f"Cannot {operation}. Data set with external ID {data_sets!r} not found"
|
|
181
|
+
)
|
|
156
182
|
data_set_ids = (data_set_id,)
|
|
157
183
|
elif isinstance(data_sets, list) and all(isinstance(item, str) for item in data_sets):
|
|
158
|
-
|
|
184
|
+
data_set_ids_list = self.client.lookup.data_sets.id(external_id=data_sets, allow_empty=False)
|
|
185
|
+
if len(data_set_ids_list) != len(data_sets):
|
|
186
|
+
missing = set(data_sets) - set(
|
|
187
|
+
self.client.lookup.data_sets.external_id([id_ for id_ in data_set_ids_list if id_ is not None])
|
|
188
|
+
)
|
|
189
|
+
raise ToolkitMissingResourceError(
|
|
190
|
+
f"Cannot {operation}. Data sets with external IDs {sorted(missing)!r} not found"
|
|
191
|
+
)
|
|
192
|
+
data_set_ids = tuple(sorted(data_set_ids_list))
|
|
159
193
|
|
|
160
194
|
return hierarchy_ids, data_set_ids
|
|
161
195
|
|
|
@@ -201,7 +235,9 @@ class LabelAggregator(MetadataAggregator, ABC, Generic[T_CogniteFilter]):
|
|
|
201
235
|
self, hierarchy: str | list[str] | None = None, data_sets: str | list[str] | None = None
|
|
202
236
|
) -> list[tuple[str, int]]:
|
|
203
237
|
"""Returns a list of labels and their counts."""
|
|
204
|
-
hierarchy_ids, data_set_ids = self._lookup_hierarchy_data_set_pair(
|
|
238
|
+
hierarchy_ids, data_set_ids = self._lookup_hierarchy_data_set_pair(
|
|
239
|
+
hierarchy, data_sets, operation="find labels"
|
|
240
|
+
)
|
|
205
241
|
return self._used_labels(hierarchy=hierarchy_ids, data_sets=data_set_ids)
|
|
206
242
|
|
|
207
243
|
@lru_cache(maxsize=1)
|
|
@@ -359,9 +395,10 @@ class RelationshipAggregator(AssetCentricAggregator):
|
|
|
359
395
|
def count(
|
|
360
396
|
self, hierarchy: str | list[str] | None = None, data_set_external_id: str | list[str] | None = None
|
|
361
397
|
) -> int:
|
|
362
|
-
if hierarchy is not None
|
|
398
|
+
if hierarchy is not None:
|
|
363
399
|
raise NotImplementedError()
|
|
364
|
-
|
|
400
|
+
dataset_id = self._to_dataset_id(data_set_external_id)
|
|
401
|
+
results = relationship_aggregate_count(self.client, dataset_id)
|
|
365
402
|
return sum(result.count for result in results)
|
|
366
403
|
|
|
367
404
|
def used_data_sets(self, hierarchy: str | None = None) -> list[str]:
|
|
@@ -378,9 +415,10 @@ class LabelCountAggregator(AssetCentricAggregator):
|
|
|
378
415
|
def count(
|
|
379
416
|
self, hierarchy: str | list[str] | None = None, data_set_external_id: str | list[str] | None = None
|
|
380
417
|
) -> int:
|
|
381
|
-
if hierarchy is not None
|
|
418
|
+
if hierarchy is not None:
|
|
382
419
|
raise NotImplementedError()
|
|
383
|
-
|
|
420
|
+
data_set_id = self._to_dataset_id(data_set_external_id)
|
|
421
|
+
return label_aggregate_count(self.client, data_set_id)
|
|
384
422
|
|
|
385
423
|
def used_data_sets(self, hierarchy: str | None = None) -> list[str]:
|
|
386
424
|
raise NotImplementedError()
|