nominal 1.96.0__py3-none-any.whl → 1.97.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 +12 -0
- nominal/core/_utils/multipart.py +43 -19
- nominal/core/client.py +52 -0
- {nominal-1.96.0.dist-info → nominal-1.97.0.dist-info}/METADATA +1 -1
- {nominal-1.96.0.dist-info → nominal-1.97.0.dist-info}/RECORD +8 -8
- {nominal-1.96.0.dist-info → nominal-1.97.0.dist-info}/WHEEL +0 -0
- {nominal-1.96.0.dist-info → nominal-1.97.0.dist-info}/entry_points.txt +0 -0
- {nominal-1.96.0.dist-info → nominal-1.97.0.dist-info}/licenses/LICENSE +0 -0
CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.97.0](https://github.com/nominal-io/nominal-client/compare/v1.96.0...v1.97.0) (2025-12-04)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add create_workbook_template ([#535](https://github.com/nominal-io/nominal-client/issues/535)) ([9c98975](https://github.com/nominal-io/nominal-client/commit/9c989753828c39e417bafed3db2981444132aeac))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* add per-part retries during multipart uploads ([#537](https://github.com/nominal-io/nominal-client/issues/537)) ([ffdbc4a](https://github.com/nominal-io/nominal-client/commit/ffdbc4ac6f82562fb9eff3fed4b254b784aa89bc))
|
|
14
|
+
|
|
3
15
|
## [1.96.0](https://github.com/nominal-io/nominal-client/compare/v1.95.0...v1.96.0) (2025-12-03)
|
|
4
16
|
|
|
5
17
|
|
nominal/core/_utils/multipart.py
CHANGED
|
@@ -27,29 +27,53 @@ def _sign_and_upload_part_job(
|
|
|
27
27
|
upload_id: str,
|
|
28
28
|
q: Queue[bytes],
|
|
29
29
|
part: int,
|
|
30
|
+
num_retries: int = 3,
|
|
30
31
|
) -> requests.Response:
|
|
31
32
|
data = q.get()
|
|
33
|
+
|
|
32
34
|
try:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
35
|
+
last_ex: Exception | None = None
|
|
36
|
+
for attempt in range(num_retries):
|
|
37
|
+
try:
|
|
38
|
+
log_extras = {"key": key, "part": part, "upload_id": upload_id, "attempt": attempt + 1}
|
|
39
|
+
|
|
40
|
+
logger.debug("Signing part %d for upload", part, extra=log_extras)
|
|
41
|
+
sign_response = upload_client.sign_part(auth_header, key, part, upload_id)
|
|
42
|
+
logger.debug(
|
|
43
|
+
"Successfully signed part %d for upload",
|
|
44
|
+
part,
|
|
45
|
+
extra={"response.url": sign_response.url, **log_extras},
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
logger.debug("Pushing part %d for multipart upload", extra=log_extras)
|
|
49
|
+
put_response = requests.put(
|
|
50
|
+
sign_response.url,
|
|
51
|
+
data=data,
|
|
52
|
+
headers=sign_response.headers,
|
|
53
|
+
verify=upload_client._verify,
|
|
54
|
+
)
|
|
55
|
+
logger.debug(
|
|
56
|
+
"Finished pushing part %d for multipart upload with status %d",
|
|
57
|
+
part,
|
|
58
|
+
put_response.status_code,
|
|
59
|
+
extra={"response.url": put_response.url, **log_extras},
|
|
60
|
+
)
|
|
61
|
+
put_response.raise_for_status()
|
|
62
|
+
return put_response
|
|
63
|
+
except Exception as ex:
|
|
64
|
+
logger.warning(
|
|
65
|
+
"Failed to upload part %d: %s",
|
|
66
|
+
part,
|
|
67
|
+
ex,
|
|
68
|
+
extra=log_extras,
|
|
69
|
+
)
|
|
70
|
+
last_ex = ex
|
|
71
|
+
|
|
72
|
+
raise (
|
|
73
|
+
last_ex
|
|
74
|
+
if last_ex
|
|
75
|
+
else RuntimeError(f"Unknown error uploading part {part} for upload_id={upload_id} and key={key}")
|
|
47
76
|
)
|
|
48
|
-
put_response.raise_for_status()
|
|
49
|
-
return put_response
|
|
50
|
-
except Exception as e:
|
|
51
|
-
logger.exception("error uploading part", exc_info=e, extra={"key": key, "upload_id": upload_id, "part": part})
|
|
52
|
-
raise e
|
|
53
77
|
finally:
|
|
54
78
|
q.task_done()
|
|
55
79
|
|
nominal/core/client.py
CHANGED
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import enum
|
|
4
4
|
import logging
|
|
5
|
+
import uuid
|
|
5
6
|
from dataclasses import dataclass, field
|
|
6
7
|
from datetime import datetime, timedelta
|
|
7
8
|
from io import TextIOBase
|
|
@@ -21,10 +22,12 @@ from nominal_api import (
|
|
|
21
22
|
scout_catalog,
|
|
22
23
|
scout_checks_api,
|
|
23
24
|
scout_datasource_connection_api,
|
|
25
|
+
scout_layout_api,
|
|
24
26
|
scout_notebook_api,
|
|
25
27
|
scout_run_api,
|
|
26
28
|
scout_template_api,
|
|
27
29
|
scout_video_api,
|
|
30
|
+
scout_workbookcommon_api,
|
|
28
31
|
secrets_api,
|
|
29
32
|
storage_datasource_api,
|
|
30
33
|
)
|
|
@@ -1478,3 +1481,52 @@ class NominalClient:
|
|
|
1478
1481
|
"nominal.core.NominalClient.create_workbook_from_template",
|
|
1479
1482
|
"use 'nominal.core.WorkbookTemplate.create_workbook' instead",
|
|
1480
1483
|
)
|
|
1484
|
+
|
|
1485
|
+
def create_workbook_template(
|
|
1486
|
+
self,
|
|
1487
|
+
title: str,
|
|
1488
|
+
*,
|
|
1489
|
+
description: str | None = None,
|
|
1490
|
+
labels: list[str] | None = None,
|
|
1491
|
+
properties: dict[str, str] | None = None,
|
|
1492
|
+
commit_message: str | None = None,
|
|
1493
|
+
workspace: Workspace | str | None = None,
|
|
1494
|
+
) -> WorkbookTemplate:
|
|
1495
|
+
"""Create an empty workbook template.
|
|
1496
|
+
|
|
1497
|
+
Args:
|
|
1498
|
+
title: Title of the workbook template
|
|
1499
|
+
description: Description of the workbook template
|
|
1500
|
+
labels: Labels to attach to the workbook template
|
|
1501
|
+
properties: Properties to attach to the workbook template
|
|
1502
|
+
commit_message: An optional message to include with the creation of the template
|
|
1503
|
+
workspace: Workspace to create the workbook template in.
|
|
1504
|
+
|
|
1505
|
+
Returns:
|
|
1506
|
+
The created WorkbookTemplate
|
|
1507
|
+
"""
|
|
1508
|
+
request = scout_template_api.CreateTemplateRequest(
|
|
1509
|
+
title=title,
|
|
1510
|
+
description=description if description is not None else "",
|
|
1511
|
+
labels=labels if labels is not None else [],
|
|
1512
|
+
properties=properties if properties is not None else {},
|
|
1513
|
+
is_published=False,
|
|
1514
|
+
layout=scout_layout_api.WorkbookLayout(
|
|
1515
|
+
v1=scout_layout_api.WorkbookLayoutV1(
|
|
1516
|
+
root_panel=scout_layout_api.Panel(
|
|
1517
|
+
tabbed=scout_layout_api.TabbedPanel(
|
|
1518
|
+
v1=scout_layout_api.TabbedPanelV1(
|
|
1519
|
+
id=str(uuid.uuid4()),
|
|
1520
|
+
tabs=[],
|
|
1521
|
+
)
|
|
1522
|
+
)
|
|
1523
|
+
)
|
|
1524
|
+
)
|
|
1525
|
+
),
|
|
1526
|
+
content=scout_workbookcommon_api.WorkbookContent(channel_variables={}, charts={}),
|
|
1527
|
+
message=commit_message if commit_message is not None else "Initial blank workbook template",
|
|
1528
|
+
workspace=self._workspace_rid_for_search(workspace or WorkspaceSearchType.ALL),
|
|
1529
|
+
)
|
|
1530
|
+
|
|
1531
|
+
template = self._clients.template.create(self._clients.auth_header, request)
|
|
1532
|
+
return WorkbookTemplate._from_conjure(self._clients, template)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
CHANGELOG.md,sha256=
|
|
1
|
+
CHANGELOG.md,sha256=6LrMT1H8kFV_1cH8Bu_s8Itk_yzsIcAd0UfnMWuHdAU,80317
|
|
2
2
|
LICENSE,sha256=zEGHG9mjDjaIS3I79O8mweQo-yiTbqx8jJvUPppVAwk,1067
|
|
3
3
|
README.md,sha256=KKe0dxh_pHXCtB7I9G4qWGQYvot_BZU8yW6MJyuyUHM,311
|
|
4
4
|
nominal/__init__.py,sha256=rbraORnXUrNn1hywLXM0XwSQCd9UmQt20PDYlsBalfE,2167
|
|
@@ -35,7 +35,7 @@ nominal/core/attachment.py,sha256=iJaDyF6JXsKxxBLA03I0WMmQF8U0bA-wRwvXMEhfWLU,42
|
|
|
35
35
|
nominal/core/bounds.py,sha256=742BWmGL3FBryRAjoiJRg2N6aVinjYkQLxN7kfnJ40Q,581
|
|
36
36
|
nominal/core/channel.py,sha256=dbe8wpfMiWqHu98x66w6GOmC9Ro33Wv9AhBVx2DvtVk,18970
|
|
37
37
|
nominal/core/checklist.py,sha256=rO1RPDYV3o2miPKF7DcCiYpj6bUN-sdtZNhJkXzkfYE,7110
|
|
38
|
-
nominal/core/client.py,sha256=
|
|
38
|
+
nominal/core/client.py,sha256=L6IQVEPTiKbOjtbn4G0_R90jbVeOOxpHBHmminGQ3FE,67403
|
|
39
39
|
nominal/core/connection.py,sha256=ySbPN_a2takVa8wIU9mK4fB6vYLyZnN-qSmXVkLUxAY,5157
|
|
40
40
|
nominal/core/containerized_extractors.py,sha256=HrcMJzdE-hH66AgYIA0LTeFELsBHa0Sm0vlsKMiIzDU,9501
|
|
41
41
|
nominal/core/data_review.py,sha256=bEnRsd8LI4x9YOBPcF2H3h5-e12A7Gh8gQfsNUAZmPQ,7922
|
|
@@ -63,7 +63,7 @@ nominal/core/_stream/write_stream_base.py,sha256=AxK3fAq3IBjNXZkxYFVXu3dGNWLCBhg
|
|
|
63
63
|
nominal/core/_utils/README.md,sha256=kWPQDc6kn-PjXFUsIH9u2nOA3RdGSXCOlxqeJSmUsPA,160
|
|
64
64
|
nominal/core/_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
65
65
|
nominal/core/_utils/api_tools.py,sha256=Z--Et7NjpCH4if72WwGm45EyqyeqK2ambcBrtOSDMrY,2949
|
|
66
|
-
nominal/core/_utils/multipart.py,sha256=
|
|
66
|
+
nominal/core/_utils/multipart.py,sha256=YZb6SDJG9eM9AmSHikMbkEOtxy1DTOi9ggVUVzO0Ur4,9998
|
|
67
67
|
nominal/core/_utils/multipart_downloader.py,sha256=zS6wxecAZYeWBfiOjtscoUVPaSiUYTI_Ckn4sknSxMM,14275
|
|
68
68
|
nominal/core/_utils/networking.py,sha256=0cted8IF52WdYAPtiAy9IeosmQkoytXOnazJkdYRkk8,5862
|
|
69
69
|
nominal/core/_utils/pagination_tools.py,sha256=cEBY1WiA1d3cWJEM0myYF_pX8JdQ_e-5asngVXrUc_Y,12152
|
|
@@ -102,8 +102,8 @@ nominal/thirdparty/polars/polars_export_handler.py,sha256=hGCSwXX9dC4MG01CmmjlTb
|
|
|
102
102
|
nominal/thirdparty/tdms/__init__.py,sha256=6n2ImFr2Wiil6JM1P5Q7Mpr0VzLcnDkmup_ftNpPq-s,142
|
|
103
103
|
nominal/thirdparty/tdms/_tdms.py,sha256=eiHFTUviyDPDClckNldjs_jTTSH_sdmboKDq0oIGChQ,8711
|
|
104
104
|
nominal/ts/__init__.py,sha256=hmd0ENvDhxRnzDKGLxIub6QG8LpcxCgcyAct029CaEs,21442
|
|
105
|
-
nominal-1.
|
|
106
|
-
nominal-1.
|
|
107
|
-
nominal-1.
|
|
108
|
-
nominal-1.
|
|
109
|
-
nominal-1.
|
|
105
|
+
nominal-1.97.0.dist-info/METADATA,sha256=f_-Nkovbw63L8TqEce4QVrxF6xRqpH8lOJwSBt97-9g,1946
|
|
106
|
+
nominal-1.97.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
107
|
+
nominal-1.97.0.dist-info/entry_points.txt,sha256=-mCLhxgg9R_lm5efT7vW9wuBH12izvY322R0a3TYxbE,66
|
|
108
|
+
nominal-1.97.0.dist-info/licenses/LICENSE,sha256=zEGHG9mjDjaIS3I79O8mweQo-yiTbqx8jJvUPppVAwk,1067
|
|
109
|
+
nominal-1.97.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|