nominal 1.100.0__py3-none-any.whl → 1.102.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.
@@ -396,7 +396,12 @@ def _get_write_stream(
396
396
  )
397
397
  elif data_format == "rust_experimental":
398
398
  # Delayed import intentionally in case of any issues with experimental and pre-compiled binaries
399
- from nominal.experimental.rust_streaming.rust_write_stream import RustWriteStream
399
+ try:
400
+ from nominal.experimental.rust_streaming.rust_write_stream import RustWriteStream
401
+ except ImportError as ex:
402
+ raise ImportError(
403
+ "nominal-streaming is required to use get_write_stream with data_format='rust_experimental'"
404
+ ) from ex
400
405
 
401
406
  return RustWriteStream._from_datasource(
402
407
  write_rid,
nominal/core/event.py CHANGED
@@ -3,15 +3,18 @@ from __future__ import annotations
3
3
  import warnings
4
4
  from dataclasses import dataclass, field
5
5
  from datetime import datetime, timedelta
6
- from enum import Enum
7
6
  from typing import Iterable, Mapping, Protocol, Sequence
8
7
 
9
8
  from nominal_api import event
10
9
  from typing_extensions import Self
11
10
 
11
+ from nominal.core import asset as core_asset
12
12
  from nominal.core._clientsbunch import HasScoutParams
13
+ from nominal.core._event_types import EventType as EventType # noqa: PLC0414
14
+ from nominal.core._event_types import SearchEventOriginType as SearchEventOriginType # noqa: PLC0414
13
15
  from nominal.core._utils.api_tools import HasRid, RefreshableMixin, rid_from_instance_or_string
14
- from nominal.core.asset import Asset
16
+ from nominal.core._utils.pagination_tools import search_events_paginated
17
+ from nominal.core._utils.query_tools import _create_search_events_query
15
18
  from nominal.ts import IntegralNanosecondsDuration, IntegralNanosecondsUTC, _SecondsNanos, _to_api_duration
16
19
 
17
20
 
@@ -50,7 +53,7 @@ class Event(HasRid, RefreshableMixin[event.Event]):
50
53
  *,
51
54
  name: str | None = None,
52
55
  description: str | None = None,
53
- assets: Iterable[Asset | str] | None = None,
56
+ assets: Iterable[core_asset.Asset | str] | None = None,
54
57
  start: datetime | IntegralNanosecondsUTC | None = None,
55
58
  duration: timedelta | IntegralNanosecondsDuration | None = None,
56
59
  properties: Mapping[str, str] | None = None,
@@ -123,34 +126,70 @@ class Event(HasRid, RefreshableMixin[event.Event]):
123
126
  )
124
127
 
125
128
 
126
- class EventType(Enum):
127
- INFO = "INFO"
128
- FLAG = "FLAG"
129
- ERROR = "ERROR"
130
- SUCCESS = "SUCCESS"
131
- UNKNOWN = "UNKNOWN"
132
-
133
- @classmethod
134
- def from_api_event_type(cls, event: event.EventType) -> EventType:
135
- if event.name == "INFO":
136
- return cls.INFO
137
- elif event.name == "FLAG":
138
- return cls.FLAG
139
- elif event.name == "ERROR":
140
- return cls.ERROR
141
- elif event.name == "SUCCESS":
142
- return cls.SUCCESS
143
- else:
144
- return cls.UNKNOWN
145
-
146
- def _to_api_event_type(self) -> event.EventType:
147
- if self.name == "INFO":
148
- return event.EventType.INFO
149
- elif self.name == "FLAG":
150
- return event.EventType.FLAG
151
- elif self.name == "ERROR":
152
- return event.EventType.ERROR
153
- elif self.name == "SUCCESS":
154
- return event.EventType.SUCCESS
155
- else:
156
- return event.EventType.UNKNOWN
129
+ def _create_event(
130
+ clients: Event._Clients,
131
+ *,
132
+ name: str,
133
+ type: EventType,
134
+ start: datetime | IntegralNanosecondsUTC,
135
+ duration: timedelta | IntegralNanosecondsDuration,
136
+ assets: Iterable[core_asset.Asset | str] | None,
137
+ description: str | None,
138
+ properties: Mapping[str, str] | None,
139
+ labels: Iterable[str] | None,
140
+ ) -> Event:
141
+ request = event.CreateEvent(
142
+ name=name,
143
+ description=description,
144
+ asset_rids=[rid_from_instance_or_string(asset) for asset in (assets or [])],
145
+ timestamp=_SecondsNanos.from_flexible(start).to_api(),
146
+ duration=_to_api_duration(duration),
147
+ origins=[],
148
+ properties=dict(properties or {}),
149
+ labels=list(labels or []),
150
+ type=type._to_api_event_type(),
151
+ )
152
+ response = clients.event.create_event(clients.auth_header, request)
153
+ return Event._from_conjure(clients, response)
154
+
155
+
156
+ def _iter_search_events(clients: Event._Clients, query: event.SearchQuery) -> Iterable[Event]:
157
+ for e in search_events_paginated(clients.event, clients.auth_header, query):
158
+ yield Event._from_conjure(clients, e)
159
+
160
+
161
+ def _search_events(
162
+ clients: Event._Clients,
163
+ *,
164
+ search_text: str | None = None,
165
+ after: str | datetime | IntegralNanosecondsUTC | None = None,
166
+ before: str | datetime | IntegralNanosecondsUTC | None = None,
167
+ asset_rids: Iterable[str] | None = None,
168
+ labels: Iterable[str] | None = None,
169
+ properties: Mapping[str, str] | None = None,
170
+ created_by_rid: str | None = None,
171
+ workbook_rid: str | None = None,
172
+ data_review_rid: str | None = None,
173
+ assignee_rid: str | None = None,
174
+ event_type: EventType | None = None,
175
+ origin_types: Iterable[SearchEventOriginType] | None = None,
176
+ workspace_rid: str | None = None,
177
+ ) -> Sequence[Event]:
178
+ query = _create_search_events_query(
179
+ asset_rids=asset_rids,
180
+ search_text=search_text,
181
+ after=after,
182
+ before=before,
183
+ labels=labels,
184
+ properties=properties,
185
+ created_by_rid=created_by_rid,
186
+ workbook_rid=workbook_rid,
187
+ data_review_rid=data_review_rid,
188
+ assignee_rid=assignee_rid,
189
+ event_type=event_type._to_api_event_type() if event_type else None,
190
+ origin_types=[origin_type._to_api_search_event_origin_type() for origin_type in origin_types]
191
+ if origin_types
192
+ else None,
193
+ workspace_rid=workspace_rid,
194
+ )
195
+ return list(_iter_search_events(clients, query))
nominal/core/filetype.py CHANGED
@@ -111,6 +111,7 @@ class FileType(NamedTuple):
111
111
 
112
112
 
113
113
  class FileTypes:
114
+ AVI: FileType = FileType(".avi", "video/x-msvideo")
114
115
  AVRO_STREAM: FileType = FileType(".avro", "application/avro")
115
116
  BINARY: FileType = FileType("", "application/octet-stream")
116
117
  CSV: FileType = FileType(".csv", "text/csv")
@@ -134,4 +135,4 @@ class FileTypes:
134
135
  _PARQUET_FILE_TYPES = (PARQUET_GZ, PARQUET)
135
136
  _PARQUET_ARCHIVE_TYPES = (PARQUET_TAR_GZ, PARQUET_TAR, PARQUET_ZIP)
136
137
  _JOURNAL_TYPES = (JOURNAL_JSONL, JOURNAL_JSONL_GZ)
137
- _VIDEO_TYPES = (MKV, MP4, TS)
138
+ _VIDEO_TYPES = (AVI, MKV, MP4, TS)
nominal/core/run.py CHANGED
@@ -6,12 +6,14 @@ from types import MappingProxyType
6
6
  from typing import Iterable, Mapping, Protocol, Sequence, cast
7
7
 
8
8
  from nominal_api import (
9
+ scout_asset_api,
9
10
  scout_run_api,
10
11
  )
11
12
  from typing_extensions import Self
12
13
 
13
14
  from nominal.core import asset as core_asset
14
15
  from nominal.core._clientsbunch import HasScoutParams
16
+ from nominal.core._event_types import EventType
15
17
  from nominal.core._utils.api_tools import (
16
18
  HasRid,
17
19
  Link,
@@ -20,15 +22,17 @@ from nominal.core._utils.api_tools import (
20
22
  create_links,
21
23
  rid_from_instance_or_string,
22
24
  )
25
+ from nominal.core.asset import _filter_scopes
23
26
  from nominal.core.attachment import Attachment, _iter_get_attachments
24
27
  from nominal.core.connection import Connection, _get_connections
25
- from nominal.core.dataset import Dataset, _get_datasets
28
+ from nominal.core.dataset import Dataset, _DatasetWrapper, _get_datasets
29
+ from nominal.core.event import Event, _create_event
26
30
  from nominal.core.video import Video, _get_video
27
31
  from nominal.ts import IntegralNanosecondsDuration, IntegralNanosecondsUTC, _SecondsNanos, _to_api_duration
28
32
 
29
33
 
30
34
  @dataclass(frozen=True)
31
- class Run(HasRid, RefreshableMixin[scout_run_api.Run]):
35
+ class Run(HasRid, RefreshableMixin[scout_run_api.Run], _DatasetWrapper):
32
36
  rid: str
33
37
  name: str
34
38
  description: str
@@ -96,6 +100,13 @@ class Run(HasRid, RefreshableMixin[scout_run_api.Run]):
96
100
  updated_run = self._clients.run.update_run(self._clients.auth_header, request, self.rid)
97
101
  return self._refresh_from_api(updated_run)
98
102
 
103
+ def _list_dataset_scopes(self) -> Sequence[scout_asset_api.DataScope]:
104
+ api_run = self._get_latest_api()
105
+ if len(api_run.assets) > 1:
106
+ raise RuntimeError("Can't retrieve dataset scopes on multi-asset runs")
107
+
108
+ return _filter_scopes(api_run.asset_data_scopes, "dataset")
109
+
99
110
  def _list_datasource_rids(
100
111
  self, datasource_type: str | None = None, property_name: str | None = None
101
112
  ) -> Mapping[str, str]:
@@ -148,6 +159,43 @@ class Run(HasRid, RefreshableMixin[scout_run_api.Run]):
148
159
  )
149
160
  self._refresh_from_api(updated_run)
150
161
 
162
+ def create_event(
163
+ self,
164
+ name: str,
165
+ type: EventType,
166
+ start: datetime | IntegralNanosecondsUTC,
167
+ duration: timedelta | IntegralNanosecondsDuration = 0,
168
+ *,
169
+ description: str | None = None,
170
+ properties: Mapping[str, str] | None = None,
171
+ labels: Iterable[str] = (),
172
+ ) -> Event:
173
+ """Create an event associated with all associated assets of this run at a given point in time.
174
+
175
+ Args:
176
+ name: Name of the event
177
+ type: Verbosity level of the event.
178
+ start: Starting timestamp of the event
179
+ duration: Duration of the event, or 0 for an event without duration.
180
+ description: Optionally, a human readable description of the event to create
181
+ properties: Key-value pairs to use as properties on the created event
182
+ labels: Sequence of labels to use on the created event.
183
+
184
+ Returns:
185
+ The created event that is associated with all of the assets associated with this run..
186
+ """
187
+ return _create_event(
188
+ self._clients,
189
+ name=name,
190
+ type=type,
191
+ start=start,
192
+ duration=duration,
193
+ description=description,
194
+ assets=self.assets,
195
+ properties=properties,
196
+ labels=labels,
197
+ )
198
+
151
199
  def add_dataset(
152
200
  self,
153
201
  ref_name: str,
@@ -325,11 +373,13 @@ class Run(HasRid, RefreshableMixin[scout_run_api.Run]):
325
373
  def archive(self) -> None:
326
374
  """Archive this run.
327
375
  Archived runs are not deleted, but are hidden from the UI.
328
-
329
- NOTE: currently, it is not possible (yet) to unarchive a run once archived.
330
376
  """
331
377
  self._clients.run.archive_run(self._clients.auth_header, self.rid)
332
378
 
379
+ def unarchive(self) -> None:
380
+ """Unarchive this run, allowing it to appear on the UI."""
381
+ self._clients.run.unarchive_run(self._clients.auth_header, self.rid)
382
+
333
383
  @classmethod
334
384
  def _from_conjure(cls, clients: _Clients, run: scout_run_api.Run) -> Self:
335
385
  return cls(
@@ -349,3 +399,34 @@ class Run(HasRid, RefreshableMixin[scout_run_api.Run]):
349
399
  created_at=_SecondsNanos.from_flexible(run.created_at).to_nanoseconds(),
350
400
  _clients=clients,
351
401
  )
402
+
403
+
404
+ def _create_run(
405
+ clients: Run._Clients,
406
+ *,
407
+ name: str,
408
+ start: datetime | IntegralNanosecondsUTC,
409
+ end: datetime | IntegralNanosecondsUTC | None,
410
+ description: str | None,
411
+ properties: Mapping[str, str] | None,
412
+ labels: Sequence[str] | None,
413
+ links: Sequence[str | Link | LinkDict] | None,
414
+ attachments: Iterable[Attachment] | Iterable[str] | None,
415
+ asset_rids: Sequence[str] | None,
416
+ ) -> Run:
417
+ """Create a run."""
418
+ request = scout_run_api.CreateRunRequest(
419
+ attachments=[rid_from_instance_or_string(a) for a in attachments or ()],
420
+ data_sources={},
421
+ description=description or "",
422
+ labels=[] if labels is None else list(labels),
423
+ links=[] if links is None else create_links(links),
424
+ properties={} if properties is None else dict(properties),
425
+ start_time=_SecondsNanos.from_flexible(start).to_scout_run_api(),
426
+ title=name,
427
+ end_time=None if end is None else _SecondsNanos.from_flexible(end).to_scout_run_api(),
428
+ assets=[] if asset_rids is None else list(asset_rids),
429
+ workspace=clients.workspace_rid,
430
+ )
431
+ response = clients.run.create_run(clients.auth_header, request)
432
+ return Run._from_conjure(clients, response)
@@ -2,8 +2,9 @@ import json
2
2
  import logging
3
3
  import re
4
4
  import uuid
5
+ from datetime import datetime, timedelta
5
6
  from pathlib import Path
6
- from typing import Any, BinaryIO, Mapping, Sequence, TypeVar, Union, cast, overload
7
+ from typing import Any, BinaryIO, Iterable, Mapping, Sequence, TypeVar, Union, cast, overload
7
8
 
8
9
  import requests
9
10
  from conjure_python_client import ConjureBeanType, ConjureEnumType, ConjureUnionType
@@ -11,7 +12,21 @@ from conjure_python_client._serde.decoder import ConjureDecoder
11
12
  from conjure_python_client._serde.encoder import ConjureEncoder
12
13
  from nominal_api import scout_layout_api, scout_template_api, scout_workbookcommon_api
13
14
 
14
- from nominal.core import Asset, Dataset, DatasetFile, FileType, NominalClient, Workbook, WorkbookTemplate
15
+ from nominal.core import (
16
+ Asset,
17
+ Dataset,
18
+ DatasetFile,
19
+ Event,
20
+ FileType,
21
+ NominalClient,
22
+ Workbook,
23
+ WorkbookTemplate,
24
+ )
25
+ from nominal.core._event_types import EventType, SearchEventOriginType
26
+ from nominal.ts import (
27
+ IntegralNanosecondsDuration,
28
+ IntegralNanosecondsUTC,
29
+ )
15
30
 
16
31
  logger = logging.getLogger(__name__)
17
32
 
@@ -278,7 +293,9 @@ def copy_workbook_template_from(
278
293
  Returns:
279
294
  The newly created WorkbookTemplate in the target workspace.
280
295
  """
281
- log_extras = {"destination_client_workspace": destination_client.get_workspace().rid}
296
+ log_extras = {
297
+ "destination_client_workspace": destination_client.get_workspace(destination_client._clients.workspace_rid).rid
298
+ }
282
299
  logger.debug(
283
300
  "Cloning workbook template: %s (rid: %s)", source_template.title, source_template.rid, extra=log_extras
284
301
  )
@@ -315,7 +332,7 @@ def copy_workbook_template_from(
315
332
  layout=new_template_layout,
316
333
  content=new_workbook_content,
317
334
  commit_message="Cloned from template",
318
- workspace_rid=destination_client.get_workspace().rid,
335
+ workspace_rid=destination_client.get_workspace(destination_client._clients.workspace_rid).rid,
319
336
  )
320
337
  logger.debug(
321
338
  "New workbook template created %s from %s (rid: %s)",
@@ -418,7 +435,9 @@ def copy_dataset_from(
418
435
  Returns:
419
436
  The newly created Dataset in the destination client.
420
437
  """
421
- log_extras = {"destination_client_workspace": destination_client.get_workspace().rid}
438
+ log_extras = {
439
+ "destination_client_workspace": destination_client.get_workspace(destination_client._clients.workspace_rid).rid
440
+ }
422
441
  logger.debug(
423
442
  "Copying dataset %s (rid: %s)",
424
443
  source_dataset.name,
@@ -438,6 +457,72 @@ def copy_dataset_from(
438
457
  return new_dataset
439
458
 
440
459
 
460
+ def clone_event(source_event: Event, destination_client: NominalClient) -> Event:
461
+ """Clones an event, maintaining all properties and linked assets.
462
+
463
+ Args:
464
+ source_event (Event): The event to copy from.
465
+ destination_client (NominalClient): The destination client.
466
+
467
+ Returns:
468
+ The cloned event.
469
+ """
470
+ return copy_event_from(source_event=source_event, destination_client=destination_client)
471
+
472
+
473
+ def copy_event_from(
474
+ source_event: Event,
475
+ destination_client: NominalClient,
476
+ *,
477
+ new_name: str | None = None,
478
+ new_type: EventType | None = None,
479
+ new_start: datetime | IntegralNanosecondsUTC | None = None,
480
+ new_duration: timedelta | IntegralNanosecondsDuration = timedelta(),
481
+ new_description: str | None = None,
482
+ new_assets: Iterable[Asset | str] = (),
483
+ new_properties: Mapping[str, str] | None = None,
484
+ new_labels: Iterable[str] = (),
485
+ ) -> Event:
486
+ """Copy an event from the source to the destination client.
487
+
488
+ Args:
489
+ source_event: The source Event to copy.
490
+ destination_client: The NominalClient to create the copied event in.
491
+ new_name: Optional new name for the copied event. If not provided, the original name is used.
492
+ new_type: Optional new type for the copied event. If not provided, the original type is used.
493
+ new_start: Optional new start time for the copied event. If not provided, the original start time is used.
494
+ new_duration: Optional new duration for the copied event. If not provided, the original duration is used.
495
+ new_description: Optional new description for the copied event. If not provided, the original description used.
496
+ new_assets: Optional new assets for the copied event. If not provided, the original assets are used.
497
+ new_properties: Optional new properties for the copied event. If not provided, the original properties are used.
498
+ new_labels: Optional new labels for the copied event. If not provided, the original labels are used.
499
+
500
+ Returns:
501
+ The newly created Event in the destination client.
502
+ """
503
+ log_extras = {
504
+ "destination_client_workspace": destination_client.get_workspace(destination_client._clients.workspace_rid).rid
505
+ }
506
+ logger.debug(
507
+ "Copying event %s (rid: %s)",
508
+ source_event.name,
509
+ source_event.rid,
510
+ extra=log_extras,
511
+ )
512
+ new_event = destination_client.create_event(
513
+ name=new_name or source_event.name,
514
+ type=new_type or source_event.type,
515
+ start=new_start or source_event.start,
516
+ duration=new_duration or source_event.duration,
517
+ description=new_description or source_event.description,
518
+ assets=new_assets or source_event.asset_rids,
519
+ properties=new_properties or source_event.properties,
520
+ labels=new_labels or source_event.labels,
521
+ )
522
+ logger.debug("New event created: %s (rid: %s)", new_event.name, new_event.rid, extra=log_extras)
523
+ return new_event
524
+
525
+
441
526
  def clone_asset(
442
527
  source_asset: Asset,
443
528
  destination_client: NominalClient,
@@ -451,7 +536,9 @@ def clone_asset(
451
536
  Returns:
452
537
  The newly created Asset in the target client.
453
538
  """
454
- return copy_asset_from(source_asset=source_asset, destination_client=destination_client, include_data=True)
539
+ return copy_asset_from(
540
+ source_asset=source_asset, destination_client=destination_client, include_data=True, include_events=True
541
+ )
455
542
 
456
543
 
457
544
  def copy_asset_from(
@@ -463,6 +550,7 @@ def copy_asset_from(
463
550
  new_asset_properties: dict[str, Any] | None = None,
464
551
  new_asset_labels: Sequence[str] | None = None,
465
552
  include_data: bool = False,
553
+ include_events: bool = False,
466
554
  ) -> Asset:
467
555
  """Copy an asset from the source to the destination client.
468
556
 
@@ -474,11 +562,14 @@ def copy_asset_from(
474
562
  new_asset_properties: Optional new properties for the copied asset. If not provided, original properties used.
475
563
  new_asset_labels: Optional new labels for the copied asset. If not provided, the original labels are used.
476
564
  include_data: Whether to include data in the copied asset.
565
+ include_events: Whether to include events in the copied dataset.
477
566
 
478
567
  Returns:
479
568
  The new asset created.
480
569
  """
481
- log_extras = {"destination_client_workspace": destination_client.get_workspace().rid}
570
+ log_extras = {
571
+ "destination_client_workspace": destination_client.get_workspace(destination_client._clients.workspace_rid).rid
572
+ }
482
573
  logger.debug("Copying asset %s (rid: %s)", source_asset.name, source_asset.rid, extra=log_extras)
483
574
  new_asset = destination_client.create_asset(
484
575
  name=new_asset_name if new_asset_name is not None else source_asset.name,
@@ -496,6 +587,14 @@ def copy_asset_from(
496
587
  )
497
588
  new_datasets.append(new_dataset)
498
589
  new_asset.add_dataset(data_scope, new_dataset)
590
+
591
+ if include_events:
592
+ source_events = source_asset.search_events(origin_types=SearchEventOriginType.get_manual_origin_types())
593
+ new_events = []
594
+ for source_event in source_events:
595
+ new_event = copy_event_from(source_event, destination_client, new_assets=[new_asset])
596
+ new_events.append(new_event)
597
+
499
598
  logger.debug("New asset created: %s (rid: %s)", new_asset, new_asset.rid, extra=log_extras)
500
599
  return new_asset
501
600
 
@@ -518,7 +617,7 @@ def copy_resources_to_destination_client(
518
617
  All of the created resources.
519
618
  """
520
619
  log_extras = {
521
- "destination_client_workspace": destination_client.get_workspace().rid,
620
+ "destination_client_workspace": destination_client.get_workspace(destination_client._clients.workspace_rid).rid,
522
621
  }
523
622
 
524
623
  if len(source_assets) != 1:
@@ -5,9 +5,7 @@ import pathlib
5
5
 
6
6
  from nominal_streaming import NominalDatasetStream
7
7
 
8
- from nominal.core._stream.write_stream import (
9
- DataStream,
10
- )
8
+ from nominal.core._stream.write_stream import DataStream
11
9
  from nominal.core.datasource import DataSource
12
10
 
13
11
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nominal
3
- Version: 1.100.0
3
+ Version: 1.102.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
@@ -21,7 +21,7 @@ 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
23
  Requires-Dist: nominal-api==0.1032.0
24
- Requires-Dist: nominal-streaming==0.5.8
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
27
27
  Requires-Dist: polars>=0.0.0
@@ -1,4 +1,4 @@
1
- CHANGELOG.md,sha256=jvj73GmZ1DOpXVyEcRVZ7Wm2ejFmH2UhBPO66Yt8wu0,83100
1
+ CHANGELOG.md,sha256=VVSixbZ3ayFrWHceTSkabfHQYIkY1HU3GRSszsywUXQ,85986
2
2
  LICENSE,sha256=zEGHG9mjDjaIS3I79O8mweQo-yiTbqx8jJvUPppVAwk,1067
3
3
  README.md,sha256=KKe0dxh_pHXCtB7I9G4qWGQYvot_BZU8yW6MJyuyUHM,311
4
4
  nominal/__init__.py,sha256=rbraORnXUrNn1hywLXM0XwSQCd9UmQt20PDYlsBalfE,2167
@@ -27,26 +27,27 @@ nominal/cli/util/global_decorators.py,sha256=SBxhz4KbMlWDcCV08feouftd3HLnBNR-JJt
27
27
  nominal/cli/util/verify_connection.py,sha256=KU17ejaDfKBLmLiZ3MZSVLyfrqNE7c6mFBvskhqQLCo,1902
28
28
  nominal/config/__init__.py,sha256=wV8cq8X3J4NTJ5H_uR5THaMT_NQpWQO5qCUGEb-rPnM,3157
29
29
  nominal/config/_config.py,sha256=yKq_H1iYJDoxRfLz2iXLbbVdoL0MTEY0FS4eVL12w0g,2004
30
- nominal/core/__init__.py,sha256=5eC2J0lzpV7JcuKDUimJCfgXuVL7HNgHrLhqxcy5NCc,2333
30
+ nominal/core/__init__.py,sha256=1MiCC44cxHYFofP4hf2fz4EIkepK-OAhDzpPFIzHbWw,2422
31
31
  nominal/core/_clientsbunch.py,sha256=YwciugX7rQ9AOPHyvKuavG7b9SlX1PURRquP37nvLqE,8458
32
32
  nominal/core/_constants.py,sha256=SrxgaSqAEB1MvTSrorgGam3eO29iCmRr6VIdajxX3gI,56
33
- nominal/core/asset.py,sha256=vWi_5jNm1sBo4jCa4wTrL65IQ7b_lefZTLRsakoW7ro,18355
33
+ nominal/core/_event_types.py,sha256=Cq_8x-zv_5EDvRo9UTbaOpenAy92bTfQxlsEuHPOhtE,3706
34
+ nominal/core/asset.py,sha256=-hNMGXiU1dPWfrzmOngbab-Hf6vfq2Rm_j0FP-woJ-s,23120
34
35
  nominal/core/attachment.py,sha256=iJaDyF6JXsKxxBLA03I0WMmQF8U0bA-wRwvXMEhfWLU,4284
35
36
  nominal/core/bounds.py,sha256=742BWmGL3FBryRAjoiJRg2N6aVinjYkQLxN7kfnJ40Q,581
36
37
  nominal/core/channel.py,sha256=dbe8wpfMiWqHu98x66w6GOmC9Ro33Wv9AhBVx2DvtVk,18970
37
38
  nominal/core/checklist.py,sha256=rO1RPDYV3o2miPKF7DcCiYpj6bUN-sdtZNhJkXzkfYE,7110
38
- nominal/core/client.py,sha256=zTaayeJf8IFA7BlNoVCaVpDA6cXIBaZGP934Tg6OhDI,67568
39
+ nominal/core/client.py,sha256=34AhkJmnftU1dumVg80jPv9fnP7W5mQrkgOR8zI0VoU,68291
39
40
  nominal/core/connection.py,sha256=ySbPN_a2takVa8wIU9mK4fB6vYLyZnN-qSmXVkLUxAY,5157
40
41
  nominal/core/containerized_extractors.py,sha256=fUz3-NHoNWYKqOCD15gLwGXDKVfdsW-x_kpXnkOI3BE,10224
41
42
  nominal/core/data_review.py,sha256=bEnRsd8LI4x9YOBPcF2H3h5-e12A7Gh8gQfsNUAZmPQ,7922
42
- nominal/core/dataset.py,sha256=SUsn6qsbuceVLRYF47IquY_sW6OBRp4aExL1F3Bsaec,34802
43
+ nominal/core/dataset.py,sha256=Rt20H2ekUbF0_YyF-OkJhs3KaRTqQzNNxyneRjIEOJk,46627
43
44
  nominal/core/dataset_file.py,sha256=oENANJ17A4K63cZ8Fr7lUm_kVPyA4fL2rUsZ3oXXk2U,16396
44
- nominal/core/datasource.py,sha256=D9jHirAzUZ0pc3nW1XIURpw1UqQoA2E-nUUylZR1jbE,16707
45
- nominal/core/event.py,sha256=D8qIX_dTjfSHN7jFW8vV-9htbQTaqk9VvRfK7t-sbbw,5891
45
+ nominal/core/datasource.py,sha256=k13B6u6uw5pd49SuVM3gXtATgqO_BUnqGUMGiiW6Moc,16920
46
+ nominal/core/event.py,sha256=8trZXyuAqRlKedgcqSgDIimXAAJBmEfDLyHkOOBwUC0,7762
46
47
  nominal/core/exceptions.py,sha256=GUpwXRgdYamLl6684FE8ttCRHkBx6WEhOZ3NPE-ybD4,2671
47
- nominal/core/filetype.py,sha256=jAPe6F7pDT8ixsD2-Y8eJdHOxgimdEQte4RQybWwsos,5465
48
+ nominal/core/filetype.py,sha256=uzKe4iNHSv27mvz8-5EJEsvGOn3msEm_IhCj8OsCAPY,5526
48
49
  nominal/core/log.py,sha256=z3hI3CIEyMwpUSWjwBsJ6a3JNGzBbsmrVusSU6uI7CY,3885
49
- nominal/core/run.py,sha256=Rqy2o6sLE5RsAvvNnle7jRPJ-8UNfHmD-pdsRTOjA8Y,14792
50
+ nominal/core/run.py,sha256=IqXCP24UhdHKkss0LbXU_zAhx-7Pf2MIQI-lic_-quw,17987
50
51
  nominal/core/secret.py,sha256=Ckq48m60i7rktxL9GY-nxHU5v8gHv9F1-JN7_MSf4bM,2863
51
52
  nominal/core/unit.py,sha256=Wa-Bvu0hD-nzxVaQJSnn5YqAfnhUd2kWw2SswXnbMHY,3161
52
53
  nominal/core/user.py,sha256=FV333TN4pQzcLh5b2CfxvBnnXyB1TrOP8Ppx1-XdaiE,481
@@ -67,7 +68,7 @@ nominal/core/_utils/multipart.py,sha256=0dA2XcTHuOQIyS0139O8WZiCjwePaD1sYDUmTgmW
67
68
  nominal/core/_utils/multipart_downloader.py,sha256=16OJEPqxCwOnfjptYdrlwQVuSUQYoe9_iiW60ZSjWos,13859
68
69
  nominal/core/_utils/networking.py,sha256=n9ZqYtnpwPCjz9C-4eixsTkrhFh-DW6lknBJlHckHhg,8200
69
70
  nominal/core/_utils/pagination_tools.py,sha256=cEBY1WiA1d3cWJEM0myYF_pX8JdQ_e-5asngVXrUc_Y,12152
70
- nominal/core/_utils/query_tools.py,sha256=rabmhqUYw0POybZtGDoMyAwwXh4VMuYM6mMf-iAfWdc,15860
71
+ nominal/core/_utils/query_tools.py,sha256=0AuIZPtxR_BgrjBjRjc8fPjPKa9zicCe1xT9znVB_RA,16137
71
72
  nominal/core/_utils/queueing.py,sha256=3qljc7dFI1UahlKjCaRVybM4poMCV5SayjyRPyXcPxg,3654
72
73
  nominal/exceptions/__init__.py,sha256=W2r_GWJkZQQ6t3HooFjGRdhIgJq3fBvRV7Yn6gseoO0,415
73
74
  nominal/experimental/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -85,9 +86,9 @@ nominal/experimental/logging/click_log_handler.py,sha256=ANLf4IGgmh95V0kJlr756wQ
85
86
  nominal/experimental/logging/nominal_log_handler.py,sha256=hyTxyjsvFnE7vtyrDJpunAqADHmXekNWALwxXPIJGCk,5120
86
87
  nominal/experimental/logging/rich_log_handler.py,sha256=8yz_VtxNgJg2oiesnXz2iXoBvQrUP5pAsYkxknOXgXA,1231
87
88
  nominal/experimental/migration/__init__.py,sha256=E2IgWJLwJ5bN6jbl8k5nHECKFx5aT11jKAzVYcyXn3o,460
88
- nominal/experimental/migration/migration_utils.py,sha256=j4In_sU_cWW1kScneMP2G8B7LHDcnY2YDE0fwIv8BiY,22831
89
+ nominal/experimental/migration/migration_utils.py,sha256=Xuu9NilMxZQU_o8tqOn9WfM25Yz720HteiyN5L9Bbhs,26792
89
90
  nominal/experimental/rust_streaming/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
90
- nominal/experimental/rust_streaming/rust_write_stream.py,sha256=UoJEujzRAPlsAq2c24fgrub3c0DO0HM10SGsIgZjPKk,1499
91
+ nominal/experimental/rust_streaming/rust_write_stream.py,sha256=E-L5JtcwPWnCEm0o4_k-AVzw173sRSgElzKrgHoYwbs,1490
91
92
  nominal/experimental/stream_v2/__init__.py,sha256=W39vK46pssx5sXvmsImMuJiEPs7iGtwrbYBI0bWnXCY,2313
92
93
  nominal/experimental/stream_v2/_serializer.py,sha256=DcGimcY1LsXNeCzOWrel3SwuvoRV4XLdOFjqjM7MgPY,1035
93
94
  nominal/experimental/stream_v2/_write_stream.py,sha256=-EncNPXUDYaL1YpFlJFEkuLgcxMdyKEXS5JJzP_2LlI,9981
@@ -104,8 +105,8 @@ nominal/thirdparty/polars/polars_export_handler.py,sha256=hGCSwXX9dC4MG01CmmjlTb
104
105
  nominal/thirdparty/tdms/__init__.py,sha256=6n2ImFr2Wiil6JM1P5Q7Mpr0VzLcnDkmup_ftNpPq-s,142
105
106
  nominal/thirdparty/tdms/_tdms.py,sha256=eiHFTUviyDPDClckNldjs_jTTSH_sdmboKDq0oIGChQ,8711
106
107
  nominal/ts/__init__.py,sha256=hmd0ENvDhxRnzDKGLxIub6QG8LpcxCgcyAct029CaEs,21442
107
- nominal-1.100.0.dist-info/METADATA,sha256=v6eSXRLbr-cRBxvxBm3hsi5cfAQavQ2Zhng00SrS3xc,1981
108
- nominal-1.100.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
109
- nominal-1.100.0.dist-info/entry_points.txt,sha256=-mCLhxgg9R_lm5efT7vW9wuBH12izvY322R0a3TYxbE,66
110
- nominal-1.100.0.dist-info/licenses/LICENSE,sha256=zEGHG9mjDjaIS3I79O8mweQo-yiTbqx8jJvUPppVAwk,1067
111
- nominal-1.100.0.dist-info/RECORD,,
108
+ nominal-1.102.0.dist-info/METADATA,sha256=vO-itznAaNKlS3Awvzo8S81LTu7iPKIyLrxEi2y5ZFs,2277
109
+ nominal-1.102.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
110
+ nominal-1.102.0.dist-info/entry_points.txt,sha256=-mCLhxgg9R_lm5efT7vW9wuBH12izvY322R0a3TYxbE,66
111
+ nominal-1.102.0.dist-info/licenses/LICENSE,sha256=zEGHG9mjDjaIS3I79O8mweQo-yiTbqx8jJvUPppVAwk,1067
112
+ nominal-1.102.0.dist-info/RECORD,,