UncountablePythonSDK 0.0.30__py3-none-any.whl → 0.0.31__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.30
3
+ Version: 0.0.31
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
@@ -28,7 +28,7 @@ Provides-Extra: test
28
28
  Requires-Dist: mypy ==1.* ; extra == 'test'
29
29
  Requires-Dist: ruff ==0.* ; extra == 'test'
30
30
  Requires-Dist: pytest ==8.* ; extra == 'test'
31
- Requires-Dist: coverage[toml] ==6.* ; extra == 'test'
31
+ Requires-Dist: coverage[toml] ==7.* ; extra == 'test'
32
32
  Requires-Dist: pytest-cov ==5.* ; extra == 'test'
33
33
  Requires-Dist: pytest-xdist ==3.* ; extra == 'test'
34
34
 
@@ -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=jNFoVqyOwGZ4GToYiyoVeFFIzJTmXMLYbv5h2FU5Sr4,139
6
+ docs/requirements.txt,sha256=NnB0-jOOufUvD3q1csl7WvQ8oHOD-5emqp_SWUXExI0,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
@@ -22,11 +22,11 @@ pkgs/argument_parser/__init__.py,sha256=CsQ6QoPKSLLRVl-z6URAmPkiUL9ZPZoV4rJHgy_-
22
22
  pkgs/argument_parser/_is_enum.py,sha256=Gw6jJa8nBwYGqXwwCZbSnWL8Rvr5alkg5lSVAqXtOZM,257
23
23
  pkgs/argument_parser/_is_namedtuple.py,sha256=Rjc1bKanIPPogl3qG5JPBxglG1TqWYOo1nxxhBASQWY,265
24
24
  pkgs/argument_parser/argument_parser.py,sha256=eqw4ge9Sh9z35Vztq_dUQUvVMluo7YgnmMjHNMhrhVw,15937
25
- pkgs/argument_parser/case_convert.py,sha256=J9wahIE-P95LvTqn4M4gDUx_RXeiW2SRo9i_1bz1E6A,558
25
+ pkgs/argument_parser/case_convert.py,sha256=NuJLJUJRbyVb6_Slen4uqaStEHbcOS1d-hBBfDrrw-c,605
26
26
  pkgs/serialization/__init__.py,sha256=quvXMSl1szddLTr4Yxo9KA9oBMoeX7qGpFkkAplFBbY,603
27
27
  pkgs/serialization/missing_sentry.py,sha256=aM_9KxbCk9dVvXvcOKgkIQBqFWvLhv8QlIUCiuFEXMo,806
28
28
  pkgs/serialization/opaque_key.py,sha256=FIfXEE0DA1U8R_taFbQ1RCoTSgehrPjP06-qvo-GeNQ,177
29
- pkgs/serialization/serial_class.py,sha256=19UIvz2XPT4k1uXtScyjVfdhfvpehZOcjV6Z27p_VFQ,5193
29
+ pkgs/serialization/serial_class.py,sha256=r0hrQdIbJA_X0W0_jKEVrxi_JzVRT9qHCjsUgGu3cCI,5290
30
30
  pkgs/serialization_util/__init__.py,sha256=4vX5j1pvd1NkznSVqwWqunVyOvQtLCgVuwRjVwDk7qg,447
31
31
  pkgs/serialization_util/_get_type_for_serialization.py,sha256=dW5_W9MFd6wgWfW5qlWork-GBb-QFLtiOZkjk2Zqn2M,1177
32
32
  pkgs/serialization_util/serialization_helpers.py,sha256=koyGyvdlEmGFK1BUiHtM2gTzAyHygbe1JpKLdZ-Aw84,5124
@@ -52,7 +52,7 @@ pkgs/type_spec/actions_registry/emit_typescript.py,sha256=ben0W7qwaVCzLO-t3NEJPP
52
52
  pkgs/type_spec/parts/base.py.prepart,sha256=wGNoDyQnLolHRZGRwHQX5TrPfKnu558NXCocYvqyroc,2174
53
53
  pkgs/type_spec/parts/base.ts.prepart,sha256=2FJJvpg2olCcavxj0nbYWdwKl6KeScour2JjSvN42l8,1001
54
54
  pkgs/type_spec/type_info/__main__.py,sha256=pmVjVqXyVh8vKTNCTFgz80Sg74C5BKToP3E6GS-X_So,857
55
- pkgs/type_spec/type_info/emit_type_info.py,sha256=nk1pKa0drccGvzPKSpub3GVctsbu70reh3_yhhJzKAo,12052
55
+ pkgs/type_spec/type_info/emit_type_info.py,sha256=S3K5_VHbhwR0A7ZiJ5Qed2zjkici-J2ZdVKPDpc2OrI,12362
56
56
  pkgs/type_spec/value_spec/__init__.py,sha256=Z-grlcZtxAfEXhPHsK0nD7PFLGsv4eqvunaPN7_TA84,83
57
57
  pkgs/type_spec/value_spec/__main__.py,sha256=-9L5pXYx02plnTetqNknaUZPieLRtzbyWdZDT6B-cWA,8294
58
58
  pkgs/type_spec/value_spec/convert_type.py,sha256=SAYyEV6orQJJbkXSE4hhtOQJ2vKUXJCKPeYPrB8G9oA,2272
@@ -76,13 +76,13 @@ uncountable/integration/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
76
76
  uncountable/integration/db/connect.py,sha256=YtQHJ1DBGPhxKFRCfiXqohOYUceKSxMVOJ88aPI48Ug,181
77
77
  uncountable/integration/executors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
78
  uncountable/integration/executors/script_executor.py,sha256=hM8E-aU8zyM6ZcBtqAqInKZ_BF93RLqEA0dU7y5FhWQ,841
79
- uncountable/types/__init__.py,sha256=ziCs6fh_WzMhHPGwFi7xCdFQoNT6PBzZyfrMANEm8g0,6816
79
+ uncountable/types/__init__.py,sha256=0UllKeQhqDy1AD5UH6tMPx0QqIuW7KFlVe1SnJkD3ro,7197
80
80
  uncountable/types/async_batch.py,sha256=aWiul1fK3-cXaCESUUJ_92FF-NuuwxSjn9n3jC9vY5o,1618
81
81
  uncountable/types/async_batch_processor.py,sha256=eNXKPOh-sCiarPvreLDEu4XbieWLe_5KXmiY984eZ5I,6083
82
82
  uncountable/types/base.py,sha256=w3BRf8SAvYPlKrcJtJcQ_WhCU3A9zy0VuRTRWRFKVUA,2709
83
83
  uncountable/types/calculations.py,sha256=16J-KKMp-I8ZQUkYNmKCHfAn6DGb99cFinALcDIdGHY,562
84
84
  uncountable/types/chemical_structure.py,sha256=zQKl53DGtQQONIUHFXuwjWLQaG7FPZY7x6SBSOzkGV0,758
85
- uncountable/types/client_base.py,sha256=RRf9_k0U4PBYrdKGu0YEZa_cWxImwyg6fayqj6yISPY,55671
85
+ uncountable/types/client_base.py,sha256=UpIXr8JvrOuA9TNHeU1paqTNiE4KHsSpzA6RCAS7bO8,58694
86
86
  uncountable/types/curves.py,sha256=qYyRntMmFNonEwTrGhquMLbgMqjyP1moQflNTP0FMec,1308
87
87
  uncountable/types/entity.py,sha256=NjMZrqBwQ7sZe_oUuJqy9IEG7dWZmFMkQQXJ0_odcnA,11637
88
88
  uncountable/types/experiment_groups.py,sha256=ZBEk06F4n98Jz3oEA09WaDmw5rqPs7iVAm_Ysr4gc_o,599
@@ -91,7 +91,7 @@ uncountable/types/fields.py,sha256=eGtZ6axTYGFxLmPAyri2LwlcR4SZ2sX2c6QDX0ybKz0,5
91
91
  uncountable/types/id_source.py,sha256=Y3suURq3L1SahZ2oHPD986SU0l3Ik-ZzH38aQKgc1Fg,1341
92
92
  uncountable/types/identifier.py,sha256=94-O3H_qNrA48tf3srwPwdu8HURkLl7_-88kUnwElZg,1455
93
93
  uncountable/types/input_attributes.py,sha256=u-JABoZ-Ij1Ynq5g6MxOgRdQeYbM7OnGP2q_N7KuVdw,826
94
- uncountable/types/inputs.py,sha256=q7fNGaSKIk3R6uXCEhSQpiHvXu82YcK3oZHDI7bxE88,1597
94
+ uncountable/types/inputs.py,sha256=KoJGGxvwqQy8Eiw5X6PVUsEHQABYMtCj40PwtECDeIc,1617
95
95
  uncountable/types/outputs.py,sha256=hSUlu41sisYKIZpPrj1G1DRfKm6hsKNcd1eNKFYb-4w,671
96
96
  uncountable/types/permissions.py,sha256=VVLnukQ4RbApFdE0sgWDZxnrRCV6gOtXxq6yM5GxQlk,1620
97
97
  uncountable/types/phases.py,sha256=eaqwQlSRC2Ug7YFL0gqLbg3wDDHeRvBOhcABG7khW8c,550
@@ -103,6 +103,7 @@ uncountable/types/recipe_metadata.py,sha256=cebGg_lJzqZzGnKnDgmuQFrw4Xhoz6HEiGM6
103
103
  uncountable/types/recipe_output_metadata.py,sha256=XJA8R1r4NTzyR_DhMkmH4ZtYD-vqpvBMji9Be8OcFmo,613
104
104
  uncountable/types/recipe_tags.py,sha256=lYpksHAxXCcIjZKR7JoZOTH2cBSovwxZaHwjZy_yqiQ,581
105
105
  uncountable/types/recipe_workflow_steps.py,sha256=LmyFwWWwJv30vuaQ4qtd0hzDdeJaIxHQZqwRb1Wi_6A,2626
106
+ uncountable/types/recipes.py,sha256=tY8MNmQiky94eIFOxSLyflXVno3pfDygxJ6WPqJlyDU,549
106
107
  uncountable/types/response.py,sha256=ZI0CG7ZxBM2k5_W-6mNMU3UlB0p1i-0nrwOvsMaS-vU,620
107
108
  uncountable/types/units.py,sha256=_kZ7KkXIbRiY2fOdkTsbJBpWRah5TCC2WWiG05e-1DA,565
108
109
  uncountable/types/users.py,sha256=SUjNHBDcImKnnE7IN096Wfr1fmjNjCkQ7yQgKUPffz8,588
@@ -117,7 +118,7 @@ uncountable/types/api/entity/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8A
117
118
  uncountable/types/api/entity/create_entities.py,sha256=vzo5hS1qcmjQdfyCMarSu8MRcRGSiholOVSCfjXlA1k,1703
118
119
  uncountable/types/api/entity/create_entity.py,sha256=ausozCQ3qPM9YUQ87bOTCKOm-zkhn4CSLJr9jLc9n2U,1873
119
120
  uncountable/types/api/entity/get_entities_data.py,sha256=XjrJGZucIn1TYUlDLRnRA0JTQw-vXHIAT-m0H9hk37A,1170
120
- uncountable/types/api/entity/list_entities.py,sha256=_bIIZJj3N0E6YiHgqzfCOKxD1fQW6biWJQMp5wIVbBw,1514
121
+ uncountable/types/api/entity/list_entities.py,sha256=Bd_Ppy2bzWve8RbplyMkEHkg07CxEIskeiTdb9Ntlfo,1673
121
122
  uncountable/types/api/entity/lock_entity.py,sha256=SbRaKDbJfoPD9uVYiGlnrsPF_HZ_6m0hPAlalZwGyag,1029
122
123
  uncountable/types/api/entity/resolve_entity_ids.py,sha256=AidGpPmI9ATDv0E7vd9LDOl3n3beGxUlRojh5uZrkl4,1086
123
124
  uncountable/types/api/entity/set_values.py,sha256=LcYrKQm5ItYLK1Vx7rRq5i6jkMLDhfEBhF0FD1GowQs,958
@@ -138,6 +139,7 @@ uncountable/types/api/inputs/get_inputs_data.py,sha256=sqZ6xEjzQqRQYMaKXLGWR8WPh
138
139
  uncountable/types/api/inputs/set_input_attribute_values.py,sha256=yvWgIVzl818ewhUA4v3ldSBfmZKngdWTtFn7fqk-dOE,1341
139
140
  uncountable/types/api/inputs/set_input_category.py,sha256=ymjMoIiWTtygwI67aVgcw6FyjWW31zBxZb78-YTNs1Y,967
140
141
  uncountable/types/api/inputs/set_input_subcategories.py,sha256=hRS1FcFWPaenO_08Ihtfy_v7MUbpiFefdK2AMv16HaI,1004
142
+ uncountable/types/api/inputs/set_intermediate_type.py,sha256=tbN3vJ0559eMKZh0kXio1nI1zxWKhZy4bZRI2LOVlGc,1109
141
143
  uncountable/types/api/material_families/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
142
144
  uncountable/types/api/material_families/update_entity_material_families.py,sha256=h-vkua57yCNSO6P1akIxmmaFdwzOXPxm2s3Xt6x1c7c,1396
143
145
  uncountable/types/api/outputs/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
@@ -154,27 +156,29 @@ uncountable/types/api/recipe_links/create_recipe_link.py,sha256=1Ok6XMGFKBIPV-uR
154
156
  uncountable/types/api/recipe_metadata/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
155
157
  uncountable/types/api/recipe_metadata/get_recipe_metadata_data.py,sha256=el6Pn5XqExX66ZEEHM8CHPxnyXSMZPdfdvLBz86sAVY,1267
156
158
  uncountable/types/api/recipes/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
159
+ uncountable/types/api/recipes/add_recipe_to_project.py,sha256=YSVxZ_tDBsyNlxCiqHF2E8pQXRjfq46X6QwoZmkbWWk,867
157
160
  uncountable/types/api/recipes/archive_recipes.py,sha256=XFCqBa90bG4Tpxu6fhUqzl7PWlY35bbzOmJf5EOviRM,852
158
- uncountable/types/api/recipes/associate_recipe_as_input.py,sha256=88a2lirEgrodyyE6og0oYtkGAWih2uJCZRmy45kTBow,976
161
+ uncountable/types/api/recipes/associate_recipe_as_input.py,sha256=Kd0ySjIL4TZKR0QVVjlIUwUSjefZ6VmVw82HV-Yofbg,1027
159
162
  uncountable/types/api/recipes/associate_recipe_as_lot.py,sha256=bTYjbnY3B7GKz4MV4UGn7vPjaqMkAfUTio8872d4iws,955
160
163
  uncountable/types/api/recipes/create_recipe.py,sha256=jizKdsc761zrJXOi0xlmge7-Z9QlzRQdbLNtUoVLQCI,1420
161
164
  uncountable/types/api/recipes/create_recipes.py,sha256=qwIYa8hfcjY7_VOFt9lxmVtJ-HOJqQN3GDNSbZsRCZU,1544
162
165
  uncountable/types/api/recipes/disassociate_recipe_as_input.py,sha256=L25fpiK1Y5PByPVVgsZy9t4podz3xSSLIwKHj8CUrSg,913
163
- uncountable/types/api/recipes/edit_recipe_inputs.py,sha256=pTw606AgLhb-oJjfj1WPyEcJ4B0tgZsvEKeqP5VZ1gY,3281
166
+ uncountable/types/api/recipes/edit_recipe_inputs.py,sha256=I0o-LKBjjNryQqwKM4g6jdy6YtX7P2Ga2lKzXU_RuRk,4153
164
167
  uncountable/types/api/recipes/get_curve.py,sha256=UIWfpqtU5sQokaxwYfQFNFl6HMyzWEF_Sjd8UMz0U88,939
165
168
  uncountable/types/api/recipes/get_recipe_calculations.py,sha256=eQmkdZzCEuq8S2f_kf_7GPvDLX1pTnY1CRmkK0SkMCI,1472
166
169
  uncountable/types/api/recipes/get_recipe_links.py,sha256=hk5dfQjv7yU2r-S9b8vwWEJLPHqU0-M6SFiTLMR3fVk,985
167
170
  uncountable/types/api/recipes/get_recipe_names.py,sha256=uCpXZq5oWjr9a_Vf-yYPaVS72XOlLHgAlju6KHeQ3UA,986
168
171
  uncountable/types/api/recipes/get_recipe_output_metadata.py,sha256=L9s2ykPP4pd02Pc98LDisY8bgV8CToS6t6fXKTWqGRw,1464
169
172
  uncountable/types/api/recipes/get_recipes_data.py,sha256=TbJo4pkp5ePgbeH1oldThpq9jWLDYRUbrYMAv8T_LsI,5518
173
+ uncountable/types/api/recipes/remove_recipe_from_project.py,sha256=cr-VnqgBNek_WInmJln0UBn1GHMNQtRw3gsFTY_G91M,872
170
174
  uncountable/types/api/recipes/set_recipe_inputs.py,sha256=lFVfv-o_O5wHuMZdH63qlG4exFTlJM078oSAtb3XNxA,1426
171
175
  uncountable/types/api/recipes/set_recipe_metadata.py,sha256=Ba6ttd1JuS_Ypt-KpckSviWtOcQ-OTdTEJiaSYyoQL8,933
172
- uncountable/types/api/recipes/set_recipe_outputs.py,sha256=QYq39TNchQ80ET1C77OE9fwhbu_HmIoEDmrQJHkkCu0,1609
176
+ uncountable/types/api/recipes/set_recipe_outputs.py,sha256=VfUL59O21qPrgD7qQ9t5OVSGcGZ2r17lW_yEzuUkrtw,1722
173
177
  uncountable/types/api/recipes/set_recipe_tags.py,sha256=U710hgq9-t6QZGRB-ZGHskpt4iXwYEjIRb67eh3P518,2453
174
178
  uncountable/types/api/recipes/unarchive_recipes.py,sha256=WcwFYbBsX2SKXnoBQ8locnRn7Bj1rHdtrURQVOfqgfU,814
175
179
  uncountable/types/api/triggers/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
176
180
  uncountable/types/api/triggers/run_trigger.py,sha256=9m9M8-nlGB_sAU2Qm2lWugp4h4Osqj6QpjNfU8osd1U,901
177
- UncountablePythonSDK-0.0.30.dist-info/METADATA,sha256=f5hNs4fbAOqCQoHlWD1eEa5QJRz0EUazKU_TCppv--g,1577
178
- UncountablePythonSDK-0.0.30.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
179
- UncountablePythonSDK-0.0.30.dist-info/top_level.txt,sha256=1UVGjAU-6hJY9qw2iJ7nCBeEwZ793AEN5ZfKX9A1uj4,31
180
- UncountablePythonSDK-0.0.30.dist-info/RECORD,,
181
+ UncountablePythonSDK-0.0.31.dist-info/METADATA,sha256=jaFYbK371JiK653-RWGnpqIWCo1Ql0gQRJ4B9_0L4EQ,1577
182
+ UncountablePythonSDK-0.0.31.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
183
+ UncountablePythonSDK-0.0.31.dist-info/top_level.txt,sha256=1UVGjAU-6hJY9qw2iJ7nCBeEwZ793AEN5ZfKX9A1uj4,31
184
+ UncountablePythonSDK-0.0.31.dist-info/RECORD,,
docs/requirements.txt CHANGED
@@ -1,7 +1,7 @@
1
- furo==2024.1.29
2
- myst-parser==2.0.0
3
- sphinx-autoapi==3.0.0
1
+ furo==2024.5.6
2
+ myst-parser==3.0.1
3
+ sphinx-autoapi==3.1.0
4
4
  sphinx-copybutton==0.5.2
5
- Sphinx==7.2.6
6
- sphinx_design==0.5.0
5
+ Sphinx==7.3.7
6
+ sphinx_design==0.6.0
7
7
  sphinx-favicon==1.0.1
@@ -4,9 +4,10 @@ import re
4
4
 
5
5
  @functools.lru_cache(maxsize=500000)
6
6
  def snake_to_camel_case(o: str) -> str:
7
- return "".join([
8
- part.title() if i > 0 else part for i, part in enumerate(o.split("_"))
9
- ])
7
+ tokens = o.split("_")
8
+ if len(tokens) < 2:
9
+ return o
10
+ return "".join([part.title() if i > 0 else part for i, part in enumerate(tokens)])
10
11
 
11
12
 
12
13
  def kebab_to_pascal_case(o: str) -> str:
@@ -16,6 +16,9 @@ class _SerialClassData:
16
16
  parse_require: set[str] = dataclasses.field(default_factory=set)
17
17
 
18
18
 
19
+ EMPTY_SERIAL_CLASS_DATA = _SerialClassData()
20
+
21
+
19
22
  def serial_class(
20
23
  *,
21
24
  unconverted_keys: Optional[set[str]] = None,
@@ -57,58 +60,49 @@ def serial_class(
57
60
 
58
61
 
59
62
  class SerialClassDataInspector:
60
- bases: list[SerialClassDataInspector]
61
-
62
63
  def __init__(
63
- self, bases: list[SerialClassDataInspector], current: _SerialClassData
64
+ self,
65
+ current: _SerialClassData,
64
66
  ) -> None:
65
- self.bases = bases
66
67
  self.current = current
67
68
 
68
69
  def has_unconverted_key(self, key: str) -> bool:
69
- if key in self.current.unconverted_keys:
70
- return True
71
- for base in self.bases:
72
- if base.has_unconverted_key(key):
73
- return True
74
- return False
70
+ return key in self.current.unconverted_keys
75
71
 
76
72
  def has_unconverted_value(self, key: str) -> bool:
77
- if key in self.current.unconverted_values:
78
- return True
79
- for base in self.bases:
80
- if base.has_unconverted_value(key):
81
- return True
82
- return False
73
+ return key in self.current.unconverted_values
83
74
 
84
75
  def has_to_string_value(self, key: str) -> bool:
85
- if key in self.current.to_string_values:
86
- return True
87
- for base in self.bases:
88
- if base.has_to_string_value(key):
89
- return True
90
- return False
76
+ return key in self.current.to_string_values
91
77
 
92
78
  def has_parse_require(self, key: str) -> bool:
93
- if key in self.current.parse_require:
94
- return True
95
- for base in self.bases:
96
- if base.has_parse_require(key):
97
- return True
98
- return False
79
+ return key in self.current.parse_require
99
80
 
100
81
 
101
- def get_serial_class_data(type_class: type[Any]) -> SerialClassDataInspector:
102
- bases = (
103
- [get_serial_class_data(base) for base in type_class.__bases__]
104
- if type_class.__bases__ is not None
105
- else []
106
- )
107
- return SerialClassDataInspector(
108
- bases,
82
+ def _get_merged_serial_class_data(type_class: type[Any]) -> _SerialClassData | None:
83
+ base_class_data = (
109
84
  cast(_SerialClassData, type_class.__unc_serial_data)
110
85
  if hasattr(type_class, "__unc_serial_data")
111
- else _SerialClassData(),
86
+ else None
87
+ )
88
+ if type_class.__bases__ is not None:
89
+ for base in type_class.__bases__:
90
+ curr_base_class_data = _get_merged_serial_class_data(base)
91
+ if curr_base_class_data is not None:
92
+ if base_class_data is None:
93
+ base_class_data = _SerialClassData()
94
+ base_class_data.unconverted_keys |= curr_base_class_data.unconverted_keys
95
+ base_class_data.unconverted_values |= (
96
+ curr_base_class_data.unconverted_values
97
+ )
98
+ base_class_data.to_string_values |= curr_base_class_data.to_string_values
99
+ base_class_data.parse_require |= curr_base_class_data.parse_require
100
+ return base_class_data
101
+
102
+
103
+ def get_serial_class_data(type_class: type[Any]) -> SerialClassDataInspector:
104
+ return SerialClassDataInspector(
105
+ _get_merged_serial_class_data(type_class) or EMPTY_SERIAL_CLASS_DATA
112
106
  )
113
107
 
114
108
 
@@ -247,17 +247,25 @@ def _extract_and_validate_layout(
247
247
  return layout
248
248
 
249
249
 
250
- def _validate_type_ext_info(stype: builder.SpecTypeDefnObject) -> ExtInfoLayout | None:
250
+ def _validate_type_ext_info(
251
+ stype: builder.SpecTypeDefnObject,
252
+ ) -> tuple[ExtInfoLayout | None, Optional[data_t.ExtInfo]]:
251
253
  ext_info = _parse_ext_info(stype.ext_info)
252
254
  if ext_info is None:
253
- return None
255
+ return None, None
256
+
257
+ if ext_info.label_fields is not None:
258
+ assert stype.properties is not None
259
+ for name in ext_info.label_fields:
260
+ prop = stype.properties.get(name)
261
+ assert prop is not None, f"missing-label-field:{name}"
254
262
 
255
263
  if not stype.is_base and isinstance(stype.base, builder.SpecTypeDefnObject):
256
- base_layout = _validate_type_ext_info(stype.base)
264
+ base_layout, _ = _validate_type_ext_info(stype.base)
257
265
  else:
258
266
  base_layout = None
259
267
 
260
- return _extract_and_validate_layout(stype, ext_info, base_layout)
268
+ return _extract_and_validate_layout(stype, ext_info, base_layout), ext_info
261
269
 
262
270
 
263
271
  def _build_map_type(
@@ -270,7 +278,7 @@ def _build_map_type(
270
278
  and not stype.is_base
271
279
  and stype.base is not None
272
280
  ):
273
- _validate_type_ext_info(stype)
281
+ _, ext_info = _validate_type_ext_info(stype)
274
282
 
275
283
  properties: dict[str, MapProperty] = {}
276
284
  map_type = MapTypeObject(
@@ -279,7 +287,7 @@ def _build_map_type(
279
287
  properties=properties,
280
288
  desc=stype.desc,
281
289
  base_type_path=type_path_of(stype.base),
282
- ext_info=_convert_ext_info(stype.ext_info),
290
+ ext_info=serialize_for_api(ext_info),
283
291
  )
284
292
 
285
293
  if stype.properties is not None:
@@ -3,6 +3,7 @@
3
3
  # ruff: noqa: E402
4
4
  # fmt: off
5
5
  # isort: skip_file
6
+ from .api.recipes import add_recipe_to_project as add_recipe_to_project_t
6
7
  from .api.recipes import archive_recipes as archive_recipes_t
7
8
  from .api.recipes import associate_recipe_as_input as associate_recipe_as_input_t
8
9
  from .api.recipes import associate_recipe_as_lot as associate_recipe_as_lot_t
@@ -61,6 +62,8 @@ from . import recipe_metadata as recipe_metadata_t
61
62
  from . import recipe_output_metadata as recipe_output_metadata_t
62
63
  from . import recipe_tags as recipe_tags_t
63
64
  from . import recipe_workflow_steps as recipe_workflow_steps_t
65
+ from . import recipes as recipes_t
66
+ from .api.recipes import remove_recipe_from_project as remove_recipe_from_project_t
64
67
  from .api.entity import resolve_entity_ids as resolve_entity_ids_t
65
68
  from .api.outputs import resolve_output_conditions as resolve_output_conditions_t
66
69
  from . import response as response_t
@@ -69,6 +72,7 @@ from .api.permissions import set_core_permissions as set_core_permissions_t
69
72
  from .api.inputs import set_input_attribute_values as set_input_attribute_values_t
70
73
  from .api.inputs import set_input_category as set_input_category_t
71
74
  from .api.inputs import set_input_subcategories as set_input_subcategories_t
75
+ from .api.inputs import set_intermediate_type as set_intermediate_type_t
72
76
  from .api.recipes import set_recipe_inputs as set_recipe_inputs_t
73
77
  from .api.recipes import set_recipe_metadata as set_recipe_metadata_t
74
78
  from .api.recipes import set_recipe_outputs as set_recipe_outputs_t
@@ -85,6 +89,7 @@ from . import workflows as workflows_t
85
89
 
86
90
 
87
91
  __all__: list[str] = [
92
+ "add_recipe_to_project_t",
88
93
  "archive_recipes_t",
89
94
  "associate_recipe_as_input_t",
90
95
  "associate_recipe_as_lot_t",
@@ -143,6 +148,8 @@ __all__: list[str] = [
143
148
  "recipe_output_metadata_t",
144
149
  "recipe_tags_t",
145
150
  "recipe_workflow_steps_t",
151
+ "recipes_t",
152
+ "remove_recipe_from_project_t",
146
153
  "resolve_entity_ids_t",
147
154
  "resolve_output_conditions_t",
148
155
  "response_t",
@@ -151,6 +158,7 @@ __all__: list[str] = [
151
158
  "set_input_attribute_values_t",
152
159
  "set_input_category_t",
153
160
  "set_input_subcategories_t",
161
+ "set_intermediate_type_t",
154
162
  "set_recipe_inputs_t",
155
163
  "set_recipe_metadata_t",
156
164
  "set_recipe_outputs_t",
@@ -8,6 +8,7 @@ import typing # noqa: F401
8
8
  import datetime # noqa: F401
9
9
  from decimal import Decimal # noqa: F401
10
10
  from dataclasses import dataclass
11
+ from pkgs.serialization import serial_class
11
12
  from pkgs.serialization import OpaqueKey
12
13
  from ... import base as base_t
13
14
  from ... import entity as entity_t
@@ -26,6 +27,9 @@ ENDPOINT_PATH = "api/external/entity/external_list_entities"
26
27
 
27
28
 
28
29
  # DO NOT MODIFY -- This file is generated by type_spec
30
+ @serial_class(
31
+ unconverted_values={"attributes"},
32
+ )
29
33
  @dataclass(kw_only=True)
30
34
  class Arguments:
31
35
  entity_type: entity_t.EntityType
@@ -36,6 +40,9 @@ class Arguments:
36
40
 
37
41
 
38
42
  # DO NOT MODIFY -- This file is generated by type_spec
43
+ @serial_class(
44
+ unconverted_values={"column_values"},
45
+ )
39
46
  @dataclass(kw_only=True)
40
47
  class EntityResult:
41
48
  entity: entity_t.Entity
@@ -0,0 +1,43 @@
1
+ # DO NOT MODIFY -- This file is generated by type_spec
2
+ # flake8: noqa: F821
3
+ # ruff: noqa: E402
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
+ from pkgs.strenum_compat import StrEnum
11
+ from dataclasses import dataclass
12
+ from ... import identifier as identifier_t
13
+
14
+ __all__: list[str] = [
15
+ "Arguments",
16
+ "Data",
17
+ "ENDPOINT_METHOD",
18
+ "ENDPOINT_PATH",
19
+ "IntermediateType",
20
+ ]
21
+
22
+ ENDPOINT_METHOD = "POST"
23
+ ENDPOINT_PATH = "api/external/inputs/set_intermediate_type"
24
+
25
+
26
+ # DO NOT MODIFY -- This file is generated by type_spec
27
+ class IntermediateType(StrEnum):
28
+ FINAL_PRODUCT = "final_product"
29
+ COMPOUND_AS_INTERMEDIATE = "compound_as_intermediate"
30
+
31
+
32
+ # DO NOT MODIFY -- This file is generated by type_spec
33
+ @dataclass(kw_only=True)
34
+ class Arguments:
35
+ input_key: identifier_t.IdentifierKey
36
+ intermediate_type: IntermediateType
37
+
38
+
39
+ # DO NOT MODIFY -- This file is generated by type_spec
40
+ @dataclass(kw_only=True)
41
+ class Data:
42
+ pass
43
+ # DO NOT MODIFY -- This file is generated by type_spec
@@ -0,0 +1,35 @@
1
+ # DO NOT MODIFY -- This file is generated by type_spec
2
+ # flake8: noqa: F821
3
+ # ruff: noqa: E402
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
+ from dataclasses import dataclass
11
+ from ... import identifier as identifier_t
12
+
13
+ __all__: list[str] = [
14
+ "Arguments",
15
+ "Data",
16
+ "ENDPOINT_METHOD",
17
+ "ENDPOINT_PATH",
18
+ ]
19
+
20
+ ENDPOINT_METHOD = "POST"
21
+ ENDPOINT_PATH = "api/external/recipes/add_recipe_to_project"
22
+
23
+
24
+ # DO NOT MODIFY -- This file is generated by type_spec
25
+ @dataclass(kw_only=True)
26
+ class Arguments:
27
+ recipe_key: identifier_t.IdentifierKey
28
+ project_key: identifier_t.IdentifierKey
29
+
30
+
31
+ # DO NOT MODIFY -- This file is generated by type_spec
32
+ @dataclass(kw_only=True)
33
+ class Data:
34
+ pass
35
+ # DO NOT MODIFY -- This file is generated by type_spec
@@ -27,6 +27,7 @@ ENDPOINT_PATH = "api/external/recipes/associate_recipe_as_input"
27
27
  class Arguments:
28
28
  recipe_key: identifier_t.IdentifierKey
29
29
  input_key: typing.Optional[identifier_t.IdentifierKey] = None
30
+ show_in_listings: typing.Optional[bool] = None
30
31
 
31
32
 
32
33
  # DO NOT MODIFY -- This file is generated by type_spec
@@ -15,6 +15,7 @@ from ... import recipe_inputs as recipe_inputs_t
15
15
  from ... import recipe_workflow_steps as recipe_workflow_steps_t
16
16
 
17
17
  __all__: list[str] = [
18
+ "AnnotationEdit",
18
19
  "Arguments",
19
20
  "Data",
20
21
  "ENDPOINT_METHOD",
@@ -25,6 +26,7 @@ __all__: list[str] = [
25
26
  "RecipeInputEditClearInputs",
26
27
  "RecipeInputEditInputBase",
27
28
  "RecipeInputEditType",
29
+ "RecipeInputEditUpdateAnnotations",
28
30
  "RecipeInputEditUpsertInput",
29
31
  ]
30
32
 
@@ -37,6 +39,7 @@ class RecipeInputEditType(StrEnum):
37
39
  CLEAR_INPUTS = "clear_inputs"
38
40
  UPSERT_INPUT = "upsert_input"
39
41
  ADD_INPUT = "add_input"
42
+ UPDATE_ANNOTATIONS = "update_annotations"
40
43
 
41
44
 
42
45
  # DO NOT MODIFY -- This file is generated by type_spec
@@ -88,7 +91,30 @@ class RecipeInputEditAddInput(RecipeInputEditInputBase):
88
91
 
89
92
 
90
93
  # DO NOT MODIFY -- This file is generated by type_spec
91
- RecipeInputEdit = typing.Union[RecipeInputEditClearInputs, RecipeInputEditUpsertInput, RecipeInputEditAddInput]
94
+ @serial_class(
95
+ to_string_values={"lower_value", "upper_value"},
96
+ )
97
+ @dataclass(kw_only=True)
98
+ class AnnotationEdit:
99
+ annotation_type_key: identifier_t.IdentifierKey
100
+ lower_value: typing.Optional[Decimal] = None
101
+ upper_value: typing.Optional[Decimal] = None
102
+
103
+
104
+ # DO NOT MODIFY -- This file is generated by type_spec
105
+ @serial_class(
106
+ parse_require={"type"},
107
+ )
108
+ @dataclass(kw_only=True)
109
+ class RecipeInputEditUpdateAnnotations(RecipeInputEditInputBase):
110
+ type: typing.Literal[RecipeInputEditType.UPDATE_ANNOTATIONS] = RecipeInputEditType.UPDATE_ANNOTATIONS
111
+ ingredient_key: identifier_t.IdentifierKey
112
+ clear_first: bool
113
+ annotations: list[AnnotationEdit]
114
+
115
+
116
+ # DO NOT MODIFY -- This file is generated by type_spec
117
+ RecipeInputEdit = typing.Union[RecipeInputEditClearInputs, RecipeInputEditUpsertInput, RecipeInputEditAddInput, RecipeInputEditUpdateAnnotations]
92
118
 
93
119
 
94
120
  # DO NOT MODIFY -- This file is generated by type_spec
@@ -0,0 +1,35 @@
1
+ # DO NOT MODIFY -- This file is generated by type_spec
2
+ # flake8: noqa: F821
3
+ # ruff: noqa: E402
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
+ from dataclasses import dataclass
11
+ from ... import identifier as identifier_t
12
+
13
+ __all__: list[str] = [
14
+ "Arguments",
15
+ "Data",
16
+ "ENDPOINT_METHOD",
17
+ "ENDPOINT_PATH",
18
+ ]
19
+
20
+ ENDPOINT_METHOD = "POST"
21
+ ENDPOINT_PATH = "api/external/recipes/remove_recipe_from_project"
22
+
23
+
24
+ # DO NOT MODIFY -- This file is generated by type_spec
25
+ @dataclass(kw_only=True)
26
+ class Arguments:
27
+ recipe_key: identifier_t.IdentifierKey
28
+ project_key: identifier_t.IdentifierKey
29
+
30
+
31
+ # DO NOT MODIFY -- This file is generated by type_spec
32
+ @dataclass(kw_only=True)
33
+ class Data:
34
+ pass
35
+ # DO NOT MODIFY -- This file is generated by type_spec
@@ -10,6 +10,7 @@ from decimal import Decimal # noqa: F401
10
10
  from dataclasses import dataclass
11
11
  from pkgs.serialization import serial_class
12
12
  from ... import base as base_t
13
+ from ... import recipes as recipes_t
13
14
  from ... import response as response_t
14
15
 
15
16
  __all__: list[str] = [
@@ -45,6 +46,7 @@ class RecipeOutputValue:
45
46
  value_numeric: typing.Optional[Decimal] = None
46
47
  value_str: typing.Optional[str] = None
47
48
  value_curve: typing.Optional[CurveValues] = None
49
+ formatting: typing.Optional[recipes_t.RecipeAttributeFormatting] = None
48
50
 
49
51
 
50
52
  # DO NOT MODIFY -- This file is generated by type_spec
@@ -9,6 +9,7 @@ import typing # noqa: F401
9
9
  import datetime # noqa: F401
10
10
  from decimal import Decimal # noqa: F401
11
11
  from pkgs.serialization import OpaqueKey
12
+ import uncountable.types.api.recipes.add_recipe_to_project as add_recipe_to_project_t
12
13
  import uncountable.types.api.recipes.archive_recipes as archive_recipes_t
13
14
  import uncountable.types.api.recipes.associate_recipe_as_input as associate_recipe_as_input_t
14
15
  import uncountable.types.api.recipes.associate_recipe_as_lot as associate_recipe_as_lot_t
@@ -55,6 +56,7 @@ from uncountable.types import recipe_identifiers as recipe_identifiers_t
55
56
  from uncountable.types import recipe_links as recipe_links_t
56
57
  from uncountable.types import recipe_metadata as recipe_metadata_t
57
58
  from uncountable.types import recipe_workflow_steps as recipe_workflow_steps_t
59
+ import uncountable.types.api.recipes.remove_recipe_from_project as remove_recipe_from_project_t
58
60
  import uncountable.types.api.entity.resolve_entity_ids as resolve_entity_ids_t
59
61
  import uncountable.types.api.outputs.resolve_output_conditions as resolve_output_conditions_t
60
62
  import uncountable.types.api.triggers.run_trigger as run_trigger_t
@@ -62,6 +64,7 @@ import uncountable.types.api.permissions.set_core_permissions as set_core_permis
62
64
  import uncountable.types.api.inputs.set_input_attribute_values as set_input_attribute_values_t
63
65
  import uncountable.types.api.inputs.set_input_category as set_input_category_t
64
66
  import uncountable.types.api.inputs.set_input_subcategories as set_input_subcategories_t
67
+ import uncountable.types.api.inputs.set_intermediate_type as set_intermediate_type_t
65
68
  import uncountable.types.api.recipes.set_recipe_inputs as set_recipe_inputs_t
66
69
  import uncountable.types.api.recipes.set_recipe_metadata as set_recipe_metadata_t
67
70
  import uncountable.types.api.recipes.set_recipe_outputs as set_recipe_outputs_t
@@ -91,6 +94,28 @@ class ClientMethods(ABC):
91
94
  def do_request(self, *, api_request: APIRequest, return_type: type[DT]) -> DT:
92
95
  ...
93
96
 
97
+ def add_recipe_to_project(
98
+ self,
99
+ *,
100
+ recipe_key: identifier_t.IdentifierKey,
101
+ project_key: identifier_t.IdentifierKey,
102
+ ) -> add_recipe_to_project_t.Data:
103
+ """Adds a recipe to a project
104
+
105
+ :param recipe_key: The identifier key of the recipe to add to the project
106
+ :param project_key: The identifier key of the project to add the recipe to
107
+ """
108
+ args = add_recipe_to_project_t.Arguments(
109
+ recipe_key=recipe_key,
110
+ project_key=project_key,
111
+ )
112
+ api_request = APIRequest(
113
+ method=add_recipe_to_project_t.ENDPOINT_METHOD,
114
+ endpoint=add_recipe_to_project_t.ENDPOINT_PATH,
115
+ args=args,
116
+ )
117
+ return self.do_request(api_request=api_request, return_type=add_recipe_to_project_t.Data)
118
+
94
119
  def archive_recipes(
95
120
  self,
96
121
  *,
@@ -118,15 +143,18 @@ class ClientMethods(ABC):
118
143
  *,
119
144
  recipe_key: identifier_t.IdentifierKey,
120
145
  input_key: typing.Optional[identifier_t.IdentifierKey] = None,
146
+ show_in_listings: typing.Optional[bool] = None,
121
147
  ) -> associate_recipe_as_input_t.Data:
122
148
  """Create or return the input association for a recipe
123
149
 
124
150
  :param recipe_key: Identifier for the recipe
125
151
  :param input_key: Identifier for an input to use for the association. Optionally supplied. If not supplied, one is created
152
+ :param show_in_listings: After associating the input should it be present in listings
126
153
  """
127
154
  args = associate_recipe_as_input_t.Arguments(
128
155
  recipe_key=recipe_key,
129
156
  input_key=input_key,
157
+ show_in_listings=show_in_listings,
130
158
  )
131
159
  api_request = APIRequest(
132
160
  method=associate_recipe_as_input_t.ENDPOINT_METHOD,
@@ -900,6 +928,28 @@ class ClientMethods(ABC):
900
928
  )
901
929
  return self.do_request(api_request=api_request, return_type=match_id_source_t.Data)
902
930
 
931
+ def remove_recipe_from_project(
932
+ self,
933
+ *,
934
+ recipe_key: identifier_t.IdentifierKey,
935
+ project_key: identifier_t.IdentifierKey,
936
+ ) -> remove_recipe_from_project_t.Data:
937
+ """Removes a recipe from a project
938
+
939
+ :param recipe_key: The identifier key of the recipe to remove from the project
940
+ :param project_key: The identifier key of the project to remove the recipe from
941
+ """
942
+ args = remove_recipe_from_project_t.Arguments(
943
+ recipe_key=recipe_key,
944
+ project_key=project_key,
945
+ )
946
+ api_request = APIRequest(
947
+ method=remove_recipe_from_project_t.ENDPOINT_METHOD,
948
+ endpoint=remove_recipe_from_project_t.ENDPOINT_PATH,
949
+ args=args,
950
+ )
951
+ return self.do_request(api_request=api_request, return_type=remove_recipe_from_project_t.Data)
952
+
903
953
  def resolve_entity_ids(
904
954
  self,
905
955
  *,
@@ -1059,6 +1109,28 @@ class ClientMethods(ABC):
1059
1109
  )
1060
1110
  return self.do_request(api_request=api_request, return_type=set_input_subcategories_t.Data)
1061
1111
 
1112
+ def set_intermediate_type(
1113
+ self,
1114
+ *,
1115
+ input_key: identifier_t.IdentifierKey,
1116
+ intermediate_type: set_intermediate_type_t.IntermediateType,
1117
+ ) -> set_intermediate_type_t.Data:
1118
+ """Sets the type of an intermediate ingredient.
1119
+
1120
+ :param input_key: The identifier key of the intermediate ingredient
1121
+ :param intermediate_type: The new type of the intermediate ingredient
1122
+ """
1123
+ args = set_intermediate_type_t.Arguments(
1124
+ input_key=input_key,
1125
+ intermediate_type=intermediate_type,
1126
+ )
1127
+ api_request = APIRequest(
1128
+ method=set_intermediate_type_t.ENDPOINT_METHOD,
1129
+ endpoint=set_intermediate_type_t.ENDPOINT_PATH,
1130
+ args=args,
1131
+ )
1132
+ return self.do_request(api_request=api_request, return_type=set_intermediate_type_t.Data)
1133
+
1062
1134
  def set_recipe_inputs(
1063
1135
  self,
1064
1136
  *,
@@ -58,4 +58,5 @@ class SimpleInput:
58
58
  name: str
59
59
  is_parameter: bool
60
60
  intermediate_recipe_id: typing.Optional[base_t.ObjectId]
61
+ input_type: str
61
62
  # DO NOT MODIFY -- This file is generated by type_spec
@@ -0,0 +1,21 @@
1
+ # DO NOT MODIFY -- This file is generated by type_spec
2
+ # flake8: noqa: F821
3
+ # ruff: noqa: E402
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
+ from dataclasses import dataclass
11
+
12
+ __all__: list[str] = [
13
+ "RecipeAttributeFormatting",
14
+ ]
15
+
16
+
17
+ # DO NOT MODIFY -- This file is generated by type_spec
18
+ @dataclass(kw_only=True)
19
+ class RecipeAttributeFormatting:
20
+ background_color: str
21
+ # DO NOT MODIFY -- This file is generated by type_spec