UncountablePythonSDK 0.0.29__py3-none-any.whl → 0.0.30__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 (75) hide show
  1. {UncountablePythonSDK-0.0.29.dist-info → UncountablePythonSDK-0.0.30.dist-info}/METADATA +3 -3
  2. {UncountablePythonSDK-0.0.29.dist-info → UncountablePythonSDK-0.0.30.dist-info}/RECORD +23 -75
  3. {UncountablePythonSDK-0.0.29.dist-info → UncountablePythonSDK-0.0.30.dist-info}/top_level.txt +0 -1
  4. docs/conf.py +9 -4
  5. examples/async_batch.py +2 -3
  6. examples/create_entity.py +4 -7
  7. examples/upload_files.py +1 -1
  8. pkgs/type_spec/emit_python.py +0 -1
  9. uncountable/__init__.py +1 -2
  10. uncountable/core/__init__.py +10 -3
  11. uncountable/core/async_batch.py +1 -1
  12. uncountable/core/client.py +27 -17
  13. uncountable/core/file_upload.py +3 -5
  14. uncountable/core/types.py +1 -1
  15. uncountable/integration/construct_client.py +1 -1
  16. uncountable/integration/cron.py +4 -2
  17. uncountable/integration/db/connect.py +1 -1
  18. uncountable/integration/entrypoint.py +4 -5
  19. uncountable/integration/executors/script_executor.py +11 -5
  20. uncountable/integration/job.py +5 -8
  21. uncountable/integration/server.py +5 -5
  22. uncountable/types/async_batch_processor.py +0 -1
  23. examples/recipe-import/importer.py +0 -39
  24. type_spec/external/api/batch/execute_batch.yaml +0 -56
  25. type_spec/external/api/batch/execute_batch_load_async.yaml +0 -18
  26. type_spec/external/api/chemical/convert_chemical_formats.yaml +0 -33
  27. type_spec/external/api/entity/create_entities.yaml +0 -45
  28. type_spec/external/api/entity/create_entity.yaml +0 -51
  29. type_spec/external/api/entity/get_entities_data.yaml +0 -29
  30. type_spec/external/api/entity/list_entities.yaml +0 -52
  31. type_spec/external/api/entity/lock_entity.yaml +0 -21
  32. type_spec/external/api/entity/resolve_entity_ids.yaml +0 -29
  33. type_spec/external/api/entity/set_values.yaml +0 -18
  34. type_spec/external/api/entity/transition_entity_phase.yaml +0 -44
  35. type_spec/external/api/entity/unlock_entity.yaml +0 -18
  36. type_spec/external/api/field_options/upsert_field_options.yaml +0 -37
  37. type_spec/external/api/id_source/list_id_source.yaml +0 -35
  38. type_spec/external/api/id_source/match_id_source.yaml +0 -32
  39. type_spec/external/api/input_groups/get_input_group_names.yaml +0 -29
  40. type_spec/external/api/inputs/create_inputs.yaml +0 -48
  41. type_spec/external/api/inputs/get_input_data.yaml +0 -95
  42. type_spec/external/api/inputs/get_input_names.yaml +0 -38
  43. type_spec/external/api/inputs/get_inputs_data.yaml +0 -82
  44. type_spec/external/api/inputs/set_input_attribute_values.yaml +0 -33
  45. type_spec/external/api/inputs/set_input_category.yaml +0 -23
  46. type_spec/external/api/inputs/set_input_subcategories.yaml +0 -23
  47. type_spec/external/api/material_families/update_entity_material_families.yaml +0 -33
  48. type_spec/external/api/outputs/get_output_data.yaml +0 -92
  49. type_spec/external/api/outputs/get_output_names.yaml +0 -35
  50. type_spec/external/api/outputs/resolve_output_conditions.yaml +0 -50
  51. type_spec/external/api/permissions/set_core_permissions.yaml +0 -69
  52. type_spec/external/api/project/get_projects.yaml +0 -42
  53. type_spec/external/api/project/get_projects_data.yaml +0 -50
  54. type_spec/external/api/recipe_links/create_recipe_link.yaml +0 -25
  55. type_spec/external/api/recipe_metadata/get_recipe_metadata_data.yaml +0 -41
  56. type_spec/external/api/recipes/archive_recipes.yaml +0 -20
  57. type_spec/external/api/recipes/associate_recipe_as_input.yaml +0 -19
  58. type_spec/external/api/recipes/associate_recipe_as_lot.yaml +0 -19
  59. type_spec/external/api/recipes/create_recipe.yaml +0 -42
  60. type_spec/external/api/recipes/create_recipes.yaml +0 -47
  61. type_spec/external/api/recipes/disassociate_recipe_as_input.yaml +0 -16
  62. type_spec/external/api/recipes/edit_recipe_inputs.yaml +0 -85
  63. type_spec/external/api/recipes/get_curve.yaml +0 -21
  64. type_spec/external/api/recipes/get_recipe_calculations.yaml +0 -39
  65. type_spec/external/api/recipes/get_recipe_links.yaml +0 -26
  66. type_spec/external/api/recipes/get_recipe_names.yaml +0 -29
  67. type_spec/external/api/recipes/get_recipe_output_metadata.yaml +0 -36
  68. type_spec/external/api/recipes/get_recipes_data.yaml +0 -244
  69. type_spec/external/api/recipes/set_recipe_inputs.yaml +0 -42
  70. type_spec/external/api/recipes/set_recipe_metadata.yaml +0 -20
  71. type_spec/external/api/recipes/set_recipe_outputs.yaml +0 -52
  72. type_spec/external/api/recipes/set_recipe_tags.yaml +0 -62
  73. type_spec/external/api/recipes/unarchive_recipes.yaml +0 -17
  74. type_spec/external/api/triggers/run_trigger.yaml +0 -18
  75. {UncountablePythonSDK-0.0.29.dist-info → UncountablePythonSDK-0.0.30.dist-info}/WHEEL +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: UncountablePythonSDK
3
- Version: 0.0.29
3
+ Version: 0.0.30
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
@@ -27,9 +27,9 @@ Requires-Dist: PyYAML ==6.*
27
27
  Provides-Extra: test
28
28
  Requires-Dist: mypy ==1.* ; extra == 'test'
29
29
  Requires-Dist: ruff ==0.* ; extra == 'test'
30
- Requires-Dist: pytest ==7.* ; extra == 'test'
30
+ Requires-Dist: pytest ==8.* ; extra == 'test'
31
31
  Requires-Dist: coverage[toml] ==6.* ; extra == 'test'
32
- Requires-Dist: pytest-cov ==4.* ; extra == 'test'
32
+ Requires-Dist: pytest-cov ==5.* ; extra == 'test'
33
33
  Requires-Dist: pytest-xdist ==3.* ; extra == 'test'
34
34
 
35
35
  # Uncountable Python SDK
@@ -1,5 +1,5 @@
1
1
  docs/.gitignore,sha256=_ebkZUcwfvfnGEJ95rfj1lxoBNd6EE9ZvtOc7FsbfFE,7
2
- docs/conf.py,sha256=_NTPzzM_NS92AWqpYdlNKQlTc-IEolfYYKLLHm6lFAk,1700
2
+ 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
@@ -14,10 +14,9 @@ docs/static/favicons/favicon-32x32.png,sha256=U4UU652zGnSeU3P9kUqxPeEnVf6zhtdNdN
14
14
  docs/static/favicons/manifest.json,sha256=6q_3nZkcg_x0xut4eE-xpdeMY1TydwiZIcbXlLAq9X8,437
15
15
  docs/static/favicons/mstile-150x150.png,sha256=eAK4QdEofhdLtfmjuPTpnX3MJqYnvGXsHYUjlcQekyY,1035
16
16
  docs/static/favicons/safari-pinned-tab.svg,sha256=S84fRnz0ZxLnQrKtmmFZytiRyu1xLtMR_RVy5jmwU7k,1926
17
- examples/async_batch.py,sha256=wpf_3P547375vTIO4pKv5vw6WCkUnzqvw_S3idfhjvM,1122
18
- examples/create_entity.py,sha256=j5dUB46_awRIsyiExE4sy4NqA9-wobAV41InQiLDgu4,601
19
- examples/upload_files.py,sha256=ZsMChgOioraVHv207YREpivAOf4dq3IxGIBoROoDX_4,482
20
- examples/recipe-import/importer.py,sha256=baD71xuNibxDTe3bGHsMEIZEf9Xtb-IumBNpCEV0RZU,1134
17
+ examples/async_batch.py,sha256=CffQ8O9drJ-Mdd6S5DnMIOBsHv5aVkTZrD3l3xBnB4s,1094
18
+ examples/create_entity.py,sha256=noZdtJ5f9Wfiob3zUH-8bDVbrCPJnFtXFk_W9pSjvUA,664
19
+ examples/upload_files.py,sha256=tUfKFqiqwnw08OL5Y8_e4j5pSRhp94cFex8XTuVa_ig,487
21
20
  pkgs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
21
  pkgs/argument_parser/__init__.py,sha256=CsQ6QoPKSLLRVl-z6URAmPkiUL9ZPZoV4rJHgy_-RjA,385
23
22
  pkgs/argument_parser/_is_enum.py,sha256=Gw6jJa8nBwYGqXwwCZbSnWL8Rvr5alkg5lSVAqXtOZM,257
@@ -40,7 +39,7 @@ pkgs/type_spec/config.py,sha256=INfEiDcUsZFUKasHprsE6i33siPB0RnfmTKOsWcGnQ8,5043
40
39
  pkgs/type_spec/emit_io_ts.py,sha256=Ghd8XYqyNYldHQDepwa9GLfHXcoi48ztBw84K28ETic,5707
41
40
  pkgs/type_spec/emit_open_api.py,sha256=rAxfPVsqJU7ass76dPhImgPao6AW6xyz-rMaQDhSp1I,23822
42
41
  pkgs/type_spec/emit_open_api_util.py,sha256=XAA6zH59aZWLVl0BvKAICXXl4sdBqx01QAtv5oB0bMI,2266
43
- pkgs/type_spec/emit_python.py,sha256=1Ei2PaqRs1qeQj5LWYfcRUHyzEoMI3DhDzomXmhX_-A,44139
42
+ pkgs/type_spec/emit_python.py,sha256=vuVgyts9zfEgRMTGsI6LKejMnq9_lxLxawjxoz4p7DE,44098
44
43
  pkgs/type_spec/emit_typescript.py,sha256=4hpCJwiDf-v8LJaNFVfFtf8zvtG73YNPFwwa_5NuffI,17729
45
44
  pkgs/type_spec/emit_typescript_util.py,sha256=93FzJnpYse4PKFzgdw4DGV4zFTi5tF4WR-CIi7cW498,873
46
45
  pkgs/type_spec/load_types.py,sha256=xEHwdB_miR3vNs161Oy1luafE0VC-yk9-utAyCJmbEo,3629
@@ -59,78 +58,27 @@ pkgs/type_spec/value_spec/__main__.py,sha256=-9L5pXYx02plnTetqNknaUZPieLRtzbyWdZ
59
58
  pkgs/type_spec/value_spec/convert_type.py,sha256=SAYyEV6orQJJbkXSE4hhtOQJ2vKUXJCKPeYPrB8G9oA,2272
60
59
  pkgs/type_spec/value_spec/emit_python.py,sha256=rjg6LIGYdaagrZ19XpDfW_Z7LPNwCMDceBje5dsMFbw,6959
61
60
  pkgs/type_spec/value_spec/types.py,sha256=a2zxbbCRWepY1l8OtjeCDKgBKFPFHVgV99oP6pTtaro,441
62
- type_spec/external/api/batch/execute_batch.yaml,sha256=gpdSev3sLEC_cMVSZdj-9bc_XDFDqdPdOII9Ojme2N8,1170
63
- type_spec/external/api/batch/execute_batch_load_async.yaml,sha256=gcn51NWLiSvlytz8k3_pDOVJLCGfdivKJPG4I9Q8CZc,435
64
- type_spec/external/api/chemical/convert_chemical_formats.yaml,sha256=EidTxMCRs-ko5yMFDptJPyAEWYZVruP41OG3cwyBLQQ,1069
65
- type_spec/external/api/entity/create_entities.yaml,sha256=RKjmb_iY4dVHf3aQUCU-OrlbTLLsCkULQ9uEfa8BMFY,1506
66
- type_spec/external/api/entity/create_entity.yaml,sha256=Orz-3RZsNy5cWXlA3BKVQDYGnGGXlCXOtsOxDSm_nRY,1701
67
- type_spec/external/api/entity/get_entities_data.yaml,sha256=3XujG7bOpuBQlfFrYtG3L4fBk7LsmdSekmP9iU0zjF0,796
68
- type_spec/external/api/entity/list_entities.yaml,sha256=l3QtxIRyDzXrSKsa1PNY7fHYRG7yx0Lf_bFEQMQ67n8,1868
69
- type_spec/external/api/entity/lock_entity.yaml,sha256=jjTlsjbOgiW3qpN7HBn_1OsMKFxAQiE-5mlEjgD2Xic,598
70
- type_spec/external/api/entity/resolve_entity_ids.yaml,sha256=Zf3OhAohwLJO7wWj0e-sK5lhIsXlD8A5Bu3OGjY4-tA,732
71
- type_spec/external/api/entity/set_values.yaml,sha256=_UDxSk09Ke0KDABt8ldOScC2CLrbAhBPArZvno5iD4I,422
72
- type_spec/external/api/entity/transition_entity_phase.yaml,sha256=2JyaP-5Kn75mnBMy58plJsbQnVH2ildcMWcy6nRD6yY,1013
73
- type_spec/external/api/entity/unlock_entity.yaml,sha256=EFmmrhbJSKGqyLdEA0fw0Dk9WaHN8TbEcfAh6eYE0ps,475
74
- type_spec/external/api/field_options/upsert_field_options.yaml,sha256=21aW5jnNwJUX_dMwNpwbij1bRN72PrbOesDi6Xqv22U,1246
75
- type_spec/external/api/id_source/list_id_source.yaml,sha256=V0KfzWGBwBkErKCMGhI8w7ZVbw98zaPuUWQxTfpsONU,1090
76
- type_spec/external/api/id_source/match_id_source.yaml,sha256=j4jDdmElYyY_ZLJQrx66ddy4JYV_9GMWQNi0G8SwY08,837
77
- type_spec/external/api/input_groups/get_input_group_names.yaml,sha256=LYgnm2Or7ZWCzDGjl53Y1PcHvej8G7Mpp5H96Z4UZCg,913
78
- type_spec/external/api/inputs/create_inputs.yaml,sha256=pX8jatpve4iJxK7kYw7SBlQXlVHJVfLDCOrDdpn8Gsw,1561
79
- type_spec/external/api/inputs/get_input_data.yaml,sha256=sQdju--rKG0-kKgT9MHYbX5JMPmVIFXPHVKchyrykp8,3895
80
- type_spec/external/api/inputs/get_input_names.yaml,sha256=b_kLmhe-H06J73cUrVg-O2m5K6Uj9WjC6XIUUdiObpU,1592
81
- type_spec/external/api/inputs/get_inputs_data.yaml,sha256=9wKwnOXC_KokThWnz5Me5RzIcGlxffwcKJtgFow-kvU,2368
82
- type_spec/external/api/inputs/set_input_attribute_values.yaml,sha256=RpOtVIWBlOp_Nd5Xp67IaQmCzGnLkNwFKQDi4WD8oX4,1021
83
- type_spec/external/api/inputs/set_input_category.yaml,sha256=2zcDYw_WzBfzFNkhfDDer45MgRxGnzOBLFicDWrvN80,676
84
- type_spec/external/api/inputs/set_input_subcategories.yaml,sha256=xbydzqVHIktslueosU3dJxdAu4a8uc5jQc5Cccdw7i8,682
85
- type_spec/external/api/material_families/update_entity_material_families.yaml,sha256=2WjU7XycTHEaZ2YA_FhwzndVN-PqWsyPCJhBE1WRKvQ,1231
86
- type_spec/external/api/outputs/get_output_data.yaml,sha256=D-xr8u1SfYUGtXG1fcAi8V44d5rVg48LtOK5BhCDXr4,3556
87
- type_spec/external/api/outputs/get_output_names.yaml,sha256=p-3ubOjEFNjV746zpAkXurCu0yVUvonDssJKk48ueVM,1404
88
- type_spec/external/api/outputs/resolve_output_conditions.yaml,sha256=lGrG6XPGiQtHx24GccPcO18xxAoMynTSC_2WwxCjFrc,1640
89
- type_spec/external/api/permissions/set_core_permissions.yaml,sha256=SDM_3FE-ur00dv6Na9HlaJBIvSPgnfqRieGDKnBR1UY,1632
90
- type_spec/external/api/project/get_projects.yaml,sha256=pQXGGPHenmFWYUuzEmZ-ORf0_d6lpQkTrXXMRrEqvDI,1676
91
- type_spec/external/api/project/get_projects_data.yaml,sha256=9Ns-KOP1qVhBaqMRCsEG6960V5mJW16TD0qRsTHznjQ,2051
92
- type_spec/external/api/recipe_links/create_recipe_link.yaml,sha256=7b2p7Ei4LnQXqccHsOVAfYyNK4WXm0n1IqxPG-qQDh0,941
93
- type_spec/external/api/recipe_metadata/get_recipe_metadata_data.yaml,sha256=3C7lCYWI1yX57lhcxU7kPPx-K6DI18CXGxQredSf-lA,1829
94
- type_spec/external/api/recipes/archive_recipes.yaml,sha256=Oe-NIFwERiG1DwgzsWj3ouKVdnRDTelrgqE5b9Bt_vQ,515
95
- type_spec/external/api/recipes/associate_recipe_as_input.yaml,sha256=7t0jto37RyLjl63-GK3mLC2uFiX1gd8vPwTwnobxkeI,654
96
- type_spec/external/api/recipes/associate_recipe_as_lot.yaml,sha256=8wzeJg5njt4qG2kavA6Jpo9PkWE6rIbuA4IPNdhcwEg,605
97
- type_spec/external/api/recipes/create_recipe.yaml,sha256=L9McbFT0fxQc8G1oepWVMbPBc3w_9HSjfhmorIWQDNc,1442
98
- type_spec/external/api/recipes/create_recipes.yaml,sha256=eXMlXRpB5TFt1mUTECBa4aAIG3KrxYT2mJ5vxmZ9Q3A,1503
99
- type_spec/external/api/recipes/disassociate_recipe_as_input.yaml,sha256=qTKQCNBNwLnbr22DQVLA6b80BdBhwnDbX1c4KoCKUm8,477
100
- type_spec/external/api/recipes/edit_recipe_inputs.yaml,sha256=ljewBw77ucvl_m_KWmSJp-nVQGvVG6cb7xVOgPIlueU,2573
101
- type_spec/external/api/recipes/get_curve.yaml,sha256=zQpPwOYqojY-YwmTjbqoGtUxpYm3vne2sYpglWbPnpw,779
102
- type_spec/external/api/recipes/get_recipe_calculations.yaml,sha256=ZE7PzfWrjS7TiO4q7iyCwEj5In8GwO6fFIYGqUlTEXo,1240
103
- type_spec/external/api/recipes/get_recipe_links.yaml,sha256=Vwm0OVWl3VvDaI7chY_oZQqD8xZ1u09iFWKkZKn1ITo,766
104
- type_spec/external/api/recipes/get_recipe_names.yaml,sha256=4tqcVj-xLeEu0lhdm8NpLYmAvfkmq08GZ0Mr59I5nLI,896
105
- type_spec/external/api/recipes/get_recipe_output_metadata.yaml,sha256=YImW94JXVKR6Wz_7R7sRbhD9Ul51Ba-j-x9vJB__AAU,1216
106
- type_spec/external/api/recipes/get_recipes_data.yaml,sha256=F1CkFOtQroweYvURkw4wJx0X3UvSl3mmz87r-MIxfto,11632
107
- type_spec/external/api/recipes/set_recipe_inputs.yaml,sha256=MvnHuzI9JKfkYZb-pC4jeE7FRpGeacJKXd5_GImsDiY,1747
108
- type_spec/external/api/recipes/set_recipe_metadata.yaml,sha256=5N9AIY9x3pZhDXyzpM__e7pyKNTI2RS7OeBmwmj5nEs,585
109
- type_spec/external/api/recipes/set_recipe_outputs.yaml,sha256=Oe8XGYXbPNmrbEDXk3qucfS1L3P9TnXI5cxaNAl6x5A,1875
110
- type_spec/external/api/recipes/set_recipe_tags.yaml,sha256=IrdkbryxZjNy8n4aMNLRTYbm27cRDfXxItk_kFgDaMM,1399
111
- type_spec/external/api/recipes/unarchive_recipes.yaml,sha256=m9WwmTHtIMVQOmX7CpbKbnuPsnTVII-4Jr9JffxMUXg,393
112
- type_spec/external/api/triggers/run_trigger.yaml,sha256=c8xDV3bQRjcRRDG4Y7kdQmMMu1fj3ae5eUi-Sdbsi54,405
113
- uncountable/__init__.py,sha256=281cC2hs8pbrD0jVKMol-tbWSh7Zcsc8oRT42dKteyE,102
61
+ uncountable/__init__.py,sha256=8l8XWNCKsu7TG94c-xa2KHpDegvxDC2FyQISdWC763Y,89
114
62
  uncountable/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
115
- uncountable/core/__init__.py,sha256=J0CeeztqyJe7klvHM-8fwSivN1sud6xZThOdaThnQrU,314
116
- uncountable/core/async_batch.py,sha256=0cRmCr6Z9sNxZyfY9Dl8wlCA4anISVZuHGgBegHhUbc,749
117
- uncountable/core/client.py,sha256=J_J9zEfSpWRx4RBSl2gIDqtUpC7ca1hpEvbHVfe7_jQ,9045
118
- uncountable/core/file_upload.py,sha256=YWOay69i_-sNGBNnwzKb3bY3OMaV4lRsdVZZK-ScXVc,2829
119
- uncountable/core/types.py,sha256=zM_FqVT41qqZAhXxKSK_kQccArfw6B_p2qMYBRKJHqE,332
63
+ uncountable/core/__init__.py,sha256=RFv0kO6rKFf1PtBPu83hCGmxqkJamRtsgQ9_-ztw7tA,341
64
+ uncountable/core/async_batch.py,sha256=Zo02TICZ7AK81Qa02NQ8fp8uaijQph1FEta28K3cKb0,749
65
+ uncountable/core/client.py,sha256=79pqKjYuoTzKnPWLMST1jS9Gcn4nxtOzWC-VaM67QgY,9401
66
+ uncountable/core/file_upload.py,sha256=t4cutIFB5rNN2qVCx3H0HotSjCSJSxis2_QBarDuXyc,2833
67
+ uncountable/core/types.py,sha256=s2CjqYJpsmbC7xMwxxT7kJ_V9bwokrjjWVVjpMcQpKI,333
120
68
  uncountable/integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
121
- uncountable/integration/construct_client.py,sha256=r6M5pnIO0fKcjf5d_AREPtWZ6AkWgcjkdu_jHQEYlT8,1084
122
- uncountable/integration/cron.py,sha256=TIPqMPMSMtMJTu4aXwLf6QY-OLrpmyITLDp48UIr4Ok,919
123
- uncountable/integration/entrypoint.py,sha256=sPtUeKJEivf0iqY-H4LHWhyeUHMZK_U4CrDj1Kw8Ld0,1395
124
- uncountable/integration/job.py,sha256=5QuCjeze9vtEirntP9P9hDD3LVrBn5pApDWh2IZeEiY,817
125
- uncountable/integration/server.py,sha256=DSYflR8tIo20Kixt4AmQI6nOP_BHeTGUiq7iFKaf31s,3342
69
+ uncountable/integration/construct_client.py,sha256=N3K-wck7teqvHTrOh0N2bGF3u6kyuwQvgo7gsKLihQ0,1077
70
+ uncountable/integration/cron.py,sha256=DNnMkeLYi70U-3wrcDAX382FgEGq16KL6xy-6OBv5Us,938
71
+ uncountable/integration/entrypoint.py,sha256=MNXl9xv0N03V3_0vplckWlUio2CDFJ0jsjM8uvY1dTE,1404
72
+ uncountable/integration/job.py,sha256=u4Vhm9l5KUvex7I7R_ysBHjmm1BBB1KvnjRvZvFkOig,807
73
+ uncountable/integration/server.py,sha256=5Wh80VyfgUUHA5NiFGn9LjS4KJ9zJz3QbNTLLKhFAso,3342
126
74
  uncountable/integration/types.py,sha256=n9idu2_qHOA5CQdE6NK8HS6aZ8ugTZKTfTTnm4sy8tI,2066
127
75
  uncountable/integration/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
128
- uncountable/integration/db/connect.py,sha256=iI9e8a2hfbFP-dvH0MGLsrG-RpM0dHKCL-oCLkah9hs,181
76
+ uncountable/integration/db/connect.py,sha256=YtQHJ1DBGPhxKFRCfiXqohOYUceKSxMVOJ88aPI48Ug,181
129
77
  uncountable/integration/executors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
130
- uncountable/integration/executors/script_executor.py,sha256=6oMPAFe0PUdqt76e8jMi4vXszGVsVHLULob7Qbl3o38,816
78
+ uncountable/integration/executors/script_executor.py,sha256=hM8E-aU8zyM6ZcBtqAqInKZ_BF93RLqEA0dU7y5FhWQ,841
131
79
  uncountable/types/__init__.py,sha256=ziCs6fh_WzMhHPGwFi7xCdFQoNT6PBzZyfrMANEm8g0,6816
132
80
  uncountable/types/async_batch.py,sha256=aWiul1fK3-cXaCESUUJ_92FF-NuuwxSjn9n3jC9vY5o,1618
133
- uncountable/types/async_batch_processor.py,sha256=jwN5BOcBSejce0RqNOYWW3sZIv5Oj2Aip1dbzAgGh6A,6117
81
+ uncountable/types/async_batch_processor.py,sha256=eNXKPOh-sCiarPvreLDEu4XbieWLe_5KXmiY984eZ5I,6083
134
82
  uncountable/types/base.py,sha256=w3BRf8SAvYPlKrcJtJcQ_WhCU3A9zy0VuRTRWRFKVUA,2709
135
83
  uncountable/types/calculations.py,sha256=16J-KKMp-I8ZQUkYNmKCHfAn6DGb99cFinALcDIdGHY,562
136
84
  uncountable/types/chemical_structure.py,sha256=zQKl53DGtQQONIUHFXuwjWLQaG7FPZY7x6SBSOzkGV0,758
@@ -226,7 +174,7 @@ uncountable/types/api/recipes/set_recipe_tags.py,sha256=U710hgq9-t6QZGRB-ZGHskpt
226
174
  uncountable/types/api/recipes/unarchive_recipes.py,sha256=WcwFYbBsX2SKXnoBQ8locnRn7Bj1rHdtrURQVOfqgfU,814
227
175
  uncountable/types/api/triggers/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
228
176
  uncountable/types/api/triggers/run_trigger.py,sha256=9m9M8-nlGB_sAU2Qm2lWugp4h4Osqj6QpjNfU8osd1U,901
229
- UncountablePythonSDK-0.0.29.dist-info/METADATA,sha256=AeSTcRIslBwKBr4qNGQlB55U9idSy18wek0K02w1Rvg,1577
230
- UncountablePythonSDK-0.0.29.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
231
- UncountablePythonSDK-0.0.29.dist-info/top_level.txt,sha256=HaMiBnH1wA7SG9-RVHIJPBH3l8X5gee2jUf-77Nz-Dk,41
232
- UncountablePythonSDK-0.0.29.dist-info/RECORD,,
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,,
@@ -1,5 +1,4 @@
1
1
  docs
2
2
  examples
3
3
  pkgs
4
- type_spec
5
4
  uncountable
docs/conf.py CHANGED
@@ -7,7 +7,6 @@
7
7
  # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
8
8
 
9
9
  from datetime import date
10
- import uncountable
11
10
 
12
11
  project = "Uncountable SDK"
13
12
  copyright = f"{date.today().year}, Uncountable Inc"
@@ -26,9 +25,15 @@ extensions = [
26
25
  myst_enable_extensions = ["fieldlist", "deflist"]
27
26
 
28
27
  autoapi_dirs = ["../uncountable"]
29
- autoapi_options = [ 'members', 'undoc-members', 'show-inheritance', 'show-module-summary', 'imported-members' ]
30
- autoapi_ignore = ['*integration*']
31
- autodoc_typehints = 'description'
28
+ autoapi_options = [
29
+ "members",
30
+ "undoc-members",
31
+ "show-inheritance",
32
+ "show-module-summary",
33
+ "imported-members",
34
+ ]
35
+ autoapi_ignore = ["*integration*"]
36
+ autodoc_typehints = "description"
32
37
 
33
38
  exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
34
39
 
examples/async_batch.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from decimal import Decimal
2
- from uncountable.core import AuthDetailsApiKey, Client
3
- from uncountable.core import AsyncBatchProcessor
2
+
3
+ from uncountable.core import AsyncBatchProcessor, AuthDetailsApiKey, Client
4
4
  from uncountable.types import (
5
5
  recipe_metadata,
6
6
  )
@@ -10,7 +10,6 @@ from uncountable.types.recipe_identifiers import (
10
10
  RecipeIdentifiers,
11
11
  )
12
12
 
13
-
14
13
  client = Client(
15
14
  base_url="https://app.uncountable.com",
16
15
  auth_details=AuthDetailsApiKey(
examples/create_entity.py CHANGED
@@ -1,23 +1,20 @@
1
1
  from uncountable.core import AuthDetailsOAuth, Client
2
+ from uncountable.core.client import ClientConfig
2
3
  from uncountable.types import (
3
4
  entity_t,
4
5
  field_values_t,
5
6
  )
6
7
 
7
-
8
8
  client = Client(
9
9
  base_url="https://app.uncountable.com",
10
- auth_details=AuthDetailsOAuth(
11
- refresh_token="x"
12
- ),
10
+ auth_details=AuthDetailsOAuth(refresh_token="x"),
11
+ config=ClientConfig(allow_insecure_tls=False),
13
12
  )
14
13
  entities = client.create_entity(
15
14
  definition_id=24,
16
15
  entity_type=entity_t.EntityType.LAB_REQUEST,
17
16
  field_values=[
18
- field_values_t.FieldRefNameValue(
19
- field_ref_name="name", value="SDK Lab Request"
20
- ),
17
+ field_values_t.FieldRefNameValue(field_ref_name="name", value="SDK Lab Request"),
21
18
  field_values_t.FieldRefNameValue(field_ref_name="materialFamilyId", value=1),
22
19
  ],
23
20
  )
examples/upload_files.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  from pprint import pprint
3
3
 
4
- from uncountable import AuthDetailsApiKey, Client, MediaFileUpload
4
+ from uncountable.core import AuthDetailsApiKey, Client, MediaFileUpload
5
5
 
6
6
  client = Client(
7
7
  base_url="http://localhost:5000",
@@ -1194,7 +1194,6 @@ ASYNC_BATCH_PROCESSOR_FILENAME = "async_batch_processor"
1194
1194
  ASYNC_BATCH_PROCESSOR_IMPORTS = [
1195
1195
  "import uuid",
1196
1196
  "from abc import ABC, abstractmethod",
1197
- "from dataclasses import dataclass",
1198
1197
  "from pkgs.serialization_util.serialization_helpers import serialize_for_api",
1199
1198
  ]
1200
1199
 
uncountable/__init__.py CHANGED
@@ -1,5 +1,4 @@
1
- from . import types
2
- from . import core
1
+ from . import core, types
3
2
 
4
3
  __all__ = []
5
4
  __all__ += types.__all__
@@ -1,6 +1,13 @@
1
+ from .async_batch import AsyncBatchProcessor
1
2
  from .client import Client
2
- from .types import AuthDetailsApiKey, AuthDetailsOAuth
3
3
  from .file_upload import MediaFileUpload, UploadedFile
4
- from .async_batch import AsyncBatchProcessor
4
+ from .types import AuthDetailsApiKey, AuthDetailsOAuth
5
5
 
6
- __all__: list[str] = ["AuthDetailsApiKey", "AuthDetailsOAuth", "AsyncBatchProcessor", "Client", "MediaFileUpload", "UploadedFile"]
6
+ __all__: list[str] = [
7
+ "AuthDetailsApiKey",
8
+ "AuthDetailsOAuth",
9
+ "AsyncBatchProcessor",
10
+ "Client",
11
+ "MediaFileUpload",
12
+ "UploadedFile",
13
+ ]
@@ -1,7 +1,7 @@
1
1
  from uncountable.core.client import Client
2
+ from uncountable.types import async_batch_t, base_t
2
3
  from uncountable.types.async_batch import AsyncBatchRequest
3
4
  from uncountable.types.async_batch_processor import AsyncBatchProcessorBase
4
- from uncountable.types import async_batch_t, base_t
5
5
 
6
6
 
7
7
  class AsyncBatchProcessor(AsyncBatchProcessorBase):
@@ -1,10 +1,11 @@
1
1
  import base64
2
- from datetime import datetime, timedelta
3
2
  import json
4
3
  import typing
5
4
  from dataclasses import dataclass
5
+ from datetime import datetime, timedelta
6
6
  from enum import StrEnum
7
7
  from urllib.parse import urljoin
8
+ from uuid import uuid4
8
9
 
9
10
  import requests
10
11
  from requests.exceptions import JSONDecodeError
@@ -18,6 +19,7 @@ from .file_upload import FileUpload, FileUploader, UploadedFile
18
19
  from .types import AuthDetailsAll, AuthDetailsApiKey, AuthDetailsOAuth
19
20
 
20
21
  DT = typing.TypeVar("DT")
22
+ UNC_REQUEST_ID_HEADER = "X-UNC-REQUEST-ID"
21
23
 
22
24
 
23
25
  class EndpointMethod(StrEnum):
@@ -30,19 +32,17 @@ class HTTPRequestBase:
30
32
  method: EndpointMethod
31
33
  url: str
32
34
  headers: dict[str, str]
33
- body: typing.Optional[typing.Union[str, dict[str, str]]] = None
34
- query_params: typing.Optional[dict[str, str]] = None
35
35
 
36
36
 
37
37
  @dataclass(kw_only=True)
38
38
  class HTTPGetRequest(HTTPRequestBase):
39
- method: typing.Literal[EndpointMethod.GET]
39
+ method = EndpointMethod.GET
40
40
  query_params: dict[str, str]
41
41
 
42
42
 
43
43
  @dataclass(kw_only=True)
44
44
  class HTTPPostRequest(HTTPRequestBase):
45
- method: typing.Literal[EndpointMethod.POST]
45
+ method = EndpointMethod.POST
46
46
  body: typing.Union[str, dict[str, str]]
47
47
 
48
48
 
@@ -101,13 +101,15 @@ class APIResponseError(BaseException):
101
101
 
102
102
  class SDKError(BaseException):
103
103
  message: str
104
+ request_id: str
104
105
 
105
- def __init__(self, message: str) -> None:
106
+ def __init__(self, message: str, *, request_id: str) -> None:
106
107
  super().__init__(message)
107
108
  self.message = message
109
+ self.request_id = request_id
108
110
 
109
111
  def __str__(self) -> str:
110
- return f"internal SDK error, please contact Uncountable support: {self.message}"
112
+ return f"internal SDK error (request id {self.request_id}), please contact Uncountable support: {self.message}"
111
113
 
112
114
 
113
115
  @dataclass(kw_only=True)
@@ -147,7 +149,9 @@ class Client(ClientMethods):
147
149
  self._file_uploader = FileUploader(self._base_url, self._auth_details)
148
150
  self._cfg = config or ClientConfig()
149
151
 
150
- def _get_response_json(self, response: requests.Response) -> dict[str, JsonValue]:
152
+ def _get_response_json(
153
+ self, response: requests.Response, request_id: str
154
+ ) -> dict[str, JsonValue]:
151
155
  if response.status_code < 200 or response.status_code > 299:
152
156
  extra_details: dict[str, JsonValue] | None = None
153
157
  try:
@@ -160,12 +164,15 @@ class Client(ClientMethods):
160
164
  status_code=response.status_code, extra_details=extra_details
161
165
  )
162
166
  try:
163
- return response.json()
164
- except JSONDecodeError:
165
- raise SDKError("unable to process response")
167
+ return typing.cast(dict[str, JsonValue], response.json())
168
+ except JSONDecodeError as e:
169
+ raise SDKError("unable to process response", request_id=request_id) from e
166
170
 
167
171
  def do_request(self, *, api_request: APIRequest, return_type: type[DT]) -> DT:
168
- http_request = self._build_http_request(api_request=api_request)
172
+ request_id = str(uuid4())
173
+ http_request = self._build_http_request(
174
+ api_request=api_request, request_id=request_id
175
+ )
169
176
  match http_request:
170
177
  case HTTPGetRequest():
171
178
  response = requests.get(
@@ -179,18 +186,17 @@ class Client(ClientMethods):
179
186
  http_request.url,
180
187
  headers=http_request.headers,
181
188
  data=http_request.body,
182
- params=http_request.query_params,
183
189
  verify=not self._cfg.allow_insecure_tls,
184
190
  )
185
191
  case _:
186
192
  typing.assert_never(http_request)
187
- response_data = self._get_response_json(response)
193
+ response_data = self._get_response_json(response, request_id=request_id)
188
194
  cached_parser = self._get_cached_parser(return_type)
189
195
  try:
190
196
  data = response_data["data"]
191
197
  return cached_parser.parse_api(data)
192
198
  except (ValueError, JSONDecodeError, KeyError) as e:
193
- raise SDKError("unable to process response") from e
199
+ raise SDKError("unable to process response", request_id=request_id) from e
194
200
 
195
201
  def _get_cached_parser(self, data_type: type[DT]) -> CachedParser[DT]:
196
202
  if data_type not in self._parser_map:
@@ -213,8 +219,9 @@ class Client(ClientMethods):
213
219
  "scope": oauth_details.scope,
214
220
  "grant_type": "client_credentials",
215
221
  },
222
+ verify=not self._cfg.allow_insecure_tls,
216
223
  )
217
- data = self._get_response_json(response)
224
+ data = self._get_response_json(response, request_id=str(uuid4()))
218
225
  token_data = oauth_bearer_token_data_parser.parse_storage(data)
219
226
  self._oauth_bearer_token_cache = OAuthBearerTokenCache(
220
227
  token=token_data.access_token,
@@ -235,8 +242,11 @@ class Client(ClientMethods):
235
242
  return {"Authorization": f"Bearer {token}"}
236
243
  typing.assert_never(self._auth_details)
237
244
 
238
- def _build_http_request(self, *, api_request: APIRequest) -> HTTPRequest:
245
+ def _build_http_request(
246
+ self, *, api_request: APIRequest, request_id: str
247
+ ) -> HTTPRequest:
239
248
  headers = self._build_auth_headers()
249
+ headers[UNC_REQUEST_ID_HEADER] = request_id
240
250
  method = api_request.method.lower()
241
251
  data = {"data": json.dumps(serialize_for_api(api_request.args))}
242
252
  match method:
@@ -4,7 +4,7 @@ from dataclasses import dataclass
4
4
  from enum import StrEnum
5
5
  from io import BytesIO
6
6
  from pathlib import Path
7
- from typing import Generator, Self
7
+ from typing import Generator, Literal, Self
8
8
 
9
9
  import aiohttp
10
10
  import aiotus
@@ -23,7 +23,7 @@ class MediaFileUpload:
23
23
  """Upload file from a path on disk"""
24
24
 
25
25
  path: str
26
- type: FileUploadType.MEDIA_FILE_UPLOAD = FileUploadType.MEDIA_FILE_UPLOAD
26
+ type: Literal[FileUploadType.MEDIA_FILE_UPLOAD] = FileUploadType.MEDIA_FILE_UPLOAD
27
27
 
28
28
 
29
29
  FileUpload = MediaFileUpload
@@ -90,9 +90,7 @@ class FileUploader:
90
90
  name=file_bytes.name, file_id=int(location.path.split("/")[-1])
91
91
  )
92
92
 
93
- def upload_files(
94
- self: Self, *, file_uploads: list[FileUpload]
95
- ) -> list[UploadedFile]:
93
+ def upload_files(self: Self, *, file_uploads: list[FileUpload]) -> list[UploadedFile]:
96
94
  return [
97
95
  asyncio.run(self._upload_file(file_upload)) for file_upload in file_uploads
98
96
  ]
uncountable/core/types.py CHANGED
@@ -13,5 +13,5 @@ class AuthDetailsOAuth:
13
13
  scope: str = "unc.rnd"
14
14
 
15
15
 
16
- AuthDetails = AuthDetailsApiKey # Legacy Mapping
16
+ AuthDetails = AuthDetailsApiKey # Legacy Mapping
17
17
  AuthDetailsAll = AuthDetailsApiKey | AuthDetailsOAuth
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  from typing import assert_never
3
3
 
4
- from uncountable.core.client import AuthDetailsApiKey, Client
4
+ from uncountable.core import AuthDetailsApiKey, Client
5
5
  from uncountable.integration.types import (
6
6
  AuthRetrievalEnv,
7
7
  ProfileMetadata,
@@ -23,6 +23,8 @@ def cron_job_executor(**kwargs: dict) -> None:
23
23
  client=construct_uncountable_client(profile_meta=args_passed.profile_metadata),
24
24
  )
25
25
 
26
- job = resolve_script_executor(args_passed.definition.executor, args_passed.profile_metadata)
26
+ job = resolve_script_executor(
27
+ args_passed.definition.executor, args_passed.profile_metadata
28
+ )
27
29
 
28
- job.run(args)
30
+ job.run(args=args)
@@ -1,8 +1,8 @@
1
1
  import os
2
+
2
3
  from sqlalchemy import create_engine
3
4
  from sqlalchemy.engine.base import Engine
4
5
 
5
6
 
6
7
  def create_db_engine() -> Engine:
7
8
  return create_engine(os.environ["UNC_SQLITE_URI"])
8
-
@@ -1,11 +1,10 @@
1
1
  import os
2
2
  from importlib import resources
3
3
 
4
- from uncountable.integration.server import IntegrationServer
5
- from uncountable.integration.types import ProfileDefinition
6
4
  from pkgs.argument_parser import CachedParser
7
5
  from uncountable.integration.db.connect import create_db_engine
8
-
6
+ from uncountable.integration.server import IntegrationServer
7
+ from uncountable.integration.types import ProfileDefinition
9
8
 
10
9
  profile_parser = CachedParser(ProfileDefinition)
11
10
 
@@ -19,8 +18,8 @@ def main() -> None:
19
18
  for entry in resources.files(profiles_module).iterdir()
20
19
  if entry.is_dir()
21
20
  ]
22
- for profile in profiles:
23
- profile_name = profile.name
21
+ for profile_file in profiles:
22
+ profile_name = profile_file.name
24
23
  try:
25
24
  profile = profile_parser.parse_yaml_resource(
26
25
  package=".".join([profiles_module, profile_name]),
@@ -1,15 +1,21 @@
1
-
2
- import os
3
1
  import importlib
4
2
  import inspect
3
+ import os
4
+
5
5
  from uncountable.integration.job import Job
6
6
  from uncountable.integration.types import JobExecutorScript, ProfileMetadata
7
7
 
8
8
 
9
- def resolve_script_executor(executor: JobExecutorScript, profile_metadata: ProfileMetadata) -> type[Job]:
10
- job_module_path = ".".join([os.environ["UNC_PROFILES_MODULE"], profile_metadata.name, executor.import_path])
9
+ def resolve_script_executor(
10
+ executor: JobExecutorScript, profile_metadata: ProfileMetadata
11
+ ) -> Job:
12
+ job_module_path = ".".join([
13
+ os.environ["UNC_PROFILES_MODULE"],
14
+ profile_metadata.name,
15
+ executor.import_path,
16
+ ])
11
17
  job_module = importlib.import_module(job_module_path)
12
- found_jobs: list[type[Job]] = []
18
+ found_jobs: list[Job] = []
13
19
  for _, job_class in inspect.getmembers(job_module, inspect.isclass):
14
20
  if getattr(job_class, "_unc_job_registered", False):
15
21
  found_jobs.append(job_class())
@@ -1,9 +1,9 @@
1
+ from abc import ABC, abstractmethod
1
2
  from dataclasses import dataclass
3
+
2
4
  from uncountable.core.client import Client
3
5
  from uncountable.integration.types import JobDefinition
4
6
 
5
- from abc import ABC, abstractmethod
6
-
7
7
 
8
8
  @dataclass
9
9
  class JobArgumentsBase:
@@ -29,17 +29,14 @@ class Job(ABC):
29
29
  _unc_job_registered: bool = False
30
30
 
31
31
  @abstractmethod
32
- def run(self, args: JobArguments) -> JobResult:
33
- ...
32
+ def run(self, args: JobArguments) -> JobResult: ...
34
33
 
35
34
 
36
35
  class CronJob(Job):
37
-
38
36
  @abstractmethod
39
- def run(self, args: CronJobArguments) -> JobResult:
40
- ...
37
+ def run(self, args: CronJobArguments) -> JobResult: ...
41
38
 
42
39
 
43
- def register_job(cls: Job):
40
+ def register_job(cls: Job) -> Job:
44
41
  cls._unc_job_registered = True
45
42
  return cls
@@ -1,15 +1,16 @@
1
1
  import signal
2
- from types import TracebackType
3
2
  from dataclasses import asdict
3
+ from types import TracebackType
4
4
  from typing import Optional, assert_never
5
+
6
+ from apscheduler.executors.pool import ThreadPoolExecutor
7
+ from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
5
8
  from apscheduler.schedulers.background import BackgroundScheduler
6
9
  from apscheduler.schedulers.base import BaseScheduler
7
- from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
8
- from apscheduler.executors.pool import ThreadPoolExecutor
9
- from uncountable.integration.cron import CronJobArgs, cron_job_executor
10
10
  from apscheduler.triggers.cron import CronTrigger
11
11
  from sqlalchemy.engine.base import Engine
12
12
 
13
+ from uncountable.integration.cron import CronJobArgs, cron_job_executor
13
14
  from uncountable.integration.types import (
14
15
  AuthRetrieval,
15
16
  CronJobDefinition,
@@ -17,7 +18,6 @@ from uncountable.integration.types import (
17
18
  ProfileMetadata,
18
19
  )
19
20
 
20
-
21
21
  _MAX_APSCHEDULER_CONCURRENT_JOBS = 1
22
22
 
23
23
 
@@ -19,7 +19,6 @@ from uncountable.types import recipe_workflow_steps as recipe_workflow_steps_t
19
19
  import uncountable.types.api.recipes.set_recipe_metadata as set_recipe_metadata_t
20
20
  import uuid
21
21
  from abc import ABC, abstractmethod
22
- from dataclasses import dataclass
23
22
  from pkgs.serialization_util.serialization_helpers import serialize_for_api
24
23
 
25
24