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,247 @@
1
+ import gzip
2
+ import sys
3
+ from abc import ABC, abstractmethod
4
+ from collections import UserList
5
+ from collections.abc import Hashable, Sequence
6
+ from typing import Any, Literal
7
+
8
+ import httpx
9
+ from cognite.client import global_config
10
+ from pydantic import BaseModel, ConfigDict, Field, JsonValue, TypeAdapter, model_validator
11
+ from pydantic.alias_generators import to_camel
12
+
13
+ from cognite_toolkit._cdf_tk.utils.http_client._exception import ToolkitAPIError
14
+ from cognite_toolkit._cdf_tk.utils.http_client._tracker import ItemsRequestTracker
15
+ from cognite_toolkit._cdf_tk.utils.useful_types import PrimitiveType
16
+
17
+ if sys.version_info >= (3, 11):
18
+ from typing import Self
19
+ else:
20
+ from typing_extensions import Self
21
+
22
+
23
+ class HTTPResult2(BaseModel):
24
+ def get_success_or_raise(self) -> "SuccessResponse2":
25
+ """Raises an exception if any response in the list indicates a failure."""
26
+ if isinstance(self, SuccessResponse2):
27
+ return self
28
+ elif isinstance(self, FailedResponse2):
29
+ raise ToolkitAPIError(f"Request failed with status code {self.status_code}: {self.error.message}")
30
+ elif isinstance(self, FailedRequest2):
31
+ raise ToolkitAPIError(f"Request failed with error: {self.error}")
32
+ else:
33
+ raise ToolkitAPIError("Unknown HTTPResult2 type")
34
+
35
+
36
+ class FailedRequest2(HTTPResult2):
37
+ error: str
38
+
39
+
40
+ class SuccessResponse2(HTTPResult2):
41
+ status_code: int
42
+ body: str
43
+ content: bytes
44
+
45
+ @property
46
+ def body_json(self) -> dict[str, Any]:
47
+ """Parse the response body as JSON."""
48
+ return TypeAdapter(dict[str, JsonValue]).validate_json(self.body)
49
+
50
+
51
+ class ErrorDetails2(BaseModel):
52
+ """This is the expected structure of error details in the CDF API"""
53
+
54
+ code: int
55
+ message: str
56
+ missing: list[JsonValue] | None = None
57
+ duplicated: list[JsonValue] | None = None
58
+ is_auto_retryable: bool | None = None
59
+
60
+ @classmethod
61
+ def from_response(cls, response: httpx.Response) -> "ErrorDetails2":
62
+ """Populate the error details from a httpx response."""
63
+ try:
64
+ res = TypeAdapter(dict[Literal["error"], ErrorDetails2]).validate_json(response.text)
65
+ except ValueError:
66
+ return cls(code=response.status_code, message=response.text)
67
+ return res["error"]
68
+
69
+
70
+ class FailedResponse2(HTTPResult2):
71
+ status_code: int
72
+ body: str
73
+ error: ErrorDetails2
74
+
75
+
76
+ class BaseRequestMessage(BaseModel, ABC):
77
+ endpoint_url: str
78
+ method: Literal["GET", "POST", "PATCH", "DELETE", "PUT"]
79
+ connect_attempt: int = 0
80
+ read_attempt: int = 0
81
+ status_attempt: int = 0
82
+ api_version: str | None = None
83
+ content_type: str = "application/json"
84
+ accept: str = "application/json"
85
+
86
+ parameters: dict[str, PrimitiveType] | None = None
87
+
88
+ @property
89
+ def total_attempts(self) -> int:
90
+ return self.connect_attempt + self.read_attempt + self.status_attempt
91
+
92
+ @property
93
+ @abstractmethod
94
+ def content(self) -> str | bytes | None: ...
95
+
96
+
97
+ class RequestMessage2(BaseRequestMessage):
98
+ data_content: bytes | None = None
99
+ body_content: dict[str, JsonValue] | None = None
100
+
101
+ @model_validator(mode="before")
102
+ def check_data_or_body(cls, values: dict[str, Any]) -> dict[str, Any]:
103
+ if values.get("data_content") is not None and values.get("body_content") is not None:
104
+ raise ValueError("Only one of data_content or body_content can be set.")
105
+ return values
106
+
107
+ @property
108
+ def content(self) -> str | bytes | None:
109
+ data: str | bytes | None = None
110
+ if self.data_content is not None:
111
+ data = self.data_content
112
+ if not global_config.disable_gzip:
113
+ data = gzip.compress(data)
114
+ elif self.body_content is not None:
115
+ # We serialize using pydantic instead of json.dumps. This is because pydantic is faster
116
+ # and handles more complex types such as datetime, float('nan'), etc.
117
+ data = _BODY_SERIALIZER.dump_json(self.body_content)
118
+ if not global_config.disable_gzip and isinstance(data, bytes):
119
+ data = gzip.compress(data)
120
+ return data
121
+
122
+
123
+ _BODY_SERIALIZER = TypeAdapter(dict[str, JsonValue])
124
+
125
+
126
+ class ItemsResultMessage2(BaseModel):
127
+ ids: list[Hashable]
128
+
129
+
130
+ class ItemsFailedRequest2(ItemsResultMessage2):
131
+ error_message: str
132
+
133
+
134
+ class ItemsSuccessResponse2(ItemsResultMessage2):
135
+ status_code: int
136
+ body: str
137
+ content: bytes
138
+
139
+
140
+ class ItemsFailedResponse2(ItemsResultMessage2):
141
+ status_code: int
142
+ error: ErrorDetails2
143
+ body: str
144
+
145
+
146
+ class BaseModelObject(BaseModel):
147
+ """Base class for all object. This includes resources and nested objects."""
148
+
149
+ # We allow extra fields to support forward compatibility.
150
+ model_config = ConfigDict(alias_generator=to_camel, extra="allow")
151
+
152
+ def dump(self, camel_case: bool = True) -> dict[str, Any]:
153
+ """Dump the resource to a dictionary.
154
+
155
+ This is the default serialization method for request resources.
156
+ """
157
+ return self.model_dump(mode="json", by_alias=camel_case, exclude_unset=True)
158
+
159
+ @classmethod
160
+ def _load(cls, resource: dict[str, Any]) -> "Self":
161
+ """Load method to match CogniteResource signature."""
162
+ return cls.model_validate(resource)
163
+
164
+
165
+ class RequestResource(BaseModelObject, ABC):
166
+ @abstractmethod
167
+ def as_id(self) -> Hashable: ...
168
+
169
+
170
+ def _set_default_tracker(data: dict[str, Any]) -> ItemsRequestTracker:
171
+ if "tracker" not in data or data["tracker"] is None:
172
+ return ItemsRequestTracker(data.get("max_failures_before_abort", 50))
173
+ return data["tracker"]
174
+
175
+
176
+ class ItemsRequest2(BaseRequestMessage):
177
+ model_config = ConfigDict(arbitrary_types_allowed=True)
178
+ items: Sequence[RequestResource]
179
+ extra_body_fields: dict[str, JsonValue] | None = None
180
+ max_failures_before_abort: int = 50
181
+ tracker: ItemsRequestTracker = Field(init=False, default_factory=_set_default_tracker, exclude=True)
182
+
183
+ @property
184
+ def content(self) -> str | bytes | None:
185
+ body: dict[str, JsonValue] = {"items": [item.dump() for item in self.items]}
186
+ if self.extra_body_fields:
187
+ body.update(self.extra_body_fields)
188
+ res = _BODY_SERIALIZER.dump_json(body)
189
+ if not global_config.disable_gzip and isinstance(res, bytes):
190
+ return gzip.compress(res)
191
+ return res
192
+
193
+ def split(self, status_attempts: int) -> list["ItemsRequest2"]:
194
+ """Split the request into multiple requests with a single item each."""
195
+ mid = len(self.items) // 2
196
+ if mid == 0:
197
+ return [self]
198
+ self.tracker.register_failure()
199
+ messages: list[ItemsRequest2] = []
200
+ for part in (self.items[:mid], self.items[mid:]):
201
+ new_request = self.model_copy(update={"items": part, "status_attempt": status_attempts})
202
+ new_request.tracker = self.tracker
203
+ messages.append(new_request)
204
+ return messages
205
+
206
+
207
+ class ItemResponse(BaseModel):
208
+ items: list[dict[str, JsonValue]]
209
+
210
+
211
+ class ItemsResultList(UserList[ItemsResultMessage2]):
212
+ def __init__(self, collection: Sequence[ItemsResultMessage2] | None = None) -> None:
213
+ super().__init__(collection or [])
214
+
215
+ def raise_for_status(self) -> None:
216
+ """Raises an exception if any response in the list indicates a failure."""
217
+ failed_responses = [resp for resp in self.data if isinstance(resp, ItemsFailedResponse2)]
218
+ failed_requests = [resp for resp in self.data if isinstance(resp, ItemsFailedRequest2)]
219
+ if not failed_responses and not failed_requests:
220
+ return
221
+ error_messages = "; ".join(f"Status {err.status_code}: {err.error.message}" for err in failed_responses)
222
+ if failed_requests:
223
+ if error_messages:
224
+ error_messages += "; "
225
+ error_messages += "; ".join(f"Request error: {err.error_message}" for err in failed_requests)
226
+ raise ToolkitAPIError(f"One or more requests failed: {error_messages}")
227
+
228
+ @property
229
+ def has_failed(self) -> bool:
230
+ """Indicates whether any response in the list indicates a failure.
231
+
232
+ Returns:
233
+ bool: True if there are any failed responses or requests, False otherwise.
234
+ """
235
+ for resp in self.data:
236
+ if isinstance(resp, ItemsFailedResponse2 | ItemsFailedRequest2):
237
+ return True
238
+ return False
239
+
240
+ def get_items(self) -> list[dict[str, JsonValue]]:
241
+ """Get the items from all successful responses."""
242
+ items: list[dict[str, JsonValue]] = []
243
+ for resp in self.data:
244
+ if isinstance(resp, ItemsSuccessResponse2):
245
+ body_json = ItemResponse.model_validate_json(resp.body)
246
+ items.extend(body_json.items)
247
+ return items
@@ -1,5 +1,6 @@
1
1
  import threading
2
2
  from dataclasses import dataclass, field
3
+ from typing import Any
3
4
 
4
5
 
5
6
  @dataclass
@@ -9,13 +10,15 @@ class ItemsRequestTracker:
9
10
  Attributes:
10
11
  max_failures_before_abort (int): Maximum number of allowed failed split requests before aborting
11
12
  the entire operation. A value of -1 indicates no early abort.
12
- lock (threading.Lock): A lock to ensure thread-safe updates to the failure count.
13
+ lock (Any): A lock to ensure thread-safe updates to the failure count.
13
14
  failed_split_count (int): The current count of failed split requests.
14
15
 
15
16
  """
16
17
 
17
18
  max_failures_before_abort: int = -1 # -1 means no early abort
18
- lock: threading.Lock = field(default_factory=threading.Lock, init=False)
19
+ # NOTE: `threading.Lock` is a factory function (backed by `_thread.allocate_lock`), not a type.
20
+ # Annotate as `Any` so Pydantic won't attempt to generate a schema for the lock field.
21
+ lock: Any = field(default_factory=threading.Lock, init=False)
19
22
  failed_split_count: int = field(default=0, init=False)
20
23
 
21
24
  def register_failure(self) -> None:
@@ -14,9 +14,6 @@ from cognite.client.data_classes import (
14
14
  filters,
15
15
  )
16
16
  from cognite.client.data_classes.aggregations import Count
17
- from cognite.client.data_classes.capabilities import (
18
- UserProfilesAcl,
19
- )
20
17
  from cognite.client.data_classes.data_modeling import ContainerId, NodeList, Space, SpaceList, View, ViewId, ViewList
21
18
  from cognite.client.data_classes.data_modeling.statistics import SpaceStatistics
22
19
  from cognite.client.utils import ms_to_datetime
@@ -24,11 +21,12 @@ from questionary import Choice
24
21
  from rich.console import Console
25
22
 
26
23
  from cognite_toolkit._cdf_tk.client import ToolkitClient
27
- from cognite_toolkit._cdf_tk.client.data_classes.canvas import Canvas
28
- from cognite_toolkit._cdf_tk.client.data_classes.charts import Chart, ChartList, Visibility
29
- from cognite_toolkit._cdf_tk.client.data_classes.migration import ResourceViewMapping
30
- from cognite_toolkit._cdf_tk.client.data_classes.raw import RawTable
31
- from cognite_toolkit._cdf_tk.exceptions import AuthorizationError, ToolkitMissingResourceError, ToolkitValueError
24
+ from cognite_toolkit._cdf_tk.client.data_classes.legacy.canvas import Canvas
25
+ from cognite_toolkit._cdf_tk.client.data_classes.legacy.charts import Chart, ChartList, Visibility
26
+ from cognite_toolkit._cdf_tk.client.data_classes.legacy.migration import ResourceViewMapping
27
+ from cognite_toolkit._cdf_tk.client.data_classes.legacy.raw import RawTable
28
+ from cognite_toolkit._cdf_tk.client.data_classes.three_d import ThreeDModelResponse
29
+ from cognite_toolkit._cdf_tk.exceptions import ToolkitMissingResourceError, ToolkitValueError
32
30
 
33
31
  from . import humanize_collection
34
32
  from .aggregators import (
@@ -309,9 +307,14 @@ class InteractiveCanvasSelect:
309
307
  opening_choices: ClassVar[list[questionary.Choice]] = [
310
308
  questionary.Choice(title="All public Canvases", value=CanvasFilter(visibility="public", select_all=True)),
311
309
  questionary.Choice(title="Selected public Canvases", value=CanvasFilter(visibility="public", select_all=False)),
312
- questionary.Choice(title="All by given user", value=CanvasFilter(created_by="user", select_all=True)),
313
- questionary.Choice(title="Selected by given user", value=CanvasFilter(created_by="user", select_all=False)),
314
- questionary.Choice(title="All Canvases", value=CanvasFilter(visibility=None, select_all=True)),
310
+ questionary.Choice(
311
+ title="All public Canvases by given user",
312
+ value=CanvasFilter(created_by="user", select_all=True, visibility="public"),
313
+ ),
314
+ questionary.Choice(
315
+ title="Selected public Canvases by given user",
316
+ value=CanvasFilter(created_by="user", select_all=False, visibility="public"),
317
+ ),
315
318
  ]
316
319
 
317
320
  def __init__(self, client: ToolkitClient) -> None:
@@ -406,13 +409,6 @@ class InteractiveChartSelect:
406
409
  return user_response
407
410
 
408
411
  def _select_external_ids(self, select_filter: ChartFilter) -> list[str]:
409
- if not self.client.iam.verify_capabilities(
410
- UserProfilesAcl([UserProfilesAcl.Action.Read], scope=UserProfilesAcl.Scope.All())
411
- ):
412
- raise AuthorizationError(
413
- "The current user does not have permission to list user profiles, "
414
- "which is required to select Charts owned by a specific user."
415
- )
416
412
  available_charts = self.client.charts.list(visibility=(select_filter.visibility or "PUBLIC"))
417
413
  if select_filter.select_all and select_filter.owned_by is None:
418
414
  return [chart.external_id for chart in available_charts]
@@ -828,3 +824,49 @@ class ResourceViewMappingInteractiveSelect:
828
824
  f"Selected Resource View Mapping is not a valid ResourceViewMapping object: {selected_mapping!r}"
829
825
  )
830
826
  return selected_mapping
827
+
828
+
829
+ class ThreeDInteractiveSelect:
830
+ def __init__(self, client: ToolkitClient, operation: str) -> None:
831
+ self.client = client
832
+ self.operation = operation
833
+
834
+ def select_three_d_models(self, model_type: Literal["classic", "dm"] | None = None) -> list[ThreeDModelResponse]:
835
+ """Select multiple 3D models interactively."""
836
+ if model_type is None:
837
+ model_type = questionary.select(
838
+ f"What type of 3D models do you want to {self.operation}?",
839
+ choices=[
840
+ Choice(title="Classic models", value="classic"),
841
+ Choice(title="Data modeling 3D", value="dm"),
842
+ ],
843
+ ).ask()
844
+ if model_type is None:
845
+ raise ToolkitValueError("No 3D model type selected.")
846
+ published = questionary.select(
847
+ f"Do you want to {self.operation} published or unpublished 3D models?",
848
+ choices=[
849
+ Choice(title="Published models", value=True),
850
+ Choice(title="Unpublished models", value=False),
851
+ Choice(title="Both published and unpublished models", value=None),
852
+ ],
853
+ ).ask()
854
+
855
+ models = self.client.tool.three_d.models.list(published=published, include_revision_info=True, limit=None)
856
+ if model_type == "classic":
857
+ models = [model for model in models if model.space is None]
858
+ else:
859
+ models = [model for model in models if model.space is not None]
860
+ if not models:
861
+ raise ToolkitMissingResourceError(
862
+ f"No 3D models found for type {model_type!r} with published={published!r}."
863
+ )
864
+
865
+ choices = [Choice(title=f"{model.name} ({model.id})", value=model) for model in models]
866
+ selected_models = questionary.checkbox(
867
+ f"Select 3D models to {self.operation}:",
868
+ choices=choices,
869
+ ).ask()
870
+ if selected_models is None or len(selected_models) == 0:
871
+ raise ToolkitValueError("No 3D models selected.")
872
+ return selected_models
@@ -1,12 +1,11 @@
1
1
  import importlib.util
2
+ from dataclasses import dataclass
2
3
  from typing import TYPE_CHECKING
3
4
 
4
5
  from cognite_toolkit._cdf_tk.exceptions import ToolkitMissingDependencyError
5
6
 
6
7
  if TYPE_CHECKING:
7
- from sqlparse.sql import Identifier
8
- from sqlparse.tokens import Token
9
- from dataclasses import dataclass
8
+ from sqlparse.sql import Identifier, Token
10
9
 
11
10
 
12
11
  @dataclass(frozen=True)
@@ -8,10 +8,13 @@ from cognite.client.data_classes._base import CogniteObject, WriteableCogniteRes
8
8
  JsonVal: TypeAlias = None | str | int | float | bool | dict[str, "JsonVal"] | list["JsonVal"]
9
9
 
10
10
  AssetCentricDestinationType: TypeAlias = Literal["assets", "files", "events", "timeseries", "sequences"]
11
- AssetCentricType: TypeAlias = Literal["asset", "file", "event", "timeseries", "sequence", "fileAnnotation"]
11
+ AssetCentricType: TypeAlias = Literal["asset", "file", "event", "timeseries", "sequence"]
12
+ AssetCentricTypeExtended: TypeAlias = Literal["asset", "file", "event", "timeseries", "sequence", "annotation"]
12
13
  AssetCentricResource: TypeAlias = Asset | FileMetadata | Event | TimeSeries
13
14
  AssetCentricResourceExtended: TypeAlias = Asset | FileMetadata | Event | TimeSeries | Annotation
14
- AssetCentricKind: TypeAlias = Literal["Assets", "Events", "TimeSeries", "FileMetadata", "FileAnnotations"]
15
+ AssetCentricKind: TypeAlias = Literal["Assets", "Events", "TimeSeries", "FileMetadata"]
16
+ AssetCentricKindExtended: TypeAlias = Literal["Assets", "Events", "TimeSeries", "FileMetadata", "Annotations"]
17
+
15
18
 
16
19
  DataType: TypeAlias = Literal["string", "integer", "float", "boolean", "json", "date", "timestamp", "epoch"]
17
20
  PythonTypes: TypeAlias = str | int | float | bool | datetime | date | dict[str, Any] | list[Any]
@@ -25,3 +28,4 @@ PrimitiveType: TypeAlias = str | int | float | bool
25
28
 
26
29
  T_WriteCogniteResource = TypeVar("T_WriteCogniteResource", bound=CogniteObject)
27
30
  T_AssetCentricResource = TypeVar("T_AssetCentricResource", bound=AssetCentricResource)
31
+ T_AssetCentricResourceExtended = TypeVar("T_AssetCentricResourceExtended", bound=AssetCentricResourceExtended)
@@ -8,18 +8,29 @@ from cognite.client.utils._text import to_snake_case
8
8
  from pydantic import BaseModel, TypeAdapter, ValidationError
9
9
  from pydantic_core import ErrorDetails
10
10
 
11
- from cognite_toolkit._cdf_tk.data_classes import BuildVariables
11
+ from cognite_toolkit._cdf_tk.cdf_toml import CDFToml
12
+ from cognite_toolkit._cdf_tk.constants import DEV_ONLY_MODULES
13
+ from cognite_toolkit._cdf_tk.data_classes import BuildConfigYAML, BuildVariables, ModuleDirectories
14
+ from cognite_toolkit._cdf_tk.exceptions import (
15
+ ToolkitDuplicatedModuleError,
16
+ ToolkitEnvError,
17
+ ToolkitMissingModuleError,
18
+ )
19
+ from cognite_toolkit._cdf_tk.hints import ModuleDefinition
12
20
  from cognite_toolkit._cdf_tk.resource_classes import BaseModelResource
13
21
  from cognite_toolkit._cdf_tk.tk_warnings import (
14
22
  DataSetMissingWarning,
23
+ MediumSeverityWarning,
15
24
  TemplateVariableWarning,
16
25
  WarningList,
17
26
  )
18
27
  from cognite_toolkit._cdf_tk.tk_warnings.fileread import ResourceFormatWarning
28
+ from cognite_toolkit._cdf_tk.utils import humanize_collection
19
29
 
20
30
  __all__ = [
21
31
  "humanize_validation_error",
22
32
  "validate_data_set_is_set",
33
+ "validate_module_selection",
23
34
  "validate_modules_variables",
24
35
  ]
25
36
 
@@ -171,6 +182,10 @@ def humanize_validation_error(error: ValidationError) -> list[str]:
171
182
  "dict_type",
172
183
  }:
173
184
  msg = f"{item['msg']}. Got {item['input']!r} of type {type(item['input']).__name__}."
185
+ elif error_type == "union_tag_not_found" and "ctx" in item and "discriminator" in item["ctx"]:
186
+ # This is when we use a discriminator field to determine the type in a union. For the user, this means they
187
+ # are missing a required field.
188
+ msg = f"Missing required field: {item['ctx']['discriminator']}"
174
189
  else:
175
190
  # Default to the Pydantic error message
176
191
  msg = item["msg"]
@@ -210,3 +225,70 @@ def as_json_path(loc: tuple[str | int, ...]) -> str:
210
225
 
211
226
  suffix = ".".join([str(x) if isinstance(x, str) else f"[{x + 1}]" for x in loc]).replace(".[", "[")
212
227
  return f"{prefix}{suffix}"
228
+
229
+
230
+ def validate_module_selection(
231
+ modules: ModuleDirectories,
232
+ config: BuildConfigYAML,
233
+ packages: dict[str, list[str]],
234
+ selected_modules: set[str | Path],
235
+ organization_dir: Path,
236
+ ) -> WarningList:
237
+ """Validates module selection and returns warnings for non-critical issues.
238
+
239
+ Critical errors (duplicate modules, missing modules, no modules selected) are still raised
240
+ as exceptions as they prevent the build from proceeding.
241
+ """
242
+ warnings: WarningList = WarningList()
243
+
244
+ # Validations: Ambiguous selection.
245
+ selected_names = {s for s in config.environment.selected if isinstance(s, str)}
246
+ if duplicate_modules := {
247
+ module_name: paths
248
+ for module_name, paths in modules.as_path_by_name().items()
249
+ if len(paths) > 1 and module_name in selected_names
250
+ }:
251
+ # If the user has selected a module by name, and there are multiple modules with that name, raise an error.
252
+ # Note, if the user uses a path to select a module, this error will not be raised.
253
+ raise ToolkitDuplicatedModuleError(
254
+ f"Ambiguous module selected in config.{config.environment.name}.yaml:", duplicate_modules
255
+ )
256
+
257
+ # Package Referenced Modules Exists
258
+ for package, package_modules in packages.items():
259
+ if package not in selected_names:
260
+ # We do not check packages that are not selected.
261
+ # Typically, the user will delete the modules that are irrelevant for them;
262
+ # thus we only check the selected packages.
263
+ continue
264
+ if missing_packages := set(package_modules) - modules.available_names:
265
+ raise ToolkitMissingModuleError(
266
+ f"Package {package} defined in {CDFToml.file_name!s} is referring "
267
+ f"the following missing modules {missing_packages}."
268
+ )
269
+
270
+ # Selected modules does not exists
271
+ if missing_modules := set(selected_modules) - modules.available:
272
+ hint = ModuleDefinition.long(missing_modules, organization_dir)
273
+ raise ToolkitMissingModuleError(
274
+ f"The following selected modules are missing, please check path: {missing_modules}.\n{hint}"
275
+ )
276
+
277
+ # Nothing is Selected
278
+ if not modules.selected:
279
+ raise ToolkitEnvError(
280
+ f"No selected modules specified in {config.filepath!s}, have you configured "
281
+ f"the environment ({config.environment.name})?"
282
+ )
283
+
284
+ # Dev modules warning (non-critical)
285
+ dev_modules = modules.available_names & DEV_ONLY_MODULES
286
+ if dev_modules and config.environment.validation_type != "dev":
287
+ warnings.append(
288
+ MediumSeverityWarning(
289
+ "The following modules should [bold]only[/bold] be used a in CDF Projects designated as dev (development): "
290
+ f"{humanize_collection(dev_modules)!r}",
291
+ )
292
+ )
293
+
294
+ return warnings
@@ -12,7 +12,7 @@ jobs:
12
12
  environment: dev
13
13
  name: Deploy
14
14
  container:
15
- image: cognite/toolkit:0.6.97
15
+ image: cognite/toolkit:0.7.39
16
16
  env:
17
17
  CDF_CLUSTER: ${{ vars.CDF_CLUSTER }}
18
18
  CDF_PROJECT: ${{ vars.CDF_PROJECT }}
@@ -10,7 +10,7 @@ jobs:
10
10
  environment: dev
11
11
  name: Deploy Dry Run
12
12
  container:
13
- image: cognite/toolkit:0.6.97
13
+ image: cognite/toolkit:0.7.39
14
14
  env:
15
15
  CDF_CLUSTER: ${{ vars.CDF_CLUSTER }}
16
16
  CDF_PROJECT: ${{ vars.CDF_PROJECT }}
@@ -4,13 +4,14 @@ default_env = "<DEFAULT_ENV_PLACEHOLDER>"
4
4
  [modules]
5
5
  # This is the version of the modules. It should not be changed manually.
6
6
  # It will be updated by the 'cdf modules upgrade' command.
7
- version = "0.6.97"
7
+ version = "0.7.39"
8
8
 
9
- [alpha_flags]
10
- external-libraries = true
11
9
 
12
10
  [plugins]
13
- run = true
11
+ dump = false
12
+ dev = false
13
+ data = false
14
+
14
15
 
15
16
  [library.toolkit-data]
16
17
  url = "https://github.com/cognitedata/toolkit-data/releases/download/latest/packages.zip"
@@ -1 +1 @@
1
- __version__ = "0.6.97"
1
+ __version__ = "0.7.39"
@@ -0,0 +1,13 @@
1
+ environment:
2
+ name: dev
3
+ project: infield-experimental-test-aws
4
+ validation-type: dev
5
+ selected:
6
+ - modules/eriks-location
7
+
8
+ variables:
9
+ modules:
10
+ eriks-location:
11
+ - location: erik-infield-cdm2
12
+ location_name: Oslo CDM - Erik tookit
13
+ location_description: Used to test toolkit ingestion for InField cdm
@@ -1,38 +1,38 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cognite_toolkit
3
- Version: 0.6.97
3
+ Version: 0.7.39
4
4
  Summary: Official Cognite Data Fusion tool for project templates and configuration deployment
5
- Project-URL: Homepage, https://docs.cognite.com/cdf/deploy/cdf_toolkit/
6
- Project-URL: Changelog, https://github.com/cognitedata/toolkit/releases
7
- Project-URL: GitHub, https://github.com/cognitedata/toolkit
8
- Project-URL: Documentation, https://docs.cognite.com/cdf/deploy/cdf_toolkit/references/resource_library
5
+ Author: Cognite AS
9
6
  Author-email: Cognite AS <support@cognite.com>
10
7
  License-Expression: Apache-2.0
11
- License-File: LICENSE
12
- Requires-Python: >=3.10
13
- Requires-Dist: cognite-sdk<8.0.0,>=7.83.0
14
- Requires-Dist: filelock>=3.18.0
15
- Requires-Dist: httpx>=0.28.1
16
- Requires-Dist: mixpanel>=4.10.1
17
- Requires-Dist: packaging>=25
18
- Requires-Dist: pandas<3.0.0,>=1.5.3
19
- Requires-Dist: pip>=25.0.1
20
- Requires-Dist: pydantic>=2.11.0
21
- Requires-Dist: python-dateutil>=2.9.0
22
8
  Requires-Dist: python-dotenv>=1.0.0
9
+ Requires-Dist: cognite-sdk>=7.87.0,<8.0.0
10
+ Requires-Dist: httpx>=0.28.1
11
+ Requires-Dist: pandas>=1.5.3,<3.0.0
23
12
  Requires-Dist: pyyaml>=6.0.1
24
- Requires-Dist: questionary>=2.0.1
13
+ Requires-Dist: typer>=0.12.0,<1.0.0
25
14
  Requires-Dist: rich>=13.9.4
26
- Requires-Dist: sentry-sdk>=2.1.0
27
- Requires-Dist: toml>=0.10.2
28
- Requires-Dist: tomli<3.0.0,>=2.0.1; python_version < '3.11'
29
- Requires-Dist: typer<1.0.0,>=0.12.0
15
+ Requires-Dist: questionary>=2.0.1
16
+ Requires-Dist: tomli>=2.0.1,<3.0.0 ; python_full_version < '3.11'
17
+ Requires-Dist: packaging>=25
30
18
  Requires-Dist: typing-extensions>=4.0.0
19
+ Requires-Dist: toml>=0.10.2
20
+ Requires-Dist: sentry-sdk>=2.1.0
21
+ Requires-Dist: mixpanel>=4.10.1
22
+ Requires-Dist: pydantic>=2.11.0
23
+ Requires-Dist: python-dateutil>=2.9.0
24
+ Requires-Dist: pip>=25.0.1
25
+ Requires-Dist: filelock>=3.18.0
26
+ Requires-Dist: sqlparse>=0.5.3 ; extra == 'sql'
27
+ Requires-Dist: pyarrow>=20.0.0 ; extra == 'table'
28
+ Requires-Dist: openpyxl>=3.1.5 ; extra == 'table'
29
+ Requires-Python: >=3.10
30
+ Project-URL: Changelog, https://github.com/cognitedata/toolkit/releases
31
+ Project-URL: Documentation, https://docs.cognite.com/cdf/deploy/cdf_toolkit/references/resource_library
32
+ Project-URL: GitHub, https://github.com/cognitedata/toolkit
33
+ Project-URL: Homepage, https://docs.cognite.com/cdf/deploy/cdf_toolkit/
31
34
  Provides-Extra: sql
32
- Requires-Dist: sqlparse>=0.5.3; extra == 'sql'
33
35
  Provides-Extra: table
34
- Requires-Dist: openpyxl>=3.1.5; extra == 'table'
35
- Requires-Dist: pyarrow>=20.0.0; extra == 'table'
36
36
  Description-Content-Type: text/markdown
37
37
 
38
38
  # Cognite Data Fusion Toolkit