cognite-toolkit 0.6.97__py3-none-any.whl → 0.7.39__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. cognite_toolkit/_cdf.py +21 -23
  2. cognite_toolkit/_cdf_tk/apps/__init__.py +4 -0
  3. cognite_toolkit/_cdf_tk/apps/_core_app.py +19 -5
  4. cognite_toolkit/_cdf_tk/apps/_data_app.py +1 -1
  5. cognite_toolkit/_cdf_tk/apps/_dev_app.py +86 -0
  6. cognite_toolkit/_cdf_tk/apps/_download_app.py +693 -25
  7. cognite_toolkit/_cdf_tk/apps/_dump_app.py +44 -102
  8. cognite_toolkit/_cdf_tk/apps/_import_app.py +41 -0
  9. cognite_toolkit/_cdf_tk/apps/_landing_app.py +18 -4
  10. cognite_toolkit/_cdf_tk/apps/_migrate_app.py +424 -9
  11. cognite_toolkit/_cdf_tk/apps/_modules_app.py +0 -3
  12. cognite_toolkit/_cdf_tk/apps/_purge.py +15 -43
  13. cognite_toolkit/_cdf_tk/apps/_run.py +11 -0
  14. cognite_toolkit/_cdf_tk/apps/_upload_app.py +45 -6
  15. cognite_toolkit/_cdf_tk/builders/__init__.py +2 -2
  16. cognite_toolkit/_cdf_tk/builders/_base.py +28 -42
  17. cognite_toolkit/_cdf_tk/builders/_raw.py +1 -1
  18. cognite_toolkit/_cdf_tk/cdf_toml.py +20 -1
  19. cognite_toolkit/_cdf_tk/client/_toolkit_client.py +32 -12
  20. cognite_toolkit/_cdf_tk/client/api/infield.py +114 -17
  21. cognite_toolkit/_cdf_tk/client/api/{canvas.py → legacy/canvas.py} +15 -7
  22. cognite_toolkit/_cdf_tk/client/api/{charts.py → legacy/charts.py} +1 -1
  23. cognite_toolkit/_cdf_tk/client/api/{extended_data_modeling.py → legacy/extended_data_modeling.py} +1 -1
  24. cognite_toolkit/_cdf_tk/client/api/{extended_files.py → legacy/extended_files.py} +2 -2
  25. cognite_toolkit/_cdf_tk/client/api/{extended_functions.py → legacy/extended_functions.py} +15 -18
  26. cognite_toolkit/_cdf_tk/client/api/{extended_raw.py → legacy/extended_raw.py} +1 -1
  27. cognite_toolkit/_cdf_tk/client/api/{extended_timeseries.py → legacy/extended_timeseries.py} +5 -2
  28. cognite_toolkit/_cdf_tk/client/api/{location_filters.py → legacy/location_filters.py} +1 -1
  29. cognite_toolkit/_cdf_tk/client/api/legacy/robotics/__init__.py +8 -0
  30. cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/capabilities.py +1 -1
  31. cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/data_postprocessing.py +1 -1
  32. cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/frames.py +1 -1
  33. cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/locations.py +1 -1
  34. cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/maps.py +1 -1
  35. cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/robots.py +2 -2
  36. cognite_toolkit/_cdf_tk/client/api/{search_config.py → legacy/search_config.py} +5 -1
  37. cognite_toolkit/_cdf_tk/client/api/migration.py +177 -4
  38. cognite_toolkit/_cdf_tk/client/api/project.py +9 -8
  39. cognite_toolkit/_cdf_tk/client/api/search.py +2 -2
  40. cognite_toolkit/_cdf_tk/client/api/streams.py +88 -0
  41. cognite_toolkit/_cdf_tk/client/api/three_d.py +384 -0
  42. cognite_toolkit/_cdf_tk/client/data_classes/api_classes.py +13 -0
  43. cognite_toolkit/_cdf_tk/client/data_classes/base.py +37 -33
  44. cognite_toolkit/_cdf_tk/client/data_classes/charts_data.py +95 -213
  45. cognite_toolkit/_cdf_tk/client/data_classes/infield.py +32 -18
  46. cognite_toolkit/_cdf_tk/client/data_classes/instance_api.py +18 -13
  47. cognite_toolkit/_cdf_tk/client/data_classes/legacy/__init__.py +0 -0
  48. cognite_toolkit/_cdf_tk/client/data_classes/{canvas.py → legacy/canvas.py} +47 -4
  49. cognite_toolkit/_cdf_tk/client/data_classes/{charts.py → legacy/charts.py} +3 -3
  50. cognite_toolkit/_cdf_tk/client/data_classes/{migration.py → legacy/migration.py} +10 -2
  51. cognite_toolkit/_cdf_tk/client/data_classes/streams.py +90 -0
  52. cognite_toolkit/_cdf_tk/client/data_classes/three_d.py +112 -0
  53. cognite_toolkit/_cdf_tk/client/testing.py +42 -18
  54. cognite_toolkit/_cdf_tk/commands/__init__.py +7 -6
  55. cognite_toolkit/_cdf_tk/commands/_changes.py +3 -42
  56. cognite_toolkit/_cdf_tk/commands/_download.py +21 -11
  57. cognite_toolkit/_cdf_tk/commands/_migrate/__init__.py +0 -2
  58. cognite_toolkit/_cdf_tk/commands/_migrate/command.py +22 -20
  59. cognite_toolkit/_cdf_tk/commands/_migrate/conversion.py +140 -92
  60. cognite_toolkit/_cdf_tk/commands/_migrate/creators.py +1 -1
  61. cognite_toolkit/_cdf_tk/commands/_migrate/data_classes.py +108 -26
  62. cognite_toolkit/_cdf_tk/commands/_migrate/data_mapper.py +448 -45
  63. cognite_toolkit/_cdf_tk/commands/_migrate/data_model.py +1 -0
  64. cognite_toolkit/_cdf_tk/commands/_migrate/default_mappings.py +6 -6
  65. cognite_toolkit/_cdf_tk/commands/_migrate/issues.py +52 -1
  66. cognite_toolkit/_cdf_tk/commands/_migrate/migration_io.py +377 -11
  67. cognite_toolkit/_cdf_tk/commands/_migrate/selectors.py +9 -4
  68. cognite_toolkit/_cdf_tk/commands/_profile.py +1 -1
  69. cognite_toolkit/_cdf_tk/commands/_purge.py +36 -39
  70. cognite_toolkit/_cdf_tk/commands/_questionary_style.py +16 -0
  71. cognite_toolkit/_cdf_tk/commands/_upload.py +109 -86
  72. cognite_toolkit/_cdf_tk/commands/about.py +221 -0
  73. cognite_toolkit/_cdf_tk/commands/auth.py +19 -12
  74. cognite_toolkit/_cdf_tk/commands/build_cmd.py +16 -62
  75. cognite_toolkit/_cdf_tk/commands/build_v2/__init__.py +0 -0
  76. cognite_toolkit/_cdf_tk/commands/build_v2/build_cmd.py +241 -0
  77. cognite_toolkit/_cdf_tk/commands/build_v2/build_input.py +85 -0
  78. cognite_toolkit/_cdf_tk/commands/build_v2/build_issues.py +27 -0
  79. cognite_toolkit/_cdf_tk/commands/clean.py +63 -16
  80. cognite_toolkit/_cdf_tk/commands/deploy.py +20 -17
  81. cognite_toolkit/_cdf_tk/commands/dump_resource.py +10 -8
  82. cognite_toolkit/_cdf_tk/commands/init.py +225 -3
  83. cognite_toolkit/_cdf_tk/commands/modules.py +20 -44
  84. cognite_toolkit/_cdf_tk/commands/pull.py +6 -19
  85. cognite_toolkit/_cdf_tk/commands/resources.py +179 -0
  86. cognite_toolkit/_cdf_tk/commands/run.py +1 -1
  87. cognite_toolkit/_cdf_tk/constants.py +20 -1
  88. cognite_toolkit/_cdf_tk/cruds/__init__.py +19 -5
  89. cognite_toolkit/_cdf_tk/cruds/_base_cruds.py +14 -70
  90. cognite_toolkit/_cdf_tk/cruds/_data_cruds.py +10 -19
  91. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/__init__.py +4 -1
  92. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/agent.py +11 -9
  93. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/auth.py +5 -15
  94. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/classic.py +45 -44
  95. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/configuration.py +5 -12
  96. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/data_organization.py +4 -13
  97. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/datamodel.py +206 -67
  98. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/extraction_pipeline.py +6 -18
  99. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/fieldops.py +126 -35
  100. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/file.py +7 -28
  101. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/function.py +23 -30
  102. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/hosted_extractors.py +12 -30
  103. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/industrial_tool.py +4 -8
  104. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/location.py +4 -16
  105. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/migration.py +5 -13
  106. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/raw.py +5 -11
  107. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/relationship.py +3 -8
  108. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/robotics.py +16 -45
  109. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/streams.py +94 -0
  110. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/three_d_model.py +3 -7
  111. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/timeseries.py +5 -15
  112. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/transformation.py +75 -32
  113. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/workflow.py +20 -40
  114. cognite_toolkit/_cdf_tk/cruds/_worker.py +24 -36
  115. cognite_toolkit/_cdf_tk/data_classes/_module_toml.py +1 -0
  116. cognite_toolkit/_cdf_tk/feature_flags.py +16 -36
  117. cognite_toolkit/_cdf_tk/plugins.py +2 -1
  118. cognite_toolkit/_cdf_tk/resource_classes/__init__.py +4 -0
  119. cognite_toolkit/_cdf_tk/resource_classes/capabilities.py +12 -0
  120. cognite_toolkit/_cdf_tk/resource_classes/functions.py +3 -1
  121. cognite_toolkit/_cdf_tk/resource_classes/infield_cdm_location_config.py +109 -0
  122. cognite_toolkit/_cdf_tk/resource_classes/migration.py +8 -17
  123. cognite_toolkit/_cdf_tk/resource_classes/search_config.py +1 -1
  124. cognite_toolkit/_cdf_tk/resource_classes/streams.py +29 -0
  125. cognite_toolkit/_cdf_tk/resource_classes/workflow_version.py +164 -5
  126. cognite_toolkit/_cdf_tk/storageio/__init__.py +9 -21
  127. cognite_toolkit/_cdf_tk/storageio/_annotations.py +19 -16
  128. cognite_toolkit/_cdf_tk/storageio/_applications.py +340 -28
  129. cognite_toolkit/_cdf_tk/storageio/_asset_centric.py +67 -104
  130. cognite_toolkit/_cdf_tk/storageio/_base.py +61 -29
  131. cognite_toolkit/_cdf_tk/storageio/_datapoints.py +276 -20
  132. cognite_toolkit/_cdf_tk/storageio/_file_content.py +435 -0
  133. cognite_toolkit/_cdf_tk/storageio/_instances.py +35 -3
  134. cognite_toolkit/_cdf_tk/storageio/_raw.py +26 -0
  135. cognite_toolkit/_cdf_tk/storageio/selectors/__init__.py +71 -4
  136. cognite_toolkit/_cdf_tk/storageio/selectors/_base.py +14 -2
  137. cognite_toolkit/_cdf_tk/storageio/selectors/_canvas.py +14 -0
  138. cognite_toolkit/_cdf_tk/storageio/selectors/_charts.py +14 -0
  139. cognite_toolkit/_cdf_tk/storageio/selectors/_datapoints.py +23 -3
  140. cognite_toolkit/_cdf_tk/storageio/selectors/_file_content.py +164 -0
  141. cognite_toolkit/_cdf_tk/storageio/selectors/_three_d.py +34 -0
  142. cognite_toolkit/_cdf_tk/tk_warnings/other.py +4 -0
  143. cognite_toolkit/_cdf_tk/tracker.py +2 -2
  144. cognite_toolkit/_cdf_tk/utils/cdf.py +1 -1
  145. cognite_toolkit/_cdf_tk/utils/dtype_conversion.py +9 -3
  146. cognite_toolkit/_cdf_tk/utils/fileio/__init__.py +2 -0
  147. cognite_toolkit/_cdf_tk/utils/fileio/_base.py +5 -1
  148. cognite_toolkit/_cdf_tk/utils/fileio/_readers.py +112 -20
  149. cognite_toolkit/_cdf_tk/utils/fileio/_writers.py +15 -15
  150. cognite_toolkit/_cdf_tk/utils/http_client/__init__.py +28 -0
  151. cognite_toolkit/_cdf_tk/utils/http_client/_client.py +285 -18
  152. cognite_toolkit/_cdf_tk/utils/http_client/_data_classes.py +56 -4
  153. cognite_toolkit/_cdf_tk/utils/http_client/_data_classes2.py +247 -0
  154. cognite_toolkit/_cdf_tk/utils/http_client/_tracker.py +5 -2
  155. cognite_toolkit/_cdf_tk/utils/interactive_select.py +60 -18
  156. cognite_toolkit/_cdf_tk/utils/sql_parser.py +2 -3
  157. cognite_toolkit/_cdf_tk/utils/useful_types.py +6 -2
  158. cognite_toolkit/_cdf_tk/validation.py +83 -1
  159. cognite_toolkit/_repo_files/GitHub/.github/workflows/deploy.yaml +1 -1
  160. cognite_toolkit/_repo_files/GitHub/.github/workflows/dry-run.yaml +1 -1
  161. cognite_toolkit/_resources/cdf.toml +5 -4
  162. cognite_toolkit/_version.py +1 -1
  163. cognite_toolkit/config.dev.yaml +13 -0
  164. {cognite_toolkit-0.6.97.dist-info → cognite_toolkit-0.7.39.dist-info}/METADATA +24 -24
  165. cognite_toolkit-0.7.39.dist-info/RECORD +322 -0
  166. cognite_toolkit-0.7.39.dist-info/WHEEL +4 -0
  167. {cognite_toolkit-0.6.97.dist-info → cognite_toolkit-0.7.39.dist-info}/entry_points.txt +1 -0
  168. cognite_toolkit/_cdf_tk/client/api/robotics/__init__.py +0 -3
  169. cognite_toolkit/_cdf_tk/commands/_migrate/canvas.py +0 -201
  170. cognite_toolkit/_cdf_tk/commands/dump_data.py +0 -489
  171. cognite_toolkit/_cdf_tk/commands/featureflag.py +0 -27
  172. cognite_toolkit/_cdf_tk/prototypes/import_app.py +0 -41
  173. cognite_toolkit/_cdf_tk/utils/table_writers.py +0 -434
  174. cognite_toolkit-0.6.97.dist-info/RECORD +0 -306
  175. cognite_toolkit-0.6.97.dist-info/WHEEL +0 -4
  176. cognite_toolkit-0.6.97.dist-info/licenses/LICENSE +0 -18
  177. /cognite_toolkit/_cdf_tk/{prototypes/commands → client/api/legacy}/__init__.py +0 -0
  178. /cognite_toolkit/_cdf_tk/client/api/{dml.py → legacy/dml.py} +0 -0
  179. /cognite_toolkit/_cdf_tk/client/api/{fixed_transformations.py → legacy/fixed_transformations.py} +0 -0
  180. /cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/api.py +0 -0
  181. /cognite_toolkit/_cdf_tk/client/api/{robotics → legacy/robotics}/utlis.py +0 -0
  182. /cognite_toolkit/_cdf_tk/client/data_classes/{apm_config_v1.py → legacy/apm_config_v1.py} +0 -0
  183. /cognite_toolkit/_cdf_tk/client/data_classes/{extendable_cognite_file.py → legacy/extendable_cognite_file.py} +0 -0
  184. /cognite_toolkit/_cdf_tk/client/data_classes/{extended_filemetadata.py → legacy/extended_filemetadata.py} +0 -0
  185. /cognite_toolkit/_cdf_tk/client/data_classes/{extended_filemetdata.py → legacy/extended_filemetdata.py} +0 -0
  186. /cognite_toolkit/_cdf_tk/client/data_classes/{extended_timeseries.py → legacy/extended_timeseries.py} +0 -0
  187. /cognite_toolkit/_cdf_tk/client/data_classes/{functions.py → legacy/functions.py} +0 -0
  188. /cognite_toolkit/_cdf_tk/client/data_classes/{graphql_data_models.py → legacy/graphql_data_models.py} +0 -0
  189. /cognite_toolkit/_cdf_tk/client/data_classes/{instances.py → legacy/instances.py} +0 -0
  190. /cognite_toolkit/_cdf_tk/client/data_classes/{location_filters.py → legacy/location_filters.py} +0 -0
  191. /cognite_toolkit/_cdf_tk/client/data_classes/{pending_instances_ids.py → legacy/pending_instances_ids.py} +0 -0
  192. /cognite_toolkit/_cdf_tk/client/data_classes/{project.py → legacy/project.py} +0 -0
  193. /cognite_toolkit/_cdf_tk/client/data_classes/{raw.py → legacy/raw.py} +0 -0
  194. /cognite_toolkit/_cdf_tk/client/data_classes/{robotics.py → legacy/robotics.py} +0 -0
  195. /cognite_toolkit/_cdf_tk/client/data_classes/{search_config.py → legacy/search_config.py} +0 -0
  196. /cognite_toolkit/_cdf_tk/client/data_classes/{sequences.py → legacy/sequences.py} +0 -0
  197. /cognite_toolkit/_cdf_tk/client/data_classes/{streamlit_.py → legacy/streamlit_.py} +0 -0
  198. /cognite_toolkit/_cdf_tk/{prototypes/commands/import_.py → commands/_import_cmd.py} +0 -0
@@ -0,0 +1,435 @@
1
+ import json
2
+ import mimetypes
3
+ from collections.abc import Iterable, MutableSequence, Sequence
4
+ from dataclasses import dataclass
5
+ from pathlib import Path
6
+ from typing import cast
7
+
8
+ import httpx
9
+ from cognite.client.data_classes import FileMetadata, FileMetadataWrite
10
+ from cognite.client.data_classes.data_modeling import NodeId, ViewId
11
+
12
+ from cognite_toolkit._cdf_tk.client import ToolkitClient
13
+ from cognite_toolkit._cdf_tk.cruds import FileMetadataCRUD
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,
21
+ ErrorDetails,
22
+ FailedResponse,
23
+ FailedResponseItems,
24
+ HTTPClient,
25
+ HTTPMessage,
26
+ ResponseList,
27
+ SimpleBodyRequest,
28
+ )
29
+ from cognite_toolkit._cdf_tk.utils.useful_types import JsonVal
30
+
31
+ from ._base import Page, UploadableStorageIO, UploadItem
32
+ from .selectors import FileContentSelector, FileIdentifierSelector, FileMetadataTemplateSelector
33
+ from .selectors._file_content import (
34
+ FILEPATH,
35
+ FileDataModelingTemplateSelector,
36
+ FileExternalID,
37
+ FileIdentifier,
38
+ FileInstanceID,
39
+ FileInternalID,
40
+ FileTemplateSelector,
41
+ )
42
+ from .selectors._file_content import NodeId as SelectorNodeId
43
+
44
+ COGNITE_FILE_VIEW = ViewId("cdf_cdm", "CogniteFile", "v1")
45
+
46
+
47
+ @dataclass
48
+ class UploadFileContentItem(UploadItem[FileMetadataWrite]):
49
+ file_path: Path
50
+ mime_type: str
51
+
52
+
53
+ @dataclass
54
+ class MetadataWithFilePath(ResourceResponseProtocol):
55
+ metadata: FileMetadata
56
+ file_path: Path
57
+
58
+ def as_write(self) -> FileMetadataWrite:
59
+ return self.metadata.as_write()
60
+
61
+
62
+ class FileContentIO(UploadableStorageIO[FileContentSelector, MetadataWithFilePath, FileMetadataWrite]):
63
+ SUPPORTED_DOWNLOAD_FORMATS = frozenset({".ndjson"})
64
+ SUPPORTED_COMPRESSIONS = frozenset({".gz"})
65
+ CHUNK_SIZE = 10
66
+ BASE_SELECTOR = FileContentSelector
67
+ KIND = "FileContent"
68
+ SUPPORTED_READ_FORMATS = frozenset({".ndjson"})
69
+ UPLOAD_ENDPOINT = "/files"
70
+
71
+ def __init__(self, client: ToolkitClient, target_dir: Path = Path.cwd()) -> None:
72
+ super().__init__(client)
73
+ self._crud = FileMetadataCRUD(client, None, None)
74
+ self._target_dir = target_dir
75
+
76
+ def as_id(self, item: MetadataWithFilePath) -> str:
77
+ return item.metadata.external_id or str(item.metadata.id)
78
+
79
+ def stream_data(
80
+ self, selector: FileContentSelector, limit: int | None = None
81
+ ) -> Iterable[Page[MetadataWithFilePath]]:
82
+ if not isinstance(selector, FileIdentifierSelector):
83
+ raise ToolkitNotImplementedError(
84
+ f"Download with the manifest, {type(selector).__name__}, is not supported for FileContentIO"
85
+ )
86
+ selected_identifiers = selector.identifiers
87
+ if limit is not None and limit < len(selected_identifiers):
88
+ selected_identifiers = selected_identifiers[:limit]
89
+ for identifiers in chunker_sequence(selected_identifiers, self.CHUNK_SIZE):
90
+ metadata = self._retrieve_metadata(identifiers)
91
+ if metadata is None:
92
+ continue
93
+ identifiers_map = self._as_metadata_map(metadata)
94
+ downloaded_files: list[MetadataWithFilePath] = []
95
+ for identifier in identifiers:
96
+ if identifier not in identifiers_map:
97
+ continue
98
+
99
+ meta = identifiers_map[identifier]
100
+ filepath = self._create_filepath(meta, selector)
101
+ download_url = self._retrieve_download_url(identifier)
102
+ if download_url is None:
103
+ continue
104
+ filepath.parent.mkdir(parents=True, exist_ok=True)
105
+ with httpx.stream("GET", download_url) as response:
106
+ if response.status_code != 200:
107
+ continue
108
+ with filepath.open(mode="wb") as file_stream:
109
+ for chunk in response.iter_bytes(chunk_size=8192):
110
+ file_stream.write(chunk)
111
+ downloaded_files.append(
112
+ MetadataWithFilePath(
113
+ metadata=meta,
114
+ file_path=filepath.relative_to(self._target_dir),
115
+ )
116
+ )
117
+ yield Page(items=downloaded_files, worker_id="Main")
118
+
119
+ def _retrieve_metadata(self, identifiers: Sequence[FileIdentifier]) -> Sequence[FileMetadata] | None:
120
+ config = self.client.config
121
+ responses = self.client.http_client.request_with_retries(
122
+ message=SimpleBodyRequest(
123
+ endpoint_url=config.create_api_url("/files/byids"),
124
+ method="POST",
125
+ body_content={
126
+ "items": [
127
+ identifier.model_dump(mode="json", by_alias=True, exclude={"id_type"})
128
+ for identifier in identifiers
129
+ ],
130
+ "ignoreUnknownIds": True,
131
+ },
132
+ )
133
+ )
134
+ if responses.has_failed:
135
+ return None
136
+ body = responses.get_first_body()
137
+ items_data = body.get("items", [])
138
+ if not isinstance(items_data, list):
139
+ return None
140
+ # MyPy does not understand that JsonVal is valid dict[Any, Any]
141
+ return [FileMetadata._load(item) for item in items_data] # type: ignore[arg-type]
142
+
143
+ @staticmethod
144
+ def _as_metadata_map(metadata: Sequence[FileMetadata]) -> dict[FileIdentifier, FileMetadata]:
145
+ identifiers_map: dict[FileIdentifier, FileMetadata] = {}
146
+ for item in metadata:
147
+ if item.id is not None:
148
+ identifiers_map[FileInternalID(internal_id=item.id)] = item
149
+ if item.external_id is not None:
150
+ identifiers_map[FileExternalID(external_id=item.external_id)] = item
151
+ if item.instance_id is not None:
152
+ identifiers_map[
153
+ FileInstanceID(
154
+ instance_id=SelectorNodeId(
155
+ space=item.instance_id.space, external_id=item.instance_id.external_id
156
+ )
157
+ )
158
+ ] = item
159
+ return identifiers_map
160
+
161
+ def _create_filepath(self, meta: FileMetadata, selector: FileIdentifierSelector) -> Path:
162
+ # We now that metadata always have name set
163
+ filename = Path(sanitize_filename(cast(str, meta.name)))
164
+ if len(filename.suffix) == 0 and meta.mime_type:
165
+ if mime_ext := mimetypes.guess_extension(meta.mime_type):
166
+ filename = filename.with_suffix(mime_ext)
167
+ directory = sanitize_filename(selector.file_directory)
168
+ if isinstance(meta.directory, str) and meta.directory != "":
169
+ directory = sanitize_filename(meta.directory.removeprefix("/"))
170
+
171
+ counter = 1
172
+ filepath = self._target_dir / directory / filename
173
+ while filepath.exists():
174
+ filepath = self._target_dir / directory / f"{filename} ({counter})"
175
+ counter += 1
176
+
177
+ return filepath
178
+
179
+ def _retrieve_download_url(self, identifier: FileIdentifier) -> str | None:
180
+ config = self.client.config
181
+ responses = self.client.http_client.request_with_retries(
182
+ message=SimpleBodyRequest(
183
+ endpoint_url=config.create_api_url("/files/downloadlink"),
184
+ method="POST",
185
+ body_content={"items": [identifier.model_dump(mode="json", by_alias=True, exclude={"id_type"})]},
186
+ )
187
+ )
188
+ try:
189
+ body = responses.get_first_body()
190
+ except ValueError:
191
+ return None
192
+ if "items" in body and isinstance(body["items"], list) and len(body["items"]) > 0:
193
+ # The API responses is not following the API docs, this is a workaround
194
+ body = body["items"][0] # type: ignore[assignment]
195
+ try:
196
+ return cast(str, body["downloadUrl"])
197
+ except (KeyError, IndexError):
198
+ return None
199
+
200
+ def count(self, selector: FileContentSelector) -> int | None:
201
+ if isinstance(selector, FileIdentifierSelector):
202
+ return len(selector.identifiers)
203
+ return None
204
+
205
+ def data_to_json_chunk(
206
+ self, data_chunk: Sequence[MetadataWithFilePath], selector: FileContentSelector | None = None
207
+ ) -> list[dict[str, JsonVal]]:
208
+ """Convert a writable Cognite resource list to a JSON-compatible chunk of data.
209
+
210
+ Args:
211
+ data_chunk: A writable Cognite resource list representing the data.
212
+ selector: The selector used for the data. (Not used in this implementation)
213
+ Returns:
214
+ A list of dictionaries, each representing the data in a JSON-compatible format.
215
+ """
216
+ result: list[dict[str, JsonVal]] = []
217
+ for item in data_chunk:
218
+ item_json = self._crud.dump_resource(item.metadata)
219
+ item_json[FILEPATH] = item.file_path.as_posix()
220
+ result.append(item_json)
221
+ return result
222
+
223
+ def json_chunk_to_data(self, data_chunk: list[tuple[str, dict[str, JsonVal]]]) -> Sequence[UploadFileContentItem]:
224
+ """Convert a JSON-compatible chunk of data back to a writable Cognite resource list.
225
+
226
+ Args:
227
+ data_chunk: A list of tuples, each containing a source ID and a dictionary representing
228
+ the data in a JSON-compatible format.
229
+ Returns:
230
+ A writable Cognite resource list representing the data.
231
+ """
232
+ result: list[UploadFileContentItem] = []
233
+ for source_id, item_json in data_chunk:
234
+ item = self.json_to_resource(item_json)
235
+ filepath = Path(cast(str | Path, item_json[FILEPATH]))
236
+ mime_type, _ = mimetypes.guess_type(filepath)
237
+ # application/octet-stream is the standard fallback for binary data when the type is unknown. (at least Claude thinks so)
238
+ result.append(
239
+ UploadFileContentItem(
240
+ source_id=source_id,
241
+ item=item,
242
+ file_path=filepath,
243
+ mime_type=mime_type or "application/octet-stream",
244
+ )
245
+ )
246
+ return result
247
+
248
+ def json_to_resource(self, item_json: dict[str, JsonVal]) -> FileMetadataWrite:
249
+ return self._crud.load_resource(item_json)
250
+
251
+ def upload_items(
252
+ self,
253
+ data_chunk: Sequence[UploadItem[FileMetadataWrite]],
254
+ http_client: HTTPClient,
255
+ selector: FileContentSelector | None = None,
256
+ ) -> Sequence[HTTPMessage]:
257
+ results: MutableSequence[HTTPMessage] = []
258
+ if isinstance(selector, FileMetadataTemplateSelector | FileIdentifierSelector):
259
+ upload_url_getter = self._upload_url_asset_centric
260
+ elif isinstance(selector, FileDataModelingTemplateSelector):
261
+ upload_url_getter = self._upload_url_data_modeling
262
+ elif selector is None:
263
+ raise ToolkitNotImplementedError("Selector must be provided for FileContentIO upload")
264
+ else:
265
+ raise ToolkitNotImplementedError(
266
+ f"Upload for the given selector, {type(selector).__name__}, is not supported for FileContentIO"
267
+ )
268
+
269
+ for item in cast(Sequence[UploadFileContentItem], data_chunk):
270
+ if not (upload_url := upload_url_getter(item, http_client, results)):
271
+ continue
272
+
273
+ content_bytes = item.file_path.read_bytes()
274
+ upload_response = http_client.request_with_retries(
275
+ message=DataBodyRequest(
276
+ endpoint_url=upload_url,
277
+ method="PUT",
278
+ content_type=item.mime_type,
279
+ data_content=content_bytes,
280
+ content_length=len(content_bytes),
281
+ )
282
+ )
283
+ results.extend(upload_response.as_item_responses(item.as_id()))
284
+ return results
285
+
286
+ def _upload_url_asset_centric(
287
+ self, item: UploadFileContentItem, http_client: HTTPClient, results: MutableSequence[HTTPMessage]
288
+ ) -> str | None:
289
+ responses = http_client.request_with_retries(
290
+ message=SimpleBodyRequest(
291
+ endpoint_url=http_client.config.create_api_url(self.UPLOAD_ENDPOINT),
292
+ method="POST",
293
+ # MyPy does not understand that .dump is valid json
294
+ body_content=item.dump(), # type: ignore[arg-type]
295
+ )
296
+ )
297
+ return self._parse_upload_link_response(responses, item, results)
298
+
299
+ def _upload_url_data_modeling(
300
+ self,
301
+ item: UploadFileContentItem,
302
+ http_client: HTTPClient,
303
+ results: MutableSequence[HTTPMessage],
304
+ created_node: bool = False,
305
+ ) -> str | None:
306
+ """Get upload URL for data modeling file upload.
307
+
308
+ We first try to get the upload link assuming the CogniteFile node already exists.
309
+ If we get a "not found" error, we create the CogniteFile node and try again.
310
+
311
+ Args:
312
+ item: The upload item containing file metadata.
313
+ http_client: The HTTP client to use for requests.
314
+ results: A mutable sequence to collect HTTP messages and errors.
315
+ created_node: A flag indicating whether the CogniteFile node has already been created.
316
+ This prevents infinite recursion.
317
+
318
+ Returns:
319
+ The upload URL as a string, or None if there was an error.
320
+
321
+ """
322
+ # We know that instance_id is always set for data modeling uploads
323
+ instance_id = cast(NodeId, item.item.instance_id)
324
+ responses = http_client.request_with_retries(
325
+ message=SimpleBodyRequest(
326
+ endpoint_url=http_client.config.create_api_url("/files/uploadlink"),
327
+ method="POST",
328
+ body_content={"items": [{"instanceId": instance_id.dump(include_instance_type=False)}]}, # type: ignore[dict-item]
329
+ )
330
+ )
331
+ # We know there is only one response since we only requested one upload link
332
+ response = responses[0]
333
+ if isinstance(response, FailedResponse) and response.error.missing and not created_node:
334
+ if self._create_cognite_file_node(instance_id, http_client, item.as_id(), results):
335
+ return self._upload_url_data_modeling(item, http_client, results, created_node=True)
336
+ else:
337
+ return None
338
+
339
+ return self._parse_upload_link_response(responses, item, results)
340
+
341
+ @classmethod
342
+ def _create_cognite_file_node(
343
+ cls, instance_id: NodeId, http_client: HTTPClient, upload_id: str, results: MutableSequence[HTTPMessage]
344
+ ) -> bool:
345
+ node_creation = http_client.request_with_retries(
346
+ message=SimpleBodyRequest(
347
+ endpoint_url=http_client.config.create_api_url("/models/instances"),
348
+ method="POST",
349
+ body_content={
350
+ "items": [
351
+ {
352
+ "space": instance_id.space,
353
+ "externalId": instance_id.external_id,
354
+ "instanceType": "node",
355
+ # When we create a node with properties in CogniteFile View even with empty properties,
356
+ # CDF will fill in empty values for all properties defined in the view (note this is only
357
+ # possible because CogniteFile view has all properties as optional). This includes properties
358
+ # in the CogniteFile container, which will trigger the file syncer to create a FileMetadata
359
+ # and link it to the CogniteFile node.
360
+ "sources": [{"source": COGNITE_FILE_VIEW.dump(include_type=True), "properties": {}}], # type: ignore[dict-item]
361
+ }
362
+ ]
363
+ },
364
+ )
365
+ )
366
+ try:
367
+ _ = node_creation.get_first_body()
368
+ except ValueError:
369
+ results.extend(node_creation.as_item_responses(upload_id))
370
+ return False
371
+ return True
372
+
373
+ @classmethod
374
+ def _parse_upload_link_response(
375
+ cls, responses: ResponseList, item: UploadFileContentItem, results: MutableSequence[HTTPMessage]
376
+ ) -> str | None:
377
+ try:
378
+ body = responses.get_first_body()
379
+ except ValueError:
380
+ results.extend(responses.as_item_responses(item.as_id()))
381
+ return None
382
+
383
+ if "items" in body and isinstance(body["items"], list) and len(body["items"]) > 0:
384
+ body = body["items"][0] # type: ignore[assignment]
385
+ try:
386
+ upload_url = cast(str, body["uploadUrl"])
387
+ except (KeyError, IndexError):
388
+ results.append(
389
+ FailedResponseItems(
390
+ status_code=200,
391
+ body=json.dumps(body),
392
+ error=ErrorDetails(code=200, message="Malformed response"),
393
+ ids=[item.as_id()],
394
+ )
395
+ )
396
+ return None
397
+ return upload_url
398
+
399
+ @classmethod
400
+ def read_chunks(
401
+ cls, reader: MultiFileReader, selector: FileContentSelector
402
+ ) -> Iterable[list[tuple[str, dict[str, JsonVal]]]]:
403
+ if isinstance(selector, FileTemplateSelector):
404
+ for chunk in chunker_sequence(reader.input_files, cls.CHUNK_SIZE):
405
+ batch: list[tuple[str, dict[str, JsonVal]]] = []
406
+ for file_path in chunk:
407
+ metadata = selector.create_instance(file_path)
408
+ metadata[FILEPATH] = file_path
409
+ batch.append((file_path.as_posix(), metadata))
410
+ yield batch
411
+ elif isinstance(selector, FileIdentifierSelector):
412
+ for item_chunk in chunker(reader.read_chunks(), cls.CHUNK_SIZE):
413
+ batch = []
414
+ for item in item_chunk:
415
+ if FILEPATH not in item:
416
+ # Todo Log warning
417
+ continue
418
+ try:
419
+ file_path = Path(item[FILEPATH])
420
+ except KeyError:
421
+ # Todo Log warning
422
+ continue
423
+ if not file_path.is_absolute():
424
+ file_path = reader.input_file.parent / file_path
425
+ item[FILEPATH] = file_path
426
+ batch.append((file_path.as_posix(), item))
427
+ yield batch
428
+ else:
429
+ raise ToolkitNotImplementedError(
430
+ f"Reading with the manifest, {type(selector).__name__}, is not supported for FileContentIO"
431
+ )
432
+
433
+ @classmethod
434
+ def count_chunks(cls, reader: MultiFileReader) -> int:
435
+ return len(reader.input_files)
@@ -4,17 +4,20 @@ from typing import ClassVar
4
4
 
5
5
  from cognite.client.data_classes.aggregations import Count
6
6
  from cognite.client.data_classes.data_modeling import (
7
+ ContainerId,
7
8
  ContainerList,
8
9
  EdgeApply,
9
10
  NodeApply,
10
11
  SpaceList,
12
+ ViewId,
11
13
  ViewList,
12
14
  )
13
15
  from cognite.client.data_classes.data_modeling.instances import Instance, InstanceApply
14
16
  from cognite.client.utils._identifier import InstanceId
15
17
 
18
+ from cognite_toolkit._cdf_tk import constants
16
19
  from cognite_toolkit._cdf_tk.client import ToolkitClient
17
- from cognite_toolkit._cdf_tk.client.data_classes.instances import InstanceList
20
+ from cognite_toolkit._cdf_tk.client.data_classes.legacy.instances import InstanceList
18
21
  from cognite_toolkit._cdf_tk.cruds import ContainerCRUD, SpaceCRUD, ViewCRUD
19
22
  from cognite_toolkit._cdf_tk.utils import sanitize_filename
20
23
  from cognite_toolkit._cdf_tk.utils.cdf import iterate_instances
@@ -54,10 +57,35 @@ class InstanceIO(
54
57
  def __init__(self, client: ToolkitClient, remove_existing_version: bool = True) -> None:
55
58
  super().__init__(client)
56
59
  self._remove_existing_version = remove_existing_version
60
+ # Cache for view to read-only properties mapping
61
+ self._view_readonly_properties_cache: dict[ViewId, set[str]] = {}
62
+ self._view_crud = ViewCRUD.create_loader(self.client)
57
63
 
58
64
  def as_id(self, item: Instance) -> str:
59
65
  return f"{item.space}:{item.external_id}"
60
66
 
67
+ def _filter_readonly_properties(self, instance: InstanceApply) -> None:
68
+ """
69
+ Filter out read-only properties from the instance.
70
+
71
+ Args:
72
+ instance: The instance to filter readonly properties from
73
+ """
74
+
75
+ for source in instance.sources:
76
+ readonly_properties = set()
77
+ if isinstance(source.source, ViewId):
78
+ if source.source not in self._view_readonly_properties_cache:
79
+ self._view_readonly_properties_cache[source.source] = self._view_crud.get_readonly_properties(
80
+ source.source
81
+ )
82
+ readonly_properties = self._view_readonly_properties_cache[source.source]
83
+ elif isinstance(source.source, ContainerId):
84
+ if source.source in constants.READONLY_CONTAINER_PROPERTIES:
85
+ readonly_properties = constants.READONLY_CONTAINER_PROPERTIES[source.source]
86
+
87
+ source.properties = {k: v for k, v in source.properties.items() if k not in readonly_properties}
88
+
61
89
  def stream_data(self, selector: InstanceSelector, limit: int | None = None) -> Iterable[Page]:
62
90
  if isinstance(selector, InstanceViewSelector | InstanceSpaceSelector):
63
91
  chunk = InstanceList([])
@@ -133,12 +161,16 @@ class InstanceIO(
133
161
  item_to_load = dict(item_json)
134
162
  if self._remove_existing_version and "existingVersion" in item_to_load:
135
163
  del item_to_load["existingVersion"]
164
+ instance: InstanceApply
136
165
  if instance_type == "node":
137
- return NodeApply._load(item_to_load, cognite_client=self.client)
166
+ instance = NodeApply._load(item_to_load, cognite_client=self.client)
138
167
  elif instance_type == "edge":
139
- return EdgeApply._load(item_to_load, cognite_client=self.client)
168
+ instance = EdgeApply._load(item_to_load, cognite_client=self.client)
140
169
  else:
141
170
  raise ValueError(f"Unknown instance type {instance_type!r}")
171
+ # Filter out read-only properties if applicable
172
+ self._filter_readonly_properties(instance)
173
+ return instance
142
174
 
143
175
  def configurations(self, selector: InstanceSelector) -> Iterable[StorageIOConfig]:
144
176
  if not isinstance(selector, InstanceViewSelector | InstanceSpaceSelector):
@@ -1,4 +1,5 @@
1
1
  from collections.abc import Iterable, Sequence
2
+ from itertools import chain
2
3
  from uuid import uuid4
3
4
 
4
5
  from cognite.client.data_classes import Row, RowWrite
@@ -6,6 +7,8 @@ from cognite.client.data_classes import Row, RowWrite
6
7
  from cognite_toolkit._cdf_tk.cruds import RawDatabaseCRUD, RawTableCRUD
7
8
  from cognite_toolkit._cdf_tk.exceptions import ToolkitValueError
8
9
  from cognite_toolkit._cdf_tk.utils import sanitize_filename
10
+ from cognite_toolkit._cdf_tk.utils.collection import chunker
11
+ from cognite_toolkit._cdf_tk.utils.fileio import MultiFileReader
9
12
  from cognite_toolkit._cdf_tk.utils.http_client import HTTPClient, HTTPMessage, ItemsRequest
10
13
  from cognite_toolkit._cdf_tk.utils.useful_types import JsonVal
11
14
 
@@ -96,3 +99,26 @@ class RawIO(
96
99
  if selector is not None and selector.key is not None and selector.key in row:
97
100
  key = str(row.pop(selector.key))
98
101
  return RowWrite(key=key, columns=row)
102
+
103
+ @classmethod
104
+ def read_chunks(
105
+ cls, reader: MultiFileReader, selector: RawTableSelector
106
+ ) -> Iterable[list[tuple[str, dict[str, JsonVal]]]]:
107
+ if not reader.is_table or selector.key is None:
108
+ yield from super().read_chunks(reader, selector)
109
+ return
110
+ data_name = "row" if reader.is_table else "line"
111
+ # Validate that the key exists in all files
112
+ for input_file in sorted(reader.input_files, key=reader._part_no):
113
+ iterable = reader.reader_class(input_file).read_chunks()
114
+ try:
115
+ first = next(iterable)
116
+ except StopIteration:
117
+ continue
118
+ if selector.key not in first:
119
+ raise ToolkitValueError(
120
+ f"Column '{selector.key}' not found in file {input_file.as_posix()!r}. Please ensure the specified column exists."
121
+ )
122
+ full_iterator = chain([first], iterable)
123
+ line_numbered_iterator = ((f"{data_name} {i}", row) for i, row in enumerate(full_iterator, start=1))
124
+ yield from chunker(line_numbered_iterator, cls.CHUNK_SIZE)
@@ -1,18 +1,35 @@
1
+ from pathlib import Path
1
2
  from typing import Annotated
2
3
 
3
- from pydantic import Field, TypeAdapter
4
+ from pydantic import Field, TypeAdapter, ValidationError
5
+
6
+ from cognite_toolkit._cdf_tk.feature_flags import Flags
7
+ from cognite_toolkit._cdf_tk.tk_warnings import MediumSeverityWarning, ToolkitWarning
8
+ from cognite_toolkit._cdf_tk.tk_warnings.fileread import ResourceFormatWarning
9
+ from cognite_toolkit._cdf_tk.utils.file import read_yaml_file
10
+ from cognite_toolkit._cdf_tk.validation import humanize_validation_error
4
11
 
5
12
  from ._asset_centric import AssetCentricFileSelector, AssetCentricSelector, AssetSubtreeSelector, DataSetSelector
6
13
  from ._base import DataSelector
7
- from ._canvas import CanvasSelector
8
- from ._charts import AllChartsSelector, ChartOwnerSelector, ChartSelector
14
+ from ._canvas import CanvasExternalIdSelector, CanvasSelector
15
+ from ._charts import AllChartsSelector, ChartExternalIdSelector, ChartOwnerSelector, ChartSelector
9
16
  from ._datapoints import (
17
+ DataPointsDataSetSelector,
10
18
  DataPointsFileSelector,
19
+ DataPointsSelector,
11
20
  ExternalIdColumn,
12
21
  InstanceColumn,
13
22
  InternalIdColumn,
14
23
  TimeSeriesColumn,
15
24
  )
25
+ from ._file_content import (
26
+ FileContentSelector,
27
+ FileDataModelingTemplate,
28
+ FileDataModelingTemplateSelector,
29
+ FileIdentifierSelector,
30
+ FileMetadataTemplate,
31
+ FileMetadataTemplateSelector,
32
+ )
16
33
  from ._instances import (
17
34
  InstanceFileSelector,
18
35
  InstanceSelector,
@@ -21,9 +38,12 @@ from ._instances import (
21
38
  SelectedView,
22
39
  )
23
40
  from ._raw import RawTableSelector, SelectedTable
41
+ from ._three_d import ThreeDModelFilteredSelector, ThreeDModelIdSelector, ThreeDSelector
24
42
 
25
43
  Selector = Annotated[
26
44
  RawTableSelector
45
+ | ThreeDModelIdSelector
46
+ | ThreeDModelFilteredSelector
27
47
  | InstanceViewSelector
28
48
  | InstanceFileSelector
29
49
  | InstanceSpaceSelector
@@ -32,25 +52,69 @@ Selector = Annotated[
32
52
  | AssetSubtreeSelector
33
53
  | AssetCentricFileSelector
34
54
  | DataSetSelector
35
- | DataPointsFileSelector,
55
+ | DataPointsDataSetSelector
56
+ | DataPointsFileSelector
57
+ | ChartExternalIdSelector
58
+ | CanvasExternalIdSelector
59
+ | FileMetadataTemplateSelector
60
+ | FileDataModelingTemplateSelector
61
+ | FileIdentifierSelector,
36
62
  Field(discriminator="type"),
37
63
  ]
38
64
 
65
+ ALPHA_SELECTORS = {FileIdentifierSelector}
66
+ INTERNAL = {ThreeDModelIdSelector, ThreeDModelFilteredSelector}
39
67
  SelectorAdapter: TypeAdapter[Selector] = TypeAdapter(Selector)
40
68
 
41
69
 
70
+ def load_selector(manifest_file: Path) -> Selector | ToolkitWarning:
71
+ """Loads a selector from a manifest file.
72
+
73
+ Args:
74
+ manifest_file: Path to the manifest file.
75
+
76
+ Returns:
77
+ A selector object or a toolkit warning if loading fails or the selector is an alpha feature that is not enabled.
78
+ """
79
+ selector_dict = read_yaml_file(manifest_file, expected_output="dict")
80
+ try:
81
+ selector = SelectorAdapter.validate_python(selector_dict)
82
+ except ValidationError as e:
83
+ errors = humanize_validation_error(e)
84
+ return ResourceFormatWarning(manifest_file, tuple(errors), text="Invalid selector in metadata file, skipping.")
85
+ if not Flags.EXTEND_UPLOAD.is_enabled() and type(selector) in ALPHA_SELECTORS:
86
+ return MediumSeverityWarning(
87
+ f"Selector type '{type(selector).__name__}' in file '{manifest_file}' is in alpha. To enable it set the alpha flag 'extend-upload = true' in your CDF.toml file."
88
+ )
89
+ elif type(selector) in INTERNAL:
90
+ return MediumSeverityWarning(
91
+ f"Selector type '{type(selector).__name__}' in file '{manifest_file}' is for internal use only and cannot be used."
92
+ )
93
+ return selector
94
+
95
+
42
96
  __all__ = [
43
97
  "AllChartsSelector",
44
98
  "AssetCentricFileSelector",
45
99
  "AssetCentricSelector",
46
100
  "AssetSubtreeSelector",
101
+ "CanvasExternalIdSelector",
47
102
  "CanvasSelector",
103
+ "ChartExternalIdSelector",
48
104
  "ChartOwnerSelector",
49
105
  "ChartSelector",
106
+ "DataPointsDataSetSelector",
50
107
  "DataPointsFileSelector",
108
+ "DataPointsSelector",
51
109
  "DataSelector",
52
110
  "DataSetSelector",
53
111
  "ExternalIdColumn",
112
+ "FileContentSelector",
113
+ "FileDataModelingTemplate",
114
+ "FileDataModelingTemplateSelector",
115
+ "FileIdentifierSelector",
116
+ "FileMetadataTemplate",
117
+ "FileMetadataTemplateSelector",
54
118
  "InstanceColumn",
55
119
  "InstanceFileSelector",
56
120
  "InstanceSelector",
@@ -62,5 +126,8 @@ __all__ = [
62
126
  "SelectedView",
63
127
  "Selector",
64
128
  "SelectorAdapter",
129
+ "ThreeDModelIdSelector",
130
+ "ThreeDSelector",
65
131
  "TimeSeriesColumn",
132
+ "load_selector",
66
133
  ]