UncountablePythonSDK 0.0.24__py3-none-any.whl → 0.0.131__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 (373) hide show
  1. docs/conf.py +60 -8
  2. docs/index.md +107 -4
  3. docs/integration_examples/create_ingredient.md +43 -0
  4. docs/integration_examples/create_output.md +56 -0
  5. docs/integration_examples/index.md +6 -0
  6. docs/justfile +2 -2
  7. docs/requirements.txt +7 -5
  8. examples/async_batch.py +5 -6
  9. examples/basic_auth.py +7 -0
  10. examples/create_entity.py +4 -6
  11. examples/create_ingredient_sdk.py +34 -0
  12. examples/download_files.py +26 -0
  13. examples/edit_recipe_inputs.py +50 -0
  14. examples/integration-server/jobs/materials_auto/concurrent_cron.py +11 -0
  15. examples/integration-server/jobs/materials_auto/example_cron.py +21 -0
  16. examples/integration-server/jobs/materials_auto/example_http.py +47 -0
  17. examples/integration-server/jobs/materials_auto/example_instrument.py +100 -0
  18. examples/integration-server/jobs/materials_auto/example_parse.py +140 -0
  19. examples/integration-server/jobs/materials_auto/example_predictions.py +61 -0
  20. examples/integration-server/jobs/materials_auto/example_runsheet_wh.py +39 -0
  21. examples/integration-server/jobs/materials_auto/example_wh.py +23 -0
  22. examples/integration-server/jobs/materials_auto/profile.yaml +104 -0
  23. examples/integration-server/pyproject.toml +224 -0
  24. examples/invoke_uploader.py +26 -0
  25. examples/oauth.py +7 -0
  26. examples/set_recipe_metadata_file.py +40 -0
  27. examples/set_recipe_output_file_sdk.py +26 -0
  28. examples/upload_files.py +2 -3
  29. pkgs/argument_parser/__init__.py +9 -0
  30. pkgs/argument_parser/_is_namedtuple.py +3 -0
  31. pkgs/argument_parser/argument_parser.py +295 -74
  32. pkgs/argument_parser/case_convert.py +4 -3
  33. pkgs/filesystem_utils/__init__.py +20 -0
  34. pkgs/filesystem_utils/_blob_session.py +144 -0
  35. pkgs/filesystem_utils/_gdrive_session.py +309 -0
  36. pkgs/filesystem_utils/_local_session.py +69 -0
  37. pkgs/filesystem_utils/_s3_session.py +118 -0
  38. pkgs/filesystem_utils/_sftp_session.py +151 -0
  39. pkgs/filesystem_utils/file_type_utils.py +91 -0
  40. pkgs/filesystem_utils/filesystem_session.py +39 -0
  41. pkgs/py.typed +0 -0
  42. pkgs/serialization/__init__.py +8 -1
  43. pkgs/serialization/annotation.py +64 -0
  44. pkgs/serialization/missing_sentry.py +1 -1
  45. pkgs/serialization/opaque_key.py +1 -1
  46. pkgs/serialization/serial_alias.py +47 -0
  47. pkgs/serialization/serial_class.py +69 -54
  48. pkgs/serialization/serial_generic.py +16 -0
  49. pkgs/serialization/serial_union.py +84 -0
  50. pkgs/serialization/yaml.py +57 -0
  51. pkgs/serialization_util/__init__.py +7 -7
  52. pkgs/serialization_util/convert_to_snakecase.py +27 -0
  53. pkgs/serialization_util/dataclasses.py +14 -0
  54. pkgs/serialization_util/serialization_helpers.py +117 -71
  55. pkgs/type_spec/actions_registry/__main__.py +0 -4
  56. pkgs/type_spec/actions_registry/emit_typescript.py +5 -5
  57. pkgs/type_spec/builder.py +438 -109
  58. pkgs/type_spec/builder_types.py +9 -0
  59. pkgs/type_spec/config.py +52 -24
  60. pkgs/type_spec/cross_output_links.py +99 -0
  61. pkgs/type_spec/emit_io_ts.py +1 -1
  62. pkgs/type_spec/emit_open_api.py +160 -41
  63. pkgs/type_spec/emit_open_api_util.py +13 -7
  64. pkgs/type_spec/emit_python.py +450 -136
  65. pkgs/type_spec/emit_typescript.py +117 -250
  66. pkgs/type_spec/emit_typescript_util.py +293 -4
  67. pkgs/type_spec/load_types.py +20 -5
  68. pkgs/type_spec/non_discriminated_union_exceptions.py +14 -0
  69. pkgs/type_spec/open_api_util.py +29 -4
  70. pkgs/type_spec/parts/base.py.prepart +13 -10
  71. pkgs/type_spec/parts/base.ts.prepart +4 -0
  72. pkgs/type_spec/type_info/__main__.py +3 -1
  73. pkgs/type_spec/type_info/emit_type_info.py +161 -32
  74. pkgs/type_spec/ui_entry_actions/__init__.py +4 -0
  75. pkgs/type_spec/ui_entry_actions/generate_ui_entry_actions.py +308 -0
  76. pkgs/type_spec/util.py +4 -4
  77. pkgs/type_spec/value_spec/__main__.py +27 -10
  78. pkgs/type_spec/value_spec/convert_type.py +21 -1
  79. pkgs/type_spec/value_spec/emit_python.py +25 -7
  80. pkgs/type_spec/value_spec/types.py +1 -1
  81. uncountable/__init__.py +1 -2
  82. uncountable/core/__init__.py +11 -3
  83. uncountable/core/async_batch.py +16 -1
  84. uncountable/core/client.py +247 -52
  85. uncountable/core/environment.py +41 -0
  86. uncountable/core/file_upload.py +67 -22
  87. uncountable/core/types.py +8 -13
  88. uncountable/integration/cli.py +142 -0
  89. uncountable/integration/construct_client.py +43 -27
  90. uncountable/integration/cron.py +12 -11
  91. uncountable/integration/db/connect.py +12 -2
  92. uncountable/integration/db/session.py +25 -0
  93. uncountable/integration/entrypoint.py +4 -34
  94. uncountable/integration/executors/executors.py +147 -0
  95. uncountable/integration/executors/generic_upload_executor.py +336 -0
  96. uncountable/integration/executors/script_executor.py +15 -9
  97. uncountable/integration/http_server/__init__.py +5 -0
  98. uncountable/integration/http_server/types.py +69 -0
  99. uncountable/integration/job.py +246 -19
  100. uncountable/integration/queue_runner/__init__.py +0 -0
  101. uncountable/integration/queue_runner/command_server/__init__.py +28 -0
  102. uncountable/integration/queue_runner/command_server/command_client.py +133 -0
  103. uncountable/integration/queue_runner/command_server/command_server.py +142 -0
  104. uncountable/integration/queue_runner/command_server/constants.py +4 -0
  105. uncountable/integration/queue_runner/command_server/protocol/__init__.py +0 -0
  106. uncountable/integration/queue_runner/command_server/protocol/command_server.proto +58 -0
  107. uncountable/integration/queue_runner/command_server/protocol/command_server_pb2.py +57 -0
  108. uncountable/integration/queue_runner/command_server/protocol/command_server_pb2.pyi +114 -0
  109. uncountable/integration/queue_runner/command_server/protocol/command_server_pb2_grpc.py +264 -0
  110. uncountable/integration/queue_runner/command_server/types.py +75 -0
  111. uncountable/integration/queue_runner/datastore/__init__.py +3 -0
  112. uncountable/integration/queue_runner/datastore/datastore_sqlite.py +250 -0
  113. uncountable/integration/queue_runner/datastore/interface.py +29 -0
  114. uncountable/integration/queue_runner/datastore/model.py +24 -0
  115. uncountable/integration/queue_runner/job_scheduler.py +200 -0
  116. uncountable/integration/queue_runner/queue_runner.py +34 -0
  117. uncountable/integration/queue_runner/types.py +7 -0
  118. uncountable/integration/queue_runner/worker.py +116 -0
  119. uncountable/integration/scan_profiles.py +67 -0
  120. uncountable/integration/scheduler.py +199 -0
  121. uncountable/integration/secret_retrieval/__init__.py +3 -0
  122. uncountable/integration/secret_retrieval/retrieve_secret.py +93 -0
  123. uncountable/integration/server.py +103 -54
  124. uncountable/integration/telemetry.py +251 -0
  125. uncountable/integration/webhook_server/entrypoint.py +97 -0
  126. uncountable/types/__init__.py +149 -30
  127. uncountable/types/api/batch/execute_batch.py +16 -9
  128. uncountable/types/api/batch/execute_batch_load_async.py +13 -7
  129. uncountable/types/api/chemical/convert_chemical_formats.py +20 -8
  130. uncountable/types/api/condition_parameters/__init__.py +1 -0
  131. uncountable/types/api/condition_parameters/upsert_condition_match.py +72 -0
  132. uncountable/types/api/entity/create_entities.py +24 -12
  133. uncountable/types/api/entity/create_entity.py +22 -13
  134. uncountable/types/api/entity/create_or_update_entity.py +48 -0
  135. uncountable/types/api/entity/export_entities.py +59 -0
  136. uncountable/types/api/entity/get_entities_data.py +18 -9
  137. uncountable/types/api/entity/grant_entity_permissions.py +48 -0
  138. uncountable/types/api/entity/list_aggregate.py +79 -0
  139. uncountable/types/api/entity/list_entities.py +53 -14
  140. uncountable/types/api/entity/lock_entity.py +45 -0
  141. uncountable/types/api/entity/lookup_entity.py +116 -0
  142. uncountable/types/api/entity/resolve_entity_ids.py +19 -10
  143. uncountable/types/api/entity/set_entity_field_values.py +44 -0
  144. uncountable/types/api/entity/set_values.py +15 -8
  145. uncountable/types/api/entity/transition_entity_phase.py +27 -12
  146. uncountable/types/api/entity/unlock_entity.py +44 -0
  147. uncountable/types/api/equipment/__init__.py +1 -0
  148. uncountable/types/api/equipment/associate_equipment_input.py +43 -0
  149. uncountable/types/api/field_options/__init__.py +1 -0
  150. uncountable/types/api/field_options/upsert_field_options.py +55 -0
  151. uncountable/types/api/files/__init__.py +1 -0
  152. uncountable/types/api/files/download_file.py +77 -0
  153. uncountable/types/api/id_source/list_id_source.py +20 -11
  154. uncountable/types/api/id_source/match_id_source.py +15 -10
  155. uncountable/types/api/input_groups/get_input_group_names.py +16 -7
  156. uncountable/types/api/inputs/create_inputs.py +28 -14
  157. uncountable/types/api/inputs/get_input_data.py +34 -16
  158. uncountable/types/api/inputs/get_input_names.py +19 -10
  159. uncountable/types/api/inputs/get_inputs_data.py +29 -11
  160. uncountable/types/api/inputs/set_input_attribute_values.py +16 -10
  161. uncountable/types/api/inputs/set_input_category.py +44 -0
  162. uncountable/types/api/inputs/set_input_subcategories.py +45 -0
  163. uncountable/types/api/inputs/set_intermediate_type.py +50 -0
  164. uncountable/types/api/integrations/__init__.py +1 -0
  165. uncountable/types/api/integrations/publish_realtime_data.py +41 -0
  166. uncountable/types/api/integrations/push_notification.py +49 -0
  167. uncountable/types/api/integrations/register_sockets_token.py +41 -0
  168. uncountable/types/api/listing/__init__.py +1 -0
  169. uncountable/types/api/listing/fetch_listing.py +58 -0
  170. uncountable/types/api/material_families/__init__.py +1 -0
  171. uncountable/types/api/material_families/update_entity_material_families.py +47 -0
  172. uncountable/types/api/notebooks/__init__.py +1 -0
  173. uncountable/types/api/notebooks/add_notebook_content.py +119 -0
  174. uncountable/types/api/outputs/get_output_data.py +32 -17
  175. uncountable/types/api/outputs/get_output_names.py +18 -9
  176. uncountable/types/api/outputs/get_output_organization.py +173 -0
  177. uncountable/types/api/outputs/resolve_output_conditions.py +23 -11
  178. uncountable/types/api/permissions/set_core_permissions.py +31 -15
  179. uncountable/types/api/project/get_projects.py +20 -11
  180. uncountable/types/api/project/get_projects_data.py +23 -14
  181. uncountable/types/api/recipe_links/create_recipe_link.py +17 -10
  182. uncountable/types/api/recipe_links/remove_recipe_link.py +45 -0
  183. uncountable/types/api/recipe_metadata/get_recipe_metadata_data.py +19 -10
  184. uncountable/types/api/recipes/add_recipe_to_project.py +42 -0
  185. uncountable/types/api/recipes/add_time_series_data.py +64 -0
  186. uncountable/types/api/recipes/archive_recipes.py +14 -7
  187. uncountable/types/api/recipes/associate_recipe_as_input.py +16 -8
  188. uncountable/types/api/recipes/associate_recipe_as_lot.py +14 -7
  189. uncountable/types/api/recipes/clear_recipe_outputs.py +42 -0
  190. uncountable/types/api/recipes/create_mix_order.py +44 -0
  191. uncountable/types/api/recipes/create_recipe.py +21 -14
  192. uncountable/types/api/recipes/create_recipes.py +25 -13
  193. uncountable/types/api/recipes/disassociate_recipe_as_input.py +14 -7
  194. uncountable/types/api/recipes/edit_recipe_inputs.py +208 -19
  195. uncountable/types/api/recipes/get_column_calculation_values.py +57 -0
  196. uncountable/types/api/recipes/get_curve.py +15 -9
  197. uncountable/types/api/recipes/get_recipe_calculations.py +17 -11
  198. uncountable/types/api/recipes/get_recipe_links.py +14 -8
  199. uncountable/types/api/recipes/get_recipe_names.py +16 -7
  200. uncountable/types/api/recipes/get_recipe_output_metadata.py +16 -10
  201. uncountable/types/api/recipes/get_recipes_data.py +96 -45
  202. uncountable/types/api/recipes/lock_recipes.py +64 -0
  203. uncountable/types/api/recipes/remove_recipe_from_project.py +42 -0
  204. uncountable/types/api/recipes/set_recipe_inputs.py +19 -13
  205. uncountable/types/api/recipes/set_recipe_metadata.py +14 -7
  206. uncountable/types/api/recipes/set_recipe_output_annotations.py +114 -0
  207. uncountable/types/api/recipes/set_recipe_output_file.py +55 -0
  208. uncountable/types/api/recipes/set_recipe_outputs.py +40 -15
  209. uncountable/types/api/recipes/set_recipe_tags.py +30 -13
  210. uncountable/types/api/recipes/set_recipe_total.py +59 -0
  211. uncountable/types/api/recipes/unarchive_recipes.py +41 -0
  212. uncountable/types/api/recipes/unlock_recipes.py +51 -0
  213. uncountable/types/api/runsheet/__init__.py +1 -0
  214. uncountable/types/api/runsheet/complete_async_upload.py +41 -0
  215. uncountable/types/api/triggers/run_trigger.py +15 -8
  216. uncountable/types/api/uploader/__init__.py +1 -0
  217. uncountable/types/api/uploader/complete_async_parse.py +46 -0
  218. uncountable/types/api/uploader/invoke_uploader.py +46 -0
  219. uncountable/types/api/user/__init__.py +1 -0
  220. uncountable/types/api/user/get_current_user_info.py +40 -0
  221. uncountable/types/async_batch.py +8 -52
  222. uncountable/types/async_batch_processor.py +694 -18
  223. uncountable/types/async_batch_t.py +108 -0
  224. uncountable/types/async_jobs.py +8 -0
  225. uncountable/types/async_jobs_t.py +52 -0
  226. uncountable/types/auth_retrieval.py +11 -0
  227. uncountable/types/auth_retrieval_t.py +75 -0
  228. uncountable/types/base.py +5 -80
  229. uncountable/types/base_t.py +87 -0
  230. uncountable/types/calculations.py +3 -19
  231. uncountable/types/calculations_t.py +26 -0
  232. uncountable/types/chemical_structure.py +3 -23
  233. uncountable/types/chemical_structure_t.py +28 -0
  234. uncountable/types/client_base.py +1170 -88
  235. uncountable/types/client_config.py +8 -0
  236. uncountable/types/client_config_t.py +36 -0
  237. uncountable/types/curves.py +5 -43
  238. uncountable/types/curves_t.py +50 -0
  239. uncountable/types/data.py +12 -0
  240. uncountable/types/data_t.py +103 -0
  241. uncountable/types/entity.py +8 -270
  242. uncountable/types/entity_t.py +446 -0
  243. uncountable/types/experiment_groups.py +3 -19
  244. uncountable/types/experiment_groups_t.py +26 -0
  245. uncountable/types/exports.py +8 -0
  246. uncountable/types/exports_t.py +34 -0
  247. uncountable/types/field_values.py +25 -61
  248. uncountable/types/field_values_t.py +302 -0
  249. uncountable/types/fields.py +3 -20
  250. uncountable/types/fields_t.py +27 -0
  251. uncountable/types/generic_upload.py +14 -0
  252. uncountable/types/generic_upload_t.py +119 -0
  253. uncountable/types/id_source.py +7 -45
  254. uncountable/types/id_source_t.py +68 -0
  255. uncountable/types/identifier.py +6 -50
  256. uncountable/types/identifier_t.py +62 -0
  257. uncountable/types/input_attributes.py +3 -25
  258. uncountable/types/input_attributes_t.py +29 -0
  259. uncountable/types/inputs.py +6 -57
  260. uncountable/types/inputs_t.py +82 -0
  261. uncountable/types/integration_server.py +8 -0
  262. uncountable/types/integration_server_t.py +46 -0
  263. uncountable/types/integration_session.py +10 -0
  264. uncountable/types/integration_session_t.py +60 -0
  265. uncountable/types/integrations.py +10 -0
  266. uncountable/types/integrations_t.py +62 -0
  267. uncountable/types/job_definition.py +28 -0
  268. uncountable/types/job_definition_t.py +285 -0
  269. uncountable/types/listing.py +9 -0
  270. uncountable/types/listing_t.py +51 -0
  271. uncountable/types/notices.py +8 -0
  272. uncountable/types/notices_t.py +37 -0
  273. uncountable/types/notifications.py +11 -0
  274. uncountable/types/notifications_t.py +74 -0
  275. uncountable/types/outputs.py +3 -22
  276. uncountable/types/outputs_t.py +29 -0
  277. uncountable/types/overrides.py +9 -0
  278. uncountable/types/overrides_t.py +49 -0
  279. uncountable/types/permissions.py +3 -42
  280. uncountable/types/permissions_t.py +45 -0
  281. uncountable/types/phases.py +3 -19
  282. uncountable/types/phases_t.py +26 -0
  283. uncountable/types/post_base.py +3 -26
  284. uncountable/types/post_base_t.py +29 -0
  285. uncountable/types/queued_job.py +17 -0
  286. uncountable/types/queued_job_t.py +140 -0
  287. uncountable/types/recipe_identifiers.py +7 -58
  288. uncountable/types/recipe_identifiers_t.py +75 -0
  289. uncountable/types/recipe_inputs.py +4 -26
  290. uncountable/types/recipe_inputs_t.py +29 -0
  291. uncountable/types/recipe_links.py +4 -46
  292. uncountable/types/recipe_links_t.py +53 -0
  293. uncountable/types/recipe_metadata.py +5 -48
  294. uncountable/types/recipe_metadata_t.py +57 -0
  295. uncountable/types/recipe_output_metadata.py +3 -20
  296. uncountable/types/recipe_output_metadata_t.py +27 -0
  297. uncountable/types/recipe_tags.py +3 -19
  298. uncountable/types/recipe_tags_t.py +26 -0
  299. uncountable/types/recipe_workflow_steps.py +9 -73
  300. uncountable/types/recipe_workflow_steps_t.py +95 -0
  301. uncountable/types/recipes.py +7 -0
  302. uncountable/types/recipes_t.py +25 -0
  303. uncountable/types/response.py +3 -21
  304. uncountable/types/response_t.py +26 -0
  305. uncountable/types/secret_retrieval.py +11 -0
  306. uncountable/types/secret_retrieval_t.py +75 -0
  307. uncountable/types/sockets.py +20 -0
  308. uncountable/types/sockets_t.py +169 -0
  309. uncountable/types/structured_filters.py +25 -0
  310. uncountable/types/structured_filters_t.py +248 -0
  311. uncountable/types/units.py +3 -19
  312. uncountable/types/units_t.py +26 -0
  313. uncountable/types/uploader.py +24 -0
  314. uncountable/types/uploader_t.py +222 -0
  315. uncountable/types/users.py +3 -20
  316. uncountable/types/users_t.py +27 -0
  317. uncountable/types/webhook_job.py +9 -0
  318. uncountable/types/webhook_job_t.py +48 -0
  319. uncountable/types/workflows.py +4 -28
  320. uncountable/types/workflows_t.py +38 -0
  321. uncountablepythonsdk-0.0.131.dist-info/METADATA +64 -0
  322. uncountablepythonsdk-0.0.131.dist-info/RECORD +363 -0
  323. {UncountablePythonSDK-0.0.24.dist-info → uncountablepythonsdk-0.0.131.dist-info}/WHEEL +1 -1
  324. {UncountablePythonSDK-0.0.24.dist-info → uncountablepythonsdk-0.0.131.dist-info}/top_level.txt +0 -1
  325. UncountablePythonSDK-0.0.24.dist-info/METADATA +0 -47
  326. UncountablePythonSDK-0.0.24.dist-info/RECORD +0 -216
  327. docs/quickstart.md +0 -19
  328. examples/recipe-import/importer.py +0 -39
  329. type_spec/external/api/batch/execute_batch.yaml +0 -56
  330. type_spec/external/api/batch/execute_batch_load_async.yaml +0 -18
  331. type_spec/external/api/chemical/convert_chemical_formats.yaml +0 -33
  332. type_spec/external/api/entity/create_entities.yaml +0 -45
  333. type_spec/external/api/entity/create_entity.yaml +0 -51
  334. type_spec/external/api/entity/get_entities_data.yaml +0 -29
  335. type_spec/external/api/entity/list_entities.yaml +0 -52
  336. type_spec/external/api/entity/resolve_entity_ids.yaml +0 -29
  337. type_spec/external/api/entity/set_values.yaml +0 -18
  338. type_spec/external/api/entity/transition_entity_phase.yaml +0 -44
  339. type_spec/external/api/id_source/list_id_source.yaml +0 -35
  340. type_spec/external/api/id_source/match_id_source.yaml +0 -32
  341. type_spec/external/api/input_groups/get_input_group_names.yaml +0 -29
  342. type_spec/external/api/inputs/create_inputs.yaml +0 -48
  343. type_spec/external/api/inputs/get_input_data.yaml +0 -95
  344. type_spec/external/api/inputs/get_input_names.yaml +0 -38
  345. type_spec/external/api/inputs/get_inputs_data.yaml +0 -82
  346. type_spec/external/api/inputs/set_input_attribute_values.yaml +0 -33
  347. type_spec/external/api/outputs/get_output_data.yaml +0 -92
  348. type_spec/external/api/outputs/get_output_names.yaml +0 -35
  349. type_spec/external/api/outputs/resolve_output_conditions.yaml +0 -50
  350. type_spec/external/api/permissions/set_core_permissions.yaml +0 -69
  351. type_spec/external/api/project/get_projects.yaml +0 -42
  352. type_spec/external/api/project/get_projects_data.yaml +0 -50
  353. type_spec/external/api/recipe_links/create_recipe_link.yaml +0 -25
  354. type_spec/external/api/recipe_metadata/get_recipe_metadata_data.yaml +0 -41
  355. type_spec/external/api/recipes/archive_recipes.yaml +0 -20
  356. type_spec/external/api/recipes/associate_recipe_as_input.yaml +0 -19
  357. type_spec/external/api/recipes/associate_recipe_as_lot.yaml +0 -19
  358. type_spec/external/api/recipes/create_recipe.yaml +0 -39
  359. type_spec/external/api/recipes/create_recipes.yaml +0 -47
  360. type_spec/external/api/recipes/disassociate_recipe_as_input.yaml +0 -16
  361. type_spec/external/api/recipes/edit_recipe_inputs.yaml +0 -85
  362. type_spec/external/api/recipes/get_curve.yaml +0 -21
  363. type_spec/external/api/recipes/get_recipe_calculations.yaml +0 -39
  364. type_spec/external/api/recipes/get_recipe_links.yaml +0 -26
  365. type_spec/external/api/recipes/get_recipe_names.yaml +0 -29
  366. type_spec/external/api/recipes/get_recipe_output_metadata.yaml +0 -36
  367. type_spec/external/api/recipes/get_recipes_data.yaml +0 -244
  368. type_spec/external/api/recipes/set_recipe_inputs.yaml +0 -42
  369. type_spec/external/api/recipes/set_recipe_metadata.yaml +0 -20
  370. type_spec/external/api/recipes/set_recipe_outputs.yaml +0 -52
  371. type_spec/external/api/recipes/set_recipe_tags.yaml +0 -62
  372. type_spec/external/api/triggers/run_trigger.yaml +0 -18
  373. uncountable/integration/types.py +0 -89
@@ -0,0 +1,142 @@
1
+ import argparse
2
+
3
+ from dateutil import tz
4
+ from opentelemetry.trace import get_current_span
5
+ from tabulate import tabulate
6
+
7
+ from uncountable.core.environment import get_local_admin_server_port
8
+ from uncountable.integration.queue_runner.command_server.command_client import (
9
+ send_job_queue_message,
10
+ send_list_queued_jobs_message,
11
+ send_retry_job_message,
12
+ )
13
+ from uncountable.integration.telemetry import Logger
14
+ from uncountable.types import queued_job_t
15
+
16
+
17
+ def register_enqueue_job_parser(
18
+ sub_parser_manager: argparse._SubParsersAction,
19
+ parents: list[argparse.ArgumentParser],
20
+ ) -> None:
21
+ run_parser = sub_parser_manager.add_parser(
22
+ "run",
23
+ parents=parents,
24
+ help="Process a job with a given host and job ID",
25
+ description="Process a job with a given host and job ID",
26
+ )
27
+ run_parser.add_argument("job_id", type=str, help="The ID of the job to process")
28
+
29
+ def _handle_enqueue_job(args: argparse.Namespace) -> None:
30
+ send_job_queue_message(
31
+ job_ref_name=args.job_id,
32
+ payload=queued_job_t.QueuedJobPayload(
33
+ invocation_context=queued_job_t.InvocationContextManual()
34
+ ),
35
+ host=args.host,
36
+ port=get_local_admin_server_port(),
37
+ )
38
+
39
+ run_parser.set_defaults(func=_handle_enqueue_job)
40
+
41
+
42
+ def register_list_queued_jobs(
43
+ sub_parser_manager: argparse._SubParsersAction,
44
+ parents: list[argparse.ArgumentParser],
45
+ ) -> None:
46
+ list_queued_jobs_parser = sub_parser_manager.add_parser(
47
+ "list-queued-jobs",
48
+ parents=parents,
49
+ help="List all jobs queued on the integration server",
50
+ description="List all jobs queued on the integration server",
51
+ )
52
+
53
+ list_queued_jobs_parser.add_argument(
54
+ "--offset",
55
+ type=int,
56
+ default=0,
57
+ help="Number of jobs to skip. Should be non-negative.",
58
+ )
59
+ list_queued_jobs_parser.add_argument(
60
+ "--limit",
61
+ type=int,
62
+ default=100,
63
+ help="A number between 1 and 100 specifying the number of jobs to return in the result set.",
64
+ )
65
+
66
+ def _handle_list_queued_jobs(args: argparse.Namespace) -> None:
67
+ queued_jobs = send_list_queued_jobs_message(
68
+ offset=args.offset,
69
+ limit=args.limit,
70
+ host=args.host,
71
+ port=get_local_admin_server_port(),
72
+ )
73
+
74
+ headers = ["UUID", "Job Ref Name", "Attempts", "Status", "Submitted At"]
75
+ rows = [
76
+ [
77
+ job.uuid,
78
+ job.job_ref_name,
79
+ job.num_attempts,
80
+ job.status,
81
+ job.submitted_at.ToDatetime(tz.UTC).astimezone(tz.tzlocal()),
82
+ ]
83
+ for job in queued_jobs
84
+ ]
85
+ print(tabulate(rows, headers=headers, tablefmt="grid"))
86
+
87
+ list_queued_jobs_parser.set_defaults(func=_handle_list_queued_jobs)
88
+
89
+
90
+ def register_retry_job_parser(
91
+ sub_parser_manager: argparse._SubParsersAction,
92
+ parents: list[argparse.ArgumentParser],
93
+ ) -> None:
94
+ retry_failed_jobs_parser = sub_parser_manager.add_parser(
95
+ "retry-job",
96
+ parents=parents,
97
+ help="Retry failed job on the integration server",
98
+ description="Retry failed job on the integration server",
99
+ )
100
+
101
+ retry_failed_jobs_parser.add_argument(
102
+ "job_uuid", type=str, help="The uuid of the job to retry"
103
+ )
104
+
105
+ def _handle_retry_job(args: argparse.Namespace) -> None:
106
+ send_retry_job_message(
107
+ job_uuid=args.job_uuid,
108
+ host=args.host,
109
+ port=get_local_admin_server_port(),
110
+ )
111
+
112
+ retry_failed_jobs_parser.set_defaults(func=_handle_retry_job)
113
+
114
+
115
+ def main() -> None:
116
+ logger = Logger(get_current_span())
117
+
118
+ main_parser = argparse.ArgumentParser(
119
+ description="Execute a given integrations server command."
120
+ )
121
+
122
+ base_parser = argparse.ArgumentParser(add_help=False)
123
+ base_parser.add_argument(
124
+ "--host", type=str, default="localhost", nargs="?", help="The host to run on"
125
+ )
126
+
127
+ subparser_action = main_parser.add_subparsers(
128
+ dest="command",
129
+ required=True,
130
+ help="The command to execute (e.g., 'run')",
131
+ )
132
+
133
+ register_enqueue_job_parser(subparser_action, parents=[base_parser])
134
+ register_retry_job_parser(subparser_action, parents=[base_parser])
135
+ register_list_queued_jobs(subparser_action, parents=[base_parser])
136
+
137
+ args = main_parser.parse_args()
138
+ with logger.push_scope(args.command):
139
+ args.func(args)
140
+
141
+
142
+ main()
@@ -1,35 +1,51 @@
1
- import os
2
- from typing import assert_never
3
-
4
- from uncountable.core.client import AuthDetailsApiKey, Client
5
- from uncountable.integration.types import (
6
- AuthRetrievalEnv,
1
+ from uncountable.core import AuthDetailsApiKey, Client
2
+ from uncountable.core.client import ClientConfig
3
+ from uncountable.core.types import AuthDetailsAll, AuthDetailsOAuth
4
+ from uncountable.integration.secret_retrieval.retrieve_secret import retrieve_secret
5
+ from uncountable.integration.telemetry import JobLogger
6
+ from uncountable.types import auth_retrieval_t
7
+ from uncountable.types.job_definition_t import (
7
8
  ProfileMetadata,
8
9
  )
9
10
 
10
11
 
11
- def _get_env_var(name: str) -> str:
12
- value = os.getenv(name)
13
- if value is None:
14
- raise Exception(f"environment variable {name} is missing")
15
- return value
16
-
17
-
18
- def construct_uncountable_client(profile_meta: ProfileMetadata) -> Client:
12
+ def _construct_auth_details(profile_meta: ProfileMetadata) -> AuthDetailsAll:
19
13
  match profile_meta.auth_retrieval:
20
- case AuthRetrievalEnv():
21
- api_id = _get_env_var(f"UNC_PROFILE_{profile_meta.name.upper()}_API_ID")
22
- api_secret_key = _get_env_var(
23
- f"UNC_PROFILE_{profile_meta.name.upper()}_API_SECRET_KEY"
14
+ case auth_retrieval_t.AuthRetrievalOAuth():
15
+ refresh_token = retrieve_secret(
16
+ profile_meta.auth_retrieval.refresh_token_secret,
17
+ profile_metadata=profile_meta,
18
+ )
19
+ return AuthDetailsOAuth(refresh_token=refresh_token)
20
+ case auth_retrieval_t.AuthRetrievalBasic():
21
+ api_id = retrieve_secret(
22
+ profile_meta.auth_retrieval.api_id_secret, profile_metadata=profile_meta
23
+ )
24
+ api_key = retrieve_secret(
25
+ profile_meta.auth_retrieval.api_key_secret,
26
+ profile_metadata=profile_meta,
24
27
  )
25
28
 
26
- assert api_id is not None
27
- assert api_secret_key is not None
29
+ return AuthDetailsApiKey(api_id=api_id, api_secret_key=api_key)
28
30
 
29
- return Client(
30
- base_url=profile_meta.base_url,
31
- auth_details=AuthDetailsApiKey(
32
- api_id=api_id, api_secret_key=api_secret_key
33
- ),
34
- )
35
- assert_never(profile_meta.auth_retrieval)
31
+
32
+ def _construct_client_config(
33
+ profile_meta: ProfileMetadata, job_logger: JobLogger
34
+ ) -> ClientConfig | None:
35
+ if profile_meta.client_options is None:
36
+ return None
37
+ return ClientConfig(
38
+ allow_insecure_tls=profile_meta.client_options.allow_insecure_tls,
39
+ extra_headers=profile_meta.client_options.extra_headers,
40
+ logger=job_logger,
41
+ )
42
+
43
+
44
+ def construct_uncountable_client(
45
+ profile_meta: ProfileMetadata, logger: JobLogger
46
+ ) -> Client:
47
+ return Client(
48
+ base_url=profile_meta.base_url,
49
+ auth_details=_construct_auth_details(profile_meta),
50
+ config=_construct_client_config(profile_meta, logger),
51
+ )
@@ -1,10 +1,12 @@
1
1
  from dataclasses import dataclass
2
2
 
3
3
  from pkgs.argument_parser import CachedParser
4
- from uncountable.integration.construct_client import construct_uncountable_client
5
- from uncountable.integration.executors.script_executor import resolve_script_executor
6
- from uncountable.integration.job import CronJobArguments
7
- from uncountable.integration.types import JobDefinition, ProfileMetadata
4
+ from uncountable.core.environment import get_local_admin_server_port
5
+ from uncountable.integration.queue_runner.command_server.command_client import (
6
+ send_job_queue_message,
7
+ )
8
+ from uncountable.types import queued_job_t
9
+ from uncountable.types.job_definition_t import JobDefinition, ProfileMetadata
8
10
 
9
11
 
10
12
  @dataclass
@@ -18,11 +20,10 @@ cron_args_parser = CachedParser(CronJobArgs)
18
20
 
19
21
  def cron_job_executor(**kwargs: dict) -> None:
20
22
  args_passed = cron_args_parser.parse_storage(kwargs)
21
- args = CronJobArguments(
22
- job_definition=args_passed.definition,
23
- client=construct_uncountable_client(profile_meta=args_passed.profile_metadata),
23
+ send_job_queue_message(
24
+ job_ref_name=args_passed.definition.id,
25
+ payload=queued_job_t.QueuedJobPayload(
26
+ invocation_context=queued_job_t.InvocationContextCron()
27
+ ),
28
+ port=get_local_admin_server_port(),
24
29
  )
25
-
26
- job = resolve_script_executor(args_passed.definition.executor, args_passed.profile_metadata)
27
-
28
- job.run(args)
@@ -1,8 +1,18 @@
1
1
  import os
2
+ from enum import StrEnum
3
+
2
4
  from sqlalchemy import create_engine
3
5
  from sqlalchemy.engine.base import Engine
4
6
 
5
7
 
6
- def create_db_engine() -> Engine:
7
- return create_engine(os.environ["UNC_SQLITE_URI"])
8
+ class IntegrationDBService(StrEnum):
9
+ CRON = "cron"
10
+ RUNNER = "runner"
11
+
8
12
 
13
+ def create_db_engine(service: IntegrationDBService) -> Engine:
14
+ match service:
15
+ case IntegrationDBService.CRON:
16
+ return create_engine(os.environ["UNC_CRON_SQLITE_URI"])
17
+ case IntegrationDBService.RUNNER:
18
+ return create_engine(os.environ["UNC_RUNNER_SQLITE_URI"])
@@ -0,0 +1,25 @@
1
+ from contextlib import _GeneratorContextManager, contextmanager
2
+ from typing import Callable, Generator
3
+
4
+ from sqlalchemy.engine import Engine
5
+ from sqlalchemy.orm import Session, sessionmaker
6
+
7
+ DBSessionMaker = Callable[[], _GeneratorContextManager[Session]]
8
+
9
+
10
+ def get_session_maker(engine: Engine) -> DBSessionMaker:
11
+ session_maker = sessionmaker(bind=engine)
12
+
13
+ @contextmanager
14
+ def session_manager() -> Generator[Session, None, None]:
15
+ session = session_maker()
16
+ try:
17
+ yield session
18
+ session.commit()
19
+ except Exception:
20
+ session.rollback()
21
+ raise
22
+ finally:
23
+ session.close()
24
+
25
+ return session_manager
@@ -1,41 +1,11 @@
1
- import os
2
- from importlib import resources
3
-
1
+ from uncountable.integration.db.connect import IntegrationDBService, create_db_engine
2
+ from uncountable.integration.scan_profiles import load_profiles
4
3
  from uncountable.integration.server import IntegrationServer
5
- from uncountable.integration.types import ProfileDefinition
6
- from pkgs.argument_parser import CachedParser
7
- from uncountable.integration.db.connect import create_db_engine
8
-
9
-
10
- profile_parser = CachedParser(ProfileDefinition)
11
4
 
12
5
 
13
6
  def main() -> None:
14
- profiles_module = os.environ["UNC_PROFILES_MODULE"]
15
- with IntegrationServer(create_db_engine()) as server:
16
- # TODO: Loop through all job spec yaml files and call server.add_job
17
- profiles = [
18
- entry
19
- for entry in resources.files(profiles_module).iterdir()
20
- if entry.is_dir()
21
- ]
22
- for profile in profiles:
23
- profile_name = profile.name
24
- try:
25
- profile = profile_parser.parse_yaml_resource(
26
- package=".".join([profiles_module, profile_name]),
27
- resource="profile.yaml",
28
- )
29
- except FileNotFoundError as e:
30
- print("WARN: profile.yaml not found", e)
31
- continue
32
- server.register_profile(
33
- profile_name=profile_name,
34
- base_url=profile.base_url,
35
- auth_retrieval=profile.auth_retrieval,
36
- jobs=profile.jobs,
37
- )
38
-
7
+ with IntegrationServer(create_db_engine(IntegrationDBService.CRON)) as server:
8
+ server.register_jobs(load_profiles())
39
9
  server.serve_forever()
40
10
 
41
11
 
@@ -0,0 +1,147 @@
1
+ from typing import assert_never
2
+
3
+ from uncountable.core.client import Client
4
+ from uncountable.integration.executors.generic_upload_executor import GenericUploadJob
5
+ from uncountable.integration.executors.script_executor import resolve_script_executor
6
+ from uncountable.integration.job import Job, JobArguments
7
+ from uncountable.types import (
8
+ async_jobs_t,
9
+ entity_t,
10
+ field_values_t,
11
+ identifier_t,
12
+ integration_server_t,
13
+ job_definition_t,
14
+ transition_entity_phase_t,
15
+ )
16
+
17
+
18
+ def resolve_executor(
19
+ job_executor: job_definition_t.JobExecutor,
20
+ profile_metadata: job_definition_t.ProfileMetadata,
21
+ ) -> Job:
22
+ match job_executor:
23
+ case job_definition_t.JobExecutorScript():
24
+ return resolve_script_executor(
25
+ job_executor, profile_metadata=profile_metadata
26
+ )
27
+ case job_definition_t.JobExecutorGenericUpload():
28
+ return GenericUploadJob(
29
+ remote_directories=job_executor.remote_directories,
30
+ upload_strategy=job_executor.upload_strategy,
31
+ data_source=job_executor.data_source,
32
+ )
33
+ assert_never(job_executor)
34
+
35
+
36
+ def _create_run_entity(
37
+ *,
38
+ client: Client,
39
+ logging_settings: job_definition_t.JobLoggingSettings,
40
+ job_uuid: str,
41
+ ) -> entity_t.Entity:
42
+ run_entity = client.create_entity(
43
+ entity_type=entity_t.EntityType.ASYNC_JOB,
44
+ definition_key=identifier_t.IdentifierKeyRefName(
45
+ ref_name="unc_integration_server_run_definition"
46
+ ),
47
+ field_values=[
48
+ field_values_t.FieldRefNameValue(
49
+ field_ref_name=async_jobs_t.ASYNC_JOB_TYPE_FIELD_REF_NAME,
50
+ value=async_jobs_t.AsyncJobType.INTEGRATION_SERVER_RUN,
51
+ ),
52
+ field_values_t.FieldRefNameValue(
53
+ field_ref_name=async_jobs_t.ASYNC_JOB_STATUS_FIELD_REF_NAME,
54
+ value=async_jobs_t.AsyncJobStatus.IN_PROGRESS,
55
+ ),
56
+ field_values_t.FieldRefNameValue(
57
+ field_ref_name=integration_server_t.INTEGRATION_SERVER_RUN_UUID_FIELD_REF_NAME,
58
+ value=job_uuid,
59
+ ),
60
+ ],
61
+ ).entity
62
+ client.transition_entity_phase(
63
+ entity=run_entity,
64
+ transition=transition_entity_phase_t.TransitionIdentifierPhases(
65
+ phase_from_key=identifier_t.IdentifierKeyRefName(
66
+ ref_name="unc_integration_server_run__queued"
67
+ ),
68
+ phase_to_key=identifier_t.IdentifierKeyRefName(
69
+ ref_name="unc_integration_server_run__started"
70
+ ),
71
+ ),
72
+ )
73
+ if logging_settings.share_with_user_groups is not None:
74
+ client.grant_entity_permissions(
75
+ entity_type=entity_t.EntityType.ASYNC_JOB,
76
+ entity_key=identifier_t.IdentifierKeyId(id=run_entity.id),
77
+ permission_types=[
78
+ entity_t.EntityPermissionType.READ,
79
+ entity_t.EntityPermissionType.WRITE,
80
+ ],
81
+ user_group_keys=logging_settings.share_with_user_groups,
82
+ )
83
+ return run_entity
84
+
85
+
86
+ def execute_job(
87
+ *,
88
+ job_definition: job_definition_t.JobDefinition,
89
+ profile_metadata: job_definition_t.ProfileMetadata,
90
+ args: JobArguments,
91
+ ) -> job_definition_t.JobResult:
92
+ with args.logger.push_scope(job_definition.name) as job_logger:
93
+ job = resolve_executor(job_definition.executor, profile_metadata)
94
+
95
+ job_logger.log_info("running job")
96
+
97
+ run_entity: entity_t.Entity | None = None
98
+ try:
99
+ if (
100
+ job_definition.logging_settings is not None
101
+ and job_definition.logging_settings.enabled
102
+ ):
103
+ run_entity = _create_run_entity(
104
+ client=args.client,
105
+ logging_settings=job_definition.logging_settings,
106
+ job_uuid=args.job_uuid,
107
+ )
108
+ result = job.run_outer(args=args)
109
+ except Exception as e:
110
+ job_logger.log_exception(e)
111
+ if run_entity is not None:
112
+ args.client.set_values(
113
+ entity=run_entity,
114
+ values=[
115
+ field_values_t.ArgumentValueRefName(
116
+ field_ref_name=async_jobs_t.ASYNC_JOB_STATUS_FIELD_REF_NAME,
117
+ value=async_jobs_t.AsyncJobStatus.ERROR,
118
+ ),
119
+ ],
120
+ )
121
+ return job_definition_t.JobResult(success=False)
122
+
123
+ if args.batch_processor.current_queue_size() != 0:
124
+ args.batch_processor.send()
125
+
126
+ submitted_batch_job_ids = args.batch_processor.get_submitted_job_ids()
127
+ job_logger.log_info(
128
+ "completed job",
129
+ attributes={
130
+ "submitted_batch_job_ids": submitted_batch_job_ids,
131
+ "success": result.success,
132
+ },
133
+ )
134
+ if run_entity is not None:
135
+ args.client.set_values(
136
+ entity=run_entity,
137
+ values=[
138
+ field_values_t.ArgumentValueRefName(
139
+ field_ref_name=async_jobs_t.ASYNC_JOB_STATUS_FIELD_REF_NAME,
140
+ value=async_jobs_t.AsyncJobStatus.COMPLETED
141
+ if result.success
142
+ else async_jobs_t.AsyncJobStatus.ERROR,
143
+ ),
144
+ ],
145
+ )
146
+
147
+ return result