nominal 1.107.0__py3-none-any.whl → 1.108.0__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.
CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.108.0](https://github.com/nominal-io/nominal-client/compare/v1.107.0...v1.108.0) (2026-01-22)
4
+
5
+
6
+ ### Features
7
+
8
+ * add channels to datasets ([#583](https://github.com/nominal-io/nominal-client/issues/583)) ([35398ef](https://github.com/nominal-io/nominal-client/commit/35398ef63633c2b2fa198d9915a85a8e19e40323))
9
+
3
10
  ## [1.107.0](https://github.com/nominal-io/nominal-client/compare/v1.106.0...v1.107.0) (2026-01-22)
4
11
 
5
12
 
@@ -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),
nominal/core/channel.py CHANGED
@@ -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],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nominal
3
- Version: 1.107.0
3
+ Version: 1.108.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
@@ -1,4 +1,4 @@
1
- CHANGELOG.md,sha256=LlvOacqO09P7ACcAptB85kdGtLUHugltOBGRdfKe5Zs,89226
1
+ CHANGELOG.md,sha256=-ls_mO5aZCjyBFUqYkMVzrqOswFIEqKJFz7r0mqSziQ,89542
2
2
  LICENSE,sha256=zEGHG9mjDjaIS3I79O8mweQo-yiTbqx8jJvUPppVAwk,1067
3
3
  README.md,sha256=KKe0dxh_pHXCtB7I9G4qWGQYvot_BZU8yW6MJyuyUHM,311
4
4
  nominal/__init__.py,sha256=rbraORnXUrNn1hywLXM0XwSQCd9UmQt20PDYlsBalfE,2167
@@ -28,14 +28,14 @@ nominal/cli/util/verify_connection.py,sha256=KU17ejaDfKBLmLiZ3MZSVLyfrqNE7c6mFBv
28
28
  nominal/config/__init__.py,sha256=wV8cq8X3J4NTJ5H_uR5THaMT_NQpWQO5qCUGEb-rPnM,3157
29
29
  nominal/config/_config.py,sha256=yKq_H1iYJDoxRfLz2iXLbbVdoL0MTEY0FS4eVL12w0g,2004
30
30
  nominal/core/__init__.py,sha256=1MiCC44cxHYFofP4hf2fz4EIkepK-OAhDzpPFIzHbWw,2422
31
- nominal/core/_clientsbunch.py,sha256=YwciugX7rQ9AOPHyvKuavG7b9SlX1PURRquP37nvLqE,8458
31
+ nominal/core/_clientsbunch.py,sha256=sn-ajYsJ2FuZGLiEYiPwkYCxLKr13w35aqWHE3TX5us,8633
32
32
  nominal/core/_constants.py,sha256=SrxgaSqAEB1MvTSrorgGam3eO29iCmRr6VIdajxX3gI,56
33
33
  nominal/core/_event_types.py,sha256=Cq_8x-zv_5EDvRo9UTbaOpenAy92bTfQxlsEuHPOhtE,3706
34
34
  nominal/core/_types.py,sha256=FktMmcQ5_rD2rbXv8_p-WISzSo8T2NtO-exsLm-iadU,122
35
35
  nominal/core/asset.py,sha256=-hNMGXiU1dPWfrzmOngbab-Hf6vfq2Rm_j0FP-woJ-s,23120
36
36
  nominal/core/attachment.py,sha256=yOtDUdkLY5MT_Rk9kUlr1yupIJN7a5pt5sJWx4RLQV8,4355
37
37
  nominal/core/bounds.py,sha256=742BWmGL3FBryRAjoiJRg2N6aVinjYkQLxN7kfnJ40Q,581
38
- nominal/core/channel.py,sha256=dbe8wpfMiWqHu98x66w6GOmC9Ro33Wv9AhBVx2DvtVk,18970
38
+ nominal/core/channel.py,sha256=e0RtbjrXYMAqyt8noe610iIFzv30z2P7oqrwq08atD8,19558
39
39
  nominal/core/checklist.py,sha256=rO1RPDYV3o2miPKF7DcCiYpj6bUN-sdtZNhJkXzkfYE,7110
40
40
  nominal/core/client.py,sha256=Awt9WPkE-YXBfOwJMTL7Su8AZFJY3UMH7IKp5hI26YQ,68328
41
41
  nominal/core/connection.py,sha256=LYllr3a1H2xp8-i4MaX1M7yK8X-HnwuIkciyK9XgLtQ,5175
@@ -43,7 +43,7 @@ nominal/core/containerized_extractors.py,sha256=fUz3-NHoNWYKqOCD15gLwGXDKVfdsW-x
43
43
  nominal/core/data_review.py,sha256=Z_W1Okp_FSQDiVCk6aKb9gV0EXbE2jtiQaPqc6TaL0g,11038
44
44
  nominal/core/dataset.py,sha256=LqofzNAlOd3S_3Aaw6b7DoY50rj6GyMHbUClIA2TmpY,46792
45
45
  nominal/core/dataset_file.py,sha256=8rCW6MO89MFbQ2NH0WtFWmJfRWeTxhmyuoGojuQQ4Qg,16545
46
- nominal/core/datasource.py,sha256=V5UahbqsCNIdml978kOHiY6boIxKxbp76KscNBpN5xc,16934
46
+ nominal/core/datasource.py,sha256=i9db5OHNdfJyb3BJmhz2uJ398MfW8zx3Ek9pw5vYn3c,18739
47
47
  nominal/core/event.py,sha256=8trZXyuAqRlKedgcqSgDIimXAAJBmEfDLyHkOOBwUC0,7762
48
48
  nominal/core/exceptions.py,sha256=GUpwXRgdYamLl6684FE8ttCRHkBx6WEhOZ3NPE-ybD4,2671
49
49
  nominal/core/filetype.py,sha256=R8goHGW4SP0iO6AoQiUil2tNVuDgaQoHclftRbw44oc,5558
@@ -110,8 +110,8 @@ nominal/thirdparty/polars/polars_export_handler.py,sha256=hGCSwXX9dC4MG01CmmjlTb
110
110
  nominal/thirdparty/tdms/__init__.py,sha256=6n2ImFr2Wiil6JM1P5Q7Mpr0VzLcnDkmup_ftNpPq-s,142
111
111
  nominal/thirdparty/tdms/_tdms.py,sha256=m4gxbpxB9MTLi2FuYvGlbUGSyDAZKFxbM3ia2x1wIz0,8746
112
112
  nominal/ts/__init__.py,sha256=hmd0ENvDhxRnzDKGLxIub6QG8LpcxCgcyAct029CaEs,21442
113
- nominal-1.107.0.dist-info/METADATA,sha256=D3fDwR5cBgflwxhfN71NUezUmPKu6m6tr1arnRs0lWk,2307
114
- nominal-1.107.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
115
- nominal-1.107.0.dist-info/entry_points.txt,sha256=-mCLhxgg9R_lm5efT7vW9wuBH12izvY322R0a3TYxbE,66
116
- nominal-1.107.0.dist-info/licenses/LICENSE,sha256=zEGHG9mjDjaIS3I79O8mweQo-yiTbqx8jJvUPppVAwk,1067
117
- nominal-1.107.0.dist-info/RECORD,,
113
+ nominal-1.108.0.dist-info/METADATA,sha256=BFL54ilX_SW2XErNJm9Q4kEow-SCxGdJcIVvqlJ0b5A,2307
114
+ nominal-1.108.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
115
+ nominal-1.108.0.dist-info/entry_points.txt,sha256=-mCLhxgg9R_lm5efT7vW9wuBH12izvY322R0a3TYxbE,66
116
+ nominal-1.108.0.dist-info/licenses/LICENSE,sha256=zEGHG9mjDjaIS3I79O8mweQo-yiTbqx8jJvUPppVAwk,1067
117
+ nominal-1.108.0.dist-info/RECORD,,