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
@@ -1,24 +1,42 @@
1
1
  import io
2
+ import typing
2
3
  from dataclasses import dataclass, field
3
4
 
4
5
  from . import builder, util
5
- from .config import TypeScriptConfig
6
+ from .builder_types import CrossOutputPaths
6
7
 
7
8
  INDENT = " "
8
9
 
9
10
  MODIFY_NOTICE = "// DO NOT MODIFY -- This file is generated by type_spec\n"
10
11
 
12
+ base_name_map = {
13
+ builder.BaseTypeName.s_boolean: "boolean",
14
+ builder.BaseTypeName.s_date: "string", # IMPROVE: Aliased DateStr
15
+ builder.BaseTypeName.s_date_time: "string", # IMPROVE: Aliased DateTimeStr
16
+ # Decimal's are marked as to_string_values thus are strings in the front-end
17
+ builder.BaseTypeName.s_decimal: "string",
18
+ builder.BaseTypeName.s_dict: "PartialRecord",
19
+ builder.BaseTypeName.s_integer: "number",
20
+ builder.BaseTypeName.s_lossy_decimal: "number",
21
+ builder.BaseTypeName.s_opaque_key: "string",
22
+ builder.BaseTypeName.s_none: "null",
23
+ builder.BaseTypeName.s_string: "string",
24
+ # UNC: global types
25
+ builder.BaseTypeName.s_json_value: "JsonValue",
26
+ }
27
+
11
28
 
12
29
  @dataclass(kw_only=True)
13
30
  class EmitTypescriptContext:
14
- config: TypeScriptConfig
15
31
  out: io.StringIO
16
32
  namespace: builder.SpecNamespace
17
33
  namespaces: set[builder.SpecNamespace] = field(default_factory=set)
34
+ cross_output_paths: CrossOutputPaths | None = None
35
+ api_endpoints: dict[builder.EndpointKey, builder.APIEndpointInfo]
18
36
 
19
37
 
20
38
  def ts_type_name(name: str) -> str:
21
- return "".join([x.capitalize() for x in name.split("_")])
39
+ return "".join([x.title() for x in name.split("_")])
22
40
 
23
41
 
24
42
  def resolve_namespace_ref(namespace: builder.SpecNamespace) -> str:
@@ -29,4 +47,275 @@ def ts_name(name: str, name_case: builder.NameCase) -> str:
29
47
  if name_case == builder.NameCase.preserve:
30
48
  return name
31
49
  bits = util.split_any_name(name)
32
- return "".join([bits[0], *[x.capitalize() for x in bits[1:]]])
50
+ return "".join([bits[0], *[x.title() for x in bits[1:]]])
51
+
52
+
53
+ def emit_value_ts(
54
+ ctx: EmitTypescriptContext,
55
+ stype: builder.SpecType,
56
+ value: typing.Any,
57
+ indent: int = 0,
58
+ ) -> str:
59
+ """Mimics emit_python even if not all types are used in TypeScript yet"""
60
+ literal = builder.unwrap_literal_type(stype)
61
+ if literal is not None:
62
+ return emit_value_ts(ctx, literal.value_type, literal.value)
63
+
64
+ if stype.is_base_type(builder.BaseTypeName.s_string):
65
+ assert isinstance(value, str)
66
+ return util.encode_common_string(value)
67
+ elif stype.is_base_type(builder.BaseTypeName.s_integer):
68
+ assert isinstance(value, int)
69
+ return str(value)
70
+ elif stype.is_base_type(builder.BaseTypeName.s_boolean):
71
+ assert isinstance(value, bool)
72
+ return "true" if value else "false"
73
+ elif stype.is_base_type(builder.BaseTypeName.s_lossy_decimal):
74
+ return str(value)
75
+ elif stype.is_base_type(builder.BaseTypeName.s_decimal):
76
+ return f"'{value}'"
77
+ elif isinstance(stype, builder.SpecTypeInstance):
78
+ if stype.defn_type.is_base_type(builder.BaseTypeName.s_list):
79
+ sub_type = stype.parameters[0]
80
+ return (
81
+ "[" + ", ".join([emit_value_ts(ctx, sub_type, x) for x in value]) + "]"
82
+ )
83
+
84
+ if stype.defn_type.is_base_type(builder.BaseTypeName.s_dict):
85
+ key_type = stype.parameters[0]
86
+ value_type = stype.parameters[1]
87
+
88
+ if not key_type.is_base_type(
89
+ builder.BaseTypeName.s_string
90
+ ) and not isinstance(key_type, builder.SpecTypeDefnStringEnum):
91
+ raise Exception("invalid dict keys -- dict keys must be string or enum")
92
+
93
+ return (
94
+ f"{{\n{INDENT * (indent + 1)}"
95
+ + f",\n{INDENT * (indent + 1)}".join(
96
+ (
97
+ f"[{emit_value_ts(ctx, key_type, dkey)}]: "
98
+ if not key_type.is_base_type(builder.BaseTypeName.s_string)
99
+ else f"{dkey}: "
100
+ )
101
+ + emit_value_ts(ctx, value_type, dvalue, indent=indent + 1)
102
+ for dkey, dvalue in value.items()
103
+ )
104
+ + f"\n{INDENT * (indent)}}}"
105
+ )
106
+
107
+ if stype.defn_type.is_base_type(builder.BaseTypeName.s_optional):
108
+ sub_type = stype.parameters[0]
109
+ if value is None:
110
+ return "null"
111
+ return emit_value_ts(ctx, sub_type, value)
112
+
113
+ elif isinstance(stype, builder.SpecTypeDefnStringEnum):
114
+ return f"{refer_to(ctx, stype)}.{ts_enum_name(value, stype.name_case)}"
115
+ elif isinstance(stype, builder.SpecTypeDefnObject):
116
+ assert isinstance(value, dict), (
117
+ f"Expected dict value for {stype.name} but got {value}"
118
+ )
119
+ obj_out = "{"
120
+ did_emit = False
121
+ for prop_name, prop in (stype.properties or {}).items():
122
+ if prop_name not in value and prop.has_default:
123
+ value_to_emit = prop.default
124
+ elif prop_name not in value:
125
+ continue
126
+ else:
127
+ value_to_emit = value[prop_name]
128
+ did_emit = True
129
+ typescript_name = ts_name(prop.name, prop.name_case)
130
+ obj_out += f"\n{INDENT * (indent + 1)}{typescript_name}: {emit_value_ts(ctx, prop.spec_type, value_to_emit, indent=indent + 1)},"
131
+ whitespace = f"\n{INDENT * indent}" if did_emit else ""
132
+ obj_out += f"{whitespace}}} as const"
133
+ return obj_out
134
+
135
+ raise Exception("invalid constant type", value, stype, type(stype))
136
+
137
+
138
+ def emit_constant_ts(ctx: EmitTypescriptContext, sconst: builder.SpecConstant) -> None:
139
+ ctx.out.write("\n\n")
140
+ ctx.out.write(MODIFY_NOTICE)
141
+ value = emit_value_ts(ctx, sconst.value_type, sconst.value)
142
+ const_name = sconst.name.upper()
143
+ ctx.out.write(f"export const {const_name} = {value}\n")
144
+
145
+
146
+ def emit_type_ts(ctx: EmitTypescriptContext, stype: builder.SpecType) -> None:
147
+ if not isinstance(stype, builder.SpecTypeDefn):
148
+ return
149
+
150
+ if stype.is_base or stype.is_predefined:
151
+ return
152
+
153
+ ctx.out.write("\n")
154
+ ctx.out.write(MODIFY_NOTICE)
155
+
156
+ if isinstance(stype, builder.SpecTypeDefnExternal):
157
+ assert not stype.is_exported, "expecting private names"
158
+ ctx.out.write("\n")
159
+ ctx.out.write(stype.external_map["ts"])
160
+ ctx.out.write("\n")
161
+ return
162
+
163
+ assert stype.is_exported, "expecting exported names"
164
+ if isinstance(stype, builder.SpecTypeDefnAlias):
165
+ ctx.out.write(f"export type {stype.name} = {refer_to(ctx, stype.alias)}\n")
166
+ return
167
+
168
+ if isinstance(stype, builder.SpecTypeDefnUnion):
169
+ ctx.out.write(
170
+ f"export type {stype.name} = {refer_to(ctx, stype.get_backing_type())}\n"
171
+ )
172
+ return
173
+
174
+ if isinstance(stype, builder.SpecTypeDefnStringEnum):
175
+ ctx.out.write(f"export enum {stype.name} {{\n")
176
+ assert stype.values
177
+ for name, entry in stype.values.items():
178
+ ctx.out.write(
179
+ f'{INDENT}{ts_enum_name(name, stype.name_case)} = "{entry.value}",\n'
180
+ )
181
+ ctx.out.write("}\n")
182
+ return
183
+
184
+ assert isinstance(stype, builder.SpecTypeDefnObject)
185
+ assert stype.base is not None
186
+
187
+ base_type = ""
188
+ if not stype.base.is_base:
189
+ base_type = f"{refer_to(ctx, stype.base)} & "
190
+
191
+ if stype.properties is None and base_type == "":
192
+ ctx.out.write(f"export type {stype.name} = TEmpty\n")
193
+ elif stype.properties is None:
194
+ ctx.out.write(f"export type {stype.name} = {base_type}{{}}\n")
195
+ else:
196
+ if isinstance(stype, builder.SpecTypeDefnObject) and len(stype.parameters) > 0:
197
+ full_type_name = f"{stype.name}<{', '.join(stype.parameters)}>"
198
+ else:
199
+ full_type_name = stype.name
200
+ ctx.out.write(f"export type {full_type_name} = {base_type}{{")
201
+ ctx.out.write("\n")
202
+ for prop in stype.properties.values():
203
+ ref_type = refer_to(ctx, prop.spec_type)
204
+ prop_name = ts_name(prop.name, prop.name_case)
205
+ if prop.has_default and not prop.parse_require:
206
+ # For now, we'll assume the generated types with defaults are meant as
207
+ # arguments, thus treat like extant==missing
208
+ # IMPROVE: if we can decide they are meant as output instead, then
209
+ # they should be marked as required
210
+ ctx.out.write(f"{INDENT}{prop_name}?: {ref_type}")
211
+ elif prop.extant == builder.PropertyExtant.missing:
212
+ # Unlike optional below, missing does not imply null is possible. They
213
+ # treated distinctly.
214
+ ctx.out.write(f"{INDENT}{prop_name}?: {ref_type}")
215
+ elif prop.extant == builder.PropertyExtant.optional:
216
+ # Need to add in |null since Python side can produce null's right now
217
+ # IMPROVE: It would be better if the serializer could instead omit the None's
218
+ # Dropping the null should be forward compatible
219
+ ctx.out.write(f"{INDENT}{prop_name}?: {ref_type} | null")
220
+ else:
221
+ ctx.out.write(f"{INDENT}{prop_name}: {ref_type}")
222
+ ctx.out.write("\n")
223
+ ctx.out.write("}\n")
224
+
225
+
226
+ def refer_to(ctx: EmitTypescriptContext, stype: builder.SpecType) -> str:
227
+ return refer_to_impl(ctx, stype)[0]
228
+
229
+
230
+ def refer_to_impl(
231
+ ctx: EmitTypescriptContext, stype: builder.SpecType
232
+ ) -> tuple[str, bool]:
233
+ """
234
+ @return (string-specific, multiple-types)
235
+ """
236
+ if isinstance(stype, builder.SpecTypeInstance):
237
+ if stype.defn_type.name == builder.BaseTypeName.s_list:
238
+ spec, multi = refer_to_impl(ctx, stype.parameters[0])
239
+ return f"({spec})[]" if multi else f"{spec}[]", False
240
+ if stype.defn_type.name == builder.BaseTypeName.s_readonly_array:
241
+ spec, multi = refer_to_impl(ctx, stype.parameters[0])
242
+ return f"readonly ({spec})[]" if multi else f"readonly {spec}[]", False
243
+ if stype.defn_type.name == builder.BaseTypeName.s_union:
244
+ return (
245
+ f"({' | '.join([refer_to(ctx, p) for p in stype.parameters])})",
246
+ False,
247
+ )
248
+ if stype.defn_type.name == builder.BaseTypeName.s_literal:
249
+ parts = []
250
+ for parameter in stype.parameters:
251
+ assert isinstance(parameter, builder.SpecTypeLiteralWrapper)
252
+ parts.append(refer_to(ctx, parameter))
253
+ return f"({' | '.join(parts)})", False
254
+ if stype.defn_type.name == builder.BaseTypeName.s_optional:
255
+ return f"{refer_to(ctx, stype.parameters[0])} | null", True
256
+ if stype.defn_type.name == builder.BaseTypeName.s_tuple:
257
+ return f"[{', '.join([refer_to(ctx, p) for p in stype.parameters])}]", False
258
+ params = ", ".join([refer_to(ctx, p) for p in stype.parameters])
259
+ return f"{refer_to(ctx, stype.defn_type)}<{params}>", False
260
+
261
+ if isinstance(stype, builder.SpecTypeLiteralWrapper):
262
+ return emit_value_ts(ctx, stype.value_type, stype.value), False
263
+
264
+ if isinstance(stype, builder.SpecTypeGenericParameter):
265
+ return stype.name, False
266
+
267
+ assert isinstance(stype, builder.SpecTypeDefn)
268
+ if stype.is_base: # assume correct namespace
269
+ if stype.name == builder.BaseTypeName.s_list:
270
+ return "any[]", False # TODO: generic type
271
+ return base_name_map[builder.BaseTypeName(stype.name)], False
272
+
273
+ if stype.namespace == ctx.namespace:
274
+ return stype.name, False
275
+
276
+ ctx.namespaces.add(stype.namespace)
277
+ return f"{resolve_namespace_ref(stype.namespace)}.{stype.name}", False
278
+
279
+
280
+ def ts_enum_name(name: str, name_case: builder.NameCase) -> str:
281
+ if name_case == builder.NameCase.js_upper:
282
+ return name.upper()
283
+ return ts_name(name, name_case)
284
+
285
+
286
+ def resolve_namespace_name(namespace: builder.SpecNamespace) -> str:
287
+ return namespace.name
288
+
289
+
290
+ def emit_namespace_imports_ts(
291
+ namespaces: set[builder.SpecNamespace],
292
+ out: io.StringIO,
293
+ current_namespace: builder.SpecNamespace,
294
+ ) -> None:
295
+ for ns in sorted(
296
+ namespaces,
297
+ key=lambda name: resolve_namespace_name(name),
298
+ ):
299
+ import_as = resolve_namespace_ref(ns)
300
+ import_path = (
301
+ "./"
302
+ if len(current_namespace.path) == 1
303
+ else "../" * (len(current_namespace.path) - 1)
304
+ )
305
+ import_from = f"{import_path}{resolve_namespace_name(ns)}"
306
+ out.write(f'import * as {import_as} from "{import_from}"\n') # noqa: E501
307
+
308
+
309
+ def emit_namespace_imports_from_root_ts(
310
+ namespaces: set[builder.SpecNamespace],
311
+ out: io.StringIO,
312
+ root: str,
313
+ ) -> None:
314
+ for ns in sorted(
315
+ namespaces,
316
+ key=lambda name: resolve_namespace_name(name),
317
+ ):
318
+ import_as = resolve_namespace_ref(ns)
319
+ out.write(
320
+ f'import * as {import_as} from "{root}/{resolve_namespace_name(ns)}"\n'
321
+ ) # noqa: E501
@@ -1,12 +1,13 @@
1
1
  import os
2
2
  from collections.abc import Callable
3
3
  from io import StringIO
4
- from typing import Optional
5
4
 
6
- import yaml
7
5
  from shelljob import fs
8
6
 
7
+ from pkgs.serialization import yaml
8
+
9
9
  from .builder import SpecBuilder
10
+ from .builder_types import CrossOutputPaths
10
11
  from .config import Config
11
12
 
12
13
  ext_map = {
@@ -40,8 +41,23 @@ def find_and_handle_files(
40
41
  handler(file_name, file.read())
41
42
 
42
43
 
43
- def load_types(config: Config) -> Optional[SpecBuilder]:
44
- builder = SpecBuilder(api_endpoints=config.api_endpoint)
44
+ def load_types(config: Config) -> SpecBuilder | None:
45
+ if config.typescript is not None and config.python is not None:
46
+ cross_output_paths = CrossOutputPaths(
47
+ python_types_output=config.python.types_output,
48
+ typescript_types_output=config.typescript.types_output,
49
+ typescript_routes_output_by_endpoint=config.typescript.endpoint_to_routes_output,
50
+ typespec_files_input=config.type_spec_types,
51
+ # IMPROVE not sure how to know which one is the correct one in emit_typescript
52
+ )
53
+ else:
54
+ cross_output_paths = None
55
+
56
+ builder = SpecBuilder(
57
+ api_endpoints=config.api_endpoint,
58
+ top_namespace=config.top_namespace,
59
+ cross_output_paths=cross_output_paths,
60
+ )
45
61
 
46
62
  def handle_builder_add(
47
63
  file_name: str, file_content: str, handler: Callable[[str, str, str], None]
@@ -114,4 +130,3 @@ def load_types(config: Config) -> Optional[SpecBuilder]:
114
130
  return None
115
131
 
116
132
  return builder
117
- return True
@@ -0,0 +1,14 @@
1
+ NON_DISCRIMINATED_UNION_EXCEPTIONS = [
2
+ "generate_tool_parameters.UnionWithoutDiscrim",
3
+ "output_calculation_entities.ConditionParameterFilterCondition",
4
+ "output_parameters.AnalyticalMethodParameterOptions",
5
+ "output_parameters.AnalyticalMethodLinkedOptionValue",
6
+ "recipes_redirect.RecipesRedirectResult",
7
+ "value_spec.ResolvedPathAll",
8
+ "weighted_sum.WeightedSumEntities",
9
+ "workflows.WorkflowTotalDisplay",
10
+ "type_info.TypeFormActionConstraint",
11
+ "structured_loading.CompatibleFilterNode",
12
+ "structured_display_element.DisplayElementColumn",
13
+ "field_values.FieldValue",
14
+ ]
@@ -1,15 +1,23 @@
1
1
  from abc import ABC, abstractmethod
2
2
  from enum import StrEnum
3
- from typing import Optional
3
+
4
+ from pkgs.serialization_util import JsonValue
4
5
 
5
6
 
6
7
  class OpenAPIType(ABC):
7
8
  description: str | None = None
8
9
  nullable: bool = False
10
+ default: JsonValue
9
11
 
10
- def __init__(self, description: str | None = None, nullable: bool = False) -> None:
12
+ def __init__(
13
+ self,
14
+ description: str | None = None,
15
+ nullable: bool = False,
16
+ default: JsonValue = None,
17
+ ) -> None:
11
18
  self.description = description
12
19
  self.nullable = nullable
20
+ self.default = default
13
21
 
14
22
  @abstractmethod
15
23
  def asdict(self) -> dict[str, object]:
@@ -20,6 +28,8 @@ class OpenAPIType(ABC):
20
28
  emitted["description"] = self.description
21
29
  if self.nullable:
22
30
  emitted["nullable"] = self.nullable
31
+ if self.default is not None:
32
+ emitted["default"] = self.default
23
33
  return emitted
24
34
 
25
35
 
@@ -158,7 +168,7 @@ class OpenAPIObjectType(OpenAPIType):
158
168
  description: str | None = None,
159
169
  nullable: bool = False,
160
170
  *,
161
- property_desc: Optional[dict[str, str]] = None,
171
+ property_desc: dict[str, str] | None = None,
162
172
  ) -> None:
163
173
  self.properties = properties
164
174
  if property_desc is None:
@@ -213,13 +223,28 @@ class OpenAPIUnionType(OpenAPIType):
213
223
  base_types: list[OpenAPIType],
214
224
  description: str | None = None,
215
225
  nullable: bool = False,
226
+ discriminator: str | None = None,
227
+ discriminator_map: dict[str, OpenAPIRefType] | None = None,
216
228
  ) -> None:
217
229
  self.base_types = base_types
230
+ self._discriminator = discriminator
231
+ self._discriminator_map = discriminator_map
218
232
  super().__init__(description=description, nullable=nullable)
219
233
 
220
234
  def asdict(self) -> dict[str, object]:
221
235
  # TODO: use parents description and nullable
222
- return {"oneOf": [base_type.asdict() for base_type in self.base_types]}
236
+ return {
237
+ "oneOf": [base_type.asdict() for base_type in self.base_types],
238
+ "discriminator": {
239
+ "propertyName": self._discriminator,
240
+ "mapping": {
241
+ discriminator_value: base_type.source
242
+ for discriminator_value, base_type in self._discriminator_map.items()
243
+ },
244
+ }
245
+ if self._discriminator is not None and self._discriminator_map is not None
246
+ else None,
247
+ }
223
248
 
224
249
 
225
250
  class OpenAPIIntersectionType(OpenAPIType):
@@ -22,10 +22,16 @@ PureJsonScalar = Union[str, float, bool, None]
22
22
  # Regular expressions for identifying ref names and IDs. Ref names should be
23
23
  # using this regular expression as a constriant in the database.
24
24
  REF_NAME_REGEX = r"^[a-zA-Z0-9_/-]+$"
25
- # Does not support nonpositive integers at the moment.
26
- ID_REGEX = r"[1-9][0-9]{0,20}"
25
+ REF_NAME_STRICT_REGEX_STRING = "^[a-zA-Z_][a-zA-Z0-9_]*$"
26
+ REF_NAME_STRICT_REGEX = rf"{REF_NAME_STRICT_REGEX_STRING}"
27
+ # Ids matching a strict integer number are converted to integers
28
+ ID_REGEX = r"-?[1-9][0-9]{0,20}"
27
29
 
28
30
 
31
+ # ENABLE_SLOTS should be removed after slots have been tested locally
32
+ import os
33
+ ENABLE_SLOTS = os.environ.get("UNC_ENABLE_DATACLASS_SLOTS") == "true"
34
+
29
35
  if TYPE_CHECKING:
30
36
  JsonValue = Union[JsonScalar, Mapping[str, "JsonValue"], Sequence["JsonValue"]]
31
37
  ExtJsonValue = JsonValue
@@ -52,15 +58,12 @@ def is_pure_json_value(value: ExtJsonValue) -> bool:
52
58
  return True
53
59
 
54
60
  if isinstance(value, list):
55
- for item in value:
56
- if not is_pure_json_value(item):
57
- return False
58
- return True
61
+ return all(is_pure_json_value(item) for item in value)
59
62
 
60
63
  if isinstance(value, dict):
61
- for key, item in value.items():
62
- if not is_pure_json_value(key) or not is_pure_json_value(item):
63
- return False
64
- return True
64
+ return all(
65
+ is_pure_json_value(key) and is_pure_json_value(item)
66
+ for key, item in value.items()
67
+ )
65
68
 
66
69
  return False
@@ -3,6 +3,7 @@
3
3
  // doesn't allow referring explicitly to global names (thus cannot override here)
4
4
  // IMPROVE: invert relationship for global.d.ts looks here instead
5
5
  import * as IO from 'io-ts';
6
+
6
7
  type localJsonScalar = JsonScalar
7
8
  type localJsonValue = JsonValue
8
9
  type localObjectId = ObjectId
@@ -28,3 +29,6 @@ export const IOJsonValue: IO.Type<JsonValue> = IO.recursion('JsonValue', () =>
28
29
  export interface nominal<T> {
29
30
  "nominal structural brand": T
30
31
  }
32
+
33
+ // Ids matching a strict integer number are converted to integers
34
+ export const ID_REGEX = /-?[1-9][0-9]{0,20}/
@@ -9,7 +9,7 @@ import sys
9
9
 
10
10
  from ..config import parse_yaml_config
11
11
  from ..load_types import load_types
12
- from .emit_type_info import emit_type_info
12
+ from .emit_type_info import emit_type_info, emit_type_info_python
13
13
 
14
14
 
15
15
  def main() -> bool:
@@ -26,6 +26,8 @@ def main() -> bool:
26
26
 
27
27
  assert config.typescript is not None
28
28
  emit_type_info(builder, config.typescript.type_info_output)
29
+ if config.python.type_info_output is not None:
30
+ emit_type_info_python(builder, config.python.type_info_output)
29
31
 
30
32
  return True
31
33