cognite-toolkit 0.7.46__py3-none-any.whl → 0.7.48__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/_migrate_app.py +6 -6
- cognite_toolkit/_cdf_tk/client/_toolkit_client.py +6 -4
- 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/containers.py +132 -0
- cognite_toolkit/_cdf_tk/client/api/data_models.py +137 -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/instances.py +139 -0
- cognite_toolkit/_cdf_tk/client/api/location_filters.py +177 -0
- cognite_toolkit/_cdf_tk/client/api/raw.py +2 -2
- 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/spaces.py +117 -0
- cognite_toolkit/_cdf_tk/client/api/streams.py +63 -55
- cognite_toolkit/_cdf_tk/client/api/three_d.py +293 -277
- cognite_toolkit/_cdf_tk/client/api/views.py +139 -0
- cognite_toolkit/_cdf_tk/client/cdf_client/api.py +42 -7
- cognite_toolkit/_cdf_tk/client/cdf_client/responses.py +11 -0
- cognite_toolkit/_cdf_tk/client/http_client/_client.py +5 -2
- cognite_toolkit/_cdf_tk/client/http_client/_data_classes.py +10 -0
- cognite_toolkit/_cdf_tk/client/http_client/_data_classes2.py +4 -3
- cognite_toolkit/_cdf_tk/client/request_classes/filters.py +75 -0
- cognite_toolkit/_cdf_tk/client/request_classes/graphql.py +28 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/agent.py +8 -2
- cognite_toolkit/_cdf_tk/client/resource_classes/apm_config.py +128 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/cognite_file.py +53 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/__init__.py +4 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_instance.py +22 -11
- cognite_toolkit/_cdf_tk/client/resource_classes/function_schedule.py +8 -4
- cognite_toolkit/_cdf_tk/client/resource_classes/group/group.py +9 -5
- cognite_toolkit/_cdf_tk/client/resource_classes/identifiers.py +7 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/location_filter.py +9 -2
- cognite_toolkit/_cdf_tk/client/resource_classes/relationship.py +9 -3
- cognite_toolkit/_cdf_tk/client/resource_classes/resource_view_mapping.py +38 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/robotics/_map.py +6 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/robotics/_robot.py +10 -5
- cognite_toolkit/_cdf_tk/client/resource_classes/streams.py +1 -20
- cognite_toolkit/_cdf_tk/client/resource_classes/three_d.py +30 -9
- cognite_toolkit/_cdf_tk/client/testing.py +2 -2
- cognite_toolkit/_cdf_tk/commands/_migrate/data_mapper.py +5 -5
- cognite_toolkit/_cdf_tk/commands/_migrate/migration_io.py +11 -7
- 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/cruds/__init__.py +11 -5
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/streams.py +14 -30
- 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/storageio/_base.py +2 -0
- cognite_toolkit/_cdf_tk/storageio/logger.py +163 -0
- cognite_toolkit/_cdf_tk/utils/__init__.py +8 -1
- cognite_toolkit/_cdf_tk/utils/interactive_select.py +3 -1
- cognite_toolkit/_cdf_tk/utils/modules.py +7 -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.46.dist-info → cognite_toolkit-0.7.48.dist-info}/METADATA +1 -1
- {cognite_toolkit-0.7.46.dist-info → cognite_toolkit-0.7.48.dist-info}/RECORD +76 -46
- cognite_toolkit/_cdf_tk/commands/build_v2/build_issues.py +0 -27
- /cognite_toolkit/_cdf_tk/client/resource_classes/{search_config_resource.py → search_config.py} +0 -0
- {cognite_toolkit-0.7.46.dist-info → cognite_toolkit-0.7.48.dist-info}/WHEEL +0 -0
- {cognite_toolkit-0.7.46.dist-info → cognite_toolkit-0.7.48.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, ConfigDict
|
|
5
|
+
|
|
6
|
+
from cognite_toolkit._cdf_tk.data_classes._module_toml import ModuleToml
|
|
7
|
+
|
|
8
|
+
if sys.version_info >= (3, 11):
|
|
9
|
+
from typing import Self
|
|
10
|
+
else:
|
|
11
|
+
from typing_extensions import Self
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Module(BaseModel):
|
|
15
|
+
model_config = ConfigDict(
|
|
16
|
+
frozen=True,
|
|
17
|
+
validate_assignment=True,
|
|
18
|
+
arbitrary_types_allowed=True,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
path: Path
|
|
22
|
+
definition: ModuleToml | None = None
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def load(cls, path: Path) -> Self:
|
|
26
|
+
definition = ModuleToml.load(path / ModuleToml.filename) if (path / ModuleToml.filename).exists() else None
|
|
27
|
+
return cls(path=path, definition=definition)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, ConfigDict
|
|
5
|
+
|
|
6
|
+
if sys.version_info >= (3, 11):
|
|
7
|
+
from typing import Self
|
|
8
|
+
else:
|
|
9
|
+
from typing_extensions import Self
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Resource(BaseModel):
|
|
13
|
+
model_config = ConfigDict(
|
|
14
|
+
frozen=True,
|
|
15
|
+
validate_assignment=True,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
path: Path
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def load(cls, path: Path) -> Self:
|
|
22
|
+
return cls(path=path)
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
import itertools
|
|
15
|
+
from collections import defaultdict
|
|
15
16
|
from typing import Literal, TypeAlias
|
|
16
17
|
|
|
17
18
|
from cognite_toolkit._cdf_tk.feature_flags import FeatureFlag, Flags
|
|
@@ -90,24 +91,28 @@ if not FeatureFlag.is_enabled(Flags.STREAMS):
|
|
|
90
91
|
if not FeatureFlag.is_enabled(Flags.SIMULATORS):
|
|
91
92
|
_EXCLUDED_CRUDS.add(SimulatorModelCRUD)
|
|
92
93
|
|
|
93
|
-
|
|
94
|
+
CRUDS_BY_FOLDER_NAME_INCLUDE_ALPHA: defaultdict[str, list[type[Loader]]] = defaultdict(list)
|
|
95
|
+
CRUDS_BY_FOLDER_NAME: defaultdict[str, list[type[Loader]]] = defaultdict(list)
|
|
94
96
|
for _loader in itertools.chain(
|
|
95
97
|
ResourceCRUD.__subclasses__(),
|
|
96
98
|
ResourceContainerCRUD.__subclasses__(),
|
|
97
99
|
DataCRUD.__subclasses__(),
|
|
98
100
|
GroupCRUD.__subclasses__(),
|
|
99
101
|
):
|
|
100
|
-
if _loader in [ResourceCRUD, ResourceContainerCRUD, DataCRUD, GroupCRUD]
|
|
102
|
+
if _loader in [ResourceCRUD, ResourceContainerCRUD, DataCRUD, GroupCRUD]:
|
|
101
103
|
# Skipping base classes
|
|
102
104
|
continue
|
|
103
|
-
if _loader.folder_name not in CRUDS_BY_FOLDER_NAME: # type: ignore[attr-defined]
|
|
104
|
-
CRUDS_BY_FOLDER_NAME[_loader.folder_name] = [] # type: ignore[attr-defined]
|
|
105
105
|
# MyPy bug: https://github.com/python/mypy/issues/4717
|
|
106
|
-
|
|
106
|
+
CRUDS_BY_FOLDER_NAME_INCLUDE_ALPHA[_loader.folder_name].append(_loader) # type: ignore[arg-type, attr-defined]
|
|
107
|
+
|
|
108
|
+
if _loader not in _EXCLUDED_CRUDS:
|
|
109
|
+
CRUDS_BY_FOLDER_NAME[_loader.folder_name].append(_loader) # type: ignore[arg-type, attr-defined]
|
|
107
110
|
del _loader # cleanup module namespace
|
|
108
111
|
|
|
112
|
+
|
|
109
113
|
# For backwards compatibility
|
|
110
114
|
CRUDS_BY_FOLDER_NAME["data_models"] = CRUDS_BY_FOLDER_NAME["data_modeling"] # Todo: Remove in v1.0
|
|
115
|
+
CRUDS_BY_FOLDER_NAME_INCLUDE_ALPHA["data_models"] = CRUDS_BY_FOLDER_NAME_INCLUDE_ALPHA["data_modeling"]
|
|
111
116
|
RESOURCE_CRUD_BY_FOLDER_NAME = {
|
|
112
117
|
folder_name: cruds
|
|
113
118
|
for folder_name, loaders in CRUDS_BY_FOLDER_NAME.items()
|
|
@@ -166,6 +171,7 @@ __all__ = [
|
|
|
166
171
|
"RESOURCE_CRUD_CONTAINER_LIST",
|
|
167
172
|
"RESOURCE_CRUD_LIST",
|
|
168
173
|
"RESOURCE_DATA_CRUD_LIST",
|
|
174
|
+
"_EXCLUDED_CRUDS",
|
|
169
175
|
"AgentCRUD",
|
|
170
176
|
"AssetCRUD",
|
|
171
177
|
"CogniteFileCRUD",
|
|
@@ -4,11 +4,10 @@ from typing import Any, final
|
|
|
4
4
|
from cognite.client.data_classes.capabilities import Capability, StreamsAcl
|
|
5
5
|
from cognite.client.utils.useful_types import SequenceNotStr
|
|
6
6
|
|
|
7
|
-
from cognite_toolkit._cdf_tk.client.
|
|
7
|
+
from cognite_toolkit._cdf_tk.client.resource_classes.identifiers import ExternalId
|
|
8
8
|
from cognite_toolkit._cdf_tk.client.resource_classes.streams import (
|
|
9
9
|
StreamRequest,
|
|
10
10
|
StreamResponse,
|
|
11
|
-
StreamResponseList,
|
|
12
11
|
)
|
|
13
12
|
from cognite_toolkit._cdf_tk.cruds._base_cruds import ResourceCRUD
|
|
14
13
|
from cognite_toolkit._cdf_tk.resource_classes import StreamYAML
|
|
@@ -17,7 +16,7 @@ from .datamodel import ContainerCRUD
|
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
@final
|
|
20
|
-
class StreamCRUD(ResourceCRUD[
|
|
19
|
+
class StreamCRUD(ResourceCRUD[ExternalId, StreamRequest, StreamResponse]):
|
|
21
20
|
folder_name = "streams"
|
|
22
21
|
resource_cls = StreamResponse
|
|
23
22
|
resource_write_cls = StreamRequest
|
|
@@ -32,14 +31,14 @@ class StreamCRUD(ResourceCRUD[str, StreamRequest, StreamResponse]):
|
|
|
32
31
|
return "streams"
|
|
33
32
|
|
|
34
33
|
@classmethod
|
|
35
|
-
def get_id(cls, item: StreamRequest | StreamResponse | dict) ->
|
|
34
|
+
def get_id(cls, item: StreamRequest | StreamResponse | dict) -> ExternalId:
|
|
36
35
|
if isinstance(item, dict):
|
|
37
|
-
return item["externalId"]
|
|
38
|
-
return item.external_id
|
|
36
|
+
return ExternalId(external_id=item["externalId"])
|
|
37
|
+
return ExternalId(external_id=item.external_id)
|
|
39
38
|
|
|
40
39
|
@classmethod
|
|
41
|
-
def dump_id(cls, id:
|
|
42
|
-
return
|
|
40
|
+
def dump_id(cls, id: ExternalId) -> dict[str, Any]:
|
|
41
|
+
return id.dump()
|
|
43
42
|
|
|
44
43
|
@classmethod
|
|
45
44
|
def get_required_capability(
|
|
@@ -55,30 +54,15 @@ class StreamCRUD(ResourceCRUD[str, StreamRequest, StreamResponse]):
|
|
|
55
54
|
)
|
|
56
55
|
return StreamsAcl(actions, StreamsAcl.Scope.All())
|
|
57
56
|
|
|
58
|
-
def create(self, items: Sequence[StreamRequest]) ->
|
|
59
|
-
|
|
60
|
-
return StreamResponseList(created)
|
|
57
|
+
def create(self, items: Sequence[StreamRequest]) -> list[StreamResponse]:
|
|
58
|
+
return self.client.streams.create(items)
|
|
61
59
|
|
|
62
|
-
def retrieve(self, ids: SequenceNotStr[
|
|
63
|
-
|
|
64
|
-
for _id in ids:
|
|
65
|
-
try:
|
|
66
|
-
_resp = self.client.streams.retrieve(_id)
|
|
67
|
-
except ToolkitAPIError:
|
|
68
|
-
continue
|
|
69
|
-
if _resp is not None:
|
|
70
|
-
retrieved.append(_resp)
|
|
71
|
-
return StreamResponseList(retrieved)
|
|
60
|
+
def retrieve(self, ids: SequenceNotStr[ExternalId]) -> list[StreamResponse]:
|
|
61
|
+
return self.client.streams.retrieve(list(ids), ignore_unknown_ids=True)
|
|
72
62
|
|
|
73
|
-
def delete(self, ids: SequenceNotStr[
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
try:
|
|
77
|
-
self.client.streams.delete(_id)
|
|
78
|
-
except ToolkitAPIError:
|
|
79
|
-
continue
|
|
80
|
-
count += 1
|
|
81
|
-
return count
|
|
63
|
+
def delete(self, ids: SequenceNotStr[ExternalId]) -> int:
|
|
64
|
+
self.client.streams.delete(list(ids), ignore_unknown_ids=True)
|
|
65
|
+
return len(ids)
|
|
82
66
|
|
|
83
67
|
def _iterate(
|
|
84
68
|
self,
|
|
@@ -29,6 +29,7 @@ from ._deploy_results import (
|
|
|
29
29
|
ResourceDeployResult,
|
|
30
30
|
UploadDeployResult,
|
|
31
31
|
)
|
|
32
|
+
from ._issues import Issue, IssueList
|
|
32
33
|
from ._module_directories import ModuleDirectories, ModuleLocation
|
|
33
34
|
from ._module_resources import ModuleResources
|
|
34
35
|
from ._packages import Package, Packages
|
|
@@ -56,6 +57,8 @@ __all__ = [
|
|
|
56
57
|
"DeployResults",
|
|
57
58
|
"Environment",
|
|
58
59
|
"InitConfigYAML",
|
|
60
|
+
"Issue",
|
|
61
|
+
"IssueList",
|
|
59
62
|
"ModuleDirectories",
|
|
60
63
|
"ModuleLocation",
|
|
61
64
|
"ModuleResources",
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from collections import UserList
|
|
3
|
+
|
|
4
|
+
if sys.version_info >= (3, 11):
|
|
5
|
+
from typing import Self
|
|
6
|
+
else:
|
|
7
|
+
from typing_extensions import Self
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
10
|
+
|
|
11
|
+
from cognite_toolkit._cdf_tk.tk_warnings import ToolkitWarning, WarningList
|
|
12
|
+
|
|
13
|
+
MODULE_ISSUE_CODE = "MOD"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Issue(BaseModel):
|
|
17
|
+
"""Base class for all issues"""
|
|
18
|
+
|
|
19
|
+
code: str
|
|
20
|
+
message: str | None = Field(default=None)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# temporary adapter to manage existing warnings
|
|
24
|
+
class IssueList(UserList[Issue]):
|
|
25
|
+
"""List of build issues."""
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
def from_warning_list(cls, warning_list: WarningList[ToolkitWarning]) -> Self:
|
|
29
|
+
"""Create a IssueList from a WarningList."""
|
|
30
|
+
return cls([Issue(code="WARN", message=warning.get_message()) for warning in warning_list])
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ModuleLoadingIssue(Issue):
|
|
34
|
+
"""Issue with the loading of a module folder."""
|
|
35
|
+
|
|
36
|
+
code: str = "MOD_001"
|
|
@@ -8,7 +8,8 @@ from pathlib import Path
|
|
|
8
8
|
from typing import Any, SupportsIndex, overload
|
|
9
9
|
|
|
10
10
|
from cognite_toolkit._cdf_tk.constants import INDEX_PATTERN
|
|
11
|
-
from cognite_toolkit._cdf_tk.utils import calculate_directory_hash
|
|
11
|
+
from cognite_toolkit._cdf_tk.utils.hashing import calculate_directory_hash
|
|
12
|
+
from cognite_toolkit._cdf_tk.utils.modules import iterate_modules, resource_folder_from_path
|
|
12
13
|
|
|
13
14
|
from ._module_toml import ModuleToml
|
|
14
15
|
|
|
@@ -11,6 +11,7 @@ from cognite_toolkit._cdf_tk.utils.collection import chunker
|
|
|
11
11
|
from cognite_toolkit._cdf_tk.utils.fileio import MultiFileReader, SchemaColumn
|
|
12
12
|
from cognite_toolkit._cdf_tk.utils.useful_types import JsonVal
|
|
13
13
|
|
|
14
|
+
from .logger import DataLogger, NoOpLogger
|
|
14
15
|
from .selectors import DataSelector
|
|
15
16
|
|
|
16
17
|
|
|
@@ -76,6 +77,7 @@ class StorageIO(ABC, Generic[T_Selector, T_ResourceResponse]):
|
|
|
76
77
|
|
|
77
78
|
def __init__(self, client: ToolkitClient) -> None:
|
|
78
79
|
self.client = client
|
|
80
|
+
self.logger: DataLogger = NoOpLogger()
|
|
79
81
|
|
|
80
82
|
@abstractmethod
|
|
81
83
|
def as_id(self, item: T_ResourceResponse) -> str:
|
|
@@ -0,0 +1,163 @@
|
|
|
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
|
+
message: str
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
OperationStatus: TypeAlias = Literal["success", "failure", "unchanged", "pending"]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ItemTracker:
|
|
24
|
+
"""Tracks issues accumulated for a single item during pipeline processing."""
|
|
25
|
+
|
|
26
|
+
def __init__(self, item_id: str) -> None:
|
|
27
|
+
self.item_id = item_id
|
|
28
|
+
self.issues: list[str] = []
|
|
29
|
+
|
|
30
|
+
def add_issue(self, issue: str) -> None:
|
|
31
|
+
"""Add an issue encountered during processing."""
|
|
32
|
+
self.issues.append(issue)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class OperationTracker(ABC):
|
|
36
|
+
"""Abstract base class for operation trackers."""
|
|
37
|
+
|
|
38
|
+
@abstractmethod
|
|
39
|
+
def add_issue(self, item_id: str, issue: str) -> None:
|
|
40
|
+
"""Add an issue to an item."""
|
|
41
|
+
raise NotImplementedError()
|
|
42
|
+
|
|
43
|
+
@abstractmethod
|
|
44
|
+
def finalize_item(self, item_id: str | list[str], status: OperationStatus) -> None:
|
|
45
|
+
"""Finalize an item with its final status."""
|
|
46
|
+
raise NotImplementedError()
|
|
47
|
+
|
|
48
|
+
@abstractmethod
|
|
49
|
+
def get_status_counts(self) -> dict[OperationStatus, int]:
|
|
50
|
+
"""Get counts per final status."""
|
|
51
|
+
raise NotImplementedError()
|
|
52
|
+
|
|
53
|
+
@abstractmethod
|
|
54
|
+
def get_issue_counts(self, status: OperationStatus) -> dict[str, int]:
|
|
55
|
+
"""Get issue counts, optionally filtered by status."""
|
|
56
|
+
raise NotImplementedError()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class NoOpTracker(OperationTracker):
|
|
60
|
+
"""A no-op tracker that does nothing."""
|
|
61
|
+
|
|
62
|
+
def add_issue(self, item_id: str, issue: str) -> None:
|
|
63
|
+
"""No-op: Discard the issue."""
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
def finalize_item(self, item_id: str | list[str], status: OperationStatus) -> None:
|
|
67
|
+
"""No-op: Do nothing."""
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
def get_status_counts(self) -> dict[OperationStatus, int]:
|
|
71
|
+
"""Return empty status counts."""
|
|
72
|
+
return {}
|
|
73
|
+
|
|
74
|
+
def get_issue_counts(self, status: OperationStatus) -> dict[str, int]:
|
|
75
|
+
"""Return empty issue counts."""
|
|
76
|
+
return {}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class MemoryOperationTracker(OperationTracker):
|
|
80
|
+
"""Tracks the overall operation progress and issues across multiple items.
|
|
81
|
+
|
|
82
|
+
Tracks counts of final statuses and issues per status.
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
def __init__(self) -> None:
|
|
86
|
+
self._lock = Lock()
|
|
87
|
+
self._active_items: dict[str, ItemTracker] = {}
|
|
88
|
+
self._status_counts: dict[OperationStatus, int] = defaultdict(int)
|
|
89
|
+
self._issue_counts: dict[OperationStatus, dict[str, int]] = defaultdict(lambda: defaultdict(int))
|
|
90
|
+
|
|
91
|
+
def add_issue(self, item_id: str, issue: str) -> None:
|
|
92
|
+
"""Add an issue to an item, creating tracker if needed."""
|
|
93
|
+
with self._lock:
|
|
94
|
+
if item_id not in self._active_items:
|
|
95
|
+
self._active_items[item_id] = ItemTracker(item_id)
|
|
96
|
+
self._active_items[item_id].add_issue(issue)
|
|
97
|
+
|
|
98
|
+
def finalize_item(self, item_id: str | list[str], status: OperationStatus) -> None:
|
|
99
|
+
"""Finalize an item with its final status.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
item_id: The item's identifier.
|
|
103
|
+
status: Final status (success, failure, unchanged).
|
|
104
|
+
"""
|
|
105
|
+
with self._lock:
|
|
106
|
+
if isinstance(item_id, list):
|
|
107
|
+
for iid in item_id:
|
|
108
|
+
self._finalize_item_unlocked(iid, status)
|
|
109
|
+
else:
|
|
110
|
+
self._finalize_item_unlocked(item_id, status)
|
|
111
|
+
|
|
112
|
+
def _finalize_item_unlocked(self, item_id: str, status: OperationStatus) -> None:
|
|
113
|
+
"""Internal method to finalize an item without acquiring the lock."""
|
|
114
|
+
tracker = self._active_items.pop(item_id, None)
|
|
115
|
+
self._status_counts[status] += 1
|
|
116
|
+
if tracker is not None:
|
|
117
|
+
for issue in tracker.issues:
|
|
118
|
+
self._issue_counts[status][issue] += 1
|
|
119
|
+
|
|
120
|
+
def get_status_counts(self) -> dict[OperationStatus, int]:
|
|
121
|
+
"""Get counts per final status."""
|
|
122
|
+
with self._lock:
|
|
123
|
+
return dict(self._status_counts)
|
|
124
|
+
|
|
125
|
+
def get_issue_counts(self, status: OperationStatus) -> dict[str, int]:
|
|
126
|
+
"""Get issue counts, optionally filtered by status."""
|
|
127
|
+
with self._lock:
|
|
128
|
+
return dict(self._issue_counts.get(status, {}))
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class DataLogger(ABC):
|
|
132
|
+
"""Abstract base class for data loggers that track operations and log entries."""
|
|
133
|
+
|
|
134
|
+
tracker: OperationTracker
|
|
135
|
+
|
|
136
|
+
@abstractmethod
|
|
137
|
+
def log(self, entry: LogEntry | Sequence[LogEntry]) -> None:
|
|
138
|
+
"""Log a detailed entry."""
|
|
139
|
+
raise NotImplementedError()
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class NoOpLogger(DataLogger):
|
|
143
|
+
"""A no-op logger that discards all log entries and does no tracking."""
|
|
144
|
+
|
|
145
|
+
def __init__(self) -> None:
|
|
146
|
+
self.tracker = NoOpTracker()
|
|
147
|
+
|
|
148
|
+
def log(self, entry: LogEntry | Sequence[LogEntry]) -> None:
|
|
149
|
+
"""Discard the log entry (no-op)."""
|
|
150
|
+
pass
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class FileDataLogger(DataLogger):
|
|
154
|
+
"""Composes aggregation tracking with detailed file logging."""
|
|
155
|
+
|
|
156
|
+
def __init__(self, writer: NDJsonWriter) -> None:
|
|
157
|
+
self.tracker = MemoryOperationTracker()
|
|
158
|
+
self._writer = writer
|
|
159
|
+
|
|
160
|
+
def log(self, entry: LogEntry | Sequence[LogEntry]) -> None:
|
|
161
|
+
"""Log a detailed entry to the file."""
|
|
162
|
+
entries = entry if isinstance(entry, Sequence) else [entry]
|
|
163
|
+
self._writer.write_chunks([e.model_dump(by_alias=True) for e in entries])
|
|
@@ -19,7 +19,13 @@ 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
|
+
)
|
|
23
29
|
from .sentry_utils import sentry_exception_filter
|
|
24
30
|
|
|
25
31
|
__all__ = [
|
|
@@ -37,6 +43,7 @@ __all__ = [
|
|
|
37
43
|
"iterate_modules",
|
|
38
44
|
"load_yaml_inject_variables",
|
|
39
45
|
"module_from_path",
|
|
46
|
+
"module_path_display_name",
|
|
40
47
|
"quote_int_value_by_key_in_yaml",
|
|
41
48
|
"read_yaml_content",
|
|
42
49
|
"read_yaml_file",
|
|
@@ -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]]:
|
cognite_toolkit/_version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.7.
|
|
1
|
+
__version__ = "0.7.48"
|