nominal 1.107.0__tar.gz → 1.109.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 (115) hide show
  1. {nominal-1.107.0 → nominal-1.109.0}/CHANGELOG.md +14 -0
  2. {nominal-1.107.0 → nominal-1.109.0}/PKG-INFO +1 -1
  3. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/_clientsbunch.py +3 -0
  4. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/channel.py +13 -0
  5. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/datasource.py +51 -0
  6. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/migration/migration_utils.py +20 -2
  7. {nominal-1.107.0 → nominal-1.109.0}/pyproject.toml +1 -1
  8. {nominal-1.107.0 → nominal-1.109.0}/.gitignore +0 -0
  9. {nominal-1.107.0 → nominal-1.109.0}/LICENSE +0 -0
  10. {nominal-1.107.0 → nominal-1.109.0}/README.md +0 -0
  11. {nominal-1.107.0 → nominal-1.109.0}/nominal/__init__.py +0 -0
  12. {nominal-1.107.0 → nominal-1.109.0}/nominal/__main__.py +0 -0
  13. {nominal-1.107.0 → nominal-1.109.0}/nominal/_utils/README.md +0 -0
  14. {nominal-1.107.0 → nominal-1.109.0}/nominal/_utils/__init__.py +0 -0
  15. {nominal-1.107.0 → nominal-1.109.0}/nominal/_utils/dataclass_tools.py +0 -0
  16. {nominal-1.107.0 → nominal-1.109.0}/nominal/_utils/deprecation_tools.py +0 -0
  17. {nominal-1.107.0 → nominal-1.109.0}/nominal/_utils/iterator_tools.py +0 -0
  18. {nominal-1.107.0 → nominal-1.109.0}/nominal/_utils/streaming_tools.py +0 -0
  19. {nominal-1.107.0 → nominal-1.109.0}/nominal/_utils/timing_tools.py +0 -0
  20. {nominal-1.107.0 → nominal-1.109.0}/nominal/cli/__init__.py +0 -0
  21. {nominal-1.107.0 → nominal-1.109.0}/nominal/cli/__main__.py +0 -0
  22. {nominal-1.107.0 → nominal-1.109.0}/nominal/cli/attachment.py +0 -0
  23. {nominal-1.107.0 → nominal-1.109.0}/nominal/cli/auth.py +0 -0
  24. {nominal-1.107.0 → nominal-1.109.0}/nominal/cli/config.py +0 -0
  25. {nominal-1.107.0 → nominal-1.109.0}/nominal/cli/dataset.py +0 -0
  26. {nominal-1.107.0 → nominal-1.109.0}/nominal/cli/download.py +0 -0
  27. {nominal-1.107.0 → nominal-1.109.0}/nominal/cli/mis.py +0 -0
  28. {nominal-1.107.0 → nominal-1.109.0}/nominal/cli/run.py +0 -0
  29. {nominal-1.107.0 → nominal-1.109.0}/nominal/cli/util/__init__.py +0 -0
  30. {nominal-1.107.0 → nominal-1.109.0}/nominal/cli/util/click_log_handler.py +0 -0
  31. {nominal-1.107.0 → nominal-1.109.0}/nominal/cli/util/global_decorators.py +0 -0
  32. {nominal-1.107.0 → nominal-1.109.0}/nominal/cli/util/verify_connection.py +0 -0
  33. {nominal-1.107.0 → nominal-1.109.0}/nominal/config/__init__.py +0 -0
  34. {nominal-1.107.0 → nominal-1.109.0}/nominal/config/_config.py +0 -0
  35. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/__init__.py +0 -0
  36. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/_constants.py +0 -0
  37. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/_event_types.py +0 -0
  38. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/_stream/__init__.py +0 -0
  39. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/_stream/batch_processor.py +0 -0
  40. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/_stream/batch_processor_proto.py +0 -0
  41. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/_stream/write_stream.py +0 -0
  42. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/_stream/write_stream_base.py +0 -0
  43. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/_types.py +0 -0
  44. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/_utils/README.md +0 -0
  45. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/_utils/__init__.py +0 -0
  46. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/_utils/api_tools.py +0 -0
  47. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/_utils/multipart.py +0 -0
  48. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/_utils/multipart_downloader.py +0 -0
  49. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/_utils/networking.py +0 -0
  50. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/_utils/pagination_tools.py +0 -0
  51. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/_utils/query_tools.py +0 -0
  52. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/_utils/queueing.py +0 -0
  53. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/asset.py +0 -0
  54. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/attachment.py +0 -0
  55. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/bounds.py +0 -0
  56. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/checklist.py +0 -0
  57. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/client.py +0 -0
  58. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/connection.py +0 -0
  59. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/containerized_extractors.py +0 -0
  60. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/data_review.py +0 -0
  61. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/dataset.py +0 -0
  62. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/dataset_file.py +0 -0
  63. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/event.py +0 -0
  64. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/exceptions.py +0 -0
  65. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/filetype.py +0 -0
  66. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/log.py +0 -0
  67. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/run.py +0 -0
  68. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/secret.py +0 -0
  69. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/unit.py +0 -0
  70. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/user.py +0 -0
  71. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/video.py +0 -0
  72. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/video_file.py +0 -0
  73. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/workbook.py +0 -0
  74. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/workbook_template.py +0 -0
  75. {nominal-1.107.0 → nominal-1.109.0}/nominal/core/workspace.py +0 -0
  76. {nominal-1.107.0 → nominal-1.109.0}/nominal/exceptions/__init__.py +0 -0
  77. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/__init__.py +0 -0
  78. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/compute/README.md +0 -0
  79. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/compute/__init__.py +0 -0
  80. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/compute/_buckets.py +0 -0
  81. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/compute/dsl/__init__.py +0 -0
  82. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/compute/dsl/_enum_expr_impls.py +0 -0
  83. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/compute/dsl/_numeric_expr_impls.py +0 -0
  84. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/compute/dsl/_range_expr_impls.py +0 -0
  85. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/compute/dsl/exprs.py +0 -0
  86. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/compute/dsl/params.py +0 -0
  87. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/dataset_utils/__init__.py +0 -0
  88. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/dataset_utils/_dataset_utils.py +0 -0
  89. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/logging/__init__.py +0 -0
  90. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/logging/click_log_handler.py +0 -0
  91. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/logging/nominal_log_handler.py +0 -0
  92. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/logging/rich_log_handler.py +0 -0
  93. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/migration/__init__.py +0 -0
  94. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/migration/migration_data_config.py +0 -0
  95. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/migration/migration_resources.py +0 -0
  96. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/rust_streaming/__init__.py +0 -0
  97. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/rust_streaming/rust_write_stream.py +0 -0
  98. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/stream_v2/__init__.py +0 -0
  99. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/stream_v2/_serializer.py +0 -0
  100. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/stream_v2/_write_stream.py +0 -0
  101. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/video_processing/__init__.py +0 -0
  102. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/video_processing/resolution.py +0 -0
  103. {nominal-1.107.0 → nominal-1.109.0}/nominal/experimental/video_processing/video_conversion.py +0 -0
  104. {nominal-1.107.0 → nominal-1.109.0}/nominal/nominal.py +0 -0
  105. {nominal-1.107.0 → nominal-1.109.0}/nominal/py.typed +0 -0
  106. {nominal-1.107.0 → nominal-1.109.0}/nominal/thirdparty/__init__.py +0 -0
  107. {nominal-1.107.0 → nominal-1.109.0}/nominal/thirdparty/matlab/__init__.py +0 -0
  108. {nominal-1.107.0 → nominal-1.109.0}/nominal/thirdparty/matlab/_matlab.py +0 -0
  109. {nominal-1.107.0 → nominal-1.109.0}/nominal/thirdparty/pandas/__init__.py +0 -0
  110. {nominal-1.107.0 → nominal-1.109.0}/nominal/thirdparty/pandas/_pandas.py +0 -0
  111. {nominal-1.107.0 → nominal-1.109.0}/nominal/thirdparty/polars/__init__.py +0 -0
  112. {nominal-1.107.0 → nominal-1.109.0}/nominal/thirdparty/polars/polars_export_handler.py +0 -0
  113. {nominal-1.107.0 → nominal-1.109.0}/nominal/thirdparty/tdms/__init__.py +0 -0
  114. {nominal-1.107.0 → nominal-1.109.0}/nominal/thirdparty/tdms/_tdms.py +0 -0
  115. {nominal-1.107.0 → nominal-1.109.0}/nominal/ts/__init__.py +0 -0
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.109.0](https://github.com/nominal-io/nominal-client/compare/v1.108.0...v1.109.0) (2026-01-23)
4
+
5
+
6
+ ### Features
7
+
8
+ * clone channels when cloning datasets ([#587](https://github.com/nominal-io/nominal-client/issues/587)) ([ab6de09](https://github.com/nominal-io/nominal-client/commit/ab6de0962c55e2c0a6933d6b9f94fb36f5e91273))
9
+
10
+ ## [1.108.0](https://github.com/nominal-io/nominal-client/compare/v1.107.0...v1.108.0) (2026-01-22)
11
+
12
+
13
+ ### Features
14
+
15
+ * add channels to datasets ([#583](https://github.com/nominal-io/nominal-client/issues/583)) ([35398ef](https://github.com/nominal-io/nominal-client/commit/35398ef63633c2b2fa198d9915a85a8e19e40323))
16
+
3
17
  ## [1.107.0](https://github.com/nominal-io/nominal-client/compare/v1.106.0...v1.107.0) (2026-01-22)
4
18
 
5
19
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nominal
3
- Version: 1.107.0
3
+ Version: 1.109.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
@@ -28,6 +28,7 @@ from nominal_api import (
28
28
  storage_writer_api,
29
29
  timeseries_channelmetadata,
30
30
  timeseries_logicalseries,
31
+ timeseries_metadata,
31
32
  upload_api,
32
33
  )
33
34
  from typing_extensions import Self
@@ -139,6 +140,7 @@ class ClientsBunch:
139
140
  proto_write: ProtoWriteService
140
141
  event: event.EventService
141
142
  channel_metadata: timeseries_channelmetadata.ChannelMetadataService
143
+ series_metadata: timeseries_metadata.SeriesMetadataService
142
144
  workspace: security_api_workspace.WorkspaceService
143
145
  containerized_extractors: ingest_api.ContainerizedExtractorService
144
146
  secrets: secrets_api.SecretService
@@ -179,6 +181,7 @@ class ClientsBunch:
179
181
  proto_write=client_factory(ProtoWriteService),
180
182
  event=client_factory(event.EventService),
181
183
  channel_metadata=client_factory(timeseries_channelmetadata.ChannelMetadataService),
184
+ series_metadata=client_factory(timeseries_metadata.SeriesMetadataService),
182
185
  workspace=client_factory(security_api_workspace.WorkspaceService),
183
186
  containerized_extractors=client_factory(ingest_api.ContainerizedExtractorService),
184
187
  secrets=client_factory(secrets_api.SecretService),
@@ -12,6 +12,7 @@ from nominal_api import (
12
12
  scout_compute_api,
13
13
  scout_dataexport_api,
14
14
  scout_datasource,
15
+ storage_series_api,
15
16
  timeseries_channelmetadata,
16
17
  timeseries_channelmetadata_api,
17
18
  timeseries_logicalseries_api,
@@ -52,6 +53,18 @@ class ChannelDataType(enum.Enum):
52
53
  else:
53
54
  return cls("UNKNOWN")
54
55
 
56
+ def _to_nominal_data_type(self) -> storage_series_api.NominalDataType:
57
+ if self == ChannelDataType.DOUBLE:
58
+ return storage_series_api.NominalDataType.DOUBLE
59
+ elif self == ChannelDataType.STRING:
60
+ return storage_series_api.NominalDataType.STRING
61
+ elif self == ChannelDataType.LOG:
62
+ return storage_series_api.NominalDataType.LOG
63
+ elif self == ChannelDataType.INT:
64
+ return storage_series_api.NominalDataType.INT64
65
+ else:
66
+ return storage_series_api.NominalDataType.UNKNOWN
67
+
55
68
 
56
69
  @dataclass
57
70
  class Channel(RefreshableMixin[timeseries_channelmetadata_api.ChannelMetadata]):
@@ -19,6 +19,8 @@ from nominal_api import (
19
19
  timeseries_channelmetadata,
20
20
  timeseries_channelmetadata_api,
21
21
  timeseries_logicalseries,
22
+ timeseries_metadata,
23
+ timeseries_metadata_api,
22
24
  upload_api,
23
25
  )
24
26
 
@@ -67,6 +69,8 @@ class DataSource(HasRid):
67
69
  @property
68
70
  def channel_metadata(self) -> timeseries_channelmetadata.ChannelMetadataService: ...
69
71
  @property
72
+ def series_metadata(self) -> timeseries_metadata.SeriesMetadataService: ...
73
+ @property
70
74
  def containerized_extractors(self) -> ingest_api.ContainerizedExtractorService: ...
71
75
 
72
76
  def get_channel(self, name: str) -> Channel:
@@ -287,6 +291,53 @@ class DataSource(HasRid):
287
291
  request = datasource_api.IndexChannelPrefixTreeRequest(self.rid, delimiter=delimiter)
288
292
  self._clients.datasource.index_channel_prefix_tree(self._clients.auth_header, request)
289
293
 
294
+ def add_channel(
295
+ self,
296
+ name: str,
297
+ data_type: ChannelDataType,
298
+ *,
299
+ description: str | None = None,
300
+ unit: str | None = None,
301
+ ) -> Channel:
302
+ """Create a new channel (series metadata) for this data source.
303
+
304
+ This creates the channel metadata entry without uploading any data points.
305
+ Use this to pre-register channels before streaming data to them.
306
+
307
+ Args:
308
+ name: The name of the channel to create.
309
+ data_type: The data type of the channel (e.g., DOUBLE, STRING, LOG, INT).
310
+ description: Optional human-readable description of the channel.
311
+ unit: Optional unit symbol to associate with the channel.
312
+
313
+ Returns:
314
+ The created Channel object.
315
+
316
+ Raises:
317
+ conjure_python_client.ConjureHTTPError: If a channel with this name already exists
318
+ or if there's an error creating the channel.
319
+ """
320
+ nominal_data_type = data_type._to_nominal_data_type()
321
+
322
+ nominal_locator = timeseries_metadata_api.NominalLocatorTemplate(
323
+ channel=name,
324
+ type=nominal_data_type,
325
+ )
326
+
327
+ locator = timeseries_metadata_api.LocatorTemplate(nominal=nominal_locator)
328
+
329
+ create_request = timeseries_metadata_api.CreateSeriesMetadataRequest(
330
+ channel=name,
331
+ data_source_rid=self.rid,
332
+ locator=locator,
333
+ tags={},
334
+ description=description,
335
+ unit=unit,
336
+ )
337
+ self._clients.series_metadata.create(self._clients.auth_header, create_request)
338
+
339
+ return self.get_channel(name)
340
+
290
341
 
291
342
  def _construct_export_request(
292
343
  channels: Sequence[Channel],
@@ -403,7 +403,7 @@ def copy_file_to_dataset(
403
403
 
404
404
 
405
405
  def clone_dataset(source_dataset: Dataset, destination_client: NominalClient) -> Dataset:
406
- """Clones a dataset, maintaining all properties and files.
406
+ """Clones a dataset, maintaining all properties, files, and channels.
407
407
 
408
408
  Args:
409
409
  source_dataset (Dataset): The dataset to copy from.
@@ -412,7 +412,11 @@ def clone_dataset(source_dataset: Dataset, destination_client: NominalClient) ->
412
412
  Returns:
413
413
  The cloned dataset.
414
414
  """
415
- return copy_dataset_from(source_dataset=source_dataset, destination_client=destination_client, include_files=True)
415
+ return copy_dataset_from(
416
+ source_dataset=source_dataset,
417
+ destination_client=destination_client,
418
+ include_files=True,
419
+ )
416
420
 
417
421
 
418
422
  def copy_dataset_from(
@@ -482,6 +486,20 @@ def copy_dataset_from(
482
486
  labels=dataset_labels,
483
487
  )
484
488
 
489
+ if preserve_uuid:
490
+ channels_copied_count = 0
491
+ for source_channel in source_dataset.search_channels():
492
+ if source_channel.data_type is None:
493
+ logger.warning("Skipping channel %s: unknown data type", source_channel.name, extra=log_extras)
494
+ continue
495
+ new_dataset.add_channel(
496
+ name=source_channel.name,
497
+ data_type=source_channel.data_type,
498
+ description=source_channel.description,
499
+ unit=source_channel.unit,
500
+ )
501
+ channels_copied_count += 1
502
+ logger.info("Copied %d channels from dataset %s", channels_copied_count, source_dataset.name, extra=log_extras)
485
503
  if include_files:
486
504
  for source_file in source_dataset.list_files():
487
505
  copy_file_to_dataset(source_file, new_dataset)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nominal"
3
- version = "1.107.0"
3
+ version = "1.109.0"
4
4
  description = "Automate Nominal workflows in Python"
5
5
  authors = [
6
6
  { name = "Alexander Reynolds", email = "alex.reynolds@nominal.io" },
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