cognite-toolkit 0.7.39__py3-none-any.whl → 0.7.51__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cognite_toolkit/_cdf_tk/apps/_download_app.py +1 -1
- cognite_toolkit/_cdf_tk/apps/_dump_app.py +1 -1
- cognite_toolkit/_cdf_tk/apps/_migrate_app.py +6 -6
- cognite_toolkit/_cdf_tk/builders/_function.py +81 -9
- cognite_toolkit/_cdf_tk/builders/_raw.py +1 -1
- cognite_toolkit/_cdf_tk/client/_resource_base.py +187 -0
- cognite_toolkit/_cdf_tk/client/_toolkit_client.py +37 -5
- cognite_toolkit/_cdf_tk/client/api/agents.py +107 -0
- cognite_toolkit/_cdf_tk/client/api/annotations.py +129 -0
- cognite_toolkit/_cdf_tk/client/api/assets.py +130 -0
- cognite_toolkit/_cdf_tk/client/api/containers.py +132 -0
- cognite_toolkit/_cdf_tk/client/api/data_models.py +137 -0
- cognite_toolkit/_cdf_tk/client/api/datasets.py +141 -0
- cognite_toolkit/_cdf_tk/client/api/events.py +129 -0
- cognite_toolkit/_cdf_tk/client/api/extraction_pipelines.py +148 -0
- cognite_toolkit/_cdf_tk/client/api/filemetadata.py +176 -0
- cognite_toolkit/_cdf_tk/client/api/function_schedules.py +115 -0
- cognite_toolkit/_cdf_tk/client/api/functions.py +113 -0
- cognite_toolkit/_cdf_tk/client/api/graphql_data_models.py +167 -0
- cognite_toolkit/_cdf_tk/client/api/groups.py +121 -0
- cognite_toolkit/_cdf_tk/client/api/hosted_extractor_destinations.py +131 -0
- cognite_toolkit/_cdf_tk/client/api/hosted_extractor_jobs.py +122 -0
- cognite_toolkit/_cdf_tk/client/api/hosted_extractor_mappings.py +129 -0
- cognite_toolkit/_cdf_tk/client/api/hosted_extractor_sources.py +136 -0
- cognite_toolkit/_cdf_tk/client/api/hosted_extractors.py +23 -0
- cognite_toolkit/_cdf_tk/client/api/infield.py +8 -8
- cognite_toolkit/_cdf_tk/client/api/instances.py +139 -0
- cognite_toolkit/_cdf_tk/client/api/labels.py +125 -0
- cognite_toolkit/_cdf_tk/client/api/legacy/canvas.py +3 -3
- cognite_toolkit/_cdf_tk/client/api/legacy/charts.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/legacy/extended_data_modeling.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/legacy/extended_files.py +2 -2
- cognite_toolkit/_cdf_tk/client/api/legacy/extended_functions.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/legacy/extended_raw.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/legacy/extended_timeseries.py +2 -2
- cognite_toolkit/_cdf_tk/client/api/legacy/location_filters.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/legacy/robotics/capabilities.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/legacy/robotics/data_postprocessing.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/legacy/robotics/frames.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/legacy/robotics/locations.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/legacy/robotics/maps.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/legacy/robotics/robots.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/legacy/search_config.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/location_filters.py +177 -0
- cognite_toolkit/_cdf_tk/client/api/migration.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/project.py +2 -2
- cognite_toolkit/_cdf_tk/client/api/raw.py +204 -0
- cognite_toolkit/_cdf_tk/client/api/relationships.py +133 -0
- cognite_toolkit/_cdf_tk/client/api/robotics.py +19 -0
- cognite_toolkit/_cdf_tk/client/api/robotics_capabilities.py +127 -0
- cognite_toolkit/_cdf_tk/client/api/robotics_data_postprocessing.py +138 -0
- cognite_toolkit/_cdf_tk/client/api/robotics_frames.py +122 -0
- cognite_toolkit/_cdf_tk/client/api/robotics_locations.py +127 -0
- cognite_toolkit/_cdf_tk/client/api/robotics_maps.py +122 -0
- cognite_toolkit/_cdf_tk/client/api/robotics_robots.py +122 -0
- cognite_toolkit/_cdf_tk/client/api/search_config.py +101 -0
- cognite_toolkit/_cdf_tk/client/api/security_categories.py +94 -0
- cognite_toolkit/_cdf_tk/client/api/sequences.py +133 -0
- cognite_toolkit/_cdf_tk/client/api/simulator_models.py +154 -0
- cognite_toolkit/_cdf_tk/client/api/simulators.py +8 -0
- cognite_toolkit/_cdf_tk/client/api/spaces.py +117 -0
- cognite_toolkit/_cdf_tk/client/api/streams.py +65 -57
- cognite_toolkit/_cdf_tk/client/api/three_d.py +300 -283
- cognite_toolkit/_cdf_tk/client/api/timeseries.py +137 -0
- cognite_toolkit/_cdf_tk/client/api/token.py +1 -1
- cognite_toolkit/_cdf_tk/client/api/transformations.py +146 -0
- cognite_toolkit/_cdf_tk/client/api/views.py +139 -0
- cognite_toolkit/_cdf_tk/client/api/workflow_triggers.py +128 -0
- cognite_toolkit/_cdf_tk/client/api/workflow_versions.py +138 -0
- cognite_toolkit/_cdf_tk/client/api/workflows.py +119 -0
- cognite_toolkit/_cdf_tk/client/cdf_client/__init__.py +10 -0
- cognite_toolkit/_cdf_tk/client/cdf_client/api.py +358 -0
- cognite_toolkit/_cdf_tk/client/cdf_client/responses.py +38 -0
- cognite_toolkit/_cdf_tk/{utils → client}/http_client/__init__.py +9 -7
- cognite_toolkit/_cdf_tk/{utils → client}/http_client/_client.py +23 -14
- cognite_toolkit/_cdf_tk/{utils → client}/http_client/_data_classes.py +12 -2
- cognite_toolkit/_cdf_tk/client/http_client/_data_classes2.py +151 -0
- cognite_toolkit/_cdf_tk/client/http_client/_exception.py +13 -0
- cognite_toolkit/_cdf_tk/client/http_client/_item_classes.py +118 -0
- cognite_toolkit/_cdf_tk/client/request_classes/base.py +19 -0
- cognite_toolkit/_cdf_tk/client/request_classes/filters.py +113 -0
- cognite_toolkit/_cdf_tk/client/request_classes/graphql.py +28 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/agent.py +130 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/annotation.py +79 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/apm_config.py +128 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/asset.py +47 -0
- cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/charts_data.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/cognite_file.py +53 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/__init__.py +168 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_constraints.py +37 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_container.py +50 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_data_model.py +73 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_data_types.py +116 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_indexes.py +26 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_instance.py +154 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_references.py +86 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_space.py +26 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_view.py +143 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_view_property.py +152 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/dataset.py +35 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/event.py +40 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/extraction_pipeline.py +59 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/filemetadata.py +52 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/function.py +53 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/function_schedule.py +65 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/graphql_data_model.py +40 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/group/__init__.py +187 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/group/_constants.py +2 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/group/acls.py +653 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/group/capability.py +56 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/group/group.py +63 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/group/scopes.py +166 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_destination.py +34 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_job.py +134 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_mapping.py +72 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_source/__init__.py +63 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_source/_auth.py +63 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_source/_base.py +26 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_source/_certificate.py +20 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_source/_eventhub.py +31 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_source/_kafka.py +53 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_source/_mqtt.py +36 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_source/_rest.py +49 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/identifiers.py +59 -0
- cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/infield.py +1 -1
- cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/instance_api.py +35 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/label.py +27 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/legacy/__init__.py +0 -0
- cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/legacy/canvas.py +48 -15
- cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/legacy/charts.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/location_filter.py +84 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/raw.py +44 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/relationship.py +49 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/resource_view_mapping.py +38 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/robotics/__init__.py +37 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/robotics/_capability.py +53 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/robotics/_common.py +34 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/robotics/_data_post_processing.py +49 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/robotics/_frame.py +46 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/robotics/_location.py +36 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/robotics/_map.py +65 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/robotics/_robot.py +58 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/search_config.py +54 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/securitycategory.py +24 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/sequence.py +45 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/sequence_rows.py +56 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/simulator_model.py +50 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/streamlit_.py +71 -0
- cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/streams.py +9 -26
- cognite_toolkit/_cdf_tk/client/resource_classes/three_d.py +135 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/timeseries.py +52 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/transformation.py +140 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/workflow.py +27 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/workflow_trigger.py +63 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/workflow_version.py +155 -0
- cognite_toolkit/_cdf_tk/client/testing.py +31 -2
- cognite_toolkit/_cdf_tk/commands/_migrate/command.py +103 -108
- cognite_toolkit/_cdf_tk/commands/_migrate/conversion.py +22 -15
- cognite_toolkit/_cdf_tk/commands/_migrate/creators.py +1 -1
- cognite_toolkit/_cdf_tk/commands/_migrate/data_classes.py +11 -10
- cognite_toolkit/_cdf_tk/commands/_migrate/data_mapper.py +148 -57
- cognite_toolkit/_cdf_tk/commands/_migrate/default_mappings.py +1 -1
- cognite_toolkit/_cdf_tk/commands/_migrate/issues.py +22 -39
- cognite_toolkit/_cdf_tk/commands/_migrate/migration_io.py +29 -27
- cognite_toolkit/_cdf_tk/commands/_profile.py +1 -1
- cognite_toolkit/_cdf_tk/commands/_purge.py +8 -8
- cognite_toolkit/_cdf_tk/commands/_upload.py +1 -1
- cognite_toolkit/_cdf_tk/commands/build_cmd.py +12 -2
- cognite_toolkit/_cdf_tk/commands/build_v2/_module_parser.py +138 -0
- cognite_toolkit/_cdf_tk/commands/build_v2/_modules_parser.py +163 -0
- cognite_toolkit/_cdf_tk/commands/build_v2/build_cmd.py +83 -96
- cognite_toolkit/_cdf_tk/commands/build_v2/{build_input.py → build_parameters.py} +8 -22
- cognite_toolkit/_cdf_tk/commands/build_v2/data_classes/_modules.py +27 -0
- cognite_toolkit/_cdf_tk/commands/build_v2/data_classes/_resource.py +22 -0
- cognite_toolkit/_cdf_tk/commands/dump_resource.py +4 -4
- cognite_toolkit/_cdf_tk/commands/pull.py +97 -2
- cognite_toolkit/_cdf_tk/commands/run.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/__init__.py +16 -6
- cognite_toolkit/_cdf_tk/cruds/_data_cruds.py +9 -5
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/__init__.py +2 -0
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/auth.py +6 -2
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/classic.py +70 -89
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/configuration.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/datamodel.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/extraction_pipeline.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/fieldops.py +14 -7
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/file.py +50 -59
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/function.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/industrial_tool.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/location.py +4 -3
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/migration.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/raw.py +6 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/relationship.py +5 -4
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/robotics.py +1 -1
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/simulators.py +122 -0
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/streams.py +15 -31
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/timeseries.py +42 -47
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/transformation.py +1 -1
- cognite_toolkit/_cdf_tk/data_classes/__init__.py +3 -0
- cognite_toolkit/_cdf_tk/data_classes/_issues.py +36 -0
- cognite_toolkit/_cdf_tk/data_classes/_module_directories.py +2 -1
- cognite_toolkit/_cdf_tk/data_classes/_tracking_info.py +4 -0
- cognite_toolkit/_cdf_tk/feature_flags.py +8 -0
- cognite_toolkit/_cdf_tk/resource_classes/__init__.py +2 -0
- cognite_toolkit/_cdf_tk/resource_classes/capabilities.py +6 -0
- cognite_toolkit/_cdf_tk/resource_classes/search_config.py +1 -1
- cognite_toolkit/_cdf_tk/resource_classes/simulator_model.py +17 -0
- cognite_toolkit/_cdf_tk/resource_classes/workflow_version.py +13 -4
- cognite_toolkit/_cdf_tk/storageio/_applications.py +53 -15
- cognite_toolkit/_cdf_tk/storageio/_asset_centric.py +117 -107
- cognite_toolkit/_cdf_tk/storageio/_base.py +3 -1
- cognite_toolkit/_cdf_tk/storageio/_datapoints.py +7 -7
- cognite_toolkit/_cdf_tk/storageio/_file_content.py +64 -54
- cognite_toolkit/_cdf_tk/storageio/_instances.py +1 -1
- cognite_toolkit/_cdf_tk/storageio/_raw.py +1 -1
- cognite_toolkit/_cdf_tk/storageio/logger.py +162 -0
- cognite_toolkit/_cdf_tk/tk_warnings/__init__.py +2 -0
- cognite_toolkit/_cdf_tk/tk_warnings/fileread.py +20 -0
- cognite_toolkit/_cdf_tk/utils/__init__.py +11 -1
- cognite_toolkit/_cdf_tk/utils/cdf.py +1 -1
- cognite_toolkit/_cdf_tk/utils/interactive_select.py +8 -6
- cognite_toolkit/_cdf_tk/utils/modules.py +7 -0
- cognite_toolkit/_cdf_tk/utils/pip_validator.py +96 -0
- cognite_toolkit/_cdf_tk/utils/useful_types.py +4 -7
- cognite_toolkit/_cdf_tk/utils/useful_types2.py +14 -0
- 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.39.dist-info → cognite_toolkit-0.7.51.dist-info}/METADATA +13 -3
- cognite_toolkit-0.7.51.dist-info/RECORD +445 -0
- {cognite_toolkit-0.7.39.dist-info → cognite_toolkit-0.7.51.dist-info}/WHEEL +2 -2
- cognite_toolkit/_cdf_tk/client/data_classes/api_classes.py +0 -30
- cognite_toolkit/_cdf_tk/client/data_classes/base.py +0 -67
- cognite_toolkit/_cdf_tk/client/data_classes/three_d.py +0 -112
- cognite_toolkit/_cdf_tk/commands/build_v2/build_issues.py +0 -27
- cognite_toolkit/_cdf_tk/utils/http_client/_data_classes2.py +0 -247
- cognite_toolkit/_cdf_tk/utils/http_client/_exception.py +0 -4
- cognite_toolkit-0.7.39.dist-info/RECORD +0 -322
- /cognite_toolkit/_cdf_tk/{utils → client}/http_client/_tracker.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes → request_classes}/__init__.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes/legacy → resource_classes}/__init__.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/capabilities.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/legacy/apm_config_v1.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/legacy/extendable_cognite_file.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/legacy/extended_filemetadata.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/legacy/extended_filemetdata.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/legacy/extended_timeseries.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/legacy/functions.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/legacy/graphql_data_models.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/legacy/instances.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/legacy/location_filters.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/legacy/migration.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/legacy/pending_instances_ids.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/legacy/project.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/legacy/raw.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/legacy/robotics.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/legacy/search_config.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/legacy/sequences.py +0 -0
- /cognite_toolkit/_cdf_tk/client/{data_classes → resource_classes}/legacy/streamlit_.py +0 -0
- {cognite_toolkit-0.7.39.dist-info → cognite_toolkit-0.7.51.dist-info}/entry_points.txt +0 -0
|
@@ -6,26 +6,28 @@ from pathlib import Path
|
|
|
6
6
|
from typing import cast
|
|
7
7
|
|
|
8
8
|
import httpx
|
|
9
|
-
from cognite.client.data_classes import
|
|
10
|
-
from cognite.client.data_classes.data_modeling import NodeId, ViewId
|
|
9
|
+
from cognite.client.data_classes.data_modeling import ViewId
|
|
11
10
|
|
|
12
11
|
from cognite_toolkit._cdf_tk.client import ToolkitClient
|
|
13
|
-
from cognite_toolkit._cdf_tk.
|
|
14
|
-
from cognite_toolkit._cdf_tk.exceptions import ToolkitNotImplementedError
|
|
15
|
-
from cognite_toolkit._cdf_tk.protocols import ResourceResponseProtocol
|
|
16
|
-
from cognite_toolkit._cdf_tk.utils import sanitize_filename
|
|
17
|
-
from cognite_toolkit._cdf_tk.utils.collection import chunker, chunker_sequence
|
|
18
|
-
from cognite_toolkit._cdf_tk.utils.fileio import MultiFileReader
|
|
19
|
-
from cognite_toolkit._cdf_tk.utils.http_client import (
|
|
20
|
-
DataBodyRequest,
|
|
12
|
+
from cognite_toolkit._cdf_tk.client.http_client import (
|
|
21
13
|
ErrorDetails,
|
|
22
|
-
|
|
14
|
+
FailedResponse2,
|
|
23
15
|
FailedResponseItems,
|
|
24
16
|
HTTPClient,
|
|
25
17
|
HTTPMessage,
|
|
26
|
-
|
|
18
|
+
HTTPResult2,
|
|
19
|
+
RequestMessage2,
|
|
27
20
|
SimpleBodyRequest,
|
|
21
|
+
SuccessResponse2,
|
|
28
22
|
)
|
|
23
|
+
from cognite_toolkit._cdf_tk.client.resource_classes.data_modeling import NodeReference
|
|
24
|
+
from cognite_toolkit._cdf_tk.client.resource_classes.filemetadata import FileMetadataRequest, FileMetadataResponse
|
|
25
|
+
from cognite_toolkit._cdf_tk.cruds import FileMetadataCRUD
|
|
26
|
+
from cognite_toolkit._cdf_tk.exceptions import ToolkitNotImplementedError
|
|
27
|
+
from cognite_toolkit._cdf_tk.protocols import ResourceResponseProtocol
|
|
28
|
+
from cognite_toolkit._cdf_tk.utils import sanitize_filename
|
|
29
|
+
from cognite_toolkit._cdf_tk.utils.collection import chunker, chunker_sequence
|
|
30
|
+
from cognite_toolkit._cdf_tk.utils.fileio import MultiFileReader
|
|
29
31
|
from cognite_toolkit._cdf_tk.utils.useful_types import JsonVal
|
|
30
32
|
|
|
31
33
|
from ._base import Page, UploadableStorageIO, UploadItem
|
|
@@ -45,21 +47,24 @@ COGNITE_FILE_VIEW = ViewId("cdf_cdm", "CogniteFile", "v1")
|
|
|
45
47
|
|
|
46
48
|
|
|
47
49
|
@dataclass
|
|
48
|
-
class UploadFileContentItem(UploadItem[
|
|
50
|
+
class UploadFileContentItem(UploadItem[FileMetadataRequest]):
|
|
49
51
|
file_path: Path
|
|
50
52
|
mime_type: str
|
|
51
53
|
|
|
54
|
+
def dump(self) -> JsonVal:
|
|
55
|
+
return self.item.dump(camel_case=True, exclude_extra=True)
|
|
56
|
+
|
|
52
57
|
|
|
53
58
|
@dataclass
|
|
54
59
|
class MetadataWithFilePath(ResourceResponseProtocol):
|
|
55
|
-
metadata:
|
|
60
|
+
metadata: FileMetadataResponse
|
|
56
61
|
file_path: Path
|
|
57
62
|
|
|
58
|
-
def as_write(self) ->
|
|
59
|
-
return self.metadata.
|
|
63
|
+
def as_write(self) -> FileMetadataRequest:
|
|
64
|
+
return self.metadata.as_request_resource()
|
|
60
65
|
|
|
61
66
|
|
|
62
|
-
class FileContentIO(UploadableStorageIO[FileContentSelector, MetadataWithFilePath,
|
|
67
|
+
class FileContentIO(UploadableStorageIO[FileContentSelector, MetadataWithFilePath, FileMetadataRequest]):
|
|
63
68
|
SUPPORTED_DOWNLOAD_FORMATS = frozenset({".ndjson"})
|
|
64
69
|
SUPPORTED_COMPRESSIONS = frozenset({".gz"})
|
|
65
70
|
CHUNK_SIZE = 10
|
|
@@ -116,7 +121,7 @@ class FileContentIO(UploadableStorageIO[FileContentSelector, MetadataWithFilePat
|
|
|
116
121
|
)
|
|
117
122
|
yield Page(items=downloaded_files, worker_id="Main")
|
|
118
123
|
|
|
119
|
-
def _retrieve_metadata(self, identifiers: Sequence[FileIdentifier]) -> Sequence[
|
|
124
|
+
def _retrieve_metadata(self, identifiers: Sequence[FileIdentifier]) -> Sequence[FileMetadataResponse] | None:
|
|
120
125
|
config = self.client.config
|
|
121
126
|
responses = self.client.http_client.request_with_retries(
|
|
122
127
|
message=SimpleBodyRequest(
|
|
@@ -137,12 +142,11 @@ class FileContentIO(UploadableStorageIO[FileContentSelector, MetadataWithFilePat
|
|
|
137
142
|
items_data = body.get("items", [])
|
|
138
143
|
if not isinstance(items_data, list):
|
|
139
144
|
return None
|
|
140
|
-
|
|
141
|
-
return [FileMetadata._load(item) for item in items_data] # type: ignore[arg-type]
|
|
145
|
+
return [FileMetadataResponse.model_validate(item) for item in items_data]
|
|
142
146
|
|
|
143
147
|
@staticmethod
|
|
144
|
-
def _as_metadata_map(metadata: Sequence[
|
|
145
|
-
identifiers_map: dict[FileIdentifier,
|
|
148
|
+
def _as_metadata_map(metadata: Sequence[FileMetadataResponse]) -> dict[FileIdentifier, FileMetadataResponse]:
|
|
149
|
+
identifiers_map: dict[FileIdentifier, FileMetadataResponse] = {}
|
|
146
150
|
for item in metadata:
|
|
147
151
|
if item.id is not None:
|
|
148
152
|
identifiers_map[FileInternalID(internal_id=item.id)] = item
|
|
@@ -158,9 +162,9 @@ class FileContentIO(UploadableStorageIO[FileContentSelector, MetadataWithFilePat
|
|
|
158
162
|
] = item
|
|
159
163
|
return identifiers_map
|
|
160
164
|
|
|
161
|
-
def _create_filepath(self, meta:
|
|
165
|
+
def _create_filepath(self, meta: FileMetadataResponse, selector: FileIdentifierSelector) -> Path:
|
|
162
166
|
# We now that metadata always have name set
|
|
163
|
-
filename = Path(sanitize_filename(
|
|
167
|
+
filename = Path(sanitize_filename(meta.name))
|
|
164
168
|
if len(filename.suffix) == 0 and meta.mime_type:
|
|
165
169
|
if mime_ext := mimetypes.guess_extension(meta.mime_type):
|
|
166
170
|
filename = filename.with_suffix(mime_ext)
|
|
@@ -245,12 +249,12 @@ class FileContentIO(UploadableStorageIO[FileContentSelector, MetadataWithFilePat
|
|
|
245
249
|
)
|
|
246
250
|
return result
|
|
247
251
|
|
|
248
|
-
def json_to_resource(self, item_json: dict[str, JsonVal]) ->
|
|
252
|
+
def json_to_resource(self, item_json: dict[str, JsonVal]) -> FileMetadataRequest:
|
|
249
253
|
return self._crud.load_resource(item_json)
|
|
250
254
|
|
|
251
255
|
def upload_items(
|
|
252
256
|
self,
|
|
253
|
-
data_chunk: Sequence[UploadItem[
|
|
257
|
+
data_chunk: Sequence[UploadItem[FileMetadataRequest]],
|
|
254
258
|
http_client: HTTPClient,
|
|
255
259
|
selector: FileContentSelector | None = None,
|
|
256
260
|
) -> Sequence[HTTPMessage]:
|
|
@@ -271,8 +275,8 @@ class FileContentIO(UploadableStorageIO[FileContentSelector, MetadataWithFilePat
|
|
|
271
275
|
continue
|
|
272
276
|
|
|
273
277
|
content_bytes = item.file_path.read_bytes()
|
|
274
|
-
upload_response = http_client.
|
|
275
|
-
|
|
278
|
+
upload_response = http_client.request_single_retries(
|
|
279
|
+
RequestMessage2(
|
|
276
280
|
endpoint_url=upload_url,
|
|
277
281
|
method="PUT",
|
|
278
282
|
content_type=item.mime_type,
|
|
@@ -280,21 +284,21 @@ class FileContentIO(UploadableStorageIO[FileContentSelector, MetadataWithFilePat
|
|
|
280
284
|
content_length=len(content_bytes),
|
|
281
285
|
)
|
|
282
286
|
)
|
|
283
|
-
results.
|
|
287
|
+
results.append(upload_response.as_item_response(item.as_id()))
|
|
284
288
|
return results
|
|
285
289
|
|
|
286
290
|
def _upload_url_asset_centric(
|
|
287
291
|
self, item: UploadFileContentItem, http_client: HTTPClient, results: MutableSequence[HTTPMessage]
|
|
288
292
|
) -> str | None:
|
|
289
|
-
|
|
290
|
-
message=
|
|
293
|
+
response = http_client.request_single_retries(
|
|
294
|
+
message=RequestMessage2(
|
|
291
295
|
endpoint_url=http_client.config.create_api_url(self.UPLOAD_ENDPOINT),
|
|
292
296
|
method="POST",
|
|
293
297
|
# MyPy does not understand that .dump is valid json
|
|
294
298
|
body_content=item.dump(), # type: ignore[arg-type]
|
|
295
299
|
)
|
|
296
300
|
)
|
|
297
|
-
return self._parse_upload_link_response(
|
|
301
|
+
return self._parse_upload_link_response(response, item, results)
|
|
298
302
|
|
|
299
303
|
def _upload_url_data_modeling(
|
|
300
304
|
self,
|
|
@@ -320,30 +324,28 @@ class FileContentIO(UploadableStorageIO[FileContentSelector, MetadataWithFilePat
|
|
|
320
324
|
|
|
321
325
|
"""
|
|
322
326
|
# We know that instance_id is always set for data modeling uploads
|
|
323
|
-
instance_id = cast(
|
|
324
|
-
|
|
325
|
-
message=
|
|
327
|
+
instance_id = cast(NodeReference, item.item.instance_id)
|
|
328
|
+
response = http_client.request_single_retries(
|
|
329
|
+
message=RequestMessage2(
|
|
326
330
|
endpoint_url=http_client.config.create_api_url("/files/uploadlink"),
|
|
327
331
|
method="POST",
|
|
328
|
-
body_content={"items": [{"instanceId": instance_id.dump(
|
|
332
|
+
body_content={"items": [{"instanceId": instance_id.dump()}]},
|
|
329
333
|
)
|
|
330
334
|
)
|
|
331
|
-
|
|
332
|
-
response = responses[0]
|
|
333
|
-
if isinstance(response, FailedResponse) and response.error.missing and not created_node:
|
|
335
|
+
if isinstance(response, FailedResponse2) and response.error.missing and not created_node:
|
|
334
336
|
if self._create_cognite_file_node(instance_id, http_client, item.as_id(), results):
|
|
335
337
|
return self._upload_url_data_modeling(item, http_client, results, created_node=True)
|
|
336
338
|
else:
|
|
337
339
|
return None
|
|
338
340
|
|
|
339
|
-
return self._parse_upload_link_response(
|
|
341
|
+
return self._parse_upload_link_response(response, item, results)
|
|
340
342
|
|
|
341
343
|
@classmethod
|
|
342
344
|
def _create_cognite_file_node(
|
|
343
|
-
cls, instance_id:
|
|
345
|
+
cls, instance_id: NodeReference, http_client: HTTPClient, upload_id: str, results: MutableSequence[HTTPMessage]
|
|
344
346
|
) -> bool:
|
|
345
|
-
node_creation = http_client.
|
|
346
|
-
message=
|
|
347
|
+
node_creation = http_client.request_single_retries(
|
|
348
|
+
message=RequestMessage2(
|
|
347
349
|
endpoint_url=http_client.config.create_api_url("/models/instances"),
|
|
348
350
|
method="POST",
|
|
349
351
|
body_content={
|
|
@@ -363,25 +365,33 @@ class FileContentIO(UploadableStorageIO[FileContentSelector, MetadataWithFilePat
|
|
|
363
365
|
},
|
|
364
366
|
)
|
|
365
367
|
)
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
return True
|
|
368
|
+
if isinstance(node_creation, SuccessResponse2):
|
|
369
|
+
# Node created successfully
|
|
370
|
+
return True
|
|
371
|
+
results.append(node_creation.as_item_response(instance_id))
|
|
372
|
+
return False
|
|
372
373
|
|
|
373
374
|
@classmethod
|
|
374
375
|
def _parse_upload_link_response(
|
|
375
|
-
cls,
|
|
376
|
+
cls, response: HTTPResult2, item: UploadFileContentItem, results: MutableSequence[HTTPMessage]
|
|
376
377
|
) -> str | None:
|
|
378
|
+
if not isinstance(response, SuccessResponse2):
|
|
379
|
+
results.append(response.as_item_response(item.as_id()))
|
|
380
|
+
return None
|
|
377
381
|
try:
|
|
378
|
-
body =
|
|
382
|
+
body = response.body_json
|
|
379
383
|
except ValueError:
|
|
380
|
-
results.
|
|
384
|
+
results.append(
|
|
385
|
+
FailedResponseItems(
|
|
386
|
+
status_code=response.status_code,
|
|
387
|
+
body=response.body,
|
|
388
|
+
error=ErrorDetails(code=response.status_code, message="Invalid JSON response"),
|
|
389
|
+
ids=[item.as_id()],
|
|
390
|
+
)
|
|
391
|
+
)
|
|
381
392
|
return None
|
|
382
|
-
|
|
383
393
|
if "items" in body and isinstance(body["items"], list) and len(body["items"]) > 0:
|
|
384
|
-
body = body["items"][0]
|
|
394
|
+
body = body["items"][0]
|
|
385
395
|
try:
|
|
386
396
|
upload_url = cast(str, body["uploadUrl"])
|
|
387
397
|
except (KeyError, IndexError):
|
|
@@ -17,7 +17,7 @@ from cognite.client.utils._identifier import InstanceId
|
|
|
17
17
|
|
|
18
18
|
from cognite_toolkit._cdf_tk import constants
|
|
19
19
|
from cognite_toolkit._cdf_tk.client import ToolkitClient
|
|
20
|
-
from cognite_toolkit._cdf_tk.client.
|
|
20
|
+
from cognite_toolkit._cdf_tk.client.resource_classes.legacy.instances import InstanceList
|
|
21
21
|
from cognite_toolkit._cdf_tk.cruds import ContainerCRUD, SpaceCRUD, ViewCRUD
|
|
22
22
|
from cognite_toolkit._cdf_tk.utils import sanitize_filename
|
|
23
23
|
from cognite_toolkit._cdf_tk.utils.cdf import iterate_instances
|
|
@@ -4,12 +4,12 @@ from uuid import uuid4
|
|
|
4
4
|
|
|
5
5
|
from cognite.client.data_classes import Row, RowWrite
|
|
6
6
|
|
|
7
|
+
from cognite_toolkit._cdf_tk.client.http_client import HTTPClient, HTTPMessage, ItemsRequest
|
|
7
8
|
from cognite_toolkit._cdf_tk.cruds import RawDatabaseCRUD, RawTableCRUD
|
|
8
9
|
from cognite_toolkit._cdf_tk.exceptions import ToolkitValueError
|
|
9
10
|
from cognite_toolkit._cdf_tk.utils import sanitize_filename
|
|
10
11
|
from cognite_toolkit._cdf_tk.utils.collection import chunker
|
|
11
12
|
from cognite_toolkit._cdf_tk.utils.fileio import MultiFileReader
|
|
12
|
-
from cognite_toolkit._cdf_tk.utils.http_client import HTTPClient, HTTPMessage, ItemsRequest
|
|
13
13
|
from cognite_toolkit._cdf_tk.utils.useful_types import JsonVal
|
|
14
14
|
|
|
15
15
|
from ._base import (
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
from threading import Lock
|
|
5
|
+
from typing import Literal, TypeAlias
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
from pydantic.alias_generators import to_camel
|
|
9
|
+
|
|
10
|
+
from cognite_toolkit._cdf_tk.utils.fileio import NDJsonWriter
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class LogEntry(BaseModel, alias_generator=to_camel, extra="ignore", populate_by_name=True):
|
|
14
|
+
"""Represents a log entry for tracking storage I/O operations."""
|
|
15
|
+
|
|
16
|
+
id: str
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
OperationStatus: TypeAlias = Literal["success", "failure", "unchanged", "pending"]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ItemTracker:
|
|
23
|
+
"""Tracks issues accumulated for a single item during pipeline processing."""
|
|
24
|
+
|
|
25
|
+
def __init__(self, item_id: str) -> None:
|
|
26
|
+
self.item_id = item_id
|
|
27
|
+
self.issues: list[str] = []
|
|
28
|
+
|
|
29
|
+
def add_issue(self, issue: str) -> None:
|
|
30
|
+
"""Add an issue encountered during processing."""
|
|
31
|
+
self.issues.append(issue)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class OperationTracker(ABC):
|
|
35
|
+
"""Abstract base class for operation trackers."""
|
|
36
|
+
|
|
37
|
+
@abstractmethod
|
|
38
|
+
def add_issue(self, item_id: str, issue: str) -> None:
|
|
39
|
+
"""Add an issue to an item."""
|
|
40
|
+
raise NotImplementedError()
|
|
41
|
+
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def finalize_item(self, item_id: str | list[str], status: OperationStatus) -> None:
|
|
44
|
+
"""Finalize an item with its final status."""
|
|
45
|
+
raise NotImplementedError()
|
|
46
|
+
|
|
47
|
+
@abstractmethod
|
|
48
|
+
def get_status_counts(self) -> dict[OperationStatus, int]:
|
|
49
|
+
"""Get counts per final status."""
|
|
50
|
+
raise NotImplementedError()
|
|
51
|
+
|
|
52
|
+
@abstractmethod
|
|
53
|
+
def get_issue_counts(self, status: OperationStatus) -> dict[str, int]:
|
|
54
|
+
"""Get issue counts, optionally filtered by status."""
|
|
55
|
+
raise NotImplementedError()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class NoOpTracker(OperationTracker):
|
|
59
|
+
"""A no-op tracker that does nothing."""
|
|
60
|
+
|
|
61
|
+
def add_issue(self, item_id: str, issue: str) -> None:
|
|
62
|
+
"""No-op: Discard the issue."""
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
def finalize_item(self, item_id: str | list[str], status: OperationStatus) -> None:
|
|
66
|
+
"""No-op: Do nothing."""
|
|
67
|
+
pass
|
|
68
|
+
|
|
69
|
+
def get_status_counts(self) -> dict[OperationStatus, int]:
|
|
70
|
+
"""Return empty status counts."""
|
|
71
|
+
return {}
|
|
72
|
+
|
|
73
|
+
def get_issue_counts(self, status: OperationStatus) -> dict[str, int]:
|
|
74
|
+
"""Return empty issue counts."""
|
|
75
|
+
return {}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class MemoryOperationTracker(OperationTracker):
|
|
79
|
+
"""Tracks the overall operation progress and issues across multiple items.
|
|
80
|
+
|
|
81
|
+
Tracks counts of final statuses and issues per status.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
def __init__(self) -> None:
|
|
85
|
+
self._lock = Lock()
|
|
86
|
+
self._active_items: dict[str, ItemTracker] = {}
|
|
87
|
+
self._status_counts: dict[OperationStatus, int] = defaultdict(int)
|
|
88
|
+
self._issue_counts: dict[OperationStatus, dict[str, int]] = defaultdict(lambda: defaultdict(int))
|
|
89
|
+
|
|
90
|
+
def add_issue(self, item_id: str, issue: str) -> None:
|
|
91
|
+
"""Add an issue to an item, creating tracker if needed."""
|
|
92
|
+
with self._lock:
|
|
93
|
+
if item_id not in self._active_items:
|
|
94
|
+
self._active_items[item_id] = ItemTracker(item_id)
|
|
95
|
+
self._active_items[item_id].add_issue(issue)
|
|
96
|
+
|
|
97
|
+
def finalize_item(self, item_id: str | list[str], status: OperationStatus) -> None:
|
|
98
|
+
"""Finalize an item with its final status.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
item_id: The item's identifier.
|
|
102
|
+
status: Final status (success, failure, unchanged).
|
|
103
|
+
"""
|
|
104
|
+
with self._lock:
|
|
105
|
+
if isinstance(item_id, list):
|
|
106
|
+
for iid in item_id:
|
|
107
|
+
self._finalize_item_unlocked(iid, status)
|
|
108
|
+
else:
|
|
109
|
+
self._finalize_item_unlocked(item_id, status)
|
|
110
|
+
|
|
111
|
+
def _finalize_item_unlocked(self, item_id: str, status: OperationStatus) -> None:
|
|
112
|
+
"""Internal method to finalize an item without acquiring the lock."""
|
|
113
|
+
tracker = self._active_items.pop(item_id, None)
|
|
114
|
+
self._status_counts[status] += 1
|
|
115
|
+
if tracker is not None:
|
|
116
|
+
for issue in tracker.issues:
|
|
117
|
+
self._issue_counts[status][issue] += 1
|
|
118
|
+
|
|
119
|
+
def get_status_counts(self) -> dict[OperationStatus, int]:
|
|
120
|
+
"""Get counts per final status."""
|
|
121
|
+
with self._lock:
|
|
122
|
+
return dict(self._status_counts)
|
|
123
|
+
|
|
124
|
+
def get_issue_counts(self, status: OperationStatus) -> dict[str, int]:
|
|
125
|
+
"""Get issue counts, optionally filtered by status."""
|
|
126
|
+
with self._lock:
|
|
127
|
+
return dict(self._issue_counts.get(status, {}))
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class DataLogger(ABC):
|
|
131
|
+
"""Abstract base class for data loggers that track operations and log entries."""
|
|
132
|
+
|
|
133
|
+
tracker: OperationTracker
|
|
134
|
+
|
|
135
|
+
@abstractmethod
|
|
136
|
+
def log(self, entry: LogEntry | Sequence[LogEntry]) -> None:
|
|
137
|
+
"""Log a detailed entry."""
|
|
138
|
+
raise NotImplementedError()
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class NoOpLogger(DataLogger):
|
|
142
|
+
"""A no-op logger that discards all log entries and does no tracking."""
|
|
143
|
+
|
|
144
|
+
def __init__(self) -> None:
|
|
145
|
+
self.tracker = NoOpTracker()
|
|
146
|
+
|
|
147
|
+
def log(self, entry: LogEntry | Sequence[LogEntry]) -> None:
|
|
148
|
+
"""Discard the log entry (no-op)."""
|
|
149
|
+
pass
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class FileDataLogger(DataLogger):
|
|
153
|
+
"""Composes aggregation tracking with detailed file logging."""
|
|
154
|
+
|
|
155
|
+
def __init__(self, writer: NDJsonWriter) -> None:
|
|
156
|
+
self.tracker = MemoryOperationTracker()
|
|
157
|
+
self._writer = writer
|
|
158
|
+
|
|
159
|
+
def log(self, entry: LogEntry | Sequence[LogEntry]) -> None:
|
|
160
|
+
"""Log a detailed entry to the file."""
|
|
161
|
+
entries = entry if isinstance(entry, Sequence) else [entry]
|
|
162
|
+
self._writer.write_chunks([e.model_dump(by_alias=True) for e in entries])
|
|
@@ -12,6 +12,7 @@ from .fileread import (
|
|
|
12
12
|
EnvironmentVariableMissingWarning,
|
|
13
13
|
FileExistsWarning,
|
|
14
14
|
FileReadWarning,
|
|
15
|
+
FunctionRequirementsValidationWarning,
|
|
15
16
|
MissingFileWarning,
|
|
16
17
|
MissingReferencedWarning,
|
|
17
18
|
MissingRequiredParameterWarning,
|
|
@@ -51,6 +52,7 @@ __all__ = [
|
|
|
51
52
|
"EnvironmentVariableMissingWarning",
|
|
52
53
|
"FileExistsWarning",
|
|
53
54
|
"FileReadWarning",
|
|
55
|
+
"FunctionRequirementsValidationWarning",
|
|
54
56
|
"GeneralWarning",
|
|
55
57
|
"HTTPWarning",
|
|
56
58
|
"HighSeverityWarning",
|
|
@@ -270,6 +270,26 @@ class StreamlitRequirementsWarning(FileReadWarning):
|
|
|
270
270
|
return f"Missing dependencies in requirements.txt: {', '.join(self.dependencies)}"
|
|
271
271
|
|
|
272
272
|
|
|
273
|
+
@dataclass(frozen=True)
|
|
274
|
+
class FunctionRequirementsValidationWarning(FileReadWarning):
|
|
275
|
+
severity: ClassVar[SeverityLevel] = SeverityLevel.HIGH
|
|
276
|
+
function_external_id: str
|
|
277
|
+
error_details: str
|
|
278
|
+
is_credential_error: bool
|
|
279
|
+
|
|
280
|
+
def get_message(self) -> str:
|
|
281
|
+
message = (
|
|
282
|
+
f"Function [bold]{self.function_external_id}[/bold] requirements.txt validation failed. "
|
|
283
|
+
f"Packages could not be resolved: {self.error_details}"
|
|
284
|
+
)
|
|
285
|
+
if self.is_credential_error:
|
|
286
|
+
message += (
|
|
287
|
+
f"\n{HINT_LEAD_TEXT}This appears to be a credential/authentication issue. "
|
|
288
|
+
"Check if the Personal Access Token (PAT) or credentials in indexUrl are valid and not expired."
|
|
289
|
+
)
|
|
290
|
+
return message
|
|
291
|
+
|
|
292
|
+
|
|
273
293
|
@dataclass(frozen=True)
|
|
274
294
|
class ResourceFormatWarning(FileReadWarning):
|
|
275
295
|
severity: ClassVar[SeverityLevel] = SeverityLevel.HIGH
|
|
@@ -19,11 +19,19 @@ from .hashing import (
|
|
|
19
19
|
calculate_hash,
|
|
20
20
|
calculate_secure_hash,
|
|
21
21
|
)
|
|
22
|
-
from .modules import
|
|
22
|
+
from .modules import (
|
|
23
|
+
find_directory_with_subdirectories,
|
|
24
|
+
iterate_modules,
|
|
25
|
+
module_from_path,
|
|
26
|
+
module_path_display_name,
|
|
27
|
+
resource_folder_from_path,
|
|
28
|
+
)
|
|
29
|
+
from .pip_validator import PipValidationResult, validate_requirements_with_pip
|
|
23
30
|
from .sentry_utils import sentry_exception_filter
|
|
24
31
|
|
|
25
32
|
__all__ = [
|
|
26
33
|
"GraphQLParser",
|
|
34
|
+
"PipValidationResult",
|
|
27
35
|
"YAMLComment",
|
|
28
36
|
"YAMLWithComments",
|
|
29
37
|
"calculate_directory_hash",
|
|
@@ -37,6 +45,7 @@ __all__ = [
|
|
|
37
45
|
"iterate_modules",
|
|
38
46
|
"load_yaml_inject_variables",
|
|
39
47
|
"module_from_path",
|
|
48
|
+
"module_path_display_name",
|
|
40
49
|
"quote_int_value_by_key_in_yaml",
|
|
41
50
|
"read_yaml_content",
|
|
42
51
|
"read_yaml_file",
|
|
@@ -50,4 +59,5 @@ __all__ = [
|
|
|
50
59
|
"stringify_value_by_key_in_yaml",
|
|
51
60
|
"tmp_build_directory",
|
|
52
61
|
"to_diff",
|
|
62
|
+
"validate_requirements_with_pip",
|
|
53
63
|
]
|
|
@@ -21,7 +21,7 @@ from filelock import BaseFileLock, FileLock, Timeout
|
|
|
21
21
|
from rich.console import Console
|
|
22
22
|
|
|
23
23
|
from cognite_toolkit._cdf_tk.client import ToolkitClient, ToolkitClientConfig
|
|
24
|
-
from cognite_toolkit._cdf_tk.client.
|
|
24
|
+
from cognite_toolkit._cdf_tk.client.resource_classes.legacy.raw import RawTable
|
|
25
25
|
from cognite_toolkit._cdf_tk.constants import ENV_VAR_PATTERN, MAX_ROW_ITERATION_RUN_QUERY, MAX_RUN_QUERY_FREQUENCY_MIN
|
|
26
26
|
from cognite_toolkit._cdf_tk.exceptions import (
|
|
27
27
|
ToolkitError,
|
|
@@ -21,11 +21,11 @@ from questionary import Choice
|
|
|
21
21
|
from rich.console import Console
|
|
22
22
|
|
|
23
23
|
from cognite_toolkit._cdf_tk.client import ToolkitClient
|
|
24
|
-
from cognite_toolkit._cdf_tk.client.
|
|
25
|
-
from cognite_toolkit._cdf_tk.client.
|
|
26
|
-
from cognite_toolkit._cdf_tk.client.
|
|
27
|
-
from cognite_toolkit._cdf_tk.client.
|
|
28
|
-
from cognite_toolkit._cdf_tk.client.
|
|
24
|
+
from cognite_toolkit._cdf_tk.client.resource_classes.legacy.canvas import Canvas
|
|
25
|
+
from cognite_toolkit._cdf_tk.client.resource_classes.legacy.charts import Chart, ChartList, Visibility
|
|
26
|
+
from cognite_toolkit._cdf_tk.client.resource_classes.legacy.migration import ResourceViewMapping
|
|
27
|
+
from cognite_toolkit._cdf_tk.client.resource_classes.legacy.raw import RawTable
|
|
28
|
+
from cognite_toolkit._cdf_tk.client.resource_classes.three_d import ThreeDModelResponse
|
|
29
29
|
from cognite_toolkit._cdf_tk.exceptions import ToolkitMissingResourceError, ToolkitValueError
|
|
30
30
|
|
|
31
31
|
from . import humanize_collection
|
|
@@ -852,7 +852,9 @@ class ThreeDInteractiveSelect:
|
|
|
852
852
|
],
|
|
853
853
|
).ask()
|
|
854
854
|
|
|
855
|
-
models = self.client.tool.three_d.
|
|
855
|
+
models = self.client.tool.three_d.models_classic.list(
|
|
856
|
+
published=published, include_revision_info=True, limit=None
|
|
857
|
+
)
|
|
856
858
|
if model_type == "classic":
|
|
857
859
|
models = [model for model in models if model.space is None]
|
|
858
860
|
else:
|
|
@@ -12,6 +12,7 @@ from cognite_toolkit._cdf_tk.constants import (
|
|
|
12
12
|
def iterate_modules(root_dir: Path) -> Iterator[tuple[Path, list[Path]]]:
|
|
13
13
|
"""Iterate over all modules in the project and yield the module directory and all files in the module.
|
|
14
14
|
|
|
15
|
+
|
|
15
16
|
Args:
|
|
16
17
|
root_dir (Path): The root directory of the project
|
|
17
18
|
|
|
@@ -110,6 +111,12 @@ def is_module_path(path: Path) -> bool:
|
|
|
110
111
|
return any(sub_folder.name in CRUDS_BY_FOLDER_NAME for sub_folder in path.iterdir() if sub_folder.is_dir())
|
|
111
112
|
|
|
112
113
|
|
|
114
|
+
def module_path_display_name(org_path: Path, module_path: Path) -> str:
|
|
115
|
+
"""Returns the module directory path relative to the organization path as a posix string."""
|
|
116
|
+
rel = module_path.relative_to(org_path)
|
|
117
|
+
return rel.as_posix()
|
|
118
|
+
|
|
119
|
+
|
|
113
120
|
def find_directory_with_subdirectories(
|
|
114
121
|
directory_name: str | None, root_directory: Path
|
|
115
122
|
) -> tuple[Path | None, list[str]]:
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""Utilities for validating Python package requirements."""
|
|
2
|
+
|
|
3
|
+
import subprocess
|
|
4
|
+
import sys
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
# Maximum number of error lines to include in warnings
|
|
9
|
+
_MAX_ERROR_LINES = 3
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class PipValidationResult:
|
|
14
|
+
"""Result from validating a requirements.txt file."""
|
|
15
|
+
|
|
16
|
+
error_message: str | None = None
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def success(self) -> bool:
|
|
20
|
+
"""Validation succeeded if there's no error message."""
|
|
21
|
+
return self.error_message is None
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def is_credential_error(self) -> bool:
|
|
25
|
+
"""Check if the error appears to be related to authentication/credentials.
|
|
26
|
+
|
|
27
|
+
Only checks for explicit HTTP authentication errors to avoid false positives
|
|
28
|
+
from legitimate package not found errors.
|
|
29
|
+
"""
|
|
30
|
+
if not self.error_message:
|
|
31
|
+
return False
|
|
32
|
+
credential_indicators = [
|
|
33
|
+
"401",
|
|
34
|
+
"403",
|
|
35
|
+
"Unauthorized",
|
|
36
|
+
"Forbidden",
|
|
37
|
+
"Authentication",
|
|
38
|
+
]
|
|
39
|
+
return any(indicator in self.error_message for indicator in credential_indicators)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def validate_requirements_with_pip(
|
|
43
|
+
requirements_txt_path: Path,
|
|
44
|
+
index_url: str | None = None,
|
|
45
|
+
extra_index_urls: list[str] | None = None,
|
|
46
|
+
timeout: int = 10,
|
|
47
|
+
) -> PipValidationResult:
|
|
48
|
+
"""Validate that requirements.txt can be resolved using pip install --dry-run.
|
|
49
|
+
|
|
50
|
+
This simulates package installation without actually installing anything.
|
|
51
|
+
It validates that:
|
|
52
|
+
- All packages exist
|
|
53
|
+
- All specified versions are available
|
|
54
|
+
- Credentials for private repositories are valid
|
|
55
|
+
- Index URLs are accessible
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
requirements_txt_path: Path to the requirements.txt file
|
|
59
|
+
index_url: Optional custom package index URL (replaces PyPI)
|
|
60
|
+
extra_index_urls: Optional additional package index URLs
|
|
61
|
+
timeout: Timeout in seconds for the pip command
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
PipValidationResult with success status and error details if failed
|
|
65
|
+
|
|
66
|
+
"""
|
|
67
|
+
if not requirements_txt_path.exists():
|
|
68
|
+
return PipValidationResult(error_message=f"Requirements file not found: {requirements_txt_path}")
|
|
69
|
+
|
|
70
|
+
# Build pip command with custom index URLs
|
|
71
|
+
args = [
|
|
72
|
+
sys.executable,
|
|
73
|
+
"-m",
|
|
74
|
+
"pip",
|
|
75
|
+
"install",
|
|
76
|
+
"--dry-run",
|
|
77
|
+
"--ignore-installed",
|
|
78
|
+
"--no-deps",
|
|
79
|
+
"--disable-pip-version-check",
|
|
80
|
+
"-r",
|
|
81
|
+
str(requirements_txt_path),
|
|
82
|
+
*(["--index-url", index_url] if index_url else []),
|
|
83
|
+
*([arg for url in (extra_index_urls or []) for arg in ["--extra-index-url", url]]),
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
result = subprocess.run(args, capture_output=True, text=True, timeout=timeout, check=False)
|
|
88
|
+
if result.returncode == 0:
|
|
89
|
+
return PipValidationResult()
|
|
90
|
+
return PipValidationResult(
|
|
91
|
+
error_message=f"pip validation failed with exit code {result.returncode}:\n{result.stderr}",
|
|
92
|
+
)
|
|
93
|
+
except subprocess.TimeoutExpired:
|
|
94
|
+
return PipValidationResult(error_message=f"pip validation timed out after {timeout} seconds")
|
|
95
|
+
except (OSError, RuntimeError) as e:
|
|
96
|
+
return PipValidationResult(error_message=f"Error running pip validation: {e!s}")
|