cognite-toolkit 0.7.27__py3-none-any.whl → 0.7.29__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.
@@ -35,19 +35,26 @@ class ToolAPI:
35
35
 
36
36
 
37
37
  class ToolkitClient(CogniteClient):
38
- def __init__(self, config: ToolkitClientConfig | None = None, enable_set_pending_ids: bool = False) -> None:
38
+ def __init__(
39
+ self,
40
+ config: ToolkitClientConfig | None = None,
41
+ enable_set_pending_ids: bool = False,
42
+ console: Console | None = None,
43
+ ) -> None:
39
44
  super().__init__(config=config)
40
45
  http_client = HTTPClient(self.config)
41
46
  self.http_client = http_client
42
47
  toolkit_config = ToolkitClientConfig.from_client_config(self.config)
43
- self.console = Console()
48
+ self.console = console or Console()
44
49
  self.tool = ToolAPI(http_client, self.console)
45
50
  self.search = SearchAPI(self._config, self._API_VERSION, self)
46
51
  self.robotics = RoboticsAPI(self._config, self._API_VERSION, self)
47
52
  self.dml = DMLAPI(self._config, self._API_VERSION, self)
48
53
  self.verify = VerifyAPI(self._config, self._API_VERSION, self)
49
54
  self.lookup = LookUpGroup(self._config, self._API_VERSION, self, self.console)
50
- self.functions: ExtendedFunctionsAPI = ExtendedFunctionsAPI(toolkit_config, self._API_VERSION, self)
55
+ self.functions: ExtendedFunctionsAPI = ExtendedFunctionsAPI(
56
+ toolkit_config, self._API_VERSION, self, self.console
57
+ )
51
58
  self.data_modeling: ExtendedDataModelingAPI = ExtendedDataModelingAPI(self._config, self._API_VERSION, self)
52
59
  if enable_set_pending_ids:
53
60
  self.time_series: ExtendedTimeSeriesAPI = ExtendedTimeSeriesAPI(self._config, self._API_VERSION, self)
@@ -17,15 +17,16 @@ class ExtendedFunctionsAPI(FunctionsAPI):
17
17
  config: ToolkitClientConfig,
18
18
  api_version: str | None,
19
19
  cognite_client: CogniteClient,
20
+ console: Console | None = None,
20
21
  ) -> None:
21
22
  """
22
23
  Extended Functions API to include custom headers and payload preparation.
23
24
  """
24
25
  super().__init__(config, api_version, cognite_client)
25
26
  self._toolkit_config = config
26
- self._toolkit_http_client = HTTPClient(config, max_retries=global_config.max_retries)
27
+ self._toolkit_http_client = HTTPClient(config, max_retries=global_config.max_retries, console=console)
27
28
 
28
- def create_with_429_retry(self, function: FunctionWrite, console: Console | None = None) -> Function:
29
+ def create_with_429_retry(self, function: FunctionWrite) -> Function:
29
30
  """Create a function with manual retry handling for 429 Too Many Requests responses.
30
31
 
31
32
  This method is a workaround for scenarios where the function creation API is temporarily unavailable
@@ -43,16 +44,13 @@ class ExtendedFunctionsAPI(FunctionsAPI):
43
44
  endpoint_url=self._toolkit_config.create_api_url("/functions"),
44
45
  method="POST",
45
46
  body_content={"items": [function.dump(camel_case=True)]},
46
- ),
47
- console=console,
47
+ )
48
48
  )
49
49
  result.raise_for_status()
50
50
  # We assume the API response is one item on a successful creation
51
51
  return Function._load(result.get_first_body()["items"][0], cognite_client=self._cognite_client) # type: ignore[arg-type,index]
52
52
 
53
- def delete_with_429_retry(
54
- self, external_id: SequenceNotStr[str], ignore_unknown_ids: bool = False, console: Console | None = None
55
- ) -> None:
53
+ def delete_with_429_retry(self, external_id: SequenceNotStr[str], ignore_unknown_ids: bool = False) -> None:
56
54
  """Delete one or more functions with retry handling for 429 Too Many Requests responses.
57
55
 
58
56
  This method is an improvement over the standard delete method in the FunctionsAPI.
@@ -77,7 +75,6 @@ class ExtendedFunctionsAPI(FunctionsAPI):
77
75
  endpoint_url=self._toolkit_config.create_api_url("/functions/delete"),
78
76
  method="POST",
79
77
  body_content=body_content,
80
- ),
81
- console=console,
78
+ )
82
79
  ).raise_for_status()
83
80
  return None
@@ -36,7 +36,7 @@ class ChartCore(WriteableCogniteResource["ChartWrite"], ABC):
36
36
  def dump(self, camel_case: bool = True) -> dict[str, Any]:
37
37
  """Convert the chart to a dictionary representation."""
38
38
  output = super().dump(camel_case=camel_case)
39
- output["data"] = self.data.dump(camel_case=camel_case)
39
+ output["data"] = self.data.model_dump(mode="json", by_alias=camel_case, exclude_unset=True)
40
40
  return output
41
41
 
42
42
 
@@ -58,7 +58,7 @@ class ChartWrite(ChartCore):
58
58
  return cls(
59
59
  external_id=resource["externalId"],
60
60
  visibility=resource["visibility"],
61
- data=ChartData._load(resource["data"], cognite_client=cognite_client),
61
+ data=ChartData._load(resource["data"]),
62
62
  )
63
63
 
64
64
 
@@ -98,7 +98,7 @@ class Chart(ChartCore):
98
98
  created_time=resource["createdTime"],
99
99
  last_updated_time=resource["lastUpdatedTime"],
100
100
  visibility=resource["visibility"],
101
- data=ChartData._load(resource["data"], cognite_client=cognite_client),
101
+ data=ChartData._load(resource["data"]),
102
102
  owner_id=resource["ownerId"],
103
103
  )
104
104
 
@@ -1,70 +1,30 @@
1
- import sys
2
- from dataclasses import dataclass, field, fields
3
- from functools import lru_cache
4
1
  from typing import Any
5
2
 
6
- from cognite.client import CogniteClient
7
- from cognite.client.data_classes._base import CogniteObject
8
3
  from cognite.client.data_classes.data_modeling import NodeId, ViewId
9
- from cognite.client.utils._auxiliary import to_camel_case
4
+ from pydantic import JsonValue, field_serializer, field_validator
10
5
 
11
- if sys.version_info >= (3, 11):
12
- from typing import Self
13
- else:
14
- from typing_extensions import Self
6
+ from .base import BaseModelObject
15
7
 
16
8
 
17
- @dataclass
18
- class ChartObject(CogniteObject):
19
- # ChartObjects are used in the frontend and the backend does not do any validation of these fields.
20
- # Therefore, to ensure that we do not lose any data, we store unknown fields in a separate dictionary.
21
- # This allows unknown fields to be preserved when loading and dumping ChartObjects
22
- # (serialization and deserialization).
23
- _unknown_fields: dict[str, object] | None = field(default=None, init=False, repr=False)
24
-
25
- @classmethod
26
- def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self:
27
- """Load a ChartObject from a dictionary."""
28
- instance = super()._load(resource, cognite_client=cognite_client)
29
- instance._unknown_fields = {k: v for k, v in resource.items() if k not in cls._known_camel_case_props()}
30
- return instance
31
-
32
- @classmethod
33
- @lru_cache(maxsize=1)
34
- def _known_camel_case_props(cls) -> set[str]:
35
- return {to_camel_case(f.name) for f in fields(cls)}
36
-
37
- def dump(self, camel_case: bool = True) -> dict[str, Any]:
38
- """Dump the ChartObject to a dictionary."""
39
- data = super().dump(camel_case=camel_case)
40
- if self._unknown_fields:
41
- data.update(self._unknown_fields)
42
- return data
43
-
44
-
45
- @dataclass
46
- class UserInfo(ChartObject):
9
+ class UserInfo(BaseModelObject):
47
10
  id: str | None = None
48
11
  email: str | None = None
49
12
  display_name: str | None = None
50
13
 
51
14
 
52
- @dataclass
53
- class ChartSettings(ChartObject):
15
+ class ChartSettings(BaseModelObject):
54
16
  show_y_axis: bool = True
55
17
  show_min_max: bool = True
56
18
  show_gridlines: bool = True
57
19
  merge_units: bool = False
58
20
 
59
21
 
60
- @dataclass
61
- class ThresholdFilter(ChartObject):
22
+ class ThresholdFilter(BaseModelObject):
62
23
  min_unit: str | None = None
63
24
  max_unit: str | None = None
64
25
 
65
26
 
66
- @dataclass
67
- class ChartCall(ChartObject):
27
+ class ChartCall(BaseModelObject):
68
28
  id: str | None = None
69
29
  hash: int | None = None
70
30
  call_id: str | None = None
@@ -72,182 +32,143 @@ class ChartCall(ChartObject):
72
32
  status: str | None = None
73
33
 
74
34
 
75
- @dataclass
76
- class SubSetting(ChartObject):
35
+ class SubSetting(BaseModelObject):
77
36
  auto_align: bool | None = None
78
37
 
79
38
 
80
- @dataclass
81
- class FlowElement(ChartObject):
39
+ class ChartPosition(BaseModelObject):
40
+ x: float | None = None
41
+ y: float | None = None
42
+
43
+
44
+ class FlowElement(BaseModelObject):
82
45
  id: str | None = None
83
46
  type: str | None = None
84
- position: tuple[float | None, float | None] | None = None
85
- data: dict[str, object] | None = None
47
+ position: ChartPosition | None = None
48
+ data: JsonValue | None = None
49
+ source: str | None = None
50
+ target: str | None = None
51
+ source_handle: str | None = None
52
+ target_handle: str | None = None
86
53
 
87
54
 
88
- @dataclass
89
- class Flow(ChartObject):
55
+ class Flow(BaseModelObject):
90
56
  zoom: float | None = None
91
57
  elements: list[FlowElement] | None = None
92
58
  position: tuple[float | None, float | None] | None = None
93
59
 
94
- def dump(self, camel_case: bool = True) -> dict[str, Any]:
95
- data = super().dump(camel_case=camel_case)
96
- if self.elements:
97
- data["elements"] = [el.dump(camel_case=camel_case) for el in self.elements]
98
- return data
99
60
 
100
- @classmethod
101
- def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self:
102
- """Load a Flow object from a dictionary."""
103
- instance = super()._load(resource, cognite_client=cognite_client)
104
- if "elements" in resource:
105
- instance.elements = [FlowElement._load(el, cognite_client=cognite_client) for el in resource["elements"]]
106
- return instance
61
+ class ChartElement(BaseModelObject):
62
+ id: str | None = None
63
+ type: str | None = None
107
64
 
108
65
 
109
- @dataclass
110
- class ChartSource(ChartObject):
111
- type: str | None = None
112
- id: str | None = None
66
+ class ChartSource(ChartElement): ...
113
67
 
114
68
 
115
- @dataclass
116
- class BaseChartElement(ChartObject):
117
- type: str | None = None
118
- id: str | None = None
119
- name: str | None = None
69
+ class ChartCoreTimeseries(ChartElement):
70
+ node_reference: NodeId | None = None
71
+ view_reference: ViewId | None = None
72
+ display_mode: str | None = None
120
73
  color: str | None = None
74
+ created_at: int | None = None
121
75
  enabled: bool | None = None
122
- line_weight: float | None = None
123
- line_style: str | None = None
124
76
  interpolation: str | None = None
125
- unit: str | None = None
77
+ line_style: str | None = None
78
+ line_weight: float | None = None
79
+ name: str | None = None
126
80
  preferred_unit: str | None = None
127
- created_at: int | None = None
128
- range: tuple[float | None, float | None] | None = None
129
- description: str | None = None
81
+ range: list[float | None] | None = None
130
82
 
83
+ @field_serializer("node_reference", when_used="always")
84
+ def serialize_node_reference(self, node_reference: NodeId | None) -> dict[str, Any] | None:
85
+ if node_reference:
86
+ return node_reference.dump(include_instance_type=False)
87
+ return None
131
88
 
132
- @dataclass
133
- class ChartCoreTimeseries(BaseChartElement):
134
- node_reference: NodeId | None = None
135
- view_reference: ViewId | None = None
136
- display_mode: str | None = None
89
+ @field_serializer("view_reference", when_used="always")
90
+ def serialize_view_reference(self, view_reference: ViewId | None) -> dict[str, Any] | None:
91
+ if view_reference:
92
+ return view_reference.dump(include_type=False)
93
+ return None
137
94
 
138
- def dump(self, camel_case: bool = True) -> dict[str, Any]:
139
- data = super().dump(camel_case=camel_case)
140
- if self.node_reference:
141
- key = "nodeReference" if camel_case else "node_reference"
142
- data[key] = self.node_reference.dump(include_instance_type=False)
143
- if self.view_reference:
144
- key = "viewReference" if camel_case else "view_reference"
145
- data[key] = self.view_reference.dump(include_type=False)
146
- return data
95
+ @field_validator("node_reference", mode="before")
96
+ @classmethod
97
+ def validate_node_reference(cls, value: Any) -> NodeId | None:
98
+ if value is None or isinstance(value, NodeId):
99
+ return value
100
+ return NodeId.load(value)
147
101
 
102
+ @field_validator("view_reference", mode="before")
148
103
  @classmethod
149
- def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self:
150
- """Load a ChartCoreTimeseries object from a dictionary."""
151
- instance = super()._load(resource, cognite_client=cognite_client)
152
- if "nodeReference" in resource:
153
- instance.node_reference = NodeId.load(resource["nodeReference"])
154
- if "viewReference" in resource:
155
- instance.view_reference = ViewId.load(resource["viewReference"])
156
- return instance
157
-
158
-
159
- @dataclass
160
- class ChartTimeseries(BaseChartElement):
104
+ def validate_view_reference(cls, value: Any) -> ViewId | None:
105
+ if value is None or isinstance(value, ViewId):
106
+ return value
107
+ return ViewId.load(value)
108
+
109
+
110
+ class ChartTimeseries(ChartElement):
111
+ color: str | None = None
112
+ created_at: int | None = None
113
+ enabled: bool | None = None
114
+ interpolation: str | None = None
115
+ line_style: str | None = None
116
+ line_weight: float | None = None
117
+ name: str | None = None
118
+ preferred_unit: str | None = None
119
+ range: list[float | None] | None = None
120
+ unit: str | None = None
161
121
  ts_id: int | None = None
162
122
  ts_external_id: str | None = None
163
123
  display_mode: str | None = None
164
124
  original_unit: str | None = None
125
+ description: str | None = None
165
126
 
166
127
 
167
- @dataclass
168
- class ChartWorkflow(BaseChartElement):
128
+ class ChartWorkflow(ChartElement):
169
129
  version: str | None = None
130
+ name: str | None = None
131
+ color: str | None = None
132
+ enabled: bool | None = None
133
+ line_weight: float | None = None
134
+ line_style: str | None = None
135
+ interpolation: str | None = None
136
+ unit: str | None = None
137
+ preferred_unit: str | None = None
138
+ range: list[float | None] | None = None
139
+ created_at: int | None = None
170
140
  settings: SubSetting | None = None
171
141
  flow: Flow | None = None
172
142
  calls: list[ChartCall] | None = None
173
143
 
174
- def dump(self, camel_case: bool = True) -> dict[str, Any]:
175
- data = super().dump(camel_case=camel_case)
176
- if self.settings:
177
- data["settings"] = self.settings.dump(camel_case=camel_case)
178
- if self.flow:
179
- data["flow"] = self.flow.dump(camel_case=camel_case)
180
- if self.calls:
181
- data["calls"] = [c.dump(camel_case=camel_case) for c in self.calls]
182
- return data
183
144
 
184
- @classmethod
185
- def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self:
186
- """Load a ChartWorkflow object from a dictionary."""
187
- instance = super()._load(resource, cognite_client=cognite_client)
188
- if "settings" in resource:
189
- instance.settings = SubSetting._load(resource["settings"], cognite_client=cognite_client)
190
- if "flow" in resource:
191
- instance.flow = Flow._load(resource["flow"], cognite_client=cognite_client)
192
- if "calls" in resource:
193
- instance.calls = [ChartCall._load(call, cognite_client=cognite_client) for call in resource["calls"]]
194
- return instance
195
-
196
-
197
- @dataclass
198
- class ChartThreshold(BaseChartElement):
145
+ class ChartThreshold(ChartElement):
199
146
  visible: bool | None = None
147
+ name: str | None = None
200
148
  source_id: str | None = None
201
149
  upper_limit: float | None = None
202
150
  filter: ThresholdFilter | None = None
203
151
  calls: list[ChartCall] | None = None
204
152
 
205
- def dump(self, camel_case: bool = True) -> dict[str, Any]:
206
- data = super().dump(camel_case=camel_case)
207
- if self.filter:
208
- data["filter"] = self.filter.dump(camel_case=camel_case)
209
- if self.calls:
210
- data["calls"] = [c.dump(camel_case=camel_case) for c in self.calls]
211
- return data
212
153
 
213
- @classmethod
214
- def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self:
215
- """Load a ChartThreshold object from a dictionary."""
216
- instance = super()._load(resource, cognite_client=cognite_client)
217
- if "filter" in resource:
218
- instance.filter = ThresholdFilter._load(resource["filter"], cognite_client=cognite_client)
219
- if "calls" in resource:
220
- instance.calls = [ChartCall._load(call, cognite_client=cognite_client) for call in resource["calls"]]
221
- return instance
222
-
223
-
224
- @dataclass
225
- class ChartScheduledCalculation(BaseChartElement):
154
+ class ChartScheduledCalculation(ChartElement):
155
+ color: str | None = None
156
+ created_at: int | None = None
157
+ description: str | None = None
158
+ enabled: bool | None = None
159
+ interpolation: str | None = None
160
+ line_style: str | None = None
161
+ line_weight: float | None = None
162
+ name: str | None = None
163
+ preferred_unit: str | None = None
164
+ range: list[float | None] | None = None
165
+ unit: str | None = None
226
166
  version: str | None = None
227
167
  settings: SubSetting | None = None
228
168
  flow: Flow | None = None
229
169
 
230
- def dump(self, camel_case: bool = True) -> dict[str, Any]:
231
- data = super().dump(camel_case=camel_case)
232
- if self.settings:
233
- data["settings"] = self.settings.dump(camel_case=camel_case)
234
- if self.flow:
235
- data["flow"] = self.flow.dump(camel_case=camel_case)
236
- return data
237
170
 
238
- @classmethod
239
- def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self:
240
- """Load a ChartScheduledCalculation object from a dictionary."""
241
- instance = super()._load(resource, cognite_client=cognite_client)
242
- if "settings" in resource:
243
- instance.settings = SubSetting._load(resource["settings"], cognite_client=cognite_client)
244
- if "flow" in resource:
245
- instance.flow = Flow._load(resource["flow"], cognite_client=cognite_client)
246
- return instance
247
-
248
-
249
- @dataclass
250
- class ChartData(ChartObject):
171
+ class ChartData(BaseModelObject):
251
172
  version: int | None = None
252
173
  name: str | None = None
253
174
  date_from: str | None = None
@@ -261,62 +182,3 @@ class ChartData(ChartObject):
261
182
  threshold_collection: list[ChartThreshold] | None = None
262
183
  scheduled_calculation_collection: list[ChartScheduledCalculation] | None = None
263
184
  settings: ChartSettings | None = None
264
-
265
- def dump(self, camel_case: bool = True) -> dict[str, Any]:
266
- """Dump the ChartData object to a dictionary."""
267
- data = super().dump(camel_case=camel_case)
268
- list_attrs = [
269
- "time_series_collection",
270
- "core_timeseries_collection",
271
- "workflow_collection",
272
- "source_collection",
273
- "threshold_collection",
274
- "scheduled_calculation_collection",
275
- ]
276
- for attr_name in list_attrs:
277
- if collection := getattr(self, attr_name):
278
- key = to_camel_case(attr_name) if camel_case else attr_name
279
- data[key] = [item.dump(camel_case=camel_case) for item in collection]
280
-
281
- single_attrs_map = {
282
- "user_info": "userInfo",
283
- "settings": "settings",
284
- }
285
- for attr_name, camel_key in single_attrs_map.items():
286
- if item := getattr(self, attr_name):
287
- key = camel_key if camel_case else attr_name
288
- data[key] = item.dump(camel_case=camel_case)
289
- return data
290
-
291
- @classmethod
292
- def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self:
293
- """Load a ChartData object from a dictionary."""
294
- instance = super()._load(resource, cognite_client=cognite_client)
295
- collections_map = [
296
- ("timeSeriesCollection", "time_series_collection", ChartTimeseries),
297
- ("coreTimeseriesCollection", "core_timeseries_collection", ChartCoreTimeseries),
298
- ("workflowCollection", "workflow_collection", ChartWorkflow),
299
- ("sourceCollection", "source_collection", ChartSource),
300
- ("thresholdCollection", "threshold_collection", ChartThreshold),
301
- ("scheduledCalculationCollection", "scheduled_calculation_collection", ChartScheduledCalculation),
302
- ]
303
- for resource_key, attr_name, subclass in collections_map:
304
- if resource_key in resource:
305
- setattr(
306
- instance,
307
- attr_name,
308
- [subclass._load(item, cognite_client=cognite_client) for item in resource[resource_key]], # type: ignore[attr-defined]
309
- )
310
- attribute_map = [
311
- ("userInfo", "user_info", UserInfo),
312
- ("settings", "settings", ChartSettings),
313
- ]
314
- for resource_key, attr_name, subclass in attribute_map:
315
- if resource_key in resource:
316
- setattr(
317
- instance,
318
- attr_name,
319
- subclass._load(resource[resource_key], cognite_client=cognite_client), # type: ignore[attr-defined]
320
- )
321
-
322
- return instance
@@ -210,16 +210,14 @@ class ChartMapper(DataMapper[ChartSelector, Chart, ChartWrite]):
210
210
  def _create_new_timeseries_core(
211
211
  self, ts_item: ChartTimeseries, node_id: NodeId, consumer_view_id: ViewId | None
212
212
  ) -> ChartCoreTimeseries:
213
- dumped = ts_item.dump(camel_case=True)
214
- for asset_centric_key in ["tsId", "tsExternalId", "originalUnit"]:
215
- dumped.pop(asset_centric_key, None)
216
-
213
+ dumped = ts_item.model_dump(mode="json", by_alias=True, exclude_unset=True)
217
214
  dumped["nodeReference"] = node_id
218
215
  dumped["viewReference"] = consumer_view_id
219
216
  new_uuid = str(uuid4())
220
217
  dumped["id"] = new_uuid
221
218
  dumped["type"] = "coreTimeseries"
222
- core_timeseries = ChartCoreTimeseries._load(dumped)
219
+ # We ignore extra here to only include the fields that are shared between ChartTimeseries and ChartCoreTimeseries
220
+ core_timeseries = ChartCoreTimeseries.model_validate(dumped, extra="ignore")
223
221
  return core_timeseries
224
222
 
225
223
  def _get_node_id_consumer_view_id(self, ts_item: ChartTimeseries) -> tuple[NodeId | None, ViewId | None]:
@@ -231,6 +231,8 @@ class AnnotationMigrationIO(
231
231
  CHUNK_SIZE = 1000
232
232
  UPLOAD_ENDPOINT = InstanceIO.UPLOAD_ENDPOINT
233
233
 
234
+ SUPPORTED_ANNOTATION_TYPES = frozenset({"diagrams.AssetLink", "diagrams.FileLink"})
235
+
234
236
  def __init__(
235
237
  self,
236
238
  client: ToolkitClient,
@@ -272,6 +274,10 @@ class AnnotationMigrationIO(
272
274
  for data_chunk in self.annotation_io.stream_data(asset_centric_selector, limit):
273
275
  mapping_list = AssetCentricMappingList[Annotation]([])
274
276
  for resource in data_chunk.items:
277
+ if resource.annotation_type not in self.SUPPORTED_ANNOTATION_TYPES:
278
+ # This should not happen, as the annotation_io should already filter these out.
279
+ # This is just in case.
280
+ continue
275
281
  mapping = AnnotationMapping(
276
282
  instance_id=EdgeId(space=self.instance_space, external_id=f"annotation_{resource.id!r}"),
277
283
  id=resource.id,
@@ -294,11 +300,15 @@ class AnnotationMigrationIO(
294
300
  resources = self.client.annotations.retrieve_multiple(current_batch.get_ids())
295
301
  resources_by_id = {resource.id: resource for resource in resources}
296
302
  not_found = 0
303
+ incorrect_type_count = 0
297
304
  for mapping in current_batch:
298
305
  resource = resources_by_id.get(mapping.id)
299
306
  if resource is None:
300
307
  not_found += 1
301
308
  continue
309
+ if resource.annotation_type not in self.SUPPORTED_ANNOTATION_TYPES:
310
+ incorrect_type_count += 1
311
+ continue
302
312
  mapping.ingestion_view = self._get_mapping(mapping.ingestion_view, resource)
303
313
  chunk.append(AssetCentricMapping(mapping=mapping, resource=resource))
304
314
  if chunk:
@@ -308,6 +318,11 @@ class AnnotationMigrationIO(
308
318
  MediumSeverityWarning(
309
319
  f"Could not find {not_found} annotations referenced in the CSV file. They will be skipped during migration."
310
320
  ).print_warning(include_timestamp=True, console=self.client.console)
321
+ if incorrect_type_count:
322
+ MediumSeverityWarning(
323
+ f"Found {incorrect_type_count} annotations with unsupported types. Only 'diagrams.AssetLink' and "
324
+ "'diagrams.FileLink' are supported. These annotations will be skipped during migration."
325
+ ).print_warning(include_timestamp=True, console=self.client.console)
311
326
 
312
327
  def _get_mapping(self, current_mapping: str | None, resource: Annotation) -> str:
313
328
  try:
@@ -320,7 +320,7 @@ class FunctionCRUD(ResourceCRUD[str, FunctionWrite, Function]):
320
320
  " problem persists, please contact Cognite support."
321
321
  )
322
322
  item.file_id = file_id
323
- created_item = self.client.functions.create_with_429_retry(item, console=self.console)
323
+ created_item = self.client.functions.create_with_429_retry(item)
324
324
  self._warn_if_cpu_or_memory_changed(created_item, item)
325
325
  created.append(created_item)
326
326
  return created
@@ -404,7 +404,7 @@ class FunctionCRUD(ResourceCRUD[str, FunctionWrite, Function]):
404
404
  def delete(self, ids: SequenceNotStr[str]) -> int:
405
405
  functions = self.retrieve(ids)
406
406
 
407
- self.client.functions.delete_with_429_retry(external_id=ids, ignore_unknown_ids=True, console=self.console)
407
+ self.client.functions.delete_with_429_retry(external_id=ids, ignore_unknown_ids=True)
408
408
  file_ids = {func.file_id for func in functions if func.file_id}
409
409
  self.client.files.delete(id=list(file_ids), ignore_unknown_ids=True)
410
410
  return len(ids)
@@ -33,7 +33,8 @@ class AnnotationIO(StorageIO[AssetCentricSelector, Annotation]):
33
33
  annotated_resource_type="file",
34
34
  annotated_resource_ids=[{"id": file_metadata.id} for file_metadata in file_chunk.items],
35
35
  annotation_type=annotation_type,
36
- )
36
+ ),
37
+ limit=-1,
37
38
  )
38
39
  if limit is not None and total + len(results) > limit:
39
40
  results = results[: limit - total]
@@ -23,6 +23,15 @@ from cognite_toolkit._cdf_tk.utils.http_client._data_classes import (
23
23
  ResponseList,
24
24
  ResponseMessage,
25
25
  )
26
+ from cognite_toolkit._cdf_tk.utils.http_client._data_classes2 import (
27
+ BaseRequestMessage,
28
+ ErrorDetails2,
29
+ FailedRequest2,
30
+ FailedResponse2,
31
+ HTTPResult2,
32
+ RequestMessage2,
33
+ SuccessResponse2,
34
+ )
26
35
  from cognite_toolkit._cdf_tk.utils.useful_types import PrimitiveType
27
36
 
28
37
  if sys.version_info >= (3, 11):
@@ -48,6 +57,7 @@ class HTTPClient:
48
57
  Default is {408, 429, 502, 503, 504}.
49
58
  split_items_status_codes (frozenset[int]): In the case of ItemRequest with multiple
50
59
  items, these status codes will trigger splitting the request into smaller batches.
60
+ console (Console | None): Optional Rich Console for printing warnings.
51
61
 
52
62
  """
53
63
 
@@ -59,6 +69,7 @@ class HTTPClient:
59
69
  pool_maxsize: int = 20,
60
70
  retry_status_codes: Set[int] = frozenset({408, 429, 502, 503, 504}),
61
71
  split_items_status_codes: Set[int] = frozenset({400, 408, 409, 422, 502, 503, 504}),
72
+ console: Console | None = None,
62
73
  ):
63
74
  self.config = config
64
75
  self._max_retries = max_retries
@@ -66,6 +77,7 @@ class HTTPClient:
66
77
  self._pool_maxsize = pool_maxsize
67
78
  self._retry_status_codes = retry_status_codes
68
79
  self._split_items_status_codes = split_items_status_codes
80
+ self._console = console
69
81
 
70
82
  # Thread-safe session for connection pooling
71
83
  self.session = self._create_thread_safe_session()
@@ -80,12 +92,11 @@ class HTTPClient:
80
92
  self.session.close()
81
93
  return False # Do not suppress exceptions
82
94
 
83
- def request(self, message: RequestMessage, console: Console | None = None) -> Sequence[HTTPMessage]:
95
+ def request(self, message: RequestMessage) -> Sequence[HTTPMessage]:
84
96
  """Send an HTTP request and return the response.
85
97
 
86
98
  Args:
87
99
  message (RequestMessage): The request message to send.
88
- console (Console | None): The rich console to use for printing warnings.
89
100
 
90
101
  Returns:
91
102
  Sequence[HTTPMessage]: The response message(s). This can also
@@ -98,12 +109,12 @@ class HTTPClient:
98
109
  return message.create_failed_request(error_msg)
99
110
  try:
100
111
  response = self._make_request(message)
101
- results = self._handle_response(response, message, console)
112
+ results = self._handle_response(response, message)
102
113
  except Exception as e:
103
114
  results = self._handle_error(e, message)
104
115
  return results
105
116
 
106
- def request_with_retries(self, message: RequestMessage, console: Console | None = None) -> ResponseList:
117
+ def request_with_retries(self, message: RequestMessage) -> ResponseList:
107
118
  """Send an HTTP request and handle retries.
108
119
 
109
120
  This method will keep retrying the request until it either succeeds or
@@ -114,7 +125,6 @@ class HTTPClient:
114
125
 
115
126
  Args:
116
127
  message (RequestMessage): The request message to send.
117
- console (Console | None): The rich console to use for printing warnings.
118
128
 
119
129
  Returns:
120
130
  Sequence[ResponseMessage | FailedRequestMessage]: The final response
@@ -127,7 +137,7 @@ class HTTPClient:
127
137
  final_responses = ResponseList([])
128
138
  while pending_requests:
129
139
  current_request = pending_requests.popleft()
130
- results = self.request(current_request, console)
140
+ results = self.request(current_request)
131
141
 
132
142
  for result in results:
133
143
  if isinstance(result, RequestMessage):
@@ -194,9 +204,7 @@ class HTTPClient:
194
204
  follow_redirects=False,
195
205
  )
196
206
 
197
- def _handle_response(
198
- self, response: httpx.Response, request: RequestMessage, console: Console | None = None
199
- ) -> Sequence[HTTPMessage]:
207
+ def _handle_response(self, response: httpx.Response, request: RequestMessage) -> Sequence[HTTPMessage]:
200
208
  if 200 <= response.status_code < 300:
201
209
  return request.create_success_response(response)
202
210
  elif (
@@ -216,11 +224,11 @@ class HTTPClient:
216
224
 
217
225
  retry_after = self._get_retry_after_in_header(response)
218
226
  if retry_after is not None and response.status_code == 429 and request.status_attempt < self._max_retries:
219
- if console is not None:
227
+ if self._console is not None:
220
228
  short_url = request.endpoint_url.removeprefix(self.config.base_api_url)
221
229
  HighSeverityWarning(
222
230
  f"Rate limit exceeded for the {short_url!r} endpoint. Retrying after {retry_after} seconds."
223
- ).print_warning(console=console)
231
+ ).print_warning(console=self._console)
224
232
  request.status_attempt += 1
225
233
  time.sleep(retry_after)
226
234
  return [request]
@@ -273,3 +281,110 @@ class HTTPClient:
273
281
  error_msg = f"RequestException after {request.total_attempts - 1} attempts ({error_type} error): {e!s}"
274
282
 
275
283
  return request.create_failed_request(error_msg)
284
+
285
+ def request_single(self, message: RequestMessage2) -> RequestMessage2 | HTTPResult2:
286
+ """Send an HTTP request and return the response.
287
+
288
+ Args:
289
+ message (RequestMessage2): The request message to send.
290
+ Returns:
291
+ HTTPMessage: The response message.
292
+ """
293
+ try:
294
+ response = self._make_request2(message)
295
+ result = self._handle_response_single(response, message)
296
+ except Exception as e:
297
+ result = self._handle_error_single(e, message)
298
+ return result
299
+
300
+ def request_single_retries(self, message: RequestMessage2) -> HTTPResult2:
301
+ """Send an HTTP request and handle retries.
302
+
303
+ This method will keep retrying the request until it either succeeds or
304
+ exhausts the maximum number of retries.
305
+
306
+ Note this method will use the current thread to process all request, thus
307
+ it is blocking.
308
+
309
+ Args:
310
+ message (RequestMessage2): The request message to send.
311
+ Returns:
312
+ HTTPMessage2: The final response message, which can be either successful response or failed request.
313
+ """
314
+ if message.total_attempts > 0:
315
+ raise RuntimeError(f"RequestMessage has already been attempted {message.total_attempts} times.")
316
+ current_request = message
317
+ while True:
318
+ result = self.request_single(current_request)
319
+ if isinstance(result, RequestMessage2):
320
+ current_request = result
321
+ elif isinstance(result, HTTPResult2):
322
+ return result
323
+ else:
324
+ raise TypeError(f"Unexpected result type: {type(result)}")
325
+
326
+ def _make_request2(self, message: BaseRequestMessage) -> httpx.Response:
327
+ headers = self._create_headers(message.api_version, message.content_type, message.accept)
328
+ return self.session.request(
329
+ method=message.method,
330
+ url=message.endpoint_url,
331
+ content=message.content,
332
+ headers=headers,
333
+ params=message.parameters,
334
+ timeout=self.config.timeout,
335
+ follow_redirects=False,
336
+ )
337
+
338
+ def _handle_response_single(
339
+ self, response: httpx.Response, request: RequestMessage2
340
+ ) -> RequestMessage2 | HTTPResult2:
341
+ if 200 <= response.status_code < 300:
342
+ return SuccessResponse2(
343
+ status_code=response.status_code,
344
+ body=response.text,
345
+ content=response.content,
346
+ )
347
+ retry_after = self._get_retry_after_in_header(response)
348
+ if retry_after is not None and response.status_code == 429 and request.status_attempt < self._max_retries:
349
+ if self._console is not None:
350
+ short_url = request.endpoint_url.removeprefix(self.config.base_api_url)
351
+ HighSeverityWarning(
352
+ f"Rate limit exceeded for the {short_url!r} endpoint. Retrying after {retry_after} seconds."
353
+ ).print_warning(console=self._console)
354
+ request.status_attempt += 1
355
+ time.sleep(retry_after)
356
+ return request
357
+
358
+ if request.status_attempt < self._max_retries and response.status_code in self._retry_status_codes:
359
+ request.status_attempt += 1
360
+ time.sleep(self._backoff_time(request.total_attempts))
361
+ return request
362
+ else:
363
+ # Permanent failure
364
+ return FailedResponse2(
365
+ status_code=response.status_code,
366
+ body=response.text,
367
+ error=ErrorDetails2.from_response(response),
368
+ )
369
+
370
+ def _handle_error_single(self, e: Exception, request: RequestMessage2) -> RequestMessage2 | HTTPResult2:
371
+ if isinstance(e, httpx.ReadTimeout | httpx.TimeoutException):
372
+ error_type = "read"
373
+ request.read_attempt += 1
374
+ attempts = request.read_attempt
375
+ elif isinstance(e, ConnectionError | httpx.ConnectError | httpx.ConnectTimeout):
376
+ error_type = "connect"
377
+ request.connect_attempt += 1
378
+ attempts = request.connect_attempt
379
+ else:
380
+ error_msg = f"Unexpected exception: {e!s}"
381
+ return FailedRequest2(error=error_msg)
382
+
383
+ if attempts <= self._max_retries:
384
+ time.sleep(self._backoff_time(request.total_attempts))
385
+ return request
386
+ else:
387
+ # We have already incremented the attempt count, so we subtract 1 here
388
+ error_msg = f"RequestException after {request.total_attempts - 1} attempts ({error_type} error): {e!s}"
389
+
390
+ return FailedRequest2(error=error_msg)
@@ -0,0 +1,97 @@
1
+ import gzip
2
+ from abc import ABC, abstractmethod
3
+ from typing import Any, Literal
4
+
5
+ import httpx
6
+ from cognite.client import global_config
7
+ from pydantic import BaseModel, JsonValue, TypeAdapter, model_validator
8
+
9
+ from cognite_toolkit._cdf_tk.utils.useful_types import PrimitiveType
10
+
11
+
12
+ class HTTPResult2(BaseModel): ...
13
+
14
+
15
+ class FailedRequest2(HTTPResult2):
16
+ error: str
17
+
18
+
19
+ class SuccessResponse2(HTTPResult2):
20
+ status_code: int
21
+ body: str
22
+ content: bytes
23
+
24
+
25
+ class ErrorDetails2(BaseModel):
26
+ """This is the expected structure of error details in the CDF API"""
27
+
28
+ code: int
29
+ message: str
30
+ missing: list[JsonValue] | None = None
31
+ duplicated: list[JsonValue] | None = None
32
+ is_auto_retryable: bool | None = None
33
+
34
+ @classmethod
35
+ def from_response(cls, response: httpx.Response) -> "ErrorDetails2":
36
+ """Populate the error details from a httpx response."""
37
+ try:
38
+ res = TypeAdapter(dict[Literal["error"], ErrorDetails2]).validate_json(response.text)
39
+ except ValueError:
40
+ return cls(code=response.status_code, message=response.text)
41
+ return res["error"]
42
+
43
+
44
+ class FailedResponse2(HTTPResult2):
45
+ status_code: int
46
+ body: str
47
+ error: ErrorDetails2
48
+
49
+
50
+ class BaseRequestMessage(BaseModel, ABC):
51
+ endpoint_url: str
52
+ method: Literal["GET", "POST", "PATCH", "DELETE", "PUT"]
53
+ connect_attempt: int = 0
54
+ read_attempt: int = 0
55
+ status_attempt: int = 0
56
+ api_version: str | None = None
57
+ content_type: str = "application/json"
58
+ accept: str = "application/json"
59
+
60
+ parameters: dict[str, PrimitiveType] | None = None
61
+
62
+ @property
63
+ def total_attempts(self) -> int:
64
+ return self.connect_attempt + self.read_attempt + self.status_attempt
65
+
66
+ @property
67
+ @abstractmethod
68
+ def content(self) -> str | bytes | None: ...
69
+
70
+
71
+ class RequestMessage2(BaseRequestMessage):
72
+ data_content: bytes | None = None
73
+ body_content: dict[str, JsonValue] | None = None
74
+
75
+ @model_validator(mode="before")
76
+ def check_data_or_body(cls, values: dict[str, Any]) -> dict[str, Any]:
77
+ if values.get("data_content") is not None and values.get("body_content") is not None:
78
+ raise ValueError("Only one of data_content or body_content can be set.")
79
+ return values
80
+
81
+ @property
82
+ def content(self) -> str | bytes | None:
83
+ data: str | bytes | None = None
84
+ if self.data_content is not None:
85
+ data = self.data_content
86
+ if not global_config.disable_gzip:
87
+ data = gzip.compress(data)
88
+ elif self.body_content is not None:
89
+ # We serialize using pydantic instead of json.dumps. This is because pydantic is faster
90
+ # and handles more complex types such as datetime, float('nan'), etc.
91
+ data = _BODY_SERIALIZER.dump_json(self.body_content)
92
+ if not global_config.disable_gzip and isinstance(data, str):
93
+ data = gzip.compress(data.encode("utf-8"))
94
+ return data
95
+
96
+
97
+ _BODY_SERIALIZER = TypeAdapter(dict[str, JsonValue])
@@ -12,7 +12,7 @@ jobs:
12
12
  environment: dev
13
13
  name: Deploy
14
14
  container:
15
- image: cognite/toolkit:0.7.27
15
+ image: cognite/toolkit:0.7.29
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.7.27
13
+ image: cognite/toolkit:0.7.29
14
14
  env:
15
15
  CDF_CLUSTER: ${{ vars.CDF_CLUSTER }}
16
16
  CDF_PROJECT: ${{ vars.CDF_PROJECT }}
@@ -4,7 +4,7 @@ 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.7.27"
7
+ version = "0.7.29"
8
8
 
9
9
 
10
10
  [plugins]
@@ -1 +1 @@
1
- __version__ = "0.7.27"
1
+ __version__ = "0.7.29"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cognite_toolkit
3
- Version: 0.7.27
3
+ Version: 0.7.29
4
4
  Summary: Official Cognite Data Fusion tool for project templates and configuration deployment
5
5
  Author: Cognite AS
6
6
  Author-email: Cognite AS <support@cognite.com>
@@ -28,14 +28,14 @@ cognite_toolkit/_cdf_tk/builders/_transformation.py,sha256=STB42zhzOW5M_-b8cKOQ_
28
28
  cognite_toolkit/_cdf_tk/cdf_toml.py,sha256=VSWV9h44HusWIaKpWgjrOMrc3hDoPTTXBXlp6-NOrIM,9079
29
29
  cognite_toolkit/_cdf_tk/client/__init__.py,sha256=a6rQXDGfW2g7K5WwrOW5oakh1TdFlBjUVjf9wusOox8,135
30
30
  cognite_toolkit/_cdf_tk/client/_constants.py,sha256=COUGcea37mDF2sf6MGqJXWmecTY_6aCImslxXrYW1I0,73
31
- cognite_toolkit/_cdf_tk/client/_toolkit_client.py,sha256=1syPhlnCWJZzLuF9e1cjID06C-eOw5VLkOYz97cg3lA,3299
31
+ cognite_toolkit/_cdf_tk/client/_toolkit_client.py,sha256=y_GGNlCtu_qcjFVIb3bwLUS9zCqzJ0BK0_K-paw1Gt4,3417
32
32
  cognite_toolkit/_cdf_tk/client/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
33
  cognite_toolkit/_cdf_tk/client/api/canvas.py,sha256=i2NwyhvmklTPx3e-yd4lvSxyn6JEjSpv8WXa1SxtmV8,8789
34
34
  cognite_toolkit/_cdf_tk/client/api/charts.py,sha256=t-VOrRGwpjmYUtUqGObQWYwGb5gOHVp4cHZBm8ZVGn0,4953
35
35
  cognite_toolkit/_cdf_tk/client/api/dml.py,sha256=8b1lo86JdvfEsz9mP2rx0Mp9fyWsU6mbXHqLBtvSidU,3546
36
36
  cognite_toolkit/_cdf_tk/client/api/extended_data_modeling.py,sha256=T08lXIrgDRGKhF-44FYoBMd4oJRYiWRzYhHsNkLyLAo,12967
37
37
  cognite_toolkit/_cdf_tk/client/api/extended_files.py,sha256=azdPnCqXUVuPLTuiV9WZ97VJTJ6mN2hOEtD9LklLw8M,9191
38
- cognite_toolkit/_cdf_tk/client/api/extended_functions.py,sha256=QaFCYmiL4KDWRpRB5gBHd6Z9fuxNLnWl16k1mOzWFuk,3608
38
+ cognite_toolkit/_cdf_tk/client/api/extended_functions.py,sha256=_MbkztZskZAt43ZERddhmeZYKHeQSDteFlnaCLL5J6k,3523
39
39
  cognite_toolkit/_cdf_tk/client/api/extended_raw.py,sha256=9DVbM2aWmIyzbaW-lh10_pzVYJUEQFnIKnxvt413Bjk,2118
40
40
  cognite_toolkit/_cdf_tk/client/api/extended_timeseries.py,sha256=xK7XhTfe4W9FvaueUIfR7Q64JOIDwq_svHRjORM76Q4,17774
41
41
  cognite_toolkit/_cdf_tk/client/api/fixed_transformations.py,sha256=m66cqbx4oCtjv5TBQOWLNFrz475qVTCXBu_pTxbdCD4,5589
@@ -67,8 +67,8 @@ cognite_toolkit/_cdf_tk/client/data_classes/apm_config_v1.py,sha256=0bPq7R0qvdf8
67
67
  cognite_toolkit/_cdf_tk/client/data_classes/base.py,sha256=QG4S0HlByMB6zwxUXWaVHwP-DrA2Y97XGN_o6QsL6FY,2776
68
68
  cognite_toolkit/_cdf_tk/client/data_classes/canvas.py,sha256=DrE-7HOLnk1ELhydySsEhw-VOjriUqB_zzon5qb7CDk,50721
69
69
  cognite_toolkit/_cdf_tk/client/data_classes/capabilities.py,sha256=muqpAC2JLCFcEpRPzuh_3sS3o_q42WFyfsGzl-LfB_U,8773
70
- cognite_toolkit/_cdf_tk/client/data_classes/charts.py,sha256=l4LM1eqn8_2lRzw-DdwwL0zxgSczC0lp1LjgW-4wqPI,3770
71
- cognite_toolkit/_cdf_tk/client/data_classes/charts_data.py,sha256=Zcx3st3bMJE2aa5U6TepDqRzqf-LuTTWW5grSaVGr9E,12244
70
+ cognite_toolkit/_cdf_tk/client/data_classes/charts.py,sha256=4ZSZDJhDP8uNubXfzphuLJzKJhL1F01grB4UesxtSbQ,3745
71
+ cognite_toolkit/_cdf_tk/client/data_classes/charts_data.py,sha256=-dFfY53cos5DwASLU18aBfYF1VC6bfaUshC2HiGJ2uI,5571
72
72
  cognite_toolkit/_cdf_tk/client/data_classes/extendable_cognite_file.py,sha256=0iyLiXEzB4WBU-DL6DZS6nD5E526cDsftMGEYXwI8r8,9764
73
73
  cognite_toolkit/_cdf_tk/client/data_classes/extended_filemetadata.py,sha256=8zfXl_bhkums3quJzdOwAjxVNY6B0hpAs6jbkekn79o,5488
74
74
  cognite_toolkit/_cdf_tk/client/data_classes/extended_filemetdata.py,sha256=gKA5UcDKweH7SlzXfyZCspMyHUo0t8R5DbzeCPpzInM,6002
@@ -103,11 +103,11 @@ cognite_toolkit/_cdf_tk/commands/_migrate/command.py,sha256=l2P0Em05aEJvNZH4WkEI
103
103
  cognite_toolkit/_cdf_tk/commands/_migrate/conversion.py,sha256=Ew9JRYrd-Ol9G9csTzpnhXAgCFnX67MwDYOTsdJLP3E,16803
104
104
  cognite_toolkit/_cdf_tk/commands/_migrate/creators.py,sha256=FTu7w3G8KyPY8pagG3KdPpOmpLcjehaAg2auEy6iM7A,9605
105
105
  cognite_toolkit/_cdf_tk/commands/_migrate/data_classes.py,sha256=_vMS_qAPj4yup1VnmmojPVigAZtyPQH7PM0Raby5tao,10619
106
- cognite_toolkit/_cdf_tk/commands/_migrate/data_mapper.py,sha256=vixRnB-4sjDCE2DafMJs_oApVe5HgwOrzSPt49ypUgM,18491
106
+ cognite_toolkit/_cdf_tk/commands/_migrate/data_mapper.py,sha256=b_6_yYibtzWiBFrYq5pB8NZUi1TRuf-DIy_GRroj4wg,18551
107
107
  cognite_toolkit/_cdf_tk/commands/_migrate/data_model.py,sha256=i1eUsNX6Dueol9STIEwyksBnBsWUk13O8qHIjW964pM,7860
108
108
  cognite_toolkit/_cdf_tk/commands/_migrate/default_mappings.py,sha256=ERn3qFrJFXdtXaMjHq3Gk7MxH03MGFk3FrtWCOBJQts,5544
109
109
  cognite_toolkit/_cdf_tk/commands/_migrate/issues.py,sha256=n8en744-r7GL9eUyxEojFes1yk69V04SnlpVXHrdPOQ,6972
110
- cognite_toolkit/_cdf_tk/commands/_migrate/migration_io.py,sha256=wrdBH5P6NgiZQSYLR0iJ3ZvqfQ5fY-_Ne2yKv9E1g4o,16277
110
+ cognite_toolkit/_cdf_tk/commands/_migrate/migration_io.py,sha256=nc77Eu1a2sGS8Pb0bkMgqWebYmWlLbQe8xPCay5aoNo,17208
111
111
  cognite_toolkit/_cdf_tk/commands/_migrate/prepare.py,sha256=RfqaNoso5CyBwc-p6ckwcYqBfZXKhdJgdGIyd0TATaI,2635
112
112
  cognite_toolkit/_cdf_tk/commands/_migrate/selectors.py,sha256=N1H_-rBpPUD6pbrlcofn1uEK1bA694EUXEe1zIXeqyo,2489
113
113
  cognite_toolkit/_cdf_tk/commands/_profile.py,sha256=_4iX3AHAI6eLmRVUlWXCSvVHx1BZW2yDr_i2i9ECg6U,43120
@@ -143,7 +143,7 @@ cognite_toolkit/_cdf_tk/cruds/_resource_cruds/datamodel.py,sha256=SagiSp3JERgEU3
143
143
  cognite_toolkit/_cdf_tk/cruds/_resource_cruds/extraction_pipeline.py,sha256=a2HywkruYNJGLZxqOjlp8mrpRGtJDPqIb6qY00eUbEI,17701
144
144
  cognite_toolkit/_cdf_tk/cruds/_resource_cruds/fieldops.py,sha256=dcC850Vyvc5Hfi9Z3MfXE8s_q14Hqq4EqegFz_V6aCI,20662
145
145
  cognite_toolkit/_cdf_tk/cruds/_resource_cruds/file.py,sha256=vyeRsiIOEbUeYslBsgXoyCk5hozDsubUilA7bdjqS5c,14855
146
- cognite_toolkit/_cdf_tk/cruds/_resource_cruds/function.py,sha256=v3kjn3igwTF53LJ6pp0O8d4S1XFJ1eXQGCchWAcaAx0,28439
146
+ cognite_toolkit/_cdf_tk/cruds/_resource_cruds/function.py,sha256=4J7ObIRT1fKl1542-byaRs3lUfx2LiNbNg55tQkIg-g,28395
147
147
  cognite_toolkit/_cdf_tk/cruds/_resource_cruds/group_scoped.py,sha256=WEg8-CxMP64WfE_XXIlH114zM51K0uLaYa4atd992zI,1690
148
148
  cognite_toolkit/_cdf_tk/cruds/_resource_cruds/hosted_extractors.py,sha256=P0hlXK0_FmO86U-gDHMHz8N0vpDtPoKupiQfhNP5KLE,14619
149
149
  cognite_toolkit/_cdf_tk/cruds/_resource_cruds/industrial_tool.py,sha256=QrgSCcLN0NtpQuP7zcCUYaWoiq3JiUB2j0A15d8MNNc,7856
@@ -238,7 +238,7 @@ cognite_toolkit/_cdf_tk/resource_classes/workflow.py,sha256=fMNfW93D8tdVwO7YgEYY
238
238
  cognite_toolkit/_cdf_tk/resource_classes/workflow_trigger.py,sha256=aSN0WFPupQ383A7RT-0Monw-inkVdYYSsK3UwHXW1HA,5216
239
239
  cognite_toolkit/_cdf_tk/resource_classes/workflow_version.py,sha256=ui724EaM9Nlm3wTnm7Givgv6GLQ-xbsfZgidyRKv09U,2991
240
240
  cognite_toolkit/_cdf_tk/storageio/__init__.py,sha256=h5Wr4i7zNIgsslrsRJxmp7ls4bNRKl0uZzQ7GLRMP7g,1920
241
- cognite_toolkit/_cdf_tk/storageio/_annotations.py,sha256=JI_g18_Y9S7pbc9gm6dZMyo3Z-bCndJXF9C2lOva0bQ,4848
241
+ cognite_toolkit/_cdf_tk/storageio/_annotations.py,sha256=QcFrikDgz-9VjNy4Xq7wchM4VOQh-z2JaHcWR2C1sEs,4879
242
242
  cognite_toolkit/_cdf_tk/storageio/_applications.py,sha256=M7FEK4xC0BjP2i6FyYs1589zEA3afJiOKCzY56RV6NU,19685
243
243
  cognite_toolkit/_cdf_tk/storageio/_asset_centric.py,sha256=TirKLSNPoLqKjczsw0djWAsR0VvopwmU23aUxrBOJN8,32464
244
244
  cognite_toolkit/_cdf_tk/storageio/_base.py,sha256=ElvqhIEBnhcz0yY1Ds164wVN0_7CFNK-uT0-z7LcR9U,13067
@@ -281,8 +281,9 @@ cognite_toolkit/_cdf_tk/utils/fileio/_writers.py,sha256=mc23m0kJgl57FUDvwLmS7yR3
281
281
  cognite_toolkit/_cdf_tk/utils/graphql_parser.py,sha256=2i2wDjg_Uw3hJ-pHtPK8hczIuCj5atrK8HZbgWJB-Pk,11532
282
282
  cognite_toolkit/_cdf_tk/utils/hashing.py,sha256=3NyNfljyYNTqAyAFBd6XlyWaj43jRzENxIuPdOY6nqo,2116
283
283
  cognite_toolkit/_cdf_tk/utils/http_client/__init__.py,sha256=G8b7Bg4yIet5R4Igh3dS2SntWzE6I0iTGBeNlNsSxkQ,857
284
- cognite_toolkit/_cdf_tk/utils/http_client/_client.py,sha256=7B9c5_mwmWlf-_juq8-oVJAnc3iJuQDPgY-8uuhD7wA,11487
284
+ cognite_toolkit/_cdf_tk/utils/http_client/_client.py,sha256=OrrGq3GjusxPPzhFoW8iyiphpdbWOWAoaYOeOy9kqjQ,16212
285
285
  cognite_toolkit/_cdf_tk/utils/http_client/_data_classes.py,sha256=8KEDyRRaOLhwN2eA2vaBAzZ__JDUicUDyir6x_PE5lk,14817
286
+ cognite_toolkit/_cdf_tk/utils/http_client/_data_classes2.py,sha256=mUrmTqTm60WP4JpMmNO07-NfgWQM8Wby7OLCo02I71U,3031
286
287
  cognite_toolkit/_cdf_tk/utils/http_client/_exception.py,sha256=fC9oW6BN0HbUe2AkYABMP7Kj0-9dNYXVFBY5RQztq2c,126
287
288
  cognite_toolkit/_cdf_tk/utils/http_client/_tracker.py,sha256=EBBnd-JZ7nc_jYNFJokCHN2UZ9sx0McFLZvlceUYYic,1215
288
289
  cognite_toolkit/_cdf_tk/utils/interactive_select.py,sha256=dP_ZFHvzQRPQxRt6EzURY3Z3Ld_otJtCz-nGqUNtt1k,35725
@@ -302,14 +303,14 @@ cognite_toolkit/_repo_files/.gitignore,sha256=ip9kf9tcC5OguF4YF4JFEApnKYw0nG0vPi
302
303
  cognite_toolkit/_repo_files/AzureDevOps/.devops/README.md,sha256=OLA0D7yCX2tACpzvkA0IfkgQ4_swSd-OlJ1tYcTBpsA,240
303
304
  cognite_toolkit/_repo_files/AzureDevOps/.devops/deploy-pipeline.yml,sha256=brULcs8joAeBC_w_aoWjDDUHs3JheLMIR9ajPUK96nc,693
304
305
  cognite_toolkit/_repo_files/AzureDevOps/.devops/dry-run-pipeline.yml,sha256=OBFDhFWK1mlT4Dc6mDUE2Es834l8sAlYG50-5RxRtHk,723
305
- cognite_toolkit/_repo_files/GitHub/.github/workflows/deploy.yaml,sha256=zf9hdCJ3SerGDrnmBTLTn3CMH0hGGYTh-hdVh3A115M,667
306
- cognite_toolkit/_repo_files/GitHub/.github/workflows/dry-run.yaml,sha256=mRRQGQOYBRdXpgyuC1O1rEH5owcwsLVI_CvEyq3iqnk,2430
307
- cognite_toolkit/_resources/cdf.toml,sha256=xSpuqW3POVKkqGWVtHMIiLc2dQZeGZpdqh1sJPHKC8A,475
308
- cognite_toolkit/_version.py,sha256=fHi3FiqQRMkjl3o8ATyV9gZrBSNTVvt5m0WxJ-NYHTA,23
306
+ cognite_toolkit/_repo_files/GitHub/.github/workflows/deploy.yaml,sha256=FQFw5rkuhjbBY-cBoP38pdrcUZF6qkK2Y9YKbab8LzU,667
307
+ cognite_toolkit/_repo_files/GitHub/.github/workflows/dry-run.yaml,sha256=e87zJqrsOVfo7QqSnIZY5U32szqyvq5Bjq-e_16xHiQ,2430
308
+ cognite_toolkit/_resources/cdf.toml,sha256=tJP7KRNhWsrkXisd58pe5ZlzUBOAfe4zR5TTAP63tzg,475
309
+ cognite_toolkit/_version.py,sha256=XdC0R1utqmwH52az-uz3mk0vLZyV2OyWiin3soRIguo,23
309
310
  cognite_toolkit/config.dev.yaml,sha256=M33FiIKdS3XKif-9vXniQ444GTZ-bLXV8aFH86u9iUQ,332
310
311
  cognite_toolkit/demo/__init__.py,sha256=-m1JoUiwRhNCL18eJ6t7fZOL7RPfowhCuqhYFtLgrss,72
311
312
  cognite_toolkit/demo/_base.py,sha256=6xKBUQpXZXGQ3fJ5f7nj7oT0s2n7OTAGIa17ZlKHZ5U,8052
312
- cognite_toolkit-0.7.27.dist-info/WHEEL,sha256=93kfTGt3a0Dykt_T-gsjtyS5_p8F_d6CE1NwmBOirzo,79
313
- cognite_toolkit-0.7.27.dist-info/entry_points.txt,sha256=EtZ17K2mUjh-AY0QNU1CPIB_aDSSOdmtNI_4Fj967mA,84
314
- cognite_toolkit-0.7.27.dist-info/METADATA,sha256=OoJ1UzFNOjp3Tja-1bdSe8LrbCq167Bq0lBnRGugbc8,4507
315
- cognite_toolkit-0.7.27.dist-info/RECORD,,
313
+ cognite_toolkit-0.7.29.dist-info/WHEEL,sha256=93kfTGt3a0Dykt_T-gsjtyS5_p8F_d6CE1NwmBOirzo,79
314
+ cognite_toolkit-0.7.29.dist-info/entry_points.txt,sha256=EtZ17K2mUjh-AY0QNU1CPIB_aDSSOdmtNI_4Fj967mA,84
315
+ cognite_toolkit-0.7.29.dist-info/METADATA,sha256=71UXU4S9UVcZVxhDGazAQOCbTSYyQzD6Kj2FkxNJHYs,4507
316
+ cognite_toolkit-0.7.29.dist-info/RECORD,,