UncountablePythonSDK 0.0.90__py3-none-any.whl → 0.0.91__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.
- {UncountablePythonSDK-0.0.90.dist-info → UncountablePythonSDK-0.0.91.dist-info}/METADATA +2 -2
- {UncountablePythonSDK-0.0.90.dist-info → UncountablePythonSDK-0.0.91.dist-info}/RECORD +34 -27
- {UncountablePythonSDK-0.0.90.dist-info → UncountablePythonSDK-0.0.91.dist-info}/WHEEL +1 -1
- docs/requirements.txt +1 -1
- examples/download_files.py +26 -0
- pkgs/argument_parser/argument_parser.py +57 -25
- pkgs/serialization/__init__.py +7 -3
- pkgs/serialization/annotation.py +64 -0
- pkgs/serialization/serial_alias.py +47 -0
- pkgs/serialization/serial_class.py +26 -32
- pkgs/serialization/serial_generic.py +16 -0
- pkgs/serialization/serial_union.py +9 -9
- pkgs/serialization_util/__init__.py +4 -0
- pkgs/serialization_util/dataclasses.py +14 -0
- pkgs/serialization_util/serialization_helpers.py +11 -3
- pkgs/type_spec/builder.py +41 -5
- pkgs/type_spec/emit_python.py +34 -6
- pkgs/type_spec/type_info/emit_type_info.py +7 -2
- uncountable/core/client.py +58 -1
- uncountable/core/environment.py +2 -2
- uncountable/integration/scheduler.py +4 -4
- uncountable/types/__init__.py +2 -0
- uncountable/types/api/chemical/convert_chemical_formats.py +7 -1
- uncountable/types/api/entity/transition_entity_phase.py +7 -1
- uncountable/types/api/files/__init__.py +1 -0
- uncountable/types/api/files/download_file.py +77 -0
- uncountable/types/api/permissions/set_core_permissions.py +7 -1
- uncountable/types/api/recipes/set_recipe_tags.py +7 -1
- uncountable/types/entity_t.py +13 -2
- uncountable/types/id_source_t.py +7 -1
- uncountable/types/identifier_t.py +7 -1
- uncountable/types/overrides_t.py +7 -1
- uncountable/types/recipe_identifiers_t.py +13 -2
- {UncountablePythonSDK-0.0.90.dist-info → UncountablePythonSDK-0.0.91.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: UncountablePythonSDK
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.91
|
|
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
|
|
@@ -43,7 +43,7 @@ Requires-Dist: mypy==1.*; extra == "test"
|
|
|
43
43
|
Requires-Dist: ruff==0.*; extra == "test"
|
|
44
44
|
Requires-Dist: pytest==8.*; extra == "test"
|
|
45
45
|
Requires-Dist: coverage[toml]==7.*; extra == "test"
|
|
46
|
-
Requires-Dist: pytest-cov==
|
|
46
|
+
Requires-Dist: pytest-cov==6.*; extra == "test"
|
|
47
47
|
Requires-Dist: pytest-xdist==3.*; extra == "test"
|
|
48
48
|
|
|
49
49
|
# Uncountable Python SDK
|
|
@@ -3,7 +3,7 @@ docs/conf.py,sha256=YF5J-9g_Wg8wXmyHsGaE8xYlDEzqocNl3UWUmP0CwBg,1702
|
|
|
3
3
|
docs/index.md,sha256=eEdirX_Ds6ICTRtIS5iT4irCquHcQyKN7E4M5QP9T8A,257
|
|
4
4
|
docs/justfile,sha256=cvNcpb-ByPOF2aCrFlg3DDZBoYMx5W8xGdr13m9HcnI,215
|
|
5
5
|
docs/quickstart.md,sha256=3GuJ0MB1O5kjlsrgAmdSkDq0rYqATrYy-tzEHDy8H-c,422
|
|
6
|
-
docs/requirements.txt,sha256
|
|
6
|
+
docs/requirements.txt,sha256=-sWMwUL2L6vU1QzoQAS-aP8oPbUqXDfMxCeeTKnShFc,138
|
|
7
7
|
docs/static/logo_blue.png,sha256=SyYpMTVhhBbhF5Wl8lWaVwz-_p1MIR6dW6bVhufQRME,46708
|
|
8
8
|
docs/static/favicons/android-chrome-192x192.png,sha256=XoF-AhD55JlSBDGsEPJKfT_VeXT-awhwKyZnxLhrwvk,1369
|
|
9
9
|
docs/static/favicons/android-chrome-512x512.png,sha256=1S4xwY9YtJQ5ifFsZ-DOzssoyBYs0t9uwdOUmYx0Xso,3888
|
|
@@ -16,6 +16,7 @@ docs/static/favicons/mstile-150x150.png,sha256=eAK4QdEofhdLtfmjuPTpnX3MJqYnvGXsH
|
|
|
16
16
|
docs/static/favicons/safari-pinned-tab.svg,sha256=S84fRnz0ZxLnQrKtmmFZytiRyu1xLtMR_RVy5jmwU7k,1926
|
|
17
17
|
examples/async_batch.py,sha256=tEyvgxk2uf681mKlN4TDuPMkb1OHyM9oO8pYW4A7HvM,1142
|
|
18
18
|
examples/create_entity.py,sha256=t6WBZsWRDbWZgFCWXKGgKL5LAB6-38oaiNYGxMAa2No,686
|
|
19
|
+
examples/download_files.py,sha256=rjv7EUgSw_W24_F5La-MljnIDQhbrvA7p2M-qPFbrXA,734
|
|
19
20
|
examples/edit_recipe_inputs.py,sha256=mtk_oSkN-OT2hKkb1XKXrRiUaGYTJstXuOKyTR51Fjo,1663
|
|
20
21
|
examples/invoke_uploader.py,sha256=rEvmVY5TjigN_-4PTQdkjY-bC5DrYMcJgquyZ4Tt5FM,748
|
|
21
22
|
examples/set_recipe_metadata_file.py,sha256=oPBhMo9T17zj4YpJRkmVH9lknYcT8livph0KssxYtg4,1048
|
|
@@ -30,7 +31,7 @@ pkgs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
30
31
|
pkgs/argument_parser/__init__.py,sha256=1qShokCP8e-h8oeO0r9EZPDOdSPUQ9Q4fAxW4tlH24I,503
|
|
31
32
|
pkgs/argument_parser/_is_enum.py,sha256=Gw6jJa8nBwYGqXwwCZbSnWL8Rvr5alkg5lSVAqXtOZM,257
|
|
32
33
|
pkgs/argument_parser/_is_namedtuple.py,sha256=Rjc1bKanIPPogl3qG5JPBxglG1TqWYOo1nxxhBASQWY,265
|
|
33
|
-
pkgs/argument_parser/argument_parser.py,sha256=
|
|
34
|
+
pkgs/argument_parser/argument_parser.py,sha256=KVYCRIQ6fgamIOf8cyxpJtn_IuHvaO0-1ah25Sf1yX8,18355
|
|
34
35
|
pkgs/argument_parser/case_convert.py,sha256=NuJLJUJRbyVb6_Slen4uqaStEHbcOS1d-hBBfDrrw-c,605
|
|
35
36
|
pkgs/filesystem_utils/__init__.py,sha256=NSsQrUCoGISBCqCCyq6_583sYHTVEQeDjDO8hvZn3ag,1261
|
|
36
37
|
pkgs/filesystem_utils/_blob_session.py,sha256=CtoB7PIocuZo8vvFIS_Rc-YR6KwzFB0rHUVPKFEbRAI,4862
|
|
@@ -40,26 +41,30 @@ pkgs/filesystem_utils/_s3_session.py,sha256=_jLK5C-UElT5Sl5teM2pFR7fQe11NlhUd04E
|
|
|
40
41
|
pkgs/filesystem_utils/_sftp_session.py,sha256=6zoF7YsEUp0GpyFb-BeIhUAWvbTK7IUjvPNJ1B0vEyI,4743
|
|
41
42
|
pkgs/filesystem_utils/file_type_utils.py,sha256=Au79J66Rh_Yyt_dXctsygPAg1Y4QRawqwRhbvnCpDIY,1933
|
|
42
43
|
pkgs/filesystem_utils/filesystem_session.py,sha256=BQ2Go8Mu9-GcnaWh2Pm4x7ugLVsres6XrOQ8RoiEpcE,1045
|
|
43
|
-
pkgs/serialization/__init__.py,sha256=
|
|
44
|
+
pkgs/serialization/__init__.py,sha256=b2sNfYICz0D6Y8shzEUfyUoHZukfuAvfuaZvg8dZHic,1163
|
|
45
|
+
pkgs/serialization/annotation.py,sha256=_BzP14N8R9cZ9GhWvaLYxUCLU1hlJZ-GYiqnLML0fiQ,2134
|
|
44
46
|
pkgs/serialization/missing_sentry.py,sha256=aM_9KxbCk9dVvXvcOKgkIQBqFWvLhv8QlIUCiuFEXMo,806
|
|
45
47
|
pkgs/serialization/opaque_key.py,sha256=8ak7aMCGWkKDjnG374yqy8gtnCCUzG2DSJEBfoPgi0c,194
|
|
46
|
-
pkgs/serialization/
|
|
47
|
-
pkgs/serialization/
|
|
48
|
+
pkgs/serialization/serial_alias.py,sha256=9xH6dUULAYV8veXX2A3eX6WY7FBIF_cABkBlqPyUci8,1347
|
|
49
|
+
pkgs/serialization/serial_class.py,sha256=NILXrtJEwRrOHECK47GyKwL3sAh2V1S-euYKnuj0vYk,6128
|
|
50
|
+
pkgs/serialization/serial_generic.py,sha256=3nO8T2aO9AF0MqOWQCVZW1zH6gAVvKpCzA46hOcwN_I,458
|
|
51
|
+
pkgs/serialization/serial_union.py,sha256=ZutLI7hH6Pf9Ih7AIJ9gXdJPXINcN1CnSv3fUq1q1a8,2750
|
|
48
52
|
pkgs/serialization/yaml.py,sha256=yoJtu7_ixnJV6uTxA_U1PpK5F_ixT08AKVh5ocyYwXM,1466
|
|
49
|
-
pkgs/serialization_util/__init__.py,sha256=
|
|
53
|
+
pkgs/serialization_util/__init__.py,sha256=N32on_ZGhdPdJ2Qdh1YDpbH6MSc9oU0b3Jsfg0MpWwE,481
|
|
50
54
|
pkgs/serialization_util/_get_type_for_serialization.py,sha256=dW5_W9MFd6wgWfW5qlWork-GBb-QFLtiOZkjk2Zqn2M,1177
|
|
51
55
|
pkgs/serialization_util/convert_to_snakecase.py,sha256=H2BAo5ZdcCDN77RpLb-uP0s7-FQ5Ukwnsd3VYc1vD0M,583
|
|
52
|
-
pkgs/serialization_util/
|
|
56
|
+
pkgs/serialization_util/dataclasses.py,sha256=uhNGXQPQLZblDFQuuwkAGmKOPiRyfDzCdg72CVtYJGA,390
|
|
57
|
+
pkgs/serialization_util/serialization_helpers.py,sha256=Djme5a5BZTnYJMHQYgrdd4emOBxtPxfV-Yt-Etco4zU,6565
|
|
53
58
|
pkgs/strenum_compat/__init__.py,sha256=wXRFeNvBm8RU6dy1PFJ5sRLgUIEeH_DVR95Sv5qpGbk,59
|
|
54
59
|
pkgs/strenum_compat/strenum_compat.py,sha256=uOUAgpYTjHs1MX8dG81jRlyTkt3KNbkV_25zp7xTX2s,36
|
|
55
60
|
pkgs/type_spec/__init__.py,sha256=h5DmJTca4QVV10sZR1x0-MlkZfuGYDfapR3zHvXfzto,19
|
|
56
61
|
pkgs/type_spec/__main__.py,sha256=5bJaX9Y_-FavP0qwzhk-z-V97UY7uaezJTa1zhO_HHQ,1048
|
|
57
|
-
pkgs/type_spec/builder.py,sha256=
|
|
62
|
+
pkgs/type_spec/builder.py,sha256=iyPjknTqdYfq6Y44PbGf-B6i5WqbdglQhPz__CZv_B8,49886
|
|
58
63
|
pkgs/type_spec/config.py,sha256=pMUNnpZRuS8hybgcPZiVYXz79qZcO9i_ZoiFAgbtVq4,4813
|
|
59
64
|
pkgs/type_spec/emit_io_ts.py,sha256=CUvBs0boB_X-Kndh66yYcqFfq3oC_LGs8YffLkJ0ZXA,5707
|
|
60
65
|
pkgs/type_spec/emit_open_api.py,sha256=_oBTuYixZUp3DT2cJaiY55VnCi_jGjqV_1vBx2dYdsw,24596
|
|
61
66
|
pkgs/type_spec/emit_open_api_util.py,sha256=x4GCiZSGdypJ9Qtm6I5W_3UvwdJyMs8_OGhJ8_THznA,2401
|
|
62
|
-
pkgs/type_spec/emit_python.py,sha256=
|
|
67
|
+
pkgs/type_spec/emit_python.py,sha256=Pdqwayqm4keMiZxVvS29xYrhuwa7Pn7OlhdVrBKgDwc,48636
|
|
63
68
|
pkgs/type_spec/emit_typescript.py,sha256=VgOD3k3hdXyrdYMMY0fZjfpE6-aCm0zuCSjvRVkRHMo,8834
|
|
64
69
|
pkgs/type_spec/emit_typescript_util.py,sha256=sugxboeMwXiIdk4RDyUR_CxU31Le3OQ7i5HmuHeSLvc,10447
|
|
65
70
|
pkgs/type_spec/load_types.py,sha256=vO8VLI7aTKzzHQIla-WO-5Z_mfTuwUqH4ZSKN9E9n5U,3688
|
|
@@ -72,7 +77,7 @@ pkgs/type_spec/actions_registry/emit_typescript.py,sha256=W1lI36ITdJ7MBf37wlTB7H
|
|
|
72
77
|
pkgs/type_spec/parts/base.py.prepart,sha256=St6P21VP8Um_nagZFuSyNzYiKDSrsK3TNOuGY_1O8cg,2186
|
|
73
78
|
pkgs/type_spec/parts/base.ts.prepart,sha256=2FJJvpg2olCcavxj0nbYWdwKl6KeScour2JjSvN42l8,1001
|
|
74
79
|
pkgs/type_spec/type_info/__main__.py,sha256=pmVjVqXyVh8vKTNCTFgz80Sg74C5BKToP3E6GS-X_So,857
|
|
75
|
-
pkgs/type_spec/type_info/emit_type_info.py,sha256=
|
|
80
|
+
pkgs/type_spec/type_info/emit_type_info.py,sha256=_rLXuU81caJRHn7NdkhwNgcrRo_lolfI5f2Nu9eT1cM,13560
|
|
76
81
|
pkgs/type_spec/value_spec/__init__.py,sha256=Z-grlcZtxAfEXhPHsK0nD7PFLGsv4eqvunaPN7_TA84,83
|
|
77
82
|
pkgs/type_spec/value_spec/__main__.py,sha256=6bzP85p_Cm4bPp5tXz8D_4p64wMn5SKsXC7SqSZquYc,8318
|
|
78
83
|
pkgs/type_spec/value_spec/convert_type.py,sha256=X5N7DOTo5XOIHbcYHh9RZFthzb2gcnYg2tRuVMBhbxY,2517
|
|
@@ -82,8 +87,8 @@ uncountable/__init__.py,sha256=8l8XWNCKsu7TG94c-xa2KHpDegvxDC2FyQISdWC763Y,89
|
|
|
82
87
|
uncountable/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
83
88
|
uncountable/core/__init__.py,sha256=RFv0kO6rKFf1PtBPu83hCGmxqkJamRtsgQ9_-ztw7tA,341
|
|
84
89
|
uncountable/core/async_batch.py,sha256=9pYGFzVCQXt8059qFHgutweGIFPquJ5Xfq6NT5P-1K0,1206
|
|
85
|
-
uncountable/core/client.py,sha256=
|
|
86
|
-
uncountable/core/environment.py,sha256=
|
|
90
|
+
uncountable/core/client.py,sha256=o6QQzbs3htVyHnP5NOcnRx037JQeGnsv1jFr8RQCzkw,13017
|
|
91
|
+
uncountable/core/environment.py,sha256=6cc-nUvUIbJMI0OSEg3dWI-iNgSYhCdUKKn607Z3QpM,1040
|
|
87
92
|
uncountable/core/file_upload.py,sha256=L1tjW-zw0vu6y7ytqSWR_aVF8OIsqlQYHCa-24kbAf4,3408
|
|
88
93
|
uncountable/core/types.py,sha256=s2CjqYJpsmbC7xMwxxT7kJ_V9bwokrjjWVVjpMcQpKI,333
|
|
89
94
|
uncountable/integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -93,7 +98,7 @@ uncountable/integration/cron.py,sha256=6eH-kIs3sdYPCyb62_L2M7U_uQTdMTdwY5hreEJb0
|
|
|
93
98
|
uncountable/integration/entrypoint.py,sha256=BHOYPQgKvZE6HG8Rv15MkdYl8lRkvfDgv1OdLo0oQ9Q,433
|
|
94
99
|
uncountable/integration/job.py,sha256=af197JUceIKzpIN5C2z8zeZOPhIQ16ipyC6qVt1WXv0,2386
|
|
95
100
|
uncountable/integration/scan_profiles.py,sha256=760zbv7O7wXxHUHqUkFBpd1Afe8hqxMPU3ugwZGdhEo,2925
|
|
96
|
-
uncountable/integration/scheduler.py,sha256=
|
|
101
|
+
uncountable/integration/scheduler.py,sha256=jrtktQYGW4QKRLH5GvhOFvCl4S9CLLhWY2GF0rzY-KM,4780
|
|
97
102
|
uncountable/integration/server.py,sha256=Hwi3fpdhcSK2HynI6Zwi7A3mWTTCaK_ic53M5-4IEp4,4716
|
|
98
103
|
uncountable/integration/telemetry.py,sha256=bX68_a2PyG23n1QtIFxcH30JynUoovMz6HgA_jgUb1A,7132
|
|
99
104
|
uncountable/integration/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -124,7 +129,7 @@ uncountable/integration/queue_runner/datastore/model.py,sha256=8-RI5A2yPZVGBLWIN
|
|
|
124
129
|
uncountable/integration/secret_retrieval/__init__.py,sha256=3QXVj35w8rRMxVvmmsViFYDi3lcb3g70incfalOEm6o,87
|
|
125
130
|
uncountable/integration/secret_retrieval/retrieve_secret.py,sha256=9iz9N8Z-B68QwFCXsx8hTYbgDbk06ejkJ3RQ9mCLMyM,3000
|
|
126
131
|
uncountable/integration/webhook_server/entrypoint.py,sha256=yQWQq_k3kbJkSsEEt6k22YwhXekezJZfV0rnn-hP-Yo,5516
|
|
127
|
-
uncountable/types/__init__.py,sha256=
|
|
132
|
+
uncountable/types/__init__.py,sha256=Tiw8iTtZGvKJ4um9nU_UU_vt_VFkjngiLm6jru5OtXM,9217
|
|
128
133
|
uncountable/types/async_batch.py,sha256=-qOtydEQDfZLkuDvQPH6PxnE_JBFeO1Ro1eaxLyiWD4,683
|
|
129
134
|
uncountable/types/async_batch_processor.py,sha256=P8ArIgnrTdsISckBy0WLRLI3-t3TJRCgpX0KEB9VlGc,14450
|
|
130
135
|
uncountable/types/async_batch_t.py,sha256=Lb-L7zGxsk1F-MIo3eSnNQStren2ad9R1mE5gIiXyhY,3077
|
|
@@ -144,7 +149,7 @@ uncountable/types/client_config_t.py,sha256=6dStfR0IEHiPW8f9_aF3DD_tHmXXw2rEVrgp
|
|
|
144
149
|
uncountable/types/curves.py,sha256=W6uMpG5SyW1MS82szNpxkFEn1MnxNpBFyFbQb2Ysfng,366
|
|
145
150
|
uncountable/types/curves_t.py,sha256=lKhRM-2cZ_sFaW7pa_I_Ipz_pJhm3_yTFehRXI79pKk,1416
|
|
146
151
|
uncountable/types/entity.py,sha256=Y7r_xuYIsY_v1NfIil_d-1_4-lUDMmOSKnMBYCJ20jM,587
|
|
147
|
-
uncountable/types/entity_t.py,sha256=
|
|
152
|
+
uncountable/types/entity_t.py,sha256=_F6632yQf7TBUS602D82JCQ333_jUGHoe4sg3Z3FbjU,17468
|
|
148
153
|
uncountable/types/experiment_groups.py,sha256=_0OXcPzSAbkE-rfKt5tPx178YJ4pcEKZvrCxUHgDnvw,309
|
|
149
154
|
uncountable/types/experiment_groups_t.py,sha256=qEs8YW0eJOJ_sCOObT5v9QRx9wsjLYpJqJhCJXa-vNA,721
|
|
150
155
|
uncountable/types/field_values.py,sha256=x3oNoMTgT9k1knWVxAVaX4krj7V8palj90FZuFtFbRw,1202
|
|
@@ -154,9 +159,9 @@ uncountable/types/fields_t.py,sha256=LZBEfBHDn2thc1u4i8BulMEcFfDxK4JA-VzahTjivNA
|
|
|
154
159
|
uncountable/types/generic_upload.py,sha256=n6hue9BX_rLSXeEt_DcGwL2ckxfNXg1wEPR9JNEGQxQ,879
|
|
155
160
|
uncountable/types/generic_upload_t.py,sha256=wTU5NfEGHm8wQzTGww42AIYnYj4CfQtUAP_22HZqavA,3830
|
|
156
161
|
uncountable/types/id_source.py,sha256=wGLA0fMl-5IqBG_fg2UDC7fY-8CWRBNFJOokejOoN_w,567
|
|
157
|
-
uncountable/types/id_source_t.py,sha256=
|
|
162
|
+
uncountable/types/id_source_t.py,sha256=eMD9sHE8d885LL98XszNYE2ZL14WixkWo0DGlo05Izg,1881
|
|
158
163
|
uncountable/types/identifier.py,sha256=6ziONd__L07ijhVwpIehUUDvxgKTtHbunk-6CivJqxQ,503
|
|
159
|
-
uncountable/types/identifier_t.py,sha256=
|
|
164
|
+
uncountable/types/identifier_t.py,sha256=BxZcstk58LA8uSQwb3glTGLbTWEYulLDU0Op8pGUQys,1820
|
|
160
165
|
uncountable/types/input_attributes.py,sha256=IrIKQnHqHdS1Utdfzr9GnOe17a8riaqYcO1r0nvtkvA,304
|
|
161
166
|
uncountable/types/input_attributes_t.py,sha256=mD9JIagE8TQ0KVwGkl-hinKz_gcunV3y30w_dW5sfeU,884
|
|
162
167
|
uncountable/types/inputs.py,sha256=jFZHyo0ZOGJ3bb4TOPXovhE3Fo1-kf7B7T3usk4Sqg8,467
|
|
@@ -168,7 +173,7 @@ uncountable/types/job_definition_t.py,sha256=whsat5825Jou1-67dbOkqiibpoavGcsaOhJ
|
|
|
168
173
|
uncountable/types/outputs.py,sha256=sUZx_X-TKCZtLm1YCEH8OISX9DdPlv9ZuUfM3-askCc,281
|
|
169
174
|
uncountable/types/outputs_t.py,sha256=AdJZvIzqikHV9CnlC24WEo0OUe-5vrD4cjMqc2txEs0,765
|
|
170
175
|
uncountable/types/overrides.py,sha256=Mv-smwK1B3pvbt48fNOiqkeQn9wMgYlBFJKUBOJqceE,431
|
|
171
|
-
uncountable/types/overrides_t.py,sha256=
|
|
176
|
+
uncountable/types/overrides_t.py,sha256=zdnvCbTUPD4VS5VdP8GkCz1IoYHoX9EaW0lp2q8d9wM,1324
|
|
172
177
|
uncountable/types/permissions.py,sha256=1mRnSsmRgjuLgp6pylTwwACD_YRIcmlqxHkufwZtMns,297
|
|
173
178
|
uncountable/types/permissions_t.py,sha256=i0vFwVvmmnInrA5qW8uuo0_tM6KYn3VYZ75d9084Vko,1625
|
|
174
179
|
uncountable/types/phases.py,sha256=YCsU77DdjRJJWdLTwLuOZNG4e9ML82NIBI1xTWr3ggA,266
|
|
@@ -178,7 +183,7 @@ uncountable/types/post_base_t.py,sha256=2et3TDnFChZcx0RWU-18RJHw9Yiyj2TJz-2tByHX
|
|
|
178
183
|
uncountable/types/queued_job.py,sha256=67exX5vfpewKzvFKxuxTLsSJTDKlE3JqKfWnnYx2Jos,842
|
|
179
184
|
uncountable/types/queued_job_t.py,sha256=tcZsYoNgNeyrjbwXpxJSLOnhgwMFdiwJ-saPga7HSac,3575
|
|
180
185
|
uncountable/types/recipe_identifiers.py,sha256=Pi5KX64kzoBp_t_tjb3uVk9Ef1WPIIXGtUdINXi5vcY,654
|
|
181
|
-
uncountable/types/recipe_identifiers_t.py,sha256=
|
|
186
|
+
uncountable/types/recipe_identifiers_t.py,sha256=gYuaucqqPcF5Nk7RzeQunrtZ0mc9S3CrDqzIAM2B7z4,2313
|
|
182
187
|
uncountable/types/recipe_inputs.py,sha256=5ThNFEOGbADqqfj1V3hNvZUcO5pn1Gm17LmzQkWDrtI,351
|
|
183
188
|
uncountable/types/recipe_inputs_t.py,sha256=t5nFzuF1AU6SUHpya6xKHSlcckmt3XxAuk9ofjZ2oGU,746
|
|
184
189
|
uncountable/types/recipe_links.py,sha256=YRiu6t7FWr7ZWycIaOPXBtQFqbY_q5unaP6KQzh1LzE,343
|
|
@@ -210,7 +215,7 @@ uncountable/types/api/batch/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8AP
|
|
|
210
215
|
uncountable/types/api/batch/execute_batch.py,sha256=Dgy_XHo4T3sVOWvHMe6AwjgI4aTnF1KtClqF_Y2_IH0,2006
|
|
211
216
|
uncountable/types/api/batch/execute_batch_load_async.py,sha256=j5a5dk0_lTJ-YslrBN29kOAMjtbZlmwYtXU1MnxEGjU,1093
|
|
212
217
|
uncountable/types/api/chemical/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
|
|
213
|
-
uncountable/types/api/chemical/convert_chemical_formats.py,sha256=
|
|
218
|
+
uncountable/types/api/chemical/convert_chemical_formats.py,sha256=Yla9ZoAn9Q_EDG4992OVsDPA0qNapBc-HLFgEBL6KCQ,1799
|
|
214
219
|
uncountable/types/api/entity/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
|
|
215
220
|
uncountable/types/api/entity/create_entities.py,sha256=XJXLcKgpiYpNLVNtkDAAe6Q09rNJSW_h2wu3i7OmFxw,1630
|
|
216
221
|
uncountable/types/api/entity/create_entity.py,sha256=N69a-4dymv2tg_Dhj6OBdnWPodFrJtn05JvLRQwoHp8,1742
|
|
@@ -221,12 +226,14 @@ uncountable/types/api/entity/lock_entity.py,sha256=mMZx2tWOtuYg0sIftdPsFWgZO5LCa
|
|
|
221
226
|
uncountable/types/api/entity/resolve_entity_ids.py,sha256=GnQjeoTdzL0PIubrLay-PpaRsYFFWVGrTxhzSmP4hhw,1387
|
|
222
227
|
uncountable/types/api/entity/set_entity_field_values.py,sha256=FA-V9NrFeoiNnHrz3bh2qzDzldI5n5ILrKVuefVuKCo,1200
|
|
223
228
|
uncountable/types/api/entity/set_values.py,sha256=O_LpcYeBXFfxxUVOL2FDDYQwU7La-IBM_uEQLgtPrVo,1125
|
|
224
|
-
uncountable/types/api/entity/transition_entity_phase.py,sha256=
|
|
229
|
+
uncountable/types/api/entity/transition_entity_phase.py,sha256=ikcxVQwurAbS1UXL0ErNcCgKFrmqSTTrKq2coQwz1rQ,2359
|
|
225
230
|
uncountable/types/api/entity/unlock_entity.py,sha256=8UGffqqV8eiSbz_-7y0W2CXLsz4IvM496RFz6L0Y23o,1150
|
|
226
231
|
uncountable/types/api/equipment/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
|
|
227
232
|
uncountable/types/api/equipment/associate_equipment_input.py,sha256=lLge_Y20IO2Rp597R7KvqGo0MV-uTJG9OU3EJYDc3E0,1197
|
|
228
233
|
uncountable/types/api/field_options/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
|
|
229
234
|
uncountable/types/api/field_options/upsert_field_options.py,sha256=UsAlRTsDWIOwPlX3iFWIPIndGQtZW--b-A1KkACd7ek,1476
|
|
235
|
+
uncountable/types/api/files/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
|
|
236
|
+
uncountable/types/api/files/download_file.py,sha256=D5NDbPawj2ylOWyY_Y6f2GB6uhs9Wn9hetWwcfSnJxs,2244
|
|
230
237
|
uncountable/types/api/id_source/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
|
|
231
238
|
uncountable/types/api/id_source/list_id_source.py,sha256=vke7Dsxo2nJ78Y7WKph-KKZIXFW7RDoJ4iJ_yUdR81A,1447
|
|
232
239
|
uncountable/types/api/id_source/match_id_source.py,sha256=V-W-JEGVx59_Ijv5neKKFlWKy0FEEwoCD10bMiERRvc,1340
|
|
@@ -248,7 +255,7 @@ uncountable/types/api/outputs/get_output_data.py,sha256=pzwLsf1_wJsZtLH-bBbS4nNW
|
|
|
248
255
|
uncountable/types/api/outputs/get_output_names.py,sha256=zsa4TtwQcGuIzBlh1jNLQ0qSGGV1trAKhj0msl0Oaz4,1397
|
|
249
256
|
uncountable/types/api/outputs/resolve_output_conditions.py,sha256=XoaDc6p3aoFhxakHfR8hOKZ0_4o3gfYOy8prSfmcPZ8,2314
|
|
250
257
|
uncountable/types/api/permissions/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
|
|
251
|
-
uncountable/types/api/permissions/set_core_permissions.py,sha256=
|
|
258
|
+
uncountable/types/api/permissions/set_core_permissions.py,sha256=R0EIY93dqcOpHLJgGzsyRZ8Bx54q5J7-MuxFjL7OpPU,3314
|
|
252
259
|
uncountable/types/api/project/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
|
|
253
260
|
uncountable/types/api/project/get_projects.py,sha256=IT8oqQSUv0Jc4Hmz5TORlzaJUWU_IQ9sXADYNOiGRL8,1517
|
|
254
261
|
uncountable/types/api/project/get_projects_data.py,sha256=yME4KRzC5pLHW_oA07kTa42icbHpdjdkFIuQR9xU5OY,1770
|
|
@@ -281,14 +288,14 @@ uncountable/types/api/recipes/set_recipe_metadata.py,sha256=AWkC5zMSMJMV6vca4uoP
|
|
|
281
288
|
uncountable/types/api/recipes/set_recipe_output_annotations.py,sha256=l3vpsKdEqLHHympLxk0av-1-9Ag7Hng5e4smVCK6QyU,3605
|
|
282
289
|
uncountable/types/api/recipes/set_recipe_output_file.py,sha256=Wta7JnKHHNmoEKtzRn0IcfI6LU4B8ZoaxacjGUp0vJc,1543
|
|
283
290
|
uncountable/types/api/recipes/set_recipe_outputs.py,sha256=AhDsFnqRAfZkVGaC7iiuM9yledOy_TU8pexrmfht8jw,2218
|
|
284
|
-
uncountable/types/api/recipes/set_recipe_tags.py,sha256=
|
|
291
|
+
uncountable/types/api/recipes/set_recipe_tags.py,sha256=a4HdVxn_cy5KDkDSNcIiutu5n4BvIscY8fP69zx-Mbc,3146
|
|
285
292
|
uncountable/types/api/recipes/unarchive_recipes.py,sha256=zPUDmKjrUB7DJcw3XVeK4zuVqz94VbHYF9oiVb-Xu40,1021
|
|
286
293
|
uncountable/types/api/recipes/unlock_recipes.py,sha256=RaC5N5rz6f3FAIaQM3NgLuXEMdvnuCl8U_19pFI6ojs,1304
|
|
287
294
|
uncountable/types/api/triggers/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
|
|
288
295
|
uncountable/types/api/triggers/run_trigger.py,sha256=-oZgPyn43xEKSCs81DVNzwaYMCdRJxbM9GY6fsqKwf4,1090
|
|
289
296
|
uncountable/types/api/uploader/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
|
|
290
297
|
uncountable/types/api/uploader/invoke_uploader.py,sha256=6mwVG136oLp9JcbB2I-kZnrcm3aeZzYZB-SFjEImY2o,1314
|
|
291
|
-
UncountablePythonSDK-0.0.
|
|
292
|
-
UncountablePythonSDK-0.0.
|
|
293
|
-
UncountablePythonSDK-0.0.
|
|
294
|
-
UncountablePythonSDK-0.0.
|
|
298
|
+
UncountablePythonSDK-0.0.91.dist-info/METADATA,sha256=np8ufRWBp_6g7awnj5D_JgmSrovIjhnCcD03fw1gWmw,2064
|
|
299
|
+
UncountablePythonSDK-0.0.91.dist-info/WHEEL,sha256=A3WOREP4zgxI0fKrHUG8DC8013e3dK3n7a6HDbcEIwE,91
|
|
300
|
+
UncountablePythonSDK-0.0.91.dist-info/top_level.txt,sha256=1UVGjAU-6hJY9qw2iJ7nCBeEwZ793AEN5ZfKX9A1uj4,31
|
|
301
|
+
UncountablePythonSDK-0.0.91.dist-info/RECORD,,
|
docs/requirements.txt
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pprint import pprint
|
|
3
|
+
|
|
4
|
+
from uncountable.core import AuthDetailsApiKey, Client
|
|
5
|
+
from uncountable.types import download_file_t, entity_t, identifier_t
|
|
6
|
+
|
|
7
|
+
client = Client(
|
|
8
|
+
base_url="http://localhost:5000",
|
|
9
|
+
auth_details=AuthDetailsApiKey(
|
|
10
|
+
api_id=os.environ["UNC_API_ID"],
|
|
11
|
+
api_secret_key=os.environ["UNC_API_SECRET_KEY"],
|
|
12
|
+
),
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
file_query = download_file_t.FileDownloadQueryEntityField(
|
|
16
|
+
entity=entity_t.EntityIdentifier(
|
|
17
|
+
type=entity_t.EntityType.LAB_REQUEST,
|
|
18
|
+
identifier_key=identifier_t.IdentifierKeyId(id=2375),
|
|
19
|
+
),
|
|
20
|
+
field_key=identifier_t.IdentifierKeyRefName(ref_name="attachments"),
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
downloaded = client.download_files(
|
|
24
|
+
file_query=file_query,
|
|
25
|
+
)
|
|
26
|
+
pprint(downloaded)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import dataclasses
|
|
2
4
|
import math
|
|
3
5
|
import types
|
|
@@ -6,6 +8,7 @@ from collections import defaultdict
|
|
|
6
8
|
from dataclasses import MISSING, dataclass
|
|
7
9
|
from datetime import date, datetime
|
|
8
10
|
from decimal import Decimal
|
|
11
|
+
from enum import Enum, auto
|
|
9
12
|
from importlib import resources
|
|
10
13
|
|
|
11
14
|
import dateutil.parser
|
|
@@ -27,11 +30,33 @@ ParserFunction = typing.Callable[[typing.Any], T]
|
|
|
27
30
|
ParserCache = dict[type[typing.Any], ParserFunction[typing.Any]]
|
|
28
31
|
|
|
29
32
|
|
|
33
|
+
class SourceEncoding(Enum):
|
|
34
|
+
API = auto()
|
|
35
|
+
STORAGE = auto()
|
|
36
|
+
|
|
37
|
+
|
|
30
38
|
@dataclass(frozen=True, eq=True)
|
|
31
39
|
class ParserOptions:
|
|
32
|
-
|
|
40
|
+
encoding: SourceEncoding
|
|
33
41
|
strict_property_parsing: bool = False
|
|
34
42
|
|
|
43
|
+
@staticmethod
|
|
44
|
+
def Api(*, strict_property_parsing: bool = False) -> ParserOptions:
|
|
45
|
+
return ParserOptions(
|
|
46
|
+
encoding=SourceEncoding.API, strict_property_parsing=strict_property_parsing
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
@staticmethod
|
|
50
|
+
def Storage(*, strict_property_parsing: bool = False) -> ParserOptions:
|
|
51
|
+
return ParserOptions(
|
|
52
|
+
encoding=SourceEncoding.STORAGE,
|
|
53
|
+
strict_property_parsing=strict_property_parsing,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def from_camel_case(self) -> bool:
|
|
58
|
+
return self.encoding == SourceEncoding.API
|
|
59
|
+
|
|
35
60
|
|
|
36
61
|
@dataclass(frozen=True)
|
|
37
62
|
class ParserContext:
|
|
@@ -138,20 +163,10 @@ def _build_parser_discriminated_union(
|
|
|
138
163
|
def _build_parser_inner(
|
|
139
164
|
parsed_type: type[T],
|
|
140
165
|
context: ParserContext,
|
|
141
|
-
*,
|
|
142
|
-
convert_string_to_snake_case: bool = False,
|
|
143
166
|
) -> ParserFunction[T]:
|
|
144
167
|
"""
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
then the generated parser will convert camel to snake case case
|
|
148
|
-
should only be True for cases like dictionary keys
|
|
149
|
-
should only be True if options.convert_to_snake_case is True
|
|
150
|
-
|
|
151
|
-
NOTE: This argument makes caching at this level difficult, as the cache-map
|
|
152
|
-
would need to vary based on this argument. For this reason only dataclasses
|
|
153
|
-
are cached now, as they don't use the argument, and they're known to be safe.
|
|
154
|
-
This is also enough to support some recursion.
|
|
168
|
+
IMPROVE: We can now cache at this level, to avoid producing redundant
|
|
169
|
+
internal parsers.
|
|
155
170
|
"""
|
|
156
171
|
|
|
157
172
|
serial_union = get_serial_union_data(parsed_type)
|
|
@@ -184,7 +199,7 @@ def _build_parser_inner(
|
|
|
184
199
|
field_name: field_parser(
|
|
185
200
|
value.get(
|
|
186
201
|
snake_to_camel_case(field_name)
|
|
187
|
-
if context.options.
|
|
202
|
+
if context.options.from_camel_case
|
|
188
203
|
else field_name
|
|
189
204
|
)
|
|
190
205
|
)
|
|
@@ -245,23 +260,32 @@ def _build_parser_inner(
|
|
|
245
260
|
args = typing.get_args(parsed_type)
|
|
246
261
|
if len(args) != 2:
|
|
247
262
|
raise ValueError("Dict types only support two arguments for now")
|
|
248
|
-
|
|
263
|
+
k_inner_parser = _build_parser_inner(
|
|
249
264
|
args[0],
|
|
250
265
|
context,
|
|
251
|
-
convert_string_to_snake_case=context.options.convert_to_snake_case,
|
|
252
266
|
)
|
|
267
|
+
|
|
268
|
+
def key_parser(value: typing.Any) -> object:
|
|
269
|
+
inner = k_inner_parser(value)
|
|
270
|
+
if (
|
|
271
|
+
isinstance(inner, str)
|
|
272
|
+
# enum keys and OpaqueData's would also have string value types,
|
|
273
|
+
# but their explicit type is not a string, thus shouldn't be converted
|
|
274
|
+
and args[0] is str
|
|
275
|
+
and context.options.from_camel_case
|
|
276
|
+
):
|
|
277
|
+
return camel_to_snake_case(value)
|
|
278
|
+
return inner
|
|
279
|
+
|
|
253
280
|
v_parser = _build_parser_inner(args[1], context)
|
|
254
281
|
return lambda value: origin(
|
|
255
|
-
(
|
|
282
|
+
(key_parser(k), v_parser(v)) for k, v in value.items()
|
|
256
283
|
)
|
|
257
284
|
|
|
258
285
|
if origin == typing.Literal:
|
|
259
286
|
valid_values: set[T] = set(typing.get_args(parsed_type))
|
|
260
287
|
return lambda value: _invoke_membership_parser(valid_values, value)
|
|
261
288
|
|
|
262
|
-
if parsed_type is str and convert_string_to_snake_case:
|
|
263
|
-
return lambda value: camel_to_snake_case(value) # type: ignore
|
|
264
|
-
|
|
265
289
|
if parsed_type is int:
|
|
266
290
|
# first parse ints to decimal to allow scientific notation and decimals
|
|
267
291
|
# e.g. (1) 1e4 => 1000, (2) 3.0 => 3
|
|
@@ -320,6 +344,16 @@ def _build_parser_inner(
|
|
|
320
344
|
raise ValueError("Missing type cannot be parsed directly")
|
|
321
345
|
|
|
322
346
|
return error
|
|
347
|
+
|
|
348
|
+
# Check last for generic annotated types and process them unwrapped
|
|
349
|
+
# this must be last, since some of the expected types, like Unions,
|
|
350
|
+
# will also be annotated, but have a special form
|
|
351
|
+
if typing.get_origin(parsed_type) is typing.Annotated:
|
|
352
|
+
return _build_parser_inner(
|
|
353
|
+
parsed_type.__origin__, # type: ignore[attr-defined]
|
|
354
|
+
context,
|
|
355
|
+
)
|
|
356
|
+
|
|
323
357
|
raise ValueError(f"Unhandled type {parsed_type}")
|
|
324
358
|
|
|
325
359
|
|
|
@@ -351,7 +385,7 @@ def _build_parser_dataclass(
|
|
|
351
385
|
return (
|
|
352
386
|
snake_to_camel_case(field_name)
|
|
353
387
|
if (
|
|
354
|
-
context.options.
|
|
388
|
+
context.options.from_camel_case
|
|
355
389
|
and not serial_class_data.has_unconverted_key(field_name)
|
|
356
390
|
)
|
|
357
391
|
else field_name
|
|
@@ -474,8 +508,7 @@ class CachedParser(typing.Generic[T]):
|
|
|
474
508
|
if self.parser_api is None:
|
|
475
509
|
self.parser_api = build_parser(
|
|
476
510
|
self.arguments,
|
|
477
|
-
ParserOptions(
|
|
478
|
-
convert_to_snake_case=True,
|
|
511
|
+
ParserOptions.Api(
|
|
479
512
|
strict_property_parsing=self.strict_property_parsing,
|
|
480
513
|
),
|
|
481
514
|
)
|
|
@@ -489,8 +522,7 @@ class CachedParser(typing.Generic[T]):
|
|
|
489
522
|
if self.parser_storage is None:
|
|
490
523
|
self.parser_storage = build_parser(
|
|
491
524
|
self.arguments,
|
|
492
|
-
ParserOptions(
|
|
493
|
-
convert_to_snake_case=False,
|
|
525
|
+
ParserOptions.Storage(
|
|
494
526
|
strict_property_parsing=self.strict_property_parsing,
|
|
495
527
|
),
|
|
496
528
|
)
|
pkgs/serialization/__init__.py
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
from .annotation import unwrap_annotated as unwrap_annotated
|
|
2
2
|
from .missing_sentry import MISSING_SENTRY as MISSING_SENTRY
|
|
3
3
|
from .missing_sentry import MissingSentryType as MissingSentryType
|
|
4
4
|
from .missing_sentry import MissingType as MissingType
|
|
5
5
|
from .missing_sentry import coalesce_missing_sentry as coalesce_missing_sentry
|
|
6
6
|
from .opaque_key import OpaqueKey as OpaqueKey
|
|
7
|
+
from .serial_alias import SerialAliasInspector as SerialAliasInspector
|
|
8
|
+
from .serial_alias import get_serial_alias_data as get_serial_alias_data
|
|
9
|
+
from .serial_alias import serial_alias_annotation as serial_alias_annotation
|
|
10
|
+
from .serial_class import SerialClassDataInspector as SerialClassDataInspector
|
|
7
11
|
from .serial_class import get_serial_class_data as get_serial_class_data
|
|
8
12
|
from .serial_class import get_serial_string_enum_data as get_serial_string_enum_data
|
|
9
13
|
from .serial_class import serial_class as serial_class
|
|
10
14
|
from .serial_class import serial_string_enum as serial_string_enum
|
|
11
|
-
from .
|
|
12
|
-
from .serial_union import serial_union_annotation as serial_union_annotation
|
|
15
|
+
from .serial_generic import get_serial_data as get_serial_data
|
|
13
16
|
from .serial_union import get_serial_union_data as get_serial_union_data
|
|
17
|
+
from .serial_union import serial_union_annotation as serial_union_annotation
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import typing
|
|
3
|
+
|
|
4
|
+
T = typing.TypeVar("T")
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclasses.dataclass(kw_only=True, frozen=True, eq=True)
|
|
8
|
+
class SerialBase:
|
|
9
|
+
named_type_path: typing.Optional[str] = None
|
|
10
|
+
# Indicates this type is allowed in dynamic lookups, such as via a named_type_path
|
|
11
|
+
# This isn't meant to be limting, but to catalog all the types where we need it
|
|
12
|
+
is_dynamic_allowed: bool = False
|
|
13
|
+
# Tracks if this data was provided as a decorator to the type.
|
|
14
|
+
# This is used to track "proper types" which are appropriate
|
|
15
|
+
# for serialization and/or dynamic discovery
|
|
16
|
+
from_decorator: bool = False
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_serial_annotation(parsed_type: type[T]) -> SerialBase | None:
|
|
20
|
+
if not hasattr(parsed_type, "__metadata__"):
|
|
21
|
+
return None
|
|
22
|
+
metadata = parsed_type.__metadata__ # type:ignore[attr-defined]
|
|
23
|
+
if not isinstance(metadata, tuple) or len(metadata) != 1:
|
|
24
|
+
return None
|
|
25
|
+
serial = metadata[0]
|
|
26
|
+
if not isinstance(serial, SerialBase):
|
|
27
|
+
return None
|
|
28
|
+
return serial
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class SerialInspector(typing.Generic[T]):
|
|
32
|
+
def __init__(self, parsed_type: type[T], serial_base: SerialBase) -> None:
|
|
33
|
+
self._parsed_type = parsed_type
|
|
34
|
+
self._serial_base = serial_base
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def named_type_path(self) -> typing.Optional[str]:
|
|
38
|
+
return self._serial_base.named_type_path
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def from_decorator(self) -> bool:
|
|
42
|
+
return self._serial_base.from_decorator
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def is_field_proper(self) -> bool:
|
|
46
|
+
return (
|
|
47
|
+
self._serial_base.from_decorator
|
|
48
|
+
and self._serial_base.named_type_path is not None
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def is_dynamic_allowed(self) -> bool:
|
|
53
|
+
return self._serial_base.is_dynamic_allowed
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def unwrap_annotated(parsed_type: type[T]) -> type[T]:
|
|
57
|
+
"""
|
|
58
|
+
If the type is an annotated type then return the origin of it.
|
|
59
|
+
Otherwise return the original type.
|
|
60
|
+
"""
|
|
61
|
+
if typing.get_origin(parsed_type) is typing.Annotated:
|
|
62
|
+
# It's unclear if there's anyway to type this correctly
|
|
63
|
+
return parsed_type.__origin__ # type:ignore[attr-defined, no-any-return]
|
|
64
|
+
return parsed_type
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import typing
|
|
3
|
+
|
|
4
|
+
from .annotation import SerialBase, SerialInspector, get_serial_annotation
|
|
5
|
+
|
|
6
|
+
T = typing.TypeVar("T")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclasses.dataclass(kw_only=True, frozen=True, eq=True)
|
|
10
|
+
class _SerialAlias(SerialBase):
|
|
11
|
+
"""
|
|
12
|
+
This class is to be kept private, to provide flexibility in registration/lookup.
|
|
13
|
+
Places that need the data should access it via help classes/methods.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def serial_alias_annotation(
|
|
18
|
+
*,
|
|
19
|
+
named_type_path: typing.Optional[str] = None,
|
|
20
|
+
is_dynamic_allowed: bool = False,
|
|
21
|
+
) -> _SerialAlias:
|
|
22
|
+
return _SerialAlias(
|
|
23
|
+
named_type_path=named_type_path,
|
|
24
|
+
from_decorator=True,
|
|
25
|
+
is_dynamic_allowed=is_dynamic_allowed,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _get_serial_alias(parsed_type: type[T]) -> _SerialAlias | None:
|
|
30
|
+
serial = get_serial_annotation(parsed_type)
|
|
31
|
+
if not isinstance(serial, _SerialAlias):
|
|
32
|
+
return None
|
|
33
|
+
return serial
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class SerialAliasInspector(SerialInspector[T]):
|
|
37
|
+
def __init__(self, parsed_type: type[T], serial_alias: _SerialAlias) -> None:
|
|
38
|
+
super().__init__(parsed_type, serial_alias)
|
|
39
|
+
self._serial_alias = serial_alias
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def get_serial_alias_data(parsed_type: type[T]) -> SerialAliasInspector[T] | None:
|
|
43
|
+
serial = _get_serial_alias(parsed_type)
|
|
44
|
+
if serial is None:
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
return SerialAliasInspector(parsed_type, serial)
|