nominal 1.104.3__tar.gz → 1.106.0__tar.gz

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 (114) hide show
  1. {nominal-1.104.3 → nominal-1.106.0}/CHANGELOG.md +19 -0
  2. {nominal-1.104.3 → nominal-1.106.0}/PKG-INFO +2 -2
  3. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/dataset.py +4 -0
  4. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/compute/_buckets.py +35 -4
  5. nominal-1.106.0/nominal/experimental/dataset_utils/__init__.py +5 -0
  6. nominal-1.106.0/nominal/experimental/dataset_utils/_dataset_utils.py +52 -0
  7. nominal-1.106.0/nominal/experimental/migration/migration_resources.py +18 -0
  8. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/migration/migration_utils.py +56 -33
  9. {nominal-1.104.3 → nominal-1.106.0}/pyproject.toml +2 -2
  10. {nominal-1.104.3 → nominal-1.106.0}/.gitignore +0 -0
  11. {nominal-1.104.3 → nominal-1.106.0}/LICENSE +0 -0
  12. {nominal-1.104.3 → nominal-1.106.0}/README.md +0 -0
  13. {nominal-1.104.3 → nominal-1.106.0}/nominal/__init__.py +0 -0
  14. {nominal-1.104.3 → nominal-1.106.0}/nominal/__main__.py +0 -0
  15. {nominal-1.104.3 → nominal-1.106.0}/nominal/_utils/README.md +0 -0
  16. {nominal-1.104.3 → nominal-1.106.0}/nominal/_utils/__init__.py +0 -0
  17. {nominal-1.104.3 → nominal-1.106.0}/nominal/_utils/dataclass_tools.py +0 -0
  18. {nominal-1.104.3 → nominal-1.106.0}/nominal/_utils/deprecation_tools.py +0 -0
  19. {nominal-1.104.3 → nominal-1.106.0}/nominal/_utils/iterator_tools.py +0 -0
  20. {nominal-1.104.3 → nominal-1.106.0}/nominal/_utils/streaming_tools.py +0 -0
  21. {nominal-1.104.3 → nominal-1.106.0}/nominal/_utils/timing_tools.py +0 -0
  22. {nominal-1.104.3 → nominal-1.106.0}/nominal/cli/__init__.py +0 -0
  23. {nominal-1.104.3 → nominal-1.106.0}/nominal/cli/__main__.py +0 -0
  24. {nominal-1.104.3 → nominal-1.106.0}/nominal/cli/attachment.py +0 -0
  25. {nominal-1.104.3 → nominal-1.106.0}/nominal/cli/auth.py +0 -0
  26. {nominal-1.104.3 → nominal-1.106.0}/nominal/cli/config.py +0 -0
  27. {nominal-1.104.3 → nominal-1.106.0}/nominal/cli/dataset.py +0 -0
  28. {nominal-1.104.3 → nominal-1.106.0}/nominal/cli/download.py +0 -0
  29. {nominal-1.104.3 → nominal-1.106.0}/nominal/cli/mis.py +0 -0
  30. {nominal-1.104.3 → nominal-1.106.0}/nominal/cli/run.py +0 -0
  31. {nominal-1.104.3 → nominal-1.106.0}/nominal/cli/util/__init__.py +0 -0
  32. {nominal-1.104.3 → nominal-1.106.0}/nominal/cli/util/click_log_handler.py +0 -0
  33. {nominal-1.104.3 → nominal-1.106.0}/nominal/cli/util/global_decorators.py +0 -0
  34. {nominal-1.104.3 → nominal-1.106.0}/nominal/cli/util/verify_connection.py +0 -0
  35. {nominal-1.104.3 → nominal-1.106.0}/nominal/config/__init__.py +0 -0
  36. {nominal-1.104.3 → nominal-1.106.0}/nominal/config/_config.py +0 -0
  37. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/__init__.py +0 -0
  38. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/_clientsbunch.py +0 -0
  39. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/_constants.py +0 -0
  40. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/_event_types.py +0 -0
  41. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/_stream/__init__.py +0 -0
  42. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/_stream/batch_processor.py +0 -0
  43. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/_stream/batch_processor_proto.py +0 -0
  44. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/_stream/write_stream.py +0 -0
  45. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/_stream/write_stream_base.py +0 -0
  46. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/_types.py +0 -0
  47. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/_utils/README.md +0 -0
  48. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/_utils/__init__.py +0 -0
  49. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/_utils/api_tools.py +0 -0
  50. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/_utils/multipart.py +0 -0
  51. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/_utils/multipart_downloader.py +0 -0
  52. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/_utils/networking.py +0 -0
  53. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/_utils/pagination_tools.py +0 -0
  54. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/_utils/query_tools.py +0 -0
  55. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/_utils/queueing.py +0 -0
  56. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/asset.py +0 -0
  57. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/attachment.py +0 -0
  58. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/bounds.py +0 -0
  59. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/channel.py +0 -0
  60. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/checklist.py +0 -0
  61. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/client.py +0 -0
  62. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/connection.py +0 -0
  63. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/containerized_extractors.py +0 -0
  64. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/data_review.py +0 -0
  65. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/dataset_file.py +0 -0
  66. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/datasource.py +0 -0
  67. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/event.py +0 -0
  68. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/exceptions.py +0 -0
  69. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/filetype.py +0 -0
  70. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/log.py +0 -0
  71. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/run.py +0 -0
  72. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/secret.py +0 -0
  73. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/unit.py +0 -0
  74. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/user.py +0 -0
  75. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/video.py +0 -0
  76. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/video_file.py +0 -0
  77. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/workbook.py +0 -0
  78. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/workbook_template.py +0 -0
  79. {nominal-1.104.3 → nominal-1.106.0}/nominal/core/workspace.py +0 -0
  80. {nominal-1.104.3 → nominal-1.106.0}/nominal/exceptions/__init__.py +0 -0
  81. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/__init__.py +0 -0
  82. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/compute/README.md +0 -0
  83. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/compute/__init__.py +0 -0
  84. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/compute/dsl/__init__.py +0 -0
  85. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/compute/dsl/_enum_expr_impls.py +0 -0
  86. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/compute/dsl/_numeric_expr_impls.py +0 -0
  87. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/compute/dsl/_range_expr_impls.py +0 -0
  88. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/compute/dsl/exprs.py +0 -0
  89. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/compute/dsl/params.py +0 -0
  90. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/logging/__init__.py +0 -0
  91. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/logging/click_log_handler.py +0 -0
  92. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/logging/nominal_log_handler.py +0 -0
  93. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/logging/rich_log_handler.py +0 -0
  94. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/migration/__init__.py +0 -0
  95. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/rust_streaming/__init__.py +0 -0
  96. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/rust_streaming/rust_write_stream.py +0 -0
  97. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/stream_v2/__init__.py +0 -0
  98. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/stream_v2/_serializer.py +0 -0
  99. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/stream_v2/_write_stream.py +0 -0
  100. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/video_processing/__init__.py +0 -0
  101. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/video_processing/resolution.py +0 -0
  102. {nominal-1.104.3 → nominal-1.106.0}/nominal/experimental/video_processing/video_conversion.py +0 -0
  103. {nominal-1.104.3 → nominal-1.106.0}/nominal/nominal.py +0 -0
  104. {nominal-1.104.3 → nominal-1.106.0}/nominal/py.typed +0 -0
  105. {nominal-1.104.3 → nominal-1.106.0}/nominal/thirdparty/__init__.py +0 -0
  106. {nominal-1.104.3 → nominal-1.106.0}/nominal/thirdparty/matlab/__init__.py +0 -0
  107. {nominal-1.104.3 → nominal-1.106.0}/nominal/thirdparty/matlab/_matlab.py +0 -0
  108. {nominal-1.104.3 → nominal-1.106.0}/nominal/thirdparty/pandas/__init__.py +0 -0
  109. {nominal-1.104.3 → nominal-1.106.0}/nominal/thirdparty/pandas/_pandas.py +0 -0
  110. {nominal-1.104.3 → nominal-1.106.0}/nominal/thirdparty/polars/__init__.py +0 -0
  111. {nominal-1.104.3 → nominal-1.106.0}/nominal/thirdparty/polars/polars_export_handler.py +0 -0
  112. {nominal-1.104.3 → nominal-1.106.0}/nominal/thirdparty/tdms/__init__.py +0 -0
  113. {nominal-1.104.3 → nominal-1.106.0}/nominal/thirdparty/tdms/_tdms.py +0 -0
  114. {nominal-1.104.3 → nominal-1.106.0}/nominal/ts/__init__.py +0 -0
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.106.0](https://github.com/nominal-io/nominal-client/compare/v1.105.0...v1.106.0) (2026-01-21)
4
+
5
+
6
+ ### Features
7
+
8
+ * create dataset with uuid endpoint for mgiration ([#580](https://github.com/nominal-io/nominal-client/issues/580)) ([f3a3b38](https://github.com/nominal-io/nominal-client/commit/f3a3b383d62e8466af617179479918ef0d1ee534))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * handle case where compute returns a non-bucketed response for a bucketed query ([#579](https://github.com/nominal-io/nominal-client/issues/579)) ([58b84f5](https://github.com/nominal-io/nominal-client/commit/58b84f55d282a84c8eb6703816b16920e3b8ecf3))
14
+
15
+ ## [1.105.0](https://github.com/nominal-io/nominal-client/compare/v1.104.3...v1.105.0) (2026-01-21)
16
+
17
+
18
+ ### Features
19
+
20
+ * refactor top-level migration config to allow for mapping of templates to assets ([#577](https://github.com/nominal-io/nominal-client/issues/577)) ([9f1f39d](https://github.com/nominal-io/nominal-client/commit/9f1f39d721ea54135441e00b0a31c8fdd78b381c))
21
+
3
22
  ## [1.104.3](https://github.com/nominal-io/nominal-client/compare/v1.104.2...v1.104.3) (2026-01-13)
4
23
 
5
24
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nominal
3
- Version: 1.104.3
3
+ Version: 1.106.0
4
4
  Summary: Automate Nominal workflows in Python
5
5
  Project-URL: Homepage, https://nominal.io
6
6
  Project-URL: Documentation, https://docs.nominal.io
@@ -20,7 +20,7 @@ Requires-Dist: cachetools>=6.1.0
20
20
  Requires-Dist: click<9,>=8
21
21
  Requires-Dist: conjure-python-client<4,>=3.1.0
22
22
  Requires-Dist: ffmpeg-python>=0.2.0
23
- Requires-Dist: nominal-api==0.1032.0
23
+ Requires-Dist: nominal-api==0.1075.0
24
24
  Requires-Dist: nominal-streaming==0.5.8; platform_python_implementation == 'CPython' and python_version >= '3.10' and ((sys_platform == 'win32' and platform_machine == 'AMD64') or (sys_platform == 'darwin' and platform_machine == 'arm64') or (sys_platform == 'linux' and (platform_machine == 'x86_64' or platform_machine == 'armv7l')))
25
25
  Requires-Dist: openpyxl>=0.0.0
26
26
  Requires-Dist: pandas>=0.0.0
@@ -1093,6 +1093,7 @@ def _construct_new_ingest_options(
1093
1093
  tag_columns=tag_columns,
1094
1094
  is_archive=file_type.is_parquet_archive(),
1095
1095
  additional_file_tags={**tags} if tags else None,
1096
+ exclude_columns=[],
1096
1097
  )
1097
1098
  )
1098
1099
  else:
@@ -1107,6 +1108,7 @@ def _construct_new_ingest_options(
1107
1108
  channel_prefix=channel_prefix,
1108
1109
  tag_columns=tag_columns,
1109
1110
  additional_file_tags={**tags} if tags else None,
1111
+ exclude_columns=[],
1110
1112
  )
1111
1113
  )
1112
1114
 
@@ -1139,6 +1141,7 @@ def _construct_existing_ingest_options(
1139
1141
  tag_columns=tag_columns,
1140
1142
  is_archive=file_type.is_parquet_archive(),
1141
1143
  additional_file_tags={**tags} if tags else None,
1144
+ exclude_columns=[],
1142
1145
  )
1143
1146
  )
1144
1147
  else:
@@ -1152,5 +1155,6 @@ def _construct_existing_ingest_options(
1152
1155
  timestamp_metadata=timestamp_metadata,
1153
1156
  tag_columns=tag_columns,
1154
1157
  additional_file_tags={**tags} if tags else None,
1158
+ exclude_columns=[],
1155
1159
  )
1156
1160
  )
@@ -317,10 +317,41 @@ def _compute_buckets(
317
317
  def _numeric_buckets_from_compute_response(
318
318
  response: scout_compute_api.ComputeNodeResponse,
319
319
  ) -> Iterable[tuple[api.Timestamp, scout_compute_api.NumericBucket]]:
320
- if response.type != "bucketedNumeric" or response.bucketed_numeric is None:
321
- return
322
-
323
- yield from zip(response.bucketed_numeric.timestamps, response.bucketed_numeric.buckets)
320
+ if response.numeric_point is not None:
321
+ # single point would be returned-- create a synthetic bucket
322
+ val = response.numeric_point.value
323
+ yield (
324
+ response.numeric_point.timestamp,
325
+ scout_compute_api.NumericBucket(
326
+ count=1,
327
+ first_point=response.numeric_point,
328
+ max=val,
329
+ mean=val,
330
+ min=val,
331
+ variance=0,
332
+ last_point=response.numeric_point,
333
+ ),
334
+ )
335
+ elif response.numeric is not None:
336
+ # Not enough points to reach the number of requested bucket count, so
337
+ # gets returned as all of the raw data.
338
+ for timestamp, value in zip(response.numeric.timestamps, response.numeric.values):
339
+ point = scout_compute_api.NumericPoint(timestamp, value)
340
+ yield (
341
+ timestamp,
342
+ scout_compute_api.NumericBucket(
343
+ count=1,
344
+ first_point=point,
345
+ max=value,
346
+ min=value,
347
+ mean=value,
348
+ variance=0,
349
+ last_point=point,
350
+ ),
351
+ )
352
+ elif response.bucketed_numeric is not None:
353
+ # Actually bucketed data
354
+ yield from zip(response.bucketed_numeric.timestamps, response.bucketed_numeric.buckets)
324
355
 
325
356
 
326
357
  def _timestamp_from_conjure(timestamp: api.Timestamp) -> params.NanosecondsUTC:
@@ -0,0 +1,5 @@
1
+ from nominal.experimental.dataset_utils._dataset_utils import create_dataset_with_uuid
2
+
3
+ __all__ = [
4
+ "create_dataset_with_uuid",
5
+ ]
@@ -0,0 +1,52 @@
1
+ from collections.abc import Mapping, Sequence
2
+
3
+ from nominal_api import scout_catalog
4
+
5
+ from nominal.core import Dataset, NominalClient
6
+
7
+
8
+ def create_dataset_with_uuid(
9
+ client: NominalClient,
10
+ dataset_uuid: str,
11
+ name: str,
12
+ *,
13
+ description: str | None = None,
14
+ labels: Sequence[str] = (),
15
+ properties: Mapping[str, str] | None = None,
16
+ ) -> Dataset:
17
+ """Create a dataset with a specific UUID.
18
+
19
+ This is useful for migrations where the dataset UUID must be controlled by the caller.
20
+ Throws a conflict error if a dataset with the specified UUID already exists.
21
+
22
+ This endpoint is not intended for general use. Use `NominalClient.create_dataset` instead
23
+ to create a new dataset with an auto-generated UUID.
24
+
25
+ Args:
26
+ client: The NominalClient to use for creating the dataset.
27
+ dataset_uuid: The UUID to assign to the new dataset.
28
+ name: Name of the dataset to create.
29
+ description: Human readable description of the dataset.
30
+ labels: Text labels to apply to the created dataset.
31
+ properties: Key-value properties to apply to the created dataset.
32
+
33
+ Returns:
34
+ Reference to the created dataset in Nominal.
35
+ """
36
+ create_dataset_request = scout_catalog.CreateDataset(
37
+ name=name,
38
+ description=description,
39
+ labels=list(labels),
40
+ properties={} if properties is None else dict(properties),
41
+ is_v2_dataset=True,
42
+ metadata={},
43
+ origin_metadata=scout_catalog.DatasetOriginMetadata(),
44
+ workspace=client._clients.workspace_rid,
45
+ marking_rids=[],
46
+ )
47
+ request = scout_catalog.CreateDatasetWithUuidRequest(
48
+ create_dataset=create_dataset_request,
49
+ uuid=dataset_uuid,
50
+ )
51
+ response = client._clients.catalog.create_dataset_with_uuid(client._clients.auth_header, request)
52
+ return Dataset._from_conjure(client._clients, response)
@@ -0,0 +1,18 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Sequence
5
+
6
+ from nominal.core.asset import Asset
7
+ from nominal.core.workbook_template import WorkbookTemplate
8
+
9
+
10
+ @dataclass(frozen=True)
11
+ class AssetResources:
12
+ asset: Asset
13
+ source_workbook_templates: Sequence[WorkbookTemplate]
14
+
15
+
16
+ @dataclass(frozen=True)
17
+ class MigrationResources:
18
+ source_assets: Sequence[AssetResources]
@@ -26,6 +26,8 @@ from nominal.core._event_types import EventType, SearchEventOriginType
26
26
  from nominal.core._utils.api_tools import Link, LinkDict
27
27
  from nominal.core.attachment import Attachment
28
28
  from nominal.core.run import Run
29
+ from nominal.experimental.dataset_utils import create_dataset_with_uuid
30
+ from nominal.experimental.migration.migration_resources import MigrationResources
29
31
  from nominal.ts import (
30
32
  IntegralNanosecondsDuration,
31
33
  IntegralNanosecondsUTC,
@@ -421,6 +423,7 @@ def copy_dataset_from(
421
423
  new_dataset_properties: dict[str, Any] | None = None,
422
424
  new_dataset_labels: Sequence[str] | None = None,
423
425
  include_files: bool = False,
426
+ preserve_uuid: bool = False,
424
427
  ) -> Dataset:
425
428
  """Copy a dataset from the source to the destination client.
426
429
 
@@ -434,6 +437,9 @@ def copy_dataset_from(
434
437
  properties are used.
435
438
  new_dataset_labels: Optional new labels for the copied dataset. If not provided, the original labels are used.
436
439
  include_files: Whether to include files in the copied dataset.
440
+ preserve_uuid: If True, create the dataset with the same UUID as the source dataset.
441
+ This is useful for migrations where references to datasets must be preserved.
442
+ Throws a conflict error if a dataset with the UUID already exists.
437
443
 
438
444
  Returns:
439
445
  The newly created Dataset in the destination client.
@@ -447,12 +453,34 @@ def copy_dataset_from(
447
453
  source_dataset.rid,
448
454
  extra=log_extras,
449
455
  )
450
- new_dataset = destination_client.create_dataset(
451
- name=new_dataset_name if new_dataset_name is not None else source_dataset.name,
452
- description=new_dataset_description if new_dataset_description is not None else source_dataset.description,
453
- properties=new_dataset_properties if new_dataset_properties is not None else source_dataset.properties,
454
- labels=new_dataset_labels if new_dataset_labels is not None else source_dataset.labels,
455
- )
456
+
457
+ dataset_name = new_dataset_name if new_dataset_name is not None else source_dataset.name
458
+ dataset_description = new_dataset_description if new_dataset_description is not None else source_dataset.description
459
+ dataset_properties = new_dataset_properties if new_dataset_properties is not None else source_dataset.properties
460
+ dataset_labels = new_dataset_labels if new_dataset_labels is not None else source_dataset.labels
461
+
462
+ if preserve_uuid:
463
+ # Extract the UUID from the source dataset's rid
464
+ match = UUID_PATTERN.search(source_dataset.rid)
465
+ if not match:
466
+ raise ValueError(f"Could not extract UUID from dataset rid: {source_dataset.rid}")
467
+ source_uuid = match.group(2)
468
+ new_dataset = create_dataset_with_uuid(
469
+ client=destination_client,
470
+ dataset_uuid=source_uuid,
471
+ name=dataset_name,
472
+ description=dataset_description,
473
+ labels=dataset_labels,
474
+ properties=dataset_properties,
475
+ )
476
+ else:
477
+ new_dataset = destination_client.create_dataset(
478
+ name=dataset_name,
479
+ description=dataset_description,
480
+ properties=dataset_properties,
481
+ labels=dataset_labels,
482
+ )
483
+
456
484
  if include_files:
457
485
  for source_file in source_dataset.list_files():
458
486
  copy_file_to_dataset(source_file, new_dataset)
@@ -681,17 +709,14 @@ def copy_asset_from(
681
709
 
682
710
  def copy_resources_to_destination_client(
683
711
  destination_client: NominalClient,
684
- source_assets: Sequence[Asset],
685
- source_workbook_templates: Sequence[WorkbookTemplate],
712
+ migration_resources: MigrationResources,
686
713
  ) -> tuple[Sequence[tuple[str, Dataset]], Sequence[Asset], Sequence[WorkbookTemplate], Sequence[Workbook]]:
687
714
  """Based on a list of assets and workbook templates, copy resources to destination client, creating
688
715
  new datasets, datafiles, and workbooks along the way.
689
716
 
690
717
  Args:
691
718
  destination_client (NominalClient): client of the tenant/workspace to copy resources to.
692
- source_assets (Sequence[Asset]): a list of assets to copy (with data)
693
- source_workbook_templates (Sequence[WorkbookTemplate]): a list of workbook templates to clone
694
- and create workbooks from.
719
+ migration_resources (MigrationResources): resources to copy.
695
720
 
696
721
  Returns:
697
722
  All of the created resources.
@@ -700,32 +725,30 @@ def copy_resources_to_destination_client(
700
725
  "destination_client_workspace": destination_client.get_workspace(destination_client._clients.workspace_rid).rid,
701
726
  }
702
727
 
703
- if len(source_assets) != 1:
704
- raise ValueError("Currently, only single asset can be used to create workbook from template")
705
-
706
728
  new_assets = []
729
+ new_templates = []
730
+ new_workbooks = []
731
+
707
732
  new_data_scopes_and_datasets: list[tuple[str, Dataset]] = []
708
- for source_asset in source_assets:
709
- new_asset = clone_asset(source_asset, destination_client)
733
+ for source_asset in migration_resources.source_assets:
734
+ new_asset = clone_asset(source_asset.asset, destination_client)
710
735
  new_assets.append(new_asset)
711
736
  new_data_scopes_and_datasets.extend(new_asset.list_datasets())
712
- new_templates = []
713
- new_workbooks = []
714
737
 
715
- for source_workbook_template in source_workbook_templates:
716
- new_template = clone_workbook_template(source_workbook_template, destination_client)
717
- new_templates.append(new_template)
718
- new_workbook = new_template.create_workbook(
719
- title=new_template.title, description=new_template.description, asset=new_assets[0]
720
- )
721
- logger.debug(
722
- "Created new workbook %s (rid: %s) from template %s (rid: %s)",
723
- new_workbook.title,
724
- new_workbook.rid,
725
- new_template.title,
726
- new_template.rid,
727
- extra=log_extras,
728
- )
729
- new_workbooks.append(new_workbook)
738
+ for source_workbook_template in source_asset.source_workbook_templates:
739
+ new_template = clone_workbook_template(source_workbook_template, destination_client)
740
+ new_templates.append(new_template)
741
+ new_workbook = new_template.create_workbook(
742
+ title=new_template.title, description=new_template.description, asset=new_assets[0]
743
+ )
744
+ logger.debug(
745
+ "Created new workbook %s (rid: %s) from template %s (rid: %s)",
746
+ new_workbook.title,
747
+ new_workbook.rid,
748
+ new_template.title,
749
+ new_template.rid,
750
+ extra=log_extras,
751
+ )
752
+ new_workbooks.append(new_workbook)
730
753
 
731
754
  return (new_data_scopes_and_datasets, new_assets, new_templates, new_workbooks)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nominal"
3
- version = "1.104.3"
3
+ version = "1.106.0"
4
4
  description = "Automate Nominal workflows in Python"
5
5
  authors = [
6
6
  { name = "Alexander Reynolds", email = "alex.reynolds@nominal.io" },
@@ -28,7 +28,7 @@ dependencies = [
28
28
  "click>=8,<9",
29
29
  "conjure-python-client>=3.1.0,<4",
30
30
  "ffmpeg-python>=0.2.0",
31
- "nominal-api==0.1032.0",
31
+ "nominal-api==0.1075.0",
32
32
  "rich>=14.1.0",
33
33
  "tabulate>=0.9.0,<0.10",
34
34
  "truststore>=0.10.4",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes