cognite-toolkit 0.6.108__py3-none-any.whl → 0.6.110__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.
@@ -135,6 +135,26 @@ class ChartCoreTimeseries(BaseChartElement):
135
135
  view_reference: ViewId | None = None
136
136
  display_mode: str | None = None
137
137
 
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
147
+
148
+ @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
+
138
158
 
139
159
  @dataclass
140
160
  class ChartTimeseries(BaseChartElement):
@@ -1,6 +1,7 @@
1
1
  from abc import ABC, abstractmethod
2
2
  from collections.abc import Sequence
3
- from typing import Generic
3
+ from typing import Generic, cast
4
+ from uuid import uuid4
4
5
 
5
6
  from cognite.client.data_classes._base import (
6
7
  T_CogniteResource,
@@ -9,20 +10,24 @@ from cognite.client.data_classes.data_modeling import (
9
10
  EdgeApply,
10
11
  InstanceApply,
11
12
  NodeApply,
13
+ NodeId,
12
14
  View,
13
15
  ViewId,
14
16
  )
15
17
 
16
18
  from cognite_toolkit._cdf_tk.client import ToolkitClient
19
+ from cognite_toolkit._cdf_tk.client.data_classes.charts import Chart, ChartWrite
20
+ from cognite_toolkit._cdf_tk.client.data_classes.charts_data import ChartCoreTimeseries, ChartSource, ChartTimeseries
17
21
  from cognite_toolkit._cdf_tk.client.data_classes.migration import ResourceViewMappingApply
18
22
  from cognite_toolkit._cdf_tk.commands._migrate.conversion import DirectRelationCache, asset_centric_to_dm
19
23
  from cognite_toolkit._cdf_tk.commands._migrate.data_classes import AssetCentricMapping
20
24
  from cognite_toolkit._cdf_tk.commands._migrate.default_mappings import create_default_mappings
21
- from cognite_toolkit._cdf_tk.commands._migrate.issues import ConversionIssue, MigrationIssue
25
+ from cognite_toolkit._cdf_tk.commands._migrate.issues import ChartMigrationIssue, ConversionIssue, MigrationIssue
22
26
  from cognite_toolkit._cdf_tk.commands._migrate.selectors import AssetCentricMigrationSelector
23
27
  from cognite_toolkit._cdf_tk.constants import MISSING_INSTANCE_SPACE
24
28
  from cognite_toolkit._cdf_tk.exceptions import ToolkitValueError
25
29
  from cognite_toolkit._cdf_tk.storageio._base import T_Selector, T_WriteCogniteResource
30
+ from cognite_toolkit._cdf_tk.storageio.selectors import ChartSelector
26
31
  from cognite_toolkit._cdf_tk.utils import humanize_collection
27
32
  from cognite_toolkit._cdf_tk.utils.useful_types import (
28
33
  T_AssetCentricResourceExtended,
@@ -120,3 +125,123 @@ class AssetCentricMapper(
120
125
  if mapping.instance_id.space == MISSING_INSTANCE_SPACE:
121
126
  conversion_issue.missing_instance_space = f"Missing instance space for dataset ID {mapping.data_set_id!r}"
122
127
  return instance, conversion_issue
128
+
129
+
130
+ class ChartMapper(DataMapper[ChartSelector, Chart, ChartWrite]):
131
+ def __init__(self, client: ToolkitClient) -> None:
132
+ self.client = client
133
+
134
+ def map(self, source: Sequence[Chart]) -> Sequence[tuple[ChartWrite | None, MigrationIssue]]:
135
+ self._populate_cache(source)
136
+ output: list[tuple[ChartWrite | None, MigrationIssue]] = []
137
+ for item in source:
138
+ mapped_item, issue = self._map_single_item(item)
139
+ output.append((mapped_item, issue))
140
+ return output
141
+
142
+ def _populate_cache(self, source: Sequence[Chart]) -> None:
143
+ """Populate the internal cache with timeseries from the source charts.
144
+
145
+ Note that the consumption views are also cached as part of the timeseries lookup.
146
+ """
147
+ timeseries_ids: set[int] = set()
148
+ timeseries_external_ids: set[str] = set()
149
+ for chart in source:
150
+ for item in chart.data.time_series_collection or []:
151
+ if item.ts_id:
152
+ timeseries_ids.add(item.ts_id)
153
+ if item.ts_external_id:
154
+ timeseries_external_ids.add(item.ts_external_id)
155
+ if timeseries_ids:
156
+ self.client.migration.lookup.time_series(list(timeseries_ids))
157
+ if timeseries_external_ids:
158
+ self.client.migration.lookup.time_series(external_id=list(timeseries_external_ids))
159
+
160
+ def _map_single_item(self, item: Chart) -> tuple[ChartWrite | None, ChartMigrationIssue]:
161
+ issue = ChartMigrationIssue(chart_external_id=item.external_id)
162
+ time_series_collection = item.data.time_series_collection or []
163
+ timeseries_core_collection = self._create_timeseries_core_collection(time_series_collection, issue)
164
+ if issue.has_issues:
165
+ return None, issue
166
+
167
+ updated_source_collection = self._update_source_collection(
168
+ item.data.source_collection or [], time_series_collection, timeseries_core_collection
169
+ )
170
+
171
+ mapped_chart = item.as_write()
172
+ mapped_chart.data.core_timeseries_collection = timeseries_core_collection
173
+ mapped_chart.data.time_series_collection = None
174
+ mapped_chart.data.source_collection = updated_source_collection
175
+ return mapped_chart, issue
176
+
177
+ def _create_timeseries_core_collection(
178
+ self, time_series_collection: list[ChartTimeseries], issue: ChartMigrationIssue
179
+ ) -> list[ChartCoreTimeseries]:
180
+ timeseries_core_collection: list[ChartCoreTimeseries] = []
181
+ for ts_item in time_series_collection or []:
182
+ node_id, consumer_view_id = self._get_node_id_consumer_view_id(ts_item)
183
+
184
+ if node_id is None:
185
+ if ts_item.ts_id is not None:
186
+ issue.missing_timeseries_ids.append(ts_item.ts_id)
187
+ elif ts_item.ts_external_id is not None:
188
+ issue.missing_timeseries_external_ids.append(ts_item.ts_external_id)
189
+ else:
190
+ issue.missing_timeseries_identifier.append(ts_item.id or "unknown")
191
+ continue
192
+
193
+ core_timeseries = self._create_new_timeseries_core(ts_item, node_id, consumer_view_id)
194
+ timeseries_core_collection.append(core_timeseries)
195
+ return timeseries_core_collection
196
+
197
+ def _create_new_timeseries_core(
198
+ self, ts_item: ChartTimeseries, node_id: NodeId, consumer_view_id: ViewId | None
199
+ ) -> ChartCoreTimeseries:
200
+ dumped = ts_item.dump(camel_case=True)
201
+ for asset_centric_key in ["tsId", "tsExternalId", "originalUnit"]:
202
+ dumped.pop(asset_centric_key, None)
203
+
204
+ dumped["nodeReference"] = node_id
205
+ dumped["viewReference"] = consumer_view_id
206
+ new_uuid = str(uuid4())
207
+ dumped["id"] = new_uuid
208
+ dumped["type"] = "coreTimeseries"
209
+ core_timeseries = ChartCoreTimeseries._load(dumped)
210
+ return core_timeseries
211
+
212
+ def _get_node_id_consumer_view_id(self, ts_item: ChartTimeseries) -> tuple[NodeId | None, ViewId | None]:
213
+ """Look up the node ID and consumer view ID for a given timeseries item.
214
+
215
+ Prioritizes lookup by internal ID, then by external ID.
216
+
217
+ Args:
218
+ ts_item: The ChartTimeseries item to look up.
219
+
220
+ Returns:
221
+ A tuple containing the consumer view ID and node ID, or None if not found.
222
+ """
223
+ node_id: NodeId | None = None
224
+ consumer_view_id: ViewId | None = None
225
+ for id_name, id_value in [("id", ts_item.ts_id), ("external_id", ts_item.ts_external_id)]:
226
+ if id_value is None:
227
+ continue
228
+ arg = {id_name: id_value}
229
+ node_id = self.client.migration.lookup.time_series(**arg) # type: ignore[arg-type]
230
+ consumer_view_id = self.client.migration.lookup.time_series.consumer_view(**arg) # type: ignore[arg-type]
231
+ if node_id is not None:
232
+ break
233
+ return node_id, consumer_view_id
234
+
235
+ def _update_source_collection(
236
+ self,
237
+ source_collection: list[ChartSource],
238
+ time_series_collection: list[ChartTimeseries],
239
+ timeseries_core_collection: list[ChartCoreTimeseries],
240
+ ) -> list[ChartSource]:
241
+ remove_ids = {ts_item.id for ts_item in time_series_collection if ts_item.id is not None}
242
+ updated_source_collection = [ts_item for ts_item in source_collection if ts_item.id not in remove_ids]
243
+ for core_ts_item in timeseries_core_collection:
244
+ # We cast there two as we set them in the _create_timeseries_core_collection method
245
+ new_source_item = ChartSource(id=cast(str, core_ts_item.id), type=cast(str, core_ts_item.type))
246
+ updated_source_collection.append(new_source_item)
247
+ return updated_source_collection
@@ -30,6 +30,27 @@ class MigrationIssue(MigrationObject):
30
30
  return True
31
31
 
32
32
 
33
+ class ChartMigrationIssue(MigrationIssue):
34
+ """Represents a chart migration issue encountered during migration.
35
+
36
+ Attributes:
37
+ chart_external_id (str): The external ID of the chart that could not be migrated.
38
+ """
39
+
40
+ type: ClassVar[str] = "chartMigration"
41
+ chart_external_id: str
42
+ missing_timeseries_ids: list[int] = Field(default_factory=list)
43
+ missing_timeseries_external_ids: list[str] = Field(default_factory=list)
44
+ missing_timeseries_identifier: list[str] = Field(default_factory=list)
45
+
46
+ @property
47
+ def has_issues(self) -> bool:
48
+ """Check if there are any issues recorded in this ChartMigrationIssue."""
49
+ return bool(
50
+ self.missing_timeseries_ids or self.missing_timeseries_external_ids or self.missing_timeseries_identifier
51
+ )
52
+
53
+
33
54
  class ReadIssue(MigrationIssue):
34
55
  """Represents a read issue encountered during migration."""
35
56
 
@@ -12,7 +12,7 @@ jobs:
12
12
  environment: dev
13
13
  name: Deploy
14
14
  container:
15
- image: cognite/toolkit:0.6.108
15
+ image: cognite/toolkit:0.6.110
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.108
13
+ image: cognite/toolkit:0.6.110
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.6.108"
7
+ version = "0.6.110"
8
8
 
9
9
  [alpha_flags]
10
10
  external-libraries = true
@@ -1 +1 @@
1
- __version__ = "0.6.108"
1
+ __version__ = "0.6.110"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cognite_toolkit
3
- Version: 0.6.108
3
+ Version: 0.6.110
4
4
  Summary: Official Cognite Data Fusion tool for project templates and configuration deployment
5
5
  Project-URL: Homepage, https://docs.cognite.com/cdf/deploy/cdf_toolkit/
6
6
  Project-URL: Changelog, https://github.com/cognitedata/toolkit/releases
@@ -10,7 +10,7 @@ Author-email: Cognite AS <support@cognite.com>
10
10
  License-Expression: Apache-2.0
11
11
  License-File: LICENSE
12
12
  Requires-Python: >=3.10
13
- Requires-Dist: cognite-sdk<8.0.0,>=7.83.0
13
+ Requires-Dist: cognite-sdk<8.0.0,>=7.87.0
14
14
  Requires-Dist: filelock>=3.18.0
15
15
  Requires-Dist: httpx>=0.28.1
16
16
  Requires-Dist: mixpanel>=4.10.1
@@ -1,6 +1,6 @@
1
1
  cognite_toolkit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  cognite_toolkit/_cdf.py,sha256=0abeQr1Tfk4lkGaoXyrnFC28wDSlR_8UGrh10noGduQ,6085
3
- cognite_toolkit/_version.py,sha256=Ld9CJTmo6UAAAhfrT6vbnYlc1obPLtNQLTmXJM2ppEI,24
3
+ cognite_toolkit/_version.py,sha256=r8GW0BNwRXUAwN3axagFdsMsJonpDcvGzFglYAFiRio,24
4
4
  cognite_toolkit/_cdf_tk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  cognite_toolkit/_cdf_tk/cdf_toml.py,sha256=VSWV9h44HusWIaKpWgjrOMrc3hDoPTTXBXlp6-NOrIM,9079
6
6
  cognite_toolkit/_cdf_tk/constants.py,sha256=Gi7iGGzdUrOnBeIK6ix3XiBieHIwzLJO5BWjDI3a6l4,7082
@@ -77,7 +77,7 @@ cognite_toolkit/_cdf_tk/client/data_classes/base.py,sha256=J9Mhf7cYObYPWJ-ne98ec
77
77
  cognite_toolkit/_cdf_tk/client/data_classes/canvas.py,sha256=1yOSXkARz6QgIUnNryRy1UbV62dPAxE9qu5jfpOmPGE,48618
78
78
  cognite_toolkit/_cdf_tk/client/data_classes/capabilities.py,sha256=muqpAC2JLCFcEpRPzuh_3sS3o_q42WFyfsGzl-LfB_U,8773
79
79
  cognite_toolkit/_cdf_tk/client/data_classes/charts.py,sha256=l4LM1eqn8_2lRzw-DdwwL0zxgSczC0lp1LjgW-4wqPI,3770
80
- cognite_toolkit/_cdf_tk/client/data_classes/charts_data.py,sha256=nPbB-hQ7Z6D21CgBI3Zl8UQzsjlsWEuwCtBt93lYQ4Q,11242
80
+ cognite_toolkit/_cdf_tk/client/data_classes/charts_data.py,sha256=Zcx3st3bMJE2aa5U6TepDqRzqf-LuTTWW5grSaVGr9E,12244
81
81
  cognite_toolkit/_cdf_tk/client/data_classes/extendable_cognite_file.py,sha256=0iyLiXEzB4WBU-DL6DZS6nD5E526cDsftMGEYXwI8r8,9764
82
82
  cognite_toolkit/_cdf_tk/client/data_classes/extended_filemetadata.py,sha256=8zfXl_bhkums3quJzdOwAjxVNY6B0hpAs6jbkekn79o,5488
83
83
  cognite_toolkit/_cdf_tk/client/data_classes/extended_filemetdata.py,sha256=gKA5UcDKweH7SlzXfyZCspMyHUo0t8R5DbzeCPpzInM,6002
@@ -130,10 +130,10 @@ cognite_toolkit/_cdf_tk/commands/_migrate/command.py,sha256=jNoqqq81lbdfDTAQ5w2c
130
130
  cognite_toolkit/_cdf_tk/commands/_migrate/conversion.py,sha256=Ew9JRYrd-Ol9G9csTzpnhXAgCFnX67MwDYOTsdJLP3E,16803
131
131
  cognite_toolkit/_cdf_tk/commands/_migrate/creators.py,sha256=FTu7w3G8KyPY8pagG3KdPpOmpLcjehaAg2auEy6iM7A,9605
132
132
  cognite_toolkit/_cdf_tk/commands/_migrate/data_classes.py,sha256=_vMS_qAPj4yup1VnmmojPVigAZtyPQH7PM0Raby5tao,10619
133
- cognite_toolkit/_cdf_tk/commands/_migrate/data_mapper.py,sha256=Y7MrE6FGa15uvboBjNyWNlslsBv4FpeP5WsrFsooxsA,5678
133
+ cognite_toolkit/_cdf_tk/commands/_migrate/data_mapper.py,sha256=Q4VZsOF7__xkbNsCbzzhu-1Q34kYrMks1sKUZCk6ItY,11731
134
134
  cognite_toolkit/_cdf_tk/commands/_migrate/data_model.py,sha256=i1eUsNX6Dueol9STIEwyksBnBsWUk13O8qHIjW964pM,7860
135
135
  cognite_toolkit/_cdf_tk/commands/_migrate/default_mappings.py,sha256=ERn3qFrJFXdtXaMjHq3Gk7MxH03MGFk3FrtWCOBJQts,5544
136
- cognite_toolkit/_cdf_tk/commands/_migrate/issues.py,sha256=lWSnuS3CfRDbA7i1g12gJ2reJnQcLmZWxHDK19-Wxkk,5772
136
+ cognite_toolkit/_cdf_tk/commands/_migrate/issues.py,sha256=L2-kODPavEwcuhte7EXANK2-rH7reiq-uNqr-3ub-no,6575
137
137
  cognite_toolkit/_cdf_tk/commands/_migrate/migration_io.py,sha256=wrdBH5P6NgiZQSYLR0iJ3ZvqfQ5fY-_Ne2yKv9E1g4o,16277
138
138
  cognite_toolkit/_cdf_tk/commands/_migrate/prepare.py,sha256=RfqaNoso5CyBwc-p6ckwcYqBfZXKhdJgdGIyd0TATaI,2635
139
139
  cognite_toolkit/_cdf_tk/commands/_migrate/selectors.py,sha256=N1H_-rBpPUD6pbrlcofn1uEK1bA694EUXEe1zIXeqyo,2489
@@ -300,13 +300,13 @@ cognite_toolkit/_repo_files/.gitignore,sha256=ip9kf9tcC5OguF4YF4JFEApnKYw0nG0vPi
300
300
  cognite_toolkit/_repo_files/AzureDevOps/.devops/README.md,sha256=OLA0D7yCX2tACpzvkA0IfkgQ4_swSd-OlJ1tYcTBpsA,240
301
301
  cognite_toolkit/_repo_files/AzureDevOps/.devops/deploy-pipeline.yml,sha256=brULcs8joAeBC_w_aoWjDDUHs3JheLMIR9ajPUK96nc,693
302
302
  cognite_toolkit/_repo_files/AzureDevOps/.devops/dry-run-pipeline.yml,sha256=OBFDhFWK1mlT4Dc6mDUE2Es834l8sAlYG50-5RxRtHk,723
303
- cognite_toolkit/_repo_files/GitHub/.github/workflows/deploy.yaml,sha256=dd1a4r1yPhWGZNiuUgz5ywOuECEdJ6n3Rd0Etma6sOU,668
304
- cognite_toolkit/_repo_files/GitHub/.github/workflows/dry-run.yaml,sha256=be_1m-aAgnzTGWdnEHIoJcQQrAm4ghUx-h171Hjzwww,2431
305
- cognite_toolkit/_resources/cdf.toml,sha256=HmbxZ9XLAQUSXhGmt6zXsKjO1fgeX9TAuU6DLjAsM9I,488
303
+ cognite_toolkit/_repo_files/GitHub/.github/workflows/deploy.yaml,sha256=sajGLbABAzcw49Ppp9445f-X0UR7aaEHM8zyQqa8OK4,668
304
+ cognite_toolkit/_repo_files/GitHub/.github/workflows/dry-run.yaml,sha256=FN7MyRwPdPA03R2VccxMZiKv58wrE1zxTUyx-oaPs2M,2431
305
+ cognite_toolkit/_resources/cdf.toml,sha256=fr1qQg8VjnRir6nN2fiK6dBQWp2GiKPKON-kM9XYktM,488
306
306
  cognite_toolkit/demo/__init__.py,sha256=-m1JoUiwRhNCL18eJ6t7fZOL7RPfowhCuqhYFtLgrss,72
307
307
  cognite_toolkit/demo/_base.py,sha256=6xKBUQpXZXGQ3fJ5f7nj7oT0s2n7OTAGIa17ZlKHZ5U,8052
308
- cognite_toolkit-0.6.108.dist-info/METADATA,sha256=Nne190DHpFhzrXHLX6poNNcqltn9G0uwJ4-daOK1b4s,4502
309
- cognite_toolkit-0.6.108.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
310
- cognite_toolkit-0.6.108.dist-info/entry_points.txt,sha256=JlR7MH1_UMogC3QOyN4-1l36VbrCX9xUdQoHGkuJ6-4,83
311
- cognite_toolkit-0.6.108.dist-info/licenses/LICENSE,sha256=CW0DRcx5tL-pCxLEN7ts2S9g2sLRAsWgHVEX4SN9_Mc,752
312
- cognite_toolkit-0.6.108.dist-info/RECORD,,
308
+ cognite_toolkit-0.6.110.dist-info/METADATA,sha256=3NOWs5ZjtTei1p98UMZs-9QKy9clBW0aqa1rY0hIp_U,4502
309
+ cognite_toolkit-0.6.110.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
310
+ cognite_toolkit-0.6.110.dist-info/entry_points.txt,sha256=JlR7MH1_UMogC3QOyN4-1l36VbrCX9xUdQoHGkuJ6-4,83
311
+ cognite_toolkit-0.6.110.dist-info/licenses/LICENSE,sha256=CW0DRcx5tL-pCxLEN7ts2S9g2sLRAsWgHVEX4SN9_Mc,752
312
+ cognite_toolkit-0.6.110.dist-info/RECORD,,