UncountablePythonSDK 0.0.86__py3-none-any.whl → 0.0.88__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.

Potentially problematic release.


This version of UncountablePythonSDK might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: UncountablePythonSDK
3
- Version: 0.0.86
3
+ Version: 0.0.88
4
4
  Summary: Uncountable SDK
5
5
  Project-URL: Homepage, https://github.com/uncountableinc/uncountable-python-sdk
6
6
  Project-URL: Repository, https://github.com/uncountableinc/uncountable-python-sdk.git
@@ -37,6 +37,7 @@ Requires-Dist: flask==3.*
37
37
  Requires-Dist: simplejson==3.*
38
38
  Requires-Dist: grpcio==1.67.1
39
39
  Requires-Dist: protobuf>=4.21.1
40
+ Requires-Dist: azure-storage-blob==12.*
40
41
  Provides-Extra: test
41
42
  Requires-Dist: mypy==1.*; extra == "test"
42
43
  Requires-Dist: ruff==0.*; extra == "test"
@@ -33,15 +33,16 @@ pkgs/argument_parser/_is_namedtuple.py,sha256=Rjc1bKanIPPogl3qG5JPBxglG1TqWYOo1n
33
33
  pkgs/argument_parser/argument_parser.py,sha256=XjWQdcWanfaCGdLx7c_yQtqbZp7db-KAWzw8sTpXOsY,17713
34
34
  pkgs/argument_parser/case_convert.py,sha256=NuJLJUJRbyVb6_Slen4uqaStEHbcOS1d-hBBfDrrw-c,605
35
35
  pkgs/filesystem_utils/__init__.py,sha256=NSsQrUCoGISBCqCCyq6_583sYHTVEQeDjDO8hvZn3ag,1261
36
+ pkgs/filesystem_utils/_blob_session.py,sha256=CtoB7PIocuZo8vvFIS_Rc-YR6KwzFB0rHUVPKFEbRAI,4862
36
37
  pkgs/filesystem_utils/_gdrive_session.py,sha256=GJuZYJq1W4QQ_7OLvZIMK99FgRq8FxJHg6cMUx9prtA,11077
37
38
  pkgs/filesystem_utils/_local_session.py,sha256=xFEYhAvNqrOYqwt4jrEYOuYkjJn0zclZhTelW_Q1-rw,2325
38
39
  pkgs/filesystem_utils/_s3_session.py,sha256=_jLK5C-UElT5Sl5teM2pFR7fQe11NlhUd04EgwN9FRs,3962
39
40
  pkgs/filesystem_utils/_sftp_session.py,sha256=6zoF7YsEUp0GpyFb-BeIhUAWvbTK7IUjvPNJ1B0vEyI,4743
40
- pkgs/filesystem_utils/file_type_utils.py,sha256=Xd-mg35mAENUgNJVz5uK8nEfrUp-NQld_gnXFEq3K-8,1487
41
+ pkgs/filesystem_utils/file_type_utils.py,sha256=Au79J66Rh_Yyt_dXctsygPAg1Y4QRawqwRhbvnCpDIY,1933
41
42
  pkgs/filesystem_utils/filesystem_session.py,sha256=BQ2Go8Mu9-GcnaWh2Pm4x7ugLVsres6XrOQ8RoiEpcE,1045
42
43
  pkgs/serialization/__init__.py,sha256=LifasRW0a50A3qRFmo2bf3FQ6TXhZWOTz2-CVTgPjcQ,753
43
44
  pkgs/serialization/missing_sentry.py,sha256=aM_9KxbCk9dVvXvcOKgkIQBqFWvLhv8QlIUCiuFEXMo,806
44
- pkgs/serialization/opaque_key.py,sha256=FIfXEE0DA1U8R_taFbQ1RCoTSgehrPjP06-qvo-GeNQ,177
45
+ pkgs/serialization/opaque_key.py,sha256=8ak7aMCGWkKDjnG374yqy8gtnCCUzG2DSJEBfoPgi0c,194
45
46
  pkgs/serialization/serial_class.py,sha256=fEceYVIV8dc3Ium-okYxp9cCNFg05HcliXqoCcV5Wcc,6151
46
47
  pkgs/serialization/serial_union.py,sha256=xpdeqCrRd0sNCaUwBQRzje6V40ndCbJpZrLX2K0d5xo,2741
47
48
  pkgs/serialization/yaml.py,sha256=yoJtu7_ixnJV6uTxA_U1PpK5F_ixT08AKVh5ocyYwXM,1466
@@ -58,9 +59,9 @@ pkgs/type_spec/config.py,sha256=pMUNnpZRuS8hybgcPZiVYXz79qZcO9i_ZoiFAgbtVq4,4813
58
59
  pkgs/type_spec/emit_io_ts.py,sha256=CUvBs0boB_X-Kndh66yYcqFfq3oC_LGs8YffLkJ0ZXA,5707
59
60
  pkgs/type_spec/emit_open_api.py,sha256=_oBTuYixZUp3DT2cJaiY55VnCi_jGjqV_1vBx2dYdsw,24596
60
61
  pkgs/type_spec/emit_open_api_util.py,sha256=x4GCiZSGdypJ9Qtm6I5W_3UvwdJyMs8_OGhJ8_THznA,2401
61
- pkgs/type_spec/emit_python.py,sha256=GC-HSMTS0E0QgREjv8DbMRA9NJ1RkYywTOTqZ5ZHmkM,47375
62
+ pkgs/type_spec/emit_python.py,sha256=iJgRfke0rCFKY_7nGWLCPR_SQ4gfRuudC6b7r5ftKPE,47456
62
63
  pkgs/type_spec/emit_typescript.py,sha256=PNeXHoeMA8UWgxsgJisIhJeFX5CNXn0NIz8UtgTvxes,8838
63
- pkgs/type_spec/emit_typescript_util.py,sha256=lG3Wtm5vN6etE0NeYrKfnrxj1vVWGzQBSDcDItaszWk,10319
64
+ pkgs/type_spec/emit_typescript_util.py,sha256=sugxboeMwXiIdk4RDyUR_CxU31Le3OQ7i5HmuHeSLvc,10447
64
65
  pkgs/type_spec/load_types.py,sha256=vO8VLI7aTKzzHQIla-WO-5Z_mfTuwUqH4ZSKN9E9n5U,3688
65
66
  pkgs/type_spec/open_api_util.py,sha256=IGh-_snGPST_P_8FdYtO8MTEa9PUxRW6Rzg9X9EgQik,7114
66
67
  pkgs/type_spec/test.py,sha256=4ueujBq-pEgnX3Z69HyPmD-bullFXmpixcpVzfOkhP4,489
@@ -81,7 +82,7 @@ uncountable/__init__.py,sha256=8l8XWNCKsu7TG94c-xa2KHpDegvxDC2FyQISdWC763Y,89
81
82
  uncountable/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
82
83
  uncountable/core/__init__.py,sha256=RFv0kO6rKFf1PtBPu83hCGmxqkJamRtsgQ9_-ztw7tA,341
83
84
  uncountable/core/async_batch.py,sha256=9pYGFzVCQXt8059qFHgutweGIFPquJ5Xfq6NT5P-1K0,1206
84
- uncountable/core/client.py,sha256=qTM61IJV4DTE2LsTZyv4kePBZAv55vncWt2rtBf-SLQ,10632
85
+ uncountable/core/client.py,sha256=SVBaoXfbV-sj7py3JHOFrQs9_i3E_7P8LqGSDeTAV5Q,11217
85
86
  uncountable/core/environment.py,sha256=K2TtE52JbW5UOBkBSc2Ee2l9rDIoRNoFDXDqRha1fJI,1036
86
87
  uncountable/core/file_upload.py,sha256=L1tjW-zw0vu6y7ytqSWR_aVF8OIsqlQYHCa-24kbAf4,3408
87
88
  uncountable/core/types.py,sha256=s2CjqYJpsmbC7xMwxxT7kJ_V9bwokrjjWVVjpMcQpKI,333
@@ -103,7 +104,7 @@ uncountable/integration/executors/executors.py,sha256=Kzisp1eKufGCWrHIw4mmAj-l1U
103
104
  uncountable/integration/executors/generic_upload_executor.py,sha256=0vs9NVk1UL2FBhiMCH6o8p4KtVXNFNvv861QCOD3UU4,10375
104
105
  uncountable/integration/executors/script_executor.py,sha256=BBQ9f0l7uH2hgKf60jtm-pONzwk-EeOhM2qBAbv_URo,846
105
106
  uncountable/integration/queue_runner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
106
- uncountable/integration/queue_runner/job_scheduler.py,sha256=lhvcl11jyk_wg9BSc1Xyh5u8iEtsdqQFW83FPLupjQI,6189
107
+ uncountable/integration/queue_runner/job_scheduler.py,sha256=2acmeWscG87MZsifxwMRMGJ4sQgQVNJNr5CqIPUg75E,6288
107
108
  uncountable/integration/queue_runner/queue_runner.py,sha256=0BmYu5zHdothTevGsB-nXg6MBd1UD-WkP3h1WCKMdQg,710
108
109
  uncountable/integration/queue_runner/types.py,sha256=8qTq29BTSa5rmW6CBlBntP0pNIiDcwu1wHa78pjroS0,219
109
110
  uncountable/integration/queue_runner/worker.py,sha256=5bcfg_1tVlAenRDCD89gJI3Ru7ev-Sk7Gok5wjLYxnI,4588
@@ -123,10 +124,10 @@ uncountable/integration/queue_runner/datastore/model.py,sha256=8-RI5A2yPZVGBLWIN
123
124
  uncountable/integration/secret_retrieval/__init__.py,sha256=3QXVj35w8rRMxVvmmsViFYDi3lcb3g70incfalOEm6o,87
124
125
  uncountable/integration/secret_retrieval/retrieve_secret.py,sha256=9iz9N8Z-B68QwFCXsx8hTYbgDbk06ejkJ3RQ9mCLMyM,3000
125
126
  uncountable/integration/webhook_server/entrypoint.py,sha256=yQWQq_k3kbJkSsEEt6k22YwhXekezJZfV0rnn-hP-Yo,5516
126
- uncountable/types/__init__.py,sha256=OAuDaFSXysVPw0Y8slVJuBviSNfAXNzPKKG2eGHeeM8,9028
127
- uncountable/types/async_batch.py,sha256=_OhT25_dEVts_z_n1kqfJH3xlZg3btLqR6TNkfFLlXE,609
128
- uncountable/types/async_batch_processor.py,sha256=DJn9KdgUv_l7ojCVJ_d9wCS3GUNc21b5cOrpunty2KU,13129
129
- uncountable/types/async_batch_t.py,sha256=niXgIM7FQXb_1RLX8CBXiGaYSa8nqd-jqX68p7gMgJo,2558
127
+ uncountable/types/__init__.py,sha256=HaqDPQiYcRk_xbKtOebSskAHBHQ_3rBd08ghBO1ZCI4,9120
128
+ uncountable/types/async_batch.py,sha256=-qOtydEQDfZLkuDvQPH6PxnE_JBFeO1Ro1eaxLyiWD4,683
129
+ uncountable/types/async_batch_processor.py,sha256=WQqEFi9azyE7Gmk2KtD7F5xMtNZOIxHLj0is67WA60s,14420
130
+ uncountable/types/async_batch_t.py,sha256=JZY4t6GuriSCDr1cWu8vs-2awGrw8Hsr5OP-SFJ5V0E,3065
130
131
  uncountable/types/async_jobs.py,sha256=gFtEPBZot72sR5zrMWc5zD5QrgNmFmGyD67Y-KhyAmo,343
131
132
  uncountable/types/async_jobs_t.py,sha256=sEh1Ev46ff4n1v8mMV3rEbH3MGmaXnLuvYf0UhDdzeU,1425
132
133
  uncountable/types/auth_retrieval.py,sha256=FY8Vr_BWD4O8PsauPNt_7_08YZSHFaUlTT72L5XJ-4o,570
@@ -137,17 +138,17 @@ uncountable/types/calculations.py,sha256=FFO_D3BbKoGDZnqWvTKpW4KF359i2vrKjpdFCLY
137
138
  uncountable/types/calculations_t.py,sha256=157qD0VqijD5kNDF5BRsfGli3WaPGnNjoo2o2CPX-Ik,669
138
139
  uncountable/types/chemical_structure.py,sha256=E-LnikTFDoVQ1b2zKaVUIO_PAKm-7aZZYJi8I8SDSic,302
139
140
  uncountable/types/chemical_structure_t.py,sha256=zDJ6WkeT3YwWZRZT21znQn2ZYelv3L7yv7kJiGoNZCw,824
140
- uncountable/types/client_base.py,sha256=fpVHWPifRToIiaBPKcM_YT8WQFrK-SW58muGnCTX3d0,68780
141
+ uncountable/types/client_base.py,sha256=7AA4rHQ0N1o22Grqij3ckyy5QbjsrGl5X6YTRfbH_fU,69635
141
142
  uncountable/types/client_config.py,sha256=4h5Liko9uKCo9_0gdbPhoK6Jr2Kv7tioLiQ8iKeq-_4,301
142
143
  uncountable/types/client_config_t.py,sha256=6dStfR0IEHiPW8f9_aF3DD_tHmXXw2rEVrgpebzq8Fg,747
143
144
  uncountable/types/curves.py,sha256=W6uMpG5SyW1MS82szNpxkFEn1MnxNpBFyFbQb2Ysfng,366
144
145
  uncountable/types/curves_t.py,sha256=lKhRM-2cZ_sFaW7pa_I_Ipz_pJhm3_yTFehRXI79pKk,1416
145
- uncountable/types/entity.py,sha256=ECvhswTj9xp4gUEKTZoZYyxHvx1oyvE5FNiGNfSyUgk,528
146
- uncountable/types/entity_t.py,sha256=MPLE0CCrROH89JUE9qyI3MLL0DtVzsuXlJ8bG-x-K4A,16731
146
+ uncountable/types/entity.py,sha256=Y7r_xuYIsY_v1NfIil_d-1_4-lUDMmOSKnMBYCJ20jM,587
147
+ uncountable/types/entity_t.py,sha256=iyf8BKII5Jy072RguoJDAg-o0ZKa8ZrVUrKPrpWLR0E,17155
147
148
  uncountable/types/experiment_groups.py,sha256=_0OXcPzSAbkE-rfKt5tPx178YJ4pcEKZvrCxUHgDnvw,309
148
149
  uncountable/types/experiment_groups_t.py,sha256=qEs8YW0eJOJ_sCOObT5v9QRx9wsjLYpJqJhCJXa-vNA,721
149
- uncountable/types/field_values.py,sha256=uuIWX-xmfvcinYPdfkWJeb56zzQY01mc9rmotMPMh24,503
150
- uncountable/types/field_values_t.py,sha256=WIGXJKtQbHroCgaHhb15H6Rzi00liSkhoi2JBMVEgv0,1935
150
+ uncountable/types/field_values.py,sha256=x3oNoMTgT9k1knWVxAVaX4krj7V8palj90FZuFtFbRw,1202
151
+ uncountable/types/field_values_t.py,sha256=7yJcaamU6x6ZkCVI73lyoh_TKUBwi-8plsc6_kzY3wE,5903
151
152
  uncountable/types/fields.py,sha256=GUY5ne8Zp2_Lalikr0zcbdJrin8dG81eyS8fKWJ9yf8,266
152
153
  uncountable/types/fields_t.py,sha256=LZBEfBHDn2thc1u4i8BulMEcFfDxK4JA-VzahTjivNA,665
153
154
  uncountable/types/generic_upload.py,sha256=n6hue9BX_rLSXeEt_DcGwL2ckxfNXg1wEPR9JNEGQxQ,879
@@ -218,6 +219,7 @@ uncountable/types/api/entity/grant_entity_permissions.py,sha256=YAXyJ3I_nqDQYFYG
218
219
  uncountable/types/api/entity/list_entities.py,sha256=ykbdq4DD31uiRz4i8LH-8LLeA2Lpp_5fWfb5fdyx248,2000
219
220
  uncountable/types/api/entity/lock_entity.py,sha256=mMZx2tWOtuYg0sIftdPsFWgZO5LCav2ubqTw97dCtDU,1197
220
221
  uncountable/types/api/entity/resolve_entity_ids.py,sha256=GnQjeoTdzL0PIubrLay-PpaRsYFFWVGrTxhzSmP4hhw,1387
222
+ uncountable/types/api/entity/set_entity_values.py,sha256=irihNNbUHScKhOWpC0D8R9b3QXPT8yuSJVBnat1Y42o,1182
221
223
  uncountable/types/api/entity/set_values.py,sha256=O_LpcYeBXFfxxUVOL2FDDYQwU7La-IBM_uEQLgtPrVo,1125
222
224
  uncountable/types/api/entity/transition_entity_phase.py,sha256=J0lO_dubmTCO9s7P2DZgC-Zq6m0VagpXfg0jZqxz5XM,2160
223
225
  uncountable/types/api/entity/unlock_entity.py,sha256=8UGffqqV8eiSbz_-7y0W2CXLsz4IvM496RFz6L0Y23o,1150
@@ -286,7 +288,7 @@ uncountable/types/api/triggers/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr
286
288
  uncountable/types/api/triggers/run_trigger.py,sha256=-oZgPyn43xEKSCs81DVNzwaYMCdRJxbM9GY6fsqKwf4,1090
287
289
  uncountable/types/api/uploader/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
288
290
  uncountable/types/api/uploader/invoke_uploader.py,sha256=6mwVG136oLp9JcbB2I-kZnrcm3aeZzYZB-SFjEImY2o,1314
289
- UncountablePythonSDK-0.0.86.dist-info/METADATA,sha256=M-eS-Ah9j0F9pCNkwlJufJM7CCpGxzqWeo_Q-Dk6SkE,2024
290
- UncountablePythonSDK-0.0.86.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
291
- UncountablePythonSDK-0.0.86.dist-info/top_level.txt,sha256=1UVGjAU-6hJY9qw2iJ7nCBeEwZ793AEN5ZfKX9A1uj4,31
292
- UncountablePythonSDK-0.0.86.dist-info/RECORD,,
291
+ UncountablePythonSDK-0.0.88.dist-info/METADATA,sha256=ffYG155Wxi8gwlAe-T91tlE8En-elS89jOL5ZgBHCQY,2064
292
+ UncountablePythonSDK-0.0.88.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
293
+ UncountablePythonSDK-0.0.88.dist-info/top_level.txt,sha256=1UVGjAU-6hJY9qw2iJ7nCBeEwZ793AEN5ZfKX9A1uj4,31
294
+ UncountablePythonSDK-0.0.88.dist-info/RECORD,,
@@ -0,0 +1,137 @@
1
+ from io import BytesIO
2
+
3
+ from azure.storage.blob import BlobServiceClient, ContainerClient
4
+
5
+ from pkgs.filesystem_utils.file_type_utils import (
6
+ FileObjectData,
7
+ FileSystemBlobConfig,
8
+ FileSystemFileReference,
9
+ FileSystemObject,
10
+ FileTransfer,
11
+ IncompatibleFileReference,
12
+ )
13
+
14
+ from .filesystem_session import FileSystemSession
15
+
16
+
17
+ def _add_slash(prefix: str) -> str:
18
+ if len(prefix) > 0 and prefix[-1] != "/":
19
+ prefix = prefix + "/"
20
+ return prefix
21
+
22
+
23
+ class BlobSession(FileSystemSession):
24
+ config: FileSystemBlobConfig
25
+
26
+ def __init__(self, blob_config: FileSystemBlobConfig) -> None:
27
+ super().__init__()
28
+ self.config = blob_config
29
+
30
+ def start(self) -> None:
31
+ self.service_client: BlobServiceClient | None = BlobServiceClient(
32
+ self.config.account_url, credential=self.config.credential
33
+ )
34
+ self.container_client: ContainerClient | None = (
35
+ self.service_client.get_container_client(self.config.container)
36
+ )
37
+
38
+ def __enter__(self) -> "BlobSession":
39
+ self.start()
40
+ return self
41
+
42
+ def __exit__(self, exc_type: object, exc_val: object, exc_tb: object) -> None:
43
+ self.service_client = None
44
+ self.container_client = None
45
+
46
+ def list_files(
47
+ self,
48
+ dir_path: FileSystemObject,
49
+ *,
50
+ recursive: bool = False,
51
+ valid_extensions: list[str] | None = None,
52
+ ) -> list[FileSystemObject]:
53
+ if not isinstance(dir_path, FileSystemFileReference):
54
+ raise IncompatibleFileReference()
55
+
56
+ assert self.service_client is not None and self.container_client is not None, (
57
+ "call to list_files on uninitialized blob session"
58
+ )
59
+
60
+ filesystem_file_references: list[FileSystemObject] = []
61
+ prefix = _add_slash(dir_path.filepath)
62
+ for blob in self.container_client.list_blobs(name_starts_with=prefix):
63
+ if not recursive and (
64
+ blob.name == prefix or "/" in blob.name[len(prefix) :]
65
+ ):
66
+ continue
67
+ if valid_extensions is None or any(
68
+ blob.name.endswith(valid_extension)
69
+ for valid_extension in valid_extensions
70
+ ):
71
+ filesystem_file_references.append(
72
+ FileSystemFileReference(
73
+ filepath=blob.name,
74
+ )
75
+ )
76
+
77
+ return filesystem_file_references
78
+
79
+ def download_files(
80
+ self,
81
+ filepaths: list[FileSystemObject],
82
+ ) -> list[FileObjectData]:
83
+ downloaded_files: list[FileObjectData] = []
84
+ assert self.service_client is not None and self.container_client is not None, (
85
+ "call to download_files on uninitialized blob session"
86
+ )
87
+
88
+ for file_object in filepaths:
89
+ if (
90
+ not isinstance(file_object, FileSystemFileReference)
91
+ or file_object.filename is None
92
+ ):
93
+ raise IncompatibleFileReference()
94
+
95
+ blob_client = self.container_client.get_blob_client(file_object.filepath)
96
+ download_stream = blob_client.download_blob()
97
+ file_data = download_stream.readall()
98
+ downloaded_files.append(
99
+ FileObjectData(
100
+ file_data=file_data,
101
+ file_IO=BytesIO(file_data),
102
+ filename=file_object.filename,
103
+ filepath=file_object.filepath,
104
+ )
105
+ )
106
+
107
+ return downloaded_files
108
+
109
+ def move_files(self, file_mappings: list[FileTransfer]) -> None:
110
+ assert self.service_client is not None and self.container_client is not None, (
111
+ "call to move_files on uninitialized blob session"
112
+ )
113
+
114
+ for src_file, dest_file in file_mappings:
115
+ if not isinstance(src_file, FileSystemFileReference) or not isinstance(
116
+ dest_file, FileSystemFileReference
117
+ ):
118
+ raise IncompatibleFileReference()
119
+
120
+ source_blob_client = self.container_client.get_blob_client(
121
+ src_file.filepath
122
+ )
123
+ dest_blob_client = self.container_client.get_blob_client(dest_file.filepath)
124
+
125
+ dest_blob_client.start_copy_from_url(source_blob_client.url)
126
+ source_blob_client.delete_blob()
127
+
128
+ def delete_files(self, filepaths: list[FileSystemObject]) -> None:
129
+ assert self.service_client is not None and self.container_client is not None, (
130
+ "call to delete_files on uninitialized blob session"
131
+ )
132
+ for file_object in filepaths:
133
+ if not isinstance(file_object, FileSystemFileReference):
134
+ raise IncompatibleFileReference()
135
+
136
+ blob_client = self.container_client.get_blob_client(file_object.filepath)
137
+ blob_client.delete_blob()
@@ -4,6 +4,12 @@ from io import BytesIO
4
4
  from typing import Optional, Union
5
5
 
6
6
  import paramiko
7
+ from azure.core.credentials import (
8
+ AzureNamedKeyCredential,
9
+ AzureSasCredential,
10
+ TokenCredential,
11
+ )
12
+ from azure.storage.blob import ContainerProperties
7
13
 
8
14
 
9
15
  @dataclass
@@ -69,3 +75,17 @@ class FileSystemS3Config:
69
75
  access_key_id: Optional[str]
70
76
  secret_access_key: Optional[str]
71
77
  session_token: Optional[str]
78
+
79
+
80
+ @dataclass(kw_only=True)
81
+ class FileSystemBlobConfig:
82
+ account_url: str
83
+ credential: (
84
+ str
85
+ | dict[str, str]
86
+ | AzureNamedKeyCredential
87
+ | AzureSasCredential
88
+ | TokenCredential
89
+ | None
90
+ )
91
+ container: ContainerProperties | str
@@ -1,4 +1,4 @@
1
1
  # Blocks a string key value from being interpreted for case conversion
2
- class OpaqueKey(str):
2
+ class OpaqueKey(str): # noqa: FURB189
3
3
  def __new__(cls, key: str) -> "OpaqueKey":
4
4
  return str.__new__(cls, key)
@@ -1148,13 +1148,15 @@ def _create_api_function(
1148
1148
 
1149
1149
  ruff_requires_wrap = len(endpoint.path_basename) > 14
1150
1150
 
1151
+ account_type = endpoint.root if endpoint.root != "external" else "materials"
1152
+
1151
1153
  api_out.write(
1152
1154
  f"""import {api_import} as api
1153
1155
  from main.db.session import Session, SessionMaker
1154
1156
  from main.site.decorators import APIError, APIResponse, {validated_method}
1155
1157
 
1156
1158
 
1157
- @{validated_method}(api.ENDPOINT_PATH, "{endpoint.root}", api.Arguments)
1159
+ @{validated_method}(api.ENDPOINT_PATH, "{account_type}", api.Arguments)
1158
1160
  def {endpoint.path_basename}({WRAP_ARGS_START if ruff_requires_wrap else ""}args: api.Arguments, client_sm: SessionMaker{WRAP_ARGS_END if ruff_requires_wrap else ""}) -> APIResponse[api.Data]:
1159
1161
  with Session(client_sm) as session:
1160
1162
  # return APIResponse(data=api.Data())
@@ -82,9 +82,11 @@ def emit_value_ts(
82
82
  return (
83
83
  "{\n\t"
84
84
  + ",\n\t".join(
85
- "["
86
- + emit_value_ts(ctx, key_type, dkey)
87
- + "]: "
85
+ (
86
+ f"[{emit_value_ts(ctx, key_type, dkey)}]: "
87
+ if not key_type.is_base_type(builder.BaseTypeName.s_string)
88
+ else f"{dkey}: "
89
+ )
88
90
  + emit_value_ts(ctx, value_type, dvalue)
89
91
  for dkey, dvalue in value.items()
90
92
  )
@@ -71,16 +71,24 @@ class APIResponseError(Exception):
71
71
  extra_details: dict[str, JsonValue] | None
72
72
 
73
73
  def __init__(
74
- self, status_code: int, message: str, extra_details: dict[str, JsonValue] | None
74
+ self,
75
+ status_code: int,
76
+ message: str,
77
+ extra_details: dict[str, JsonValue] | None,
78
+ request_id: str,
75
79
  ) -> None:
76
80
  super().__init__(status_code, message, extra_details)
77
81
  self.status_code = status_code
78
82
  self.message = message
79
83
  self.extra_details = extra_details
84
+ self.request_id = request_id
80
85
 
81
86
  @classmethod
82
87
  def construct_error(
83
- cls, status_code: int, extra_details: dict[str, JsonValue] | None
88
+ cls,
89
+ status_code: int,
90
+ extra_details: dict[str, JsonValue] | None,
91
+ request_id: str,
84
92
  ) -> "APIResponseError":
85
93
  message: str
86
94
  match status_code:
@@ -103,9 +111,21 @@ class APIResponseError(Exception):
103
111
  case _:
104
112
  message = "unknown error"
105
113
  return APIResponseError(
106
- status_code=status_code, message=message, extra_details=extra_details
114
+ status_code=status_code,
115
+ message=message,
116
+ extra_details=extra_details,
117
+ request_id=request_id,
107
118
  )
108
119
 
120
+ def __str__(self) -> str:
121
+ details_obj = {
122
+ "request_id": self.request_id,
123
+ "status_code": self.status_code,
124
+ "extra_details": self.extra_details,
125
+ }
126
+ details = json.dumps(details_obj)
127
+ return f"API response error ({self.status_code}): '{self.message}'. Details: {details}"
128
+
109
129
 
110
130
  class SDKError(Exception):
111
131
  message: str
@@ -174,7 +194,9 @@ class Client(ClientMethods):
174
194
  except JSONDecodeError:
175
195
  pass
176
196
  raise APIResponseError.construct_error(
177
- status_code=response.status_code, extra_details=extra_details
197
+ status_code=response.status_code,
198
+ extra_details=extra_details,
199
+ request_id=request_id,
178
200
  )
179
201
  try:
180
202
  return typing.cast(dict[str, JsonValue], response.json())
@@ -106,7 +106,10 @@ async def start_scheduler(command_queue: CommandQueue) -> None:
106
106
  ) -> str:
107
107
  if isinstance(
108
108
  payload.invocation_context,
109
- queued_job_t.InvocationContextCron,
109
+ (
110
+ queued_job_t.InvocationContextCron,
111
+ queued_job_t.InvocationContextManual,
112
+ ),
110
113
  ):
111
114
  existing_queued_jobs = datastore.load_job_queue()
112
115
  duplicate_job = next(
@@ -85,6 +85,7 @@ from . import response_t as response_t
85
85
  from .api.triggers import run_trigger as run_trigger_t
86
86
  from . import secret_retrieval_t as secret_retrieval_t
87
87
  from .api.permissions import set_core_permissions as set_core_permissions_t
88
+ from .api.entity import set_entity_values as set_entity_values_t
88
89
  from .api.inputs import set_input_attribute_values as set_input_attribute_values_t
89
90
  from .api.inputs import set_input_category as set_input_category_t
90
91
  from .api.inputs import set_input_subcategories as set_input_subcategories_t
@@ -191,6 +192,7 @@ __all__: list[str] = [
191
192
  "run_trigger_t",
192
193
  "secret_retrieval_t",
193
194
  "set_core_permissions_t",
195
+ "set_entity_values_t",
194
196
  "set_input_attribute_values_t",
195
197
  "set_input_category_t",
196
198
  "set_input_subcategories_t",
@@ -0,0 +1,44 @@
1
+ # DO NOT MODIFY -- This file is generated by type_spec
2
+ # flake8: noqa: F821
3
+ # ruff: noqa: E402 Q003
4
+ # fmt: off
5
+ # isort: skip_file
6
+ from __future__ import annotations
7
+ import typing # noqa: F401
8
+ import datetime # noqa: F401
9
+ from decimal import Decimal # noqa: F401
10
+ import dataclasses
11
+ from pkgs.serialization import serial_class
12
+ from ... import async_batch_t
13
+ from ... import entity_t
14
+ from ... import field_values_t
15
+
16
+ __all__: list[str] = [
17
+ "Arguments",
18
+ "Data",
19
+ "ENDPOINT_METHOD",
20
+ "ENDPOINT_PATH",
21
+ ]
22
+
23
+ ENDPOINT_METHOD = "POST"
24
+ ENDPOINT_PATH = "api/external/entity/set_entity_values"
25
+
26
+
27
+ # DO NOT MODIFY -- This file is generated by type_spec
28
+ @serial_class(
29
+ named_type_path="sdk.api.entity.set_entity_values.Arguments",
30
+ )
31
+ @dataclasses.dataclass(kw_only=True)
32
+ class Arguments:
33
+ entity_identifier: entity_t.EntityIdentifier
34
+ field_values: list[field_values_t.FieldArgumentValue]
35
+
36
+
37
+ # DO NOT MODIFY -- This file is generated by type_spec
38
+ @serial_class(
39
+ named_type_path="sdk.api.entity.set_entity_values.Data",
40
+ )
41
+ @dataclasses.dataclass(kw_only=True)
42
+ class Data(async_batch_t.AsyncBatchActionReturn):
43
+ pass
44
+ # DO NOT MODIFY -- This file is generated by type_spec
@@ -6,6 +6,7 @@
6
6
  # Kept only for SDK backwards compatibility
7
7
  from .async_batch_t import AsyncBatchRequestPath as AsyncBatchRequestPath
8
8
  from .async_batch_t import AsyncBatchRequest as AsyncBatchRequest
9
+ from .async_batch_t import AsyncBatchResultValue as AsyncBatchResultValue
9
10
  from .async_batch_t import AsyncBatchActionReturn as AsyncBatchActionReturn
10
11
  from .async_batch_t import SavedAsyncBatchActionReturn as SavedAsyncBatchActionReturn
11
12
  from .async_batch_t import QueuedAsyncBatchRequest as QueuedAsyncBatchRequest
@@ -16,6 +16,7 @@ import uncountable.types.api.recipes.clear_recipe_outputs as clear_recipe_output
16
16
  import uncountable.types.api.recipes.create_recipe as create_recipe_t
17
17
  import uncountable.types.api.recipes.edit_recipe_inputs as edit_recipe_inputs_t
18
18
  from uncountable.types import entity_t
19
+ from uncountable.types import field_values_t
19
20
  from uncountable.types import generic_upload_t
20
21
  import uncountable.types.api.entity.grant_entity_permissions as grant_entity_permissions_t
21
22
  from uncountable.types import identifier_t
@@ -23,6 +24,7 @@ import uncountable.types.api.uploader.invoke_uploader as invoke_uploader_t
23
24
  from uncountable.types import recipe_identifiers_t
24
25
  from uncountable.types import recipe_metadata_t
25
26
  from uncountable.types import recipe_workflow_steps_t
27
+ import uncountable.types.api.entity.set_entity_values as set_entity_values_t
26
28
  import uncountable.types.api.recipes.set_recipe_metadata as set_recipe_metadata_t
27
29
  import uuid
28
30
  from abc import ABC, abstractmethod
@@ -311,6 +313,41 @@ class AsyncBatchProcessorBase(ABC):
311
313
  batch_reference=req.batch_reference,
312
314
  )
313
315
 
316
+ def set_entity_values(
317
+ self,
318
+ *,
319
+ entity_identifier: entity_t.EntityIdentifier,
320
+ field_values: list[field_values_t.FieldArgumentValue],
321
+ depends_on: typing.Optional[list[str]] = None,
322
+ ) -> async_batch_t.QueuedAsyncBatchRequest:
323
+ """Sets field values for an entity
324
+
325
+ :param entity_identifier: Entity to update
326
+ :param field_values: Field values to set
327
+ :param depends_on: A list of batch reference keys to process before processing this request
328
+ """
329
+ args = set_entity_values_t.Arguments(
330
+ entity_identifier=entity_identifier,
331
+ field_values=field_values,
332
+ )
333
+ json_data = serialize_for_api(args)
334
+
335
+ batch_reference = str(uuid.uuid4())
336
+
337
+ req = async_batch_t.AsyncBatchRequest(
338
+ path=async_batch_t.AsyncBatchRequestPath.SET_ENTITY_VALUES,
339
+ data=json_data,
340
+ depends_on=depends_on,
341
+ batch_reference=batch_reference,
342
+ )
343
+
344
+ self._enqueue(req)
345
+
346
+ return async_batch_t.QueuedAsyncBatchRequest(
347
+ path=req.path,
348
+ batch_reference=req.batch_reference,
349
+ )
350
+
314
351
  def set_recipe_metadata(
315
352
  self,
316
353
  *,
@@ -11,11 +11,13 @@ from pkgs.strenum_compat import StrEnum
11
11
  import dataclasses
12
12
  from pkgs.serialization import serial_class
13
13
  from . import base_t
14
+ from . import entity_t
14
15
 
15
16
  __all__: list[str] = [
16
17
  "AsyncBatchActionReturn",
17
18
  "AsyncBatchRequest",
18
19
  "AsyncBatchRequestPath",
20
+ "AsyncBatchResultValue",
19
21
  "QueuedAsyncBatchRequest",
20
22
  "SavedAsyncBatchActionReturn",
21
23
  ]
@@ -35,6 +37,7 @@ class AsyncBatchRequestPath(StrEnum):
35
37
  ASSOCIATE_RECIPE_AS_INPUT = "recipes/associate_recipe_as_input"
36
38
  CLEAR_RECIPE_OUTPUTS = "recipes/clear_recipe_outputs"
37
39
  GRANT_ENTITY_PERMISSIONS = "entity/grant_entity_permissions"
40
+ SET_ENTITY_VALUES = "entity/set_entity_values"
38
41
 
39
42
 
40
43
  # DO NOT MODIFY -- This file is generated by type_spec
@@ -50,6 +53,17 @@ class AsyncBatchRequest:
50
53
  depends_on: typing.Optional[list[str]] = None
51
54
 
52
55
 
56
+ # DO NOT MODIFY -- This file is generated by type_spec
57
+ @serial_class(
58
+ named_type_path="sdk.async_batch.AsyncBatchResultValue",
59
+ unconverted_values={"value"},
60
+ )
61
+ @dataclasses.dataclass(kw_only=True)
62
+ class AsyncBatchResultValue:
63
+ data_key: str
64
+ value: base_t.JsonValue
65
+
66
+
53
67
  # DO NOT MODIFY -- This file is generated by type_spec
54
68
  @serial_class(
55
69
  named_type_path="sdk.async_batch.AsyncBatchActionReturn",
@@ -58,6 +72,8 @@ class AsyncBatchRequest:
58
72
  class AsyncBatchActionReturn:
59
73
  modification_made: bool
60
74
  result_id: typing.Optional[base_t.ObjectId] = None
75
+ entity: typing.Optional[entity_t.Entity] = None
76
+ result_values: typing.Optional[list[AsyncBatchResultValue]] = None
61
77
 
62
78
 
63
79
  # DO NOT MODIFY -- This file is generated by type_spec
@@ -69,6 +69,7 @@ import uncountable.types.api.entity.resolve_entity_ids as resolve_entity_ids_t
69
69
  import uncountable.types.api.outputs.resolve_output_conditions as resolve_output_conditions_t
70
70
  import uncountable.types.api.triggers.run_trigger as run_trigger_t
71
71
  import uncountable.types.api.permissions.set_core_permissions as set_core_permissions_t
72
+ import uncountable.types.api.entity.set_entity_values as set_entity_values_t
72
73
  import uncountable.types.api.inputs.set_input_attribute_values as set_input_attribute_values_t
73
74
  import uncountable.types.api.inputs.set_input_category as set_input_category_t
74
75
  import uncountable.types.api.inputs.set_input_subcategories as set_input_subcategories_t
@@ -1232,6 +1233,28 @@ class ClientMethods(ABC):
1232
1233
  )
1233
1234
  return self.do_request(api_request=api_request, return_type=set_core_permissions_t.Data)
1234
1235
 
1236
+ def set_entity_values(
1237
+ self,
1238
+ *,
1239
+ entity_identifier: entity_t.EntityIdentifier,
1240
+ field_values: list[field_values_t.FieldArgumentValue],
1241
+ ) -> set_entity_values_t.Data:
1242
+ """Sets field values for an entity
1243
+
1244
+ :param entity_identifier: Entity to update
1245
+ :param field_values: Field values to set
1246
+ """
1247
+ args = set_entity_values_t.Arguments(
1248
+ entity_identifier=entity_identifier,
1249
+ field_values=field_values,
1250
+ )
1251
+ api_request = APIRequest(
1252
+ method=set_entity_values_t.ENDPOINT_METHOD,
1253
+ endpoint=set_entity_values_t.ENDPOINT_PATH,
1254
+ args=args,
1255
+ )
1256
+ return self.do_request(api_request=api_request, return_type=set_entity_values_t.Data)
1257
+
1235
1258
  def set_input_attribute_values(
1236
1259
  self,
1237
1260
  *,
@@ -9,4 +9,5 @@ from .entity_t import LimitedEntityType as LimitedEntityType
9
9
  from .entity_t import EntityPermissionType as EntityPermissionType
10
10
  from .entity_t import GrantableEntityPermissionType as GrantableEntityPermissionType
11
11
  from .entity_t import Entity as Entity
12
+ from .entity_t import EntityIdentifier as EntityIdentifier
12
13
  # DO NOT MODIFY -- This file is generated by type_spec
@@ -12,9 +12,11 @@ import dataclasses
12
12
  from pkgs.serialization import serial_class
13
13
  from pkgs.serialization import serial_string_enum
14
14
  from . import base_t
15
+ from . import identifier_t
15
16
 
16
17
  __all__: list[str] = [
17
18
  "Entity",
19
+ "EntityIdentifier",
18
20
  "EntityPermissionType",
19
21
  "EntityType",
20
22
  "GrantableEntityPermissionType",
@@ -47,7 +49,7 @@ __all__: list[str] = [
47
49
  "doe_run": "Suggest Experiments",
48
50
  "email_record_external": "External Emails",
49
51
  "email_relay_server": "Email Relay Server",
50
- "enter_recipe_view_preference": "Enter Recipe View Preference",
52
+ "enter_recipe_view_preference": "Enter Experiment View Preference",
51
53
  "entities_viewed": "Entities Viewed",
52
54
  "entity_annotation": "Annotation",
53
55
  "entity_field": "Field",
@@ -90,7 +92,7 @@ __all__: list[str] = [
90
92
  "license": "License",
91
93
  "maintenance_schedule": "Maintenance Schedule",
92
94
  "material_family": "Material Family",
93
- "measurement_group_recipe": "Measurement Group Recipe",
95
+ "measurement_group_recipe": "Measurement Group Experiment",
94
96
  "ml_job": "Batch Processing Job",
95
97
  "naming_scheme": "Naming Scheme",
96
98
  "naming_counter": "Naming Counter",
@@ -106,7 +108,7 @@ __all__: list[str] = [
106
108
  "output_condition_parameter_analytical_method": "Output Condition Parameter Analytical Method",
107
109
  "output_group": "Output Group",
108
110
  "permission": "Permission",
109
- "permissions_recipe_link_inheritance": "Permissions Recipe Link Inheritance",
111
+ "permissions_recipe_link_inheritance": "Permissions Experiment Link Inheritance",
110
112
  "phase_workflow": "Phase Workflow",
111
113
  "platform_config": "Platform Config",
112
114
  "predictive_model": "Predictive Model",
@@ -115,21 +117,21 @@ __all__: list[str] = [
115
117
  "project_workbook_comment": "Notebook Cell Comment",
116
118
  "recipe": "Experiment",
117
119
  "recipe_audit_log": "Experiment Audit Log",
118
- "recipe_calculation": "Recipe Calculation",
120
+ "recipe_calculation": "Experiment Calculation",
119
121
  "recipe_check": "Experiment Check",
120
- "recipe_export": "Recipe Export",
122
+ "recipe_export": "Experiment Export",
121
123
  "recipe_goal": "Experiment Goal",
122
- "recipe_ingredient": "Recipe Ingredient",
123
- "recipe_ingredient_actual": "Recipe Ingredient Actual",
124
- "recipe_ingredients_compounded": "Recipe Ingredients Compounded",
125
- "recipe_ingredients_compounded_calculation": "Recipe Ingredients Compounded Caclulation",
126
- "recipe_output": "Recipe Output",
127
- "recipe_output_metadata": "Recipe Output Metadata",
128
- "recipe_permission_view": "Recipe Permission View",
129
- "recipe_project": "Recipe Project",
130
- "recipe_step": "Recipe Step",
131
- "recipe_workflow_step": "Recipe Workflow Step",
132
- "recipe_tag": "Recipe Tag",
124
+ "recipe_ingredient": "Experiment Ingredient",
125
+ "recipe_ingredient_actual": "Experiment Ingredient Actual",
126
+ "recipe_ingredients_compounded": "Experiment Ingredients Compounded",
127
+ "recipe_ingredients_compounded_calculation": "Experiment Ingredients Compounded Caclulation",
128
+ "recipe_output": "Experiment Output",
129
+ "recipe_output_metadata": "Experiment Output Metadata",
130
+ "recipe_permission_view": "Experiment Permission View",
131
+ "recipe_project": "Experiment Project",
132
+ "recipe_step": "Experiment Step",
133
+ "recipe_workflow_step": "Experiment Workflow Step",
134
+ "recipe_tag": "Experiment Tag",
133
135
  "recipe_metadata": "Experiment Metadata",
134
136
  "recipe_metadata_mapping": "Experiment Metadata Mapping",
135
137
  "metadata_value": "Metadata Value",
@@ -343,7 +345,7 @@ class EntityType(StrEnum):
343
345
 
344
346
 
345
347
  # DO NOT MODIFY -- This file is generated by type_spec
346
- LimitedEntityType = typing.Union[typing.Literal[EntityType.LAB_REQUEST], typing.Literal[EntityType.APPROVAL], typing.Literal[EntityType.CUSTOM_ENTITY], typing.Literal[EntityType.INVENTORY_AMOUNT], typing.Literal[EntityType.TASK], typing.Literal[EntityType.PROJECT], typing.Literal[EntityType.EQUIPMENT], typing.Literal[EntityType.INV_LOCAL_LOCATIONS], typing.Literal[EntityType.FIELD_OPTION_SET], typing.Literal[EntityType.WEBHOOK], typing.Literal[EntityType.SPECS], typing.Literal[EntityType.GOAL], typing.Literal[EntityType.INGREDIENT_TAG_MAP], typing.Literal[EntityType.INGREDIENT_TAG], typing.Literal[EntityType.CONDITION_PARAMETER], typing.Literal[EntityType.OUTPUT], typing.Literal[EntityType.ASYNC_JOB]]
348
+ LimitedEntityType = typing.Union[typing.Literal[EntityType.LAB_REQUEST], typing.Literal[EntityType.APPROVAL], typing.Literal[EntityType.CUSTOM_ENTITY], typing.Literal[EntityType.INVENTORY_AMOUNT], typing.Literal[EntityType.TASK], typing.Literal[EntityType.PROJECT], typing.Literal[EntityType.EQUIPMENT], typing.Literal[EntityType.INV_LOCAL_LOCATIONS], typing.Literal[EntityType.FIELD_OPTION_SET], typing.Literal[EntityType.WEBHOOK], typing.Literal[EntityType.SPECS], typing.Literal[EntityType.GOAL], typing.Literal[EntityType.INGREDIENT_TAG_MAP], typing.Literal[EntityType.INGREDIENT_TAG], typing.Literal[EntityType.CONDITION_PARAMETER], typing.Literal[EntityType.OUTPUT], typing.Literal[EntityType.OUTPUT_CONDITION_PARAMETER], typing.Literal[EntityType.ASYNC_JOB]]
347
349
 
348
350
 
349
351
  # DO NOT MODIFY -- This file is generated by type_spec
@@ -367,4 +369,14 @@ GrantableEntityPermissionType = typing.Union[typing.Literal[EntityPermissionType
367
369
  class Entity:
368
370
  id: base_t.ObjectId
369
371
  type: EntityType
372
+
373
+
374
+ # DO NOT MODIFY -- This file is generated by type_spec
375
+ @serial_class(
376
+ named_type_path="sdk.entity.EntityIdentifier",
377
+ )
378
+ @dataclasses.dataclass(kw_only=True)
379
+ class EntityIdentifier:
380
+ identifier_key: identifier_t.IdentifierKey
381
+ type: EntityType
370
382
  # DO NOT MODIFY -- This file is generated by type_spec
@@ -8,4 +8,15 @@ from .field_values_t import FieldRefNameValue as FieldRefNameValue
8
8
  from .field_values_t import FieldRefIdNameValue as FieldRefIdNameValue
9
9
  from .field_values_t import ArgumentValueRefName as ArgumentValueRefName
10
10
  from .field_values_t import ArgumentValueId as ArgumentValueId
11
+ from .field_values_t import FieldValueType as FieldValueType
12
+ from .field_values_t import FieldValueBase as FieldValueBase
13
+ from .field_values_t import FieldValueFiles as FieldValueFiles
14
+ from .field_values_t import FieldValueId as FieldValueId
15
+ from .field_values_t import FieldValueIds as FieldValueIds
16
+ from .field_values_t import FieldValueText as FieldValueText
17
+ from .field_values_t import FieldValueBoolean as FieldValueBoolean
18
+ from .field_values_t import FieldValueNumeric as FieldValueNumeric
19
+ from .field_values_t import FieldValueBatchReference as FieldValueBatchReference
20
+ from .field_values_t import FieldValue as FieldValue
21
+ from .field_values_t import FieldArgumentValue as FieldArgumentValue
11
22
  # DO NOT MODIFY -- This file is generated by type_spec
@@ -7,15 +7,30 @@ from __future__ import annotations
7
7
  import typing # noqa: F401
8
8
  import datetime # noqa: F401
9
9
  from decimal import Decimal # noqa: F401
10
+ from pkgs.strenum_compat import StrEnum
10
11
  import dataclasses
11
12
  from pkgs.serialization import serial_class
13
+ from pkgs.serialization import serial_union_annotation
12
14
  from . import base_t
15
+ from . import entity_t
16
+ from . import identifier_t
13
17
 
14
18
  __all__: list[str] = [
15
19
  "ArgumentValueId",
16
20
  "ArgumentValueRefName",
21
+ "FieldArgumentValue",
17
22
  "FieldRefIdNameValue",
18
23
  "FieldRefNameValue",
24
+ "FieldValue",
25
+ "FieldValueBase",
26
+ "FieldValueBatchReference",
27
+ "FieldValueBoolean",
28
+ "FieldValueFiles",
29
+ "FieldValueId",
30
+ "FieldValueIds",
31
+ "FieldValueNumeric",
32
+ "FieldValueText",
33
+ "FieldValueType",
19
34
  ]
20
35
 
21
36
 
@@ -66,4 +81,124 @@ class ArgumentValueId:
66
81
  field_id: base_t.ObjectId
67
82
  value: base_t.JsonValue
68
83
  row_index: typing.Optional[typing.Optional[int]] = None
84
+
85
+
86
+ # DO NOT MODIFY -- This file is generated by type_spec
87
+ class FieldValueType(StrEnum):
88
+ FILES = "files"
89
+ TEXT = "text"
90
+ ID = "id"
91
+ IDS = "ids"
92
+ BOOLEAN = "boolean"
93
+ NUMERIC = "numeric"
94
+ BATCH_REFERENCE = "batch_reference"
95
+
96
+
97
+ # DO NOT MODIFY -- This file is generated by type_spec
98
+ @serial_class(
99
+ named_type_path="sdk.field_values.FieldValueBase",
100
+ )
101
+ @dataclasses.dataclass(kw_only=True)
102
+ class FieldValueBase:
103
+ type: FieldValueType
104
+
105
+
106
+ # DO NOT MODIFY -- This file is generated by type_spec
107
+ @serial_class(
108
+ named_type_path="sdk.field_values.FieldValueFiles",
109
+ parse_require={"type"},
110
+ )
111
+ @dataclasses.dataclass(kw_only=True)
112
+ class FieldValueFiles(FieldValueBase):
113
+ type: typing.Literal[FieldValueType.FILES] = FieldValueType.FILES
114
+ file_ids: list[base_t.ObjectId]
115
+
116
+
117
+ # DO NOT MODIFY -- This file is generated by type_spec
118
+ @serial_class(
119
+ named_type_path="sdk.field_values.FieldValueId",
120
+ parse_require={"type"},
121
+ )
122
+ @dataclasses.dataclass(kw_only=True)
123
+ class FieldValueId(FieldValueBase):
124
+ type: typing.Literal[FieldValueType.ID] = FieldValueType.ID
125
+ entity_type: entity_t.EntityType
126
+ identifier_key: identifier_t.IdentifierKey
127
+
128
+
129
+ # DO NOT MODIFY -- This file is generated by type_spec
130
+ @serial_class(
131
+ named_type_path="sdk.field_values.FieldValueIds",
132
+ parse_require={"type"},
133
+ )
134
+ @dataclasses.dataclass(kw_only=True)
135
+ class FieldValueIds(FieldValueBase):
136
+ type: typing.Literal[FieldValueType.IDS] = FieldValueType.IDS
137
+ entity_type: entity_t.EntityType
138
+ identifier_keys: list[identifier_t.IdentifierKey]
139
+
140
+
141
+ # DO NOT MODIFY -- This file is generated by type_spec
142
+ @serial_class(
143
+ named_type_path="sdk.field_values.FieldValueText",
144
+ parse_require={"type"},
145
+ )
146
+ @dataclasses.dataclass(kw_only=True)
147
+ class FieldValueText(FieldValueBase):
148
+ type: typing.Literal[FieldValueType.TEXT] = FieldValueType.TEXT
149
+ value: str
150
+
151
+
152
+ # DO NOT MODIFY -- This file is generated by type_spec
153
+ @serial_class(
154
+ named_type_path="sdk.field_values.FieldValueBoolean",
155
+ parse_require={"type"},
156
+ )
157
+ @dataclasses.dataclass(kw_only=True)
158
+ class FieldValueBoolean(FieldValueBase):
159
+ type: typing.Literal[FieldValueType.BOOLEAN] = FieldValueType.BOOLEAN
160
+ value: bool
161
+
162
+
163
+ # DO NOT MODIFY -- This file is generated by type_spec
164
+ @serial_class(
165
+ named_type_path="sdk.field_values.FieldValueNumeric",
166
+ to_string_values={"value"},
167
+ parse_require={"type"},
168
+ )
169
+ @dataclasses.dataclass(kw_only=True)
170
+ class FieldValueNumeric(FieldValueBase):
171
+ type: typing.Literal[FieldValueType.NUMERIC] = FieldValueType.NUMERIC
172
+ value: Decimal
173
+
174
+
175
+ # DO NOT MODIFY -- This file is generated by type_spec
176
+ @serial_class(
177
+ named_type_path="sdk.field_values.FieldValueBatchReference",
178
+ parse_require={"type"},
179
+ )
180
+ @dataclasses.dataclass(kw_only=True)
181
+ class FieldValueBatchReference(FieldValueBase):
182
+ type: typing.Literal[FieldValueType.BATCH_REFERENCE] = FieldValueType.BATCH_REFERENCE
183
+ reference_key: identifier_t.IdentifierKeyBatchReference
184
+ data_key: str
185
+
186
+
187
+ # DO NOT MODIFY -- This file is generated by type_spec
188
+ FieldValue = typing.Annotated[
189
+ typing.Union[FieldValueFiles, FieldValueId, FieldValueIds, FieldValueText, FieldValueBoolean, FieldValueNumeric, FieldValueBatchReference],
190
+ serial_union_annotation(
191
+ named_type_path="sdk.field_values.FieldValue",
192
+ ),
193
+ ]
194
+
195
+
196
+ # DO NOT MODIFY -- This file is generated by type_spec
197
+ @serial_class(
198
+ named_type_path="sdk.field_values.FieldArgumentValue",
199
+ )
200
+ @dataclasses.dataclass(kw_only=True)
201
+ class FieldArgumentValue:
202
+ field_key: identifier_t.IdentifierKey
203
+ value: FieldValue
69
204
  # DO NOT MODIFY -- This file is generated by type_spec