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.

Files changed (34) hide show
  1. {UncountablePythonSDK-0.0.90.dist-info → UncountablePythonSDK-0.0.91.dist-info}/METADATA +2 -2
  2. {UncountablePythonSDK-0.0.90.dist-info → UncountablePythonSDK-0.0.91.dist-info}/RECORD +34 -27
  3. {UncountablePythonSDK-0.0.90.dist-info → UncountablePythonSDK-0.0.91.dist-info}/WHEEL +1 -1
  4. docs/requirements.txt +1 -1
  5. examples/download_files.py +26 -0
  6. pkgs/argument_parser/argument_parser.py +57 -25
  7. pkgs/serialization/__init__.py +7 -3
  8. pkgs/serialization/annotation.py +64 -0
  9. pkgs/serialization/serial_alias.py +47 -0
  10. pkgs/serialization/serial_class.py +26 -32
  11. pkgs/serialization/serial_generic.py +16 -0
  12. pkgs/serialization/serial_union.py +9 -9
  13. pkgs/serialization_util/__init__.py +4 -0
  14. pkgs/serialization_util/dataclasses.py +14 -0
  15. pkgs/serialization_util/serialization_helpers.py +11 -3
  16. pkgs/type_spec/builder.py +41 -5
  17. pkgs/type_spec/emit_python.py +34 -6
  18. pkgs/type_spec/type_info/emit_type_info.py +7 -2
  19. uncountable/core/client.py +58 -1
  20. uncountable/core/environment.py +2 -2
  21. uncountable/integration/scheduler.py +4 -4
  22. uncountable/types/__init__.py +2 -0
  23. uncountable/types/api/chemical/convert_chemical_formats.py +7 -1
  24. uncountable/types/api/entity/transition_entity_phase.py +7 -1
  25. uncountable/types/api/files/__init__.py +1 -0
  26. uncountable/types/api/files/download_file.py +77 -0
  27. uncountable/types/api/permissions/set_core_permissions.py +7 -1
  28. uncountable/types/api/recipes/set_recipe_tags.py +7 -1
  29. uncountable/types/entity_t.py +13 -2
  30. uncountable/types/id_source_t.py +7 -1
  31. uncountable/types/identifier_t.py +7 -1
  32. uncountable/types/overrides_t.py +7 -1
  33. uncountable/types/recipe_identifiers_t.py +13 -2
  34. {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.90
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==5.*; extra == "test"
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=XNw3eJfJPf6Z2DpwtcNgEJpoEKS0g5v3vY6UBFtiEKM,138
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=XjWQdcWanfaCGdLx7c_yQtqbZp7db-KAWzw8sTpXOsY,17713
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=6zgJCsQjjWs4Vj1Z6i3rWpZrziy92xt4ayOJswxv45o,832
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/serial_class.py,sha256=fEceYVIV8dc3Ium-okYxp9cCNFg05HcliXqoCcV5Wcc,6151
47
- pkgs/serialization/serial_union.py,sha256=xpdeqCrRd0sNCaUwBQRzje6V40ndCbJpZrLX2K0d5xo,2741
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=MVKqHTUl2YnWZAFG9xCxu1SgmkQ5xPofrAGlYg6h7rI,330
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/serialization_helpers.py,sha256=B8W82-KT10nQYmDk5uhAqB5QNS-dsxzXMFhtTmooMqw,6365
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=0CF9xJaZ74LsmRh4GzgxBsUkTjAObariAB0M399r-MI,48796
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=iJgRfke0rCFKY_7nGWLCPR_SQ4gfRuudC6b7r5ftKPE,47456
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=EzX0ONjrLtQFlN5cEAaw2RPVyadmgmZazOfqHUbL_PI,13362
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=rIdwZoXKor8XCOemItSG624aHV2DHIh8trq2uCGXZ_Y,11251
86
- uncountable/core/environment.py,sha256=K2TtE52JbW5UOBkBSc2Ee2l9rDIoRNoFDXDqRha1fJI,1036
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=Q8N3QqsiS2Y48uj13Dmb027SmsMG4htrGWjiUKVFmh4,4784
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=jQpQR-ISmkhyC7XziQbuUnMBP2Qa8C5ixgczj_4WDJw,9138
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=oFgQaCIP25viCk-HN3l3ggyR6GqKGWXkWJ_1K9xvqRY,17175
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=s2oOCO2Ap7dt5BVOTiXsclD5m7SG_e0D8M2GOhCjuNg,1715
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=3YvYoYEWjxIaslyaEwnvhatbsgRC9Hm4EMsRUXzUXvc,1652
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=0K2kflxM8ogEi4HHs3RlpVXCZ30Bk3XeWiqHh3DGzbc,1146
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=9FhWx-mHWGvHBwUysxE614-AV9uOuSE1VWRNE_iW5YU,2009
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=xLpma1W1O9MzgxM4CCl5GPnpj3dpqRHhKcXr3b_ToAo,1589
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=J0lO_dubmTCO9s7P2DZgC-Zq6m0VagpXfg0jZqxz5XM,2160
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=mkaSWfrRJQIFIcOIC1yslhJd_SQykkiK26x7RwUX1L4,3117
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=HJ5SYiNaQjmmEfNggZ1kzi-zFsjn0F4XXVGHpiEnGM0,2959
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.90.dist-info/METADATA,sha256=8_VsTo7yg4CfYb7io56h0z1Tm4laQsg1uBoWUdqA_JM,2064
292
- UncountablePythonSDK-0.0.90.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
293
- UncountablePythonSDK-0.0.90.dist-info/top_level.txt,sha256=1UVGjAU-6hJY9qw2iJ7nCBeEwZ793AEN5ZfKX9A1uj4,31
294
- UncountablePythonSDK-0.0.90.dist-info/RECORD,,
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: setuptools (75.7.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
docs/requirements.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  furo==2024.8.6
2
2
  myst-parser==4.0.0
3
- sphinx-autoapi==3.3.0
3
+ sphinx-autoapi==3.4.0
4
4
  sphinx-copybutton==0.5.2
5
5
  Sphinx==8.1.3
6
6
  sphinx_design==0.6.1
@@ -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
- convert_to_snake_case: bool
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
- convert_to_snake_case - internal flag
146
- if convert_to_snake_case is True, and parsed_type is str,
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.convert_to_snake_case
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
- k_parser = _build_parser_inner(
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
- (k_parser(k), v_parser(v)) for k, v in value.items()
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.convert_to_snake_case
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
  )
@@ -1,13 +1,17 @@
1
- # flake8:noqa
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 .serial_class import SerialClassDataInspector as SerialClassDataInspector
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)