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,11 +1,15 @@
1
1
  import copy
2
2
  import dataclasses
3
+ import decimal
3
4
  import io
4
5
  import json
5
- from typing import Any, Optional, TypeAlias, Union, cast
6
+ from enum import Enum
7
+ from typing import Any, cast
6
8
 
7
- from main.base.types import data_t
8
- from main.base.types.base import PureJsonValue
9
+ import yaml
10
+
11
+ from main.base.types import data_t, type_info_t
12
+ from main.base.types.base_t import PureJsonValue
9
13
  from pkgs.argument_parser import CachedParser
10
14
  from pkgs.serialization_util import serialize_for_api, serialize_for_storage
11
15
 
@@ -13,7 +17,7 @@ from .. import builder, util
13
17
  from ..emit_typescript_util import MODIFY_NOTICE, ts_name
14
18
  from ..value_spec import convert_to_value_spec_type
15
19
 
16
- ext_info_parser = CachedParser(data_t.ExtInfo)
20
+ ext_info_parser = CachedParser(type_info_t.ExtInfo, strict_property_parsing=True)
17
21
 
18
22
 
19
23
  def type_path_of(stype: builder.SpecType) -> object: # NamePath
@@ -37,10 +41,23 @@ def type_path_of(stype: builder.SpecType) -> object: # NamePath
37
41
  parts: list[object] = ["$literal"]
38
42
  for parameter in stype.parameters:
39
43
  assert isinstance(parameter, builder.SpecTypeLiteralWrapper)
44
+ emit_value = parameter.value
45
+ if isinstance(parameter.value_type, builder.SpecTypeDefnObject):
46
+ emit_value = parameter.value
47
+ assert isinstance(emit_value, (str, bool)), (
48
+ f"invalid-literal-value:{emit_value}"
49
+ )
50
+ elif isinstance(parameter.value_type, builder.SpecTypeDefnStringEnum):
51
+ key = parameter.value
52
+ assert isinstance(key, str)
53
+ emit_value = parameter.value_type.values[key].value
54
+ else:
55
+ raise Exception("unhandled-literal-type")
56
+
40
57
  # This allows expansion to enum literal values later
41
58
  parts.append([
42
59
  "$value",
43
- parameter.value,
60
+ emit_value,
44
61
  type_path_of(parameter.value_type),
45
62
  ])
46
63
  return parts
@@ -69,12 +86,21 @@ def _dict_null_strip(data: dict[str, object]) -> dict[str, object]:
69
86
  }
70
87
 
71
88
 
89
+ class JsonEncoder(json.JSONEncoder):
90
+ """We have some defaults of special types that we need to emit"""
91
+
92
+ def default(self, obj: object) -> object:
93
+ if isinstance(obj, decimal.Decimal):
94
+ return str(obj)
95
+ return json.JSONEncoder.default(self, obj)
96
+
97
+
72
98
  def emit_type_info(build: builder.SpecBuilder, output: str) -> None:
73
99
  type_map = _build_map_all(build)
74
100
 
75
101
  # sort for stability, indent for smaller diffs
76
102
  stripped = _dict_null_strip(dataclasses.asdict(type_map))
77
- serial = json.dumps(stripped, sort_keys=True, indent=2)
103
+ serial = json.dumps(stripped, sort_keys=True, indent=2, cls=JsonEncoder)
78
104
  type_map_out = io.StringIO()
79
105
  type_map_out.write(MODIFY_NOTICE)
80
106
  type_map_out.write(f"export const TYPE_MAP = {serial}")
@@ -82,6 +108,35 @@ def emit_type_info(build: builder.SpecBuilder, output: str) -> None:
82
108
  util.rewrite_file(f"{output}/type_map.ts", type_map_out.getvalue())
83
109
 
84
110
 
111
+ def _convert_value_for_yaml_dump(value: Any) -> Any:
112
+ if isinstance(value, Enum):
113
+ return value.value
114
+ elif isinstance(value, list):
115
+ return [_convert_value_for_yaml_dump(item) for item in value]
116
+ elif isinstance(value, dict):
117
+ return {k: _convert_value_for_yaml_dump(v) for k, v in value.items()}
118
+ elif isinstance(value, decimal.Decimal):
119
+ return str(value)
120
+ else:
121
+ return value
122
+
123
+
124
+ def asdict_for_yaml_dump(dataclass_instance: Any) -> Any:
125
+ return {
126
+ k: _convert_value_for_yaml_dump(v)
127
+ for k, v in dataclasses.asdict(dataclass_instance).items()
128
+ }
129
+
130
+
131
+ def emit_type_info_python(build: builder.SpecBuilder, output: str) -> None:
132
+ type_map = _build_map_all(build, python=True)
133
+
134
+ stripped = _dict_null_strip(asdict_for_yaml_dump(type_map))
135
+
136
+ yaml_content = yaml.dump(stripped, default_flow_style=False, sort_keys=True)
137
+ util.rewrite_file(f"{output}/type_map.yaml", yaml_content)
138
+
139
+
85
140
  @dataclasses.dataclass
86
141
  class MapProperty:
87
142
  api_name: str
@@ -93,7 +148,7 @@ class MapProperty:
93
148
  desc: str | None
94
149
  # We don't have typing on defaults yet, relying on emitters to check it. Limit
95
150
  # use of this field, as it'll necessarily change when adding type info
96
- default: object
151
+ default: PureJsonValue
97
152
 
98
153
 
99
154
  @dataclasses.dataclass
@@ -116,12 +171,19 @@ class MapTypeAlias(MapTypeBase):
116
171
  discriminator: str | None
117
172
 
118
173
 
174
+ @dataclasses.dataclass
175
+ class StringEnumValue:
176
+ value: str
177
+ label: str
178
+ deprecated: bool = False
179
+
180
+
119
181
  @dataclasses.dataclass
120
182
  class MapStringEnum(MapTypeBase):
121
- values: dict[str, str]
183
+ values: dict[str, StringEnumValue]
122
184
 
123
185
 
124
- MapType: TypeAlias = Union[MapTypeObject, MapTypeAlias, MapStringEnum]
186
+ MapType = MapTypeObject | MapTypeAlias | MapStringEnum
125
187
 
126
188
 
127
189
  @dataclasses.dataclass
@@ -134,11 +196,14 @@ class MapAll:
134
196
  namespaces: dict[str, MapNamespace]
135
197
 
136
198
 
137
- def _build_map_all(build: builder.SpecBuilder) -> MapAll:
199
+ def _build_map_all(build: builder.SpecBuilder, *, python: bool = False) -> MapAll:
138
200
  map_all = MapAll(namespaces={})
139
201
 
140
202
  for namespace in build.namespaces.values():
141
- if not namespace.emit_type_info:
203
+ if not python and not namespace.emit_type_info:
204
+ continue
205
+
206
+ if python and not namespace.emit_type_info_python:
142
207
  continue
143
208
 
144
209
  map_namespace = MapNamespace(types={})
@@ -159,9 +224,9 @@ class InheritablePropertyParts:
159
224
  at that level, but that needs to be done in builder. When that is done, the
160
225
  "label" and "desc" could probably be removed from this list."""
161
226
 
162
- label: Optional[str] = None
163
- desc: Optional[str] = None
164
- ext_info: Optional[data_t.ExtInfo] = None
227
+ label: str | None = None
228
+ desc: str | None = None
229
+ ext_info: type_info_t.ExtInfo | None = None
165
230
 
166
231
 
167
232
  def _extract_inheritable_property_parts(
@@ -188,8 +253,13 @@ def _extract_inheritable_property_parts(
188
253
  elif base_parts.ext_info is None:
189
254
  ext_info = local_ext_info
190
255
  else:
191
- ext_info = data_t.ExtInfo(
192
- **(local_ext_info.__dict__ | base_parts.ext_info.__dict__)
256
+ ext_info = dataclasses.replace(
257
+ local_ext_info,
258
+ **{
259
+ field.name: getattr(base_parts.ext_info, field.name)
260
+ for field in dataclasses.fields(type_info_t.ExtInfo)
261
+ if getattr(base_parts.ext_info, field.name) is not None
262
+ },
193
263
  )
194
264
 
195
265
  return InheritablePropertyParts(label=label, desc=desc, ext_info=ext_info)
@@ -201,7 +271,7 @@ ALL_FIELDS_GROUP = "*all_fields"
201
271
 
202
272
  def _extract_and_validate_layout(
203
273
  stype: builder.SpecTypeDefnObject,
204
- ext_info: data_t.ExtInfo,
274
+ ext_info: type_info_t.ExtInfo,
205
275
  base_layout: ExtInfoLayout | None,
206
276
  ) -> ExtInfoLayout:
207
277
  """
@@ -217,13 +287,15 @@ def _extract_and_validate_layout(
217
287
  for group in ext_info.layout.groups:
218
288
  fields = set(group.fields or [])
219
289
  for field in fields:
220
- assert field in stype.properties, f"layout-refers-to-missing-field:{field}"
290
+ assert field in stype.properties or field == DISCRIMINATOR_COMMON_NAME, (
291
+ f"layout-refers-to-missing-field:{field}"
292
+ )
221
293
 
222
294
  local_ref_name = None
223
295
  if group.ref_name is not None:
224
- assert (
225
- base_layout is None or base_layout.get(group.ref_name) is None
226
- ), f"group-name-duplicate-in-base:{group.ref_name}"
296
+ assert base_layout is None or base_layout.get(group.ref_name) is None, (
297
+ f"group-name-duplicate-in-base:{group.ref_name}"
298
+ )
227
299
  local_ref_name = group.ref_name
228
300
 
229
301
  if group.extends:
@@ -242,22 +314,60 @@ def _extract_and_validate_layout(
242
314
  assert group_ref_name in layout, f"missing-base-group:{group_ref_name}"
243
315
 
244
316
  for prop_ref_name in stype.properties:
245
- assert prop_ref_name in all_fields_group, f"layout-missing-field:{prop_ref_name}"
317
+ assert prop_ref_name in all_fields_group, (
318
+ f"layout-missing-field:{prop_ref_name}"
319
+ )
246
320
 
247
321
  return layout
248
322
 
249
323
 
250
- def _validate_type_ext_info(stype: builder.SpecTypeDefnObject) -> ExtInfoLayout | None:
324
+ def _pull_property_from_type_recursively(
325
+ stype: builder.SpecTypeDefnObject,
326
+ property_name: str,
327
+ ) -> builder.SpecProperty | None:
328
+ assert stype.properties is not None
329
+ prop = stype.properties.get(property_name)
330
+ if prop is not None:
331
+ return prop
332
+
333
+ if stype.base is None:
334
+ return None
335
+
336
+ return _pull_property_from_type_recursively(stype.base, property_name)
337
+
338
+
339
+ DISCRIMINATOR_COMMON_NAME = "type"
340
+
341
+
342
+ def _validate_type_ext_info(
343
+ stype: builder.SpecTypeDefnObject,
344
+ ) -> tuple[ExtInfoLayout | None, type_info_t.ExtInfo | None]:
251
345
  ext_info = _parse_ext_info(stype.ext_info)
252
346
  if ext_info is None:
253
- return None
347
+ return None, None
348
+
349
+ if ext_info.label_fields is not None:
350
+ assert stype.properties is not None
351
+ for name in ext_info.label_fields:
352
+ if name == DISCRIMINATOR_COMMON_NAME:
353
+ continue
354
+ prop = _pull_property_from_type_recursively(stype, name)
355
+ assert prop is not None, f"missing-label-field:{name}"
356
+
357
+ if ext_info.actions is not None:
358
+ assert stype.properties is not None
359
+ for action in ext_info.actions:
360
+ if action.property == DISCRIMINATOR_COMMON_NAME:
361
+ continue
362
+ prop = _pull_property_from_type_recursively(stype, action.property)
363
+ assert prop is not None, f"missing-action-field:{action.property}"
254
364
 
255
365
  if not stype.is_base and isinstance(stype.base, builder.SpecTypeDefnObject):
256
- base_layout = _validate_type_ext_info(stype.base)
366
+ base_layout, _ = _validate_type_ext_info(stype.base)
257
367
  else:
258
368
  base_layout = None
259
369
 
260
- return _extract_and_validate_layout(stype, ext_info, base_layout)
370
+ return _extract_and_validate_layout(stype, ext_info, base_layout), ext_info
261
371
 
262
372
 
263
373
  def _build_map_type(
@@ -270,7 +380,7 @@ def _build_map_type(
270
380
  and not stype.is_base
271
381
  and stype.base is not None
272
382
  ):
273
- _validate_type_ext_info(stype)
383
+ _, ext_info = _validate_type_ext_info(stype)
274
384
 
275
385
  properties: dict[str, MapProperty] = {}
276
386
  map_type = MapTypeObject(
@@ -279,7 +389,7 @@ def _build_map_type(
279
389
  properties=properties,
280
390
  desc=stype.desc,
281
391
  base_type_path=type_path_of(stype.base),
282
- ext_info=_convert_ext_info(stype.ext_info),
392
+ ext_info=serialize_for_api(ext_info), # type: ignore[arg-type]
283
393
  )
284
394
 
285
395
  if stype.properties is not None:
@@ -293,7 +403,7 @@ def _build_map_type(
293
403
  api_name=ts_name(prop.name, prop.name_case),
294
404
  extant=prop.extant,
295
405
  type_path=type_path_of(prop.spec_type),
296
- ext_info=serialize_for_api(parts.ext_info),
406
+ ext_info=serialize_for_api(parts.ext_info), # type: ignore[arg-type]
297
407
  desc=parts.desc,
298
408
  default=prop.default,
299
409
  )
@@ -311,6 +421,19 @@ def _build_map_type(
311
421
  discriminator=stype.discriminator,
312
422
  )
313
423
 
424
+ if isinstance(stype, builder.SpecTypeDefnUnion):
425
+ # Emit as a basic alias for now, as the front-end supports only those for now
426
+ # IMPROVE: We should emit a proper union type and support that
427
+ backing = stype.get_backing_type()
428
+ return MapTypeAlias(
429
+ type_name=stype.name,
430
+ label=stype.label,
431
+ desc=stype.desc,
432
+ alias_type_path=type_path_of(backing),
433
+ ext_info=_convert_ext_info(stype.ext_info),
434
+ discriminator=stype.discriminator,
435
+ )
436
+
314
437
  if isinstance(stype, builder.SpecTypeDefnStringEnum):
315
438
  return MapStringEnum(
316
439
  type_name=stype.name,
@@ -320,7 +443,11 @@ def _build_map_type(
320
443
  # IMPROVE: We probably want the label here, but this requires a change
321
444
  # to the front-end type-info and form code to handle
322
445
  values={
323
- entry.value: (entry.label or entry.name)
446
+ entry.value: StringEnumValue(
447
+ value=entry.value,
448
+ label=entry.label or entry.name,
449
+ deprecated=entry.deprecated,
450
+ )
324
451
  for entry in stype.values.values()
325
452
  },
326
453
  )
@@ -328,7 +455,7 @@ def _build_map_type(
328
455
  return None
329
456
 
330
457
 
331
- def _parse_ext_info(in_ext: Any) -> Optional[data_t.ExtInfo]:
458
+ def _parse_ext_info(in_ext: Any) -> type_info_t.ExtInfo | None:
332
459
  if in_ext is None:
333
460
  return None
334
461
  assert isinstance(in_ext, dict)
@@ -346,10 +473,12 @@ def _parse_ext_info(in_ext: Any) -> Optional[data_t.ExtInfo]:
346
473
  df["result_type"] = serialize_for_storage(converted)
347
474
  mod_ext["data_format"] = df
348
475
 
476
+ if "open_api" in mod_ext:
477
+ del mod_ext["open_api"]
349
478
  return ext_info_parser.parse_storage(mod_ext)
350
479
 
351
480
 
352
- def _convert_ext_info(in_ext: Any) -> Optional[PureJsonValue]:
481
+ def _convert_ext_info(in_ext: Any) -> PureJsonValue | None:
353
482
  # we need to convert this to API storage since it'll be used as-is in the UI
354
483
  parsed = _parse_ext_info(in_ext)
355
484
  return cast(PureJsonValue, serialize_for_api(parsed))
@@ -0,0 +1,4 @@
1
+ # CLOSED MODULE
2
+ from .generate_ui_entry_actions import (
3
+ generate_entry_actions_typescript as generate_entry_actions_typescript,
4
+ )
@@ -0,0 +1,308 @@
1
+ import json
2
+ import re
3
+ from dataclasses import dataclass
4
+ from io import StringIO
5
+ from pathlib import Path
6
+ from typing import assert_never
7
+
8
+ from main.base.types import (
9
+ base_t,
10
+ ui_entry_actions_t,
11
+ )
12
+ from pkgs.serialization_util import serialize_for_api
13
+ from pkgs.type_spec import emit_typescript_util
14
+ from pkgs.type_spec.builder import (
15
+ BaseTypeName,
16
+ NameCase,
17
+ RawDict,
18
+ SpecBuilder,
19
+ SpecNamespace,
20
+ SpecTypeDefnObject,
21
+ )
22
+ from pkgs.type_spec.config import Config
23
+ from pkgs.type_spec.load_types import load_types
24
+ from pkgs.type_spec.util import rewrite_file
25
+ from pkgs.type_spec.value_spec.convert_type import convert_from_value_spec_type
26
+
27
+ _INIT_ACTION_INDEX_TYPE_DATA = {
28
+ "EntryActionInfo<InputT, OutputT>": {
29
+ "type": BaseTypeName.s_object,
30
+ "properties": {"inputs": {"type": "InputT"}, "outputs": {"type": "OutputT"}},
31
+ }
32
+ }
33
+ _TYPES_ROOT = "unc_types"
34
+
35
+
36
+ @dataclass(kw_only=True)
37
+ class EntryActionTypeInfo:
38
+ inputs_type: SpecTypeDefnObject
39
+ outputs_type: SpecTypeDefnObject
40
+ name: str
41
+
42
+
43
+ def ui_entry_variable_to_type_spec_type(
44
+ variable: ui_entry_actions_t.UiEntryActionVariable,
45
+ ) -> str:
46
+ match variable:
47
+ case ui_entry_actions_t.UiEntryActionVariableString():
48
+ return BaseTypeName.s_string
49
+ case ui_entry_actions_t.UiEntryActionVariableSingleEntity():
50
+ return "ObjectId"
51
+ case _:
52
+ assert_never(variable)
53
+
54
+
55
+ def construct_inputs_type_data(
56
+ vars: dict[str, ui_entry_actions_t.UiEntryActionVariable],
57
+ ) -> RawDict:
58
+ if len(vars) == 0:
59
+ return {"type": BaseTypeName.s_object}
60
+ properties: dict[str, dict[str, str]] = {}
61
+ for input_name, input_defn in (vars).items():
62
+ properties[f"{input_name}"] = {
63
+ "type": ui_entry_variable_to_type_spec_type(input_defn)
64
+ }
65
+ return {"type": BaseTypeName.s_object, "properties": properties}
66
+
67
+
68
+ def construct_outputs_type_data(
69
+ vars: dict[str, ui_entry_actions_t.UiEntryActionOutput],
70
+ ) -> RawDict:
71
+ if len(vars) == 0:
72
+ return {"type": BaseTypeName.s_object}
73
+ properties: dict[str, dict[str, str]] = {}
74
+ for output_name, output_defn in (vars).items():
75
+ # All outputs are optional
76
+ properties[f"{output_name}"] = {
77
+ "type": f"Optional<{convert_from_value_spec_type(output_defn.vs_type)}>"
78
+ }
79
+ return {"type": BaseTypeName.s_object, "properties": properties}
80
+
81
+
82
+ def construct_outputs_type(
83
+ *,
84
+ action_scope: ui_entry_actions_t.ActionScope,
85
+ vars: dict[str, ui_entry_actions_t.UiEntryActionOutput],
86
+ builder: SpecBuilder,
87
+ namespace: SpecNamespace,
88
+ ) -> SpecTypeDefnObject:
89
+ stype = SpecTypeDefnObject(
90
+ namespace=namespace,
91
+ name=emit_typescript_util.ts_type_name(f"{action_scope}_outputs"),
92
+ )
93
+ namespace.types[stype.name] = stype
94
+ stype.process(
95
+ builder=builder,
96
+ data=construct_outputs_type_data(vars=vars),
97
+ )
98
+ return stype
99
+
100
+
101
+ def construct_inputs_type(
102
+ *,
103
+ action_scope: ui_entry_actions_t.ActionScope,
104
+ vars: dict[str, ui_entry_actions_t.UiEntryActionVariable],
105
+ builder: SpecBuilder,
106
+ namespace: SpecNamespace,
107
+ ) -> SpecTypeDefnObject:
108
+ stype = SpecTypeDefnObject(
109
+ namespace=namespace,
110
+ name=emit_typescript_util.ts_type_name(f"{action_scope}_inputs"),
111
+ )
112
+ stype.process(builder=builder, data=construct_inputs_type_data(vars))
113
+ namespace.types[stype.name] = stype
114
+ return stype
115
+
116
+
117
+ def _get_types_root(destination_root: Path) -> Path:
118
+ return destination_root / "types"
119
+
120
+
121
+ def emit_imports_ts(
122
+ namespaces: set[SpecNamespace],
123
+ out: StringIO,
124
+ ) -> None:
125
+ for ns in sorted(
126
+ namespaces,
127
+ key=lambda ns: ns.name,
128
+ ):
129
+ import_as = emit_typescript_util.resolve_namespace_ref(ns)
130
+ import_from = f"{_TYPES_ROOT}/{ns.name}"
131
+ out.write(f'import * as {import_as} from "{import_from}"\n')
132
+
133
+
134
+ def emit_entry_action_definition(
135
+ *,
136
+ ctx: emit_typescript_util.EmitTypescriptContext,
137
+ defn: ui_entry_actions_t.UiEntryActionDefinition,
138
+ builder: SpecBuilder,
139
+ action_scope: ui_entry_actions_t.ActionScope,
140
+ ) -> EntryActionTypeInfo:
141
+ inputs_type = construct_inputs_type(
142
+ action_scope=action_scope,
143
+ vars=defn.inputs,
144
+ builder=builder,
145
+ namespace=ctx.namespace,
146
+ )
147
+ outputs_type = construct_outputs_type(
148
+ action_scope=action_scope,
149
+ vars=defn.outputs,
150
+ builder=builder,
151
+ namespace=ctx.namespace,
152
+ )
153
+
154
+ return EntryActionTypeInfo(
155
+ inputs_type=inputs_type,
156
+ outputs_type=outputs_type,
157
+ name=action_scope,
158
+ )
159
+
160
+
161
+ def _validate_input(input: ui_entry_actions_t.UiEntryActionVariable) -> None:
162
+ if "_" in input.vs_var_name:
163
+ raise ValueError(f"Expected camelCase for variable {input.vs_var_name}")
164
+ if not re.fullmatch(base_t.REF_NAME_STRICT_REGEX, input.vs_var_name):
165
+ raise ValueError(
166
+ f"Variable {input.vs_var_name} has invalid syntax. See REF_NAME_STRICT_REGEX"
167
+ )
168
+
169
+
170
+ def emit_query_index(
171
+ ctx: emit_typescript_util.EmitTypescriptContext,
172
+ defn_infos: list[EntryActionTypeInfo],
173
+ index_path: Path,
174
+ builder: SpecBuilder,
175
+ definitions: dict[
176
+ ui_entry_actions_t.ActionScope, ui_entry_actions_t.UiEntryActionDefinition
177
+ ],
178
+ ) -> bool:
179
+ query_index_type_data = {
180
+ **_INIT_ACTION_INDEX_TYPE_DATA,
181
+ "EntityActionTypeLookup": {
182
+ "type": BaseTypeName.s_object,
183
+ "properties": {
184
+ defn_info.name: {
185
+ "type": f"EntryActionInfo<{defn_info.inputs_type.name},{defn_info.outputs_type.name}>",
186
+ "name_case": NameCase.preserve,
187
+ }
188
+ for defn_info in defn_infos
189
+ },
190
+ },
191
+ "InputInfo": {
192
+ "type": BaseTypeName.s_object,
193
+ "properties": {
194
+ "value_spec_var": {"type": "String"},
195
+ "type": {"type": "ui_entry_actions.UiEntryActionDataType"},
196
+ "variable": {"type": "ui_entry_actions.UiEntryActionVariable"},
197
+ },
198
+ },
199
+ "OutputInfo": {
200
+ "type": BaseTypeName.s_object,
201
+ "properties": {
202
+ "name": {"type": "String"},
203
+ "desc": {"type": "String"},
204
+ "type": {"type": "value_spec.BaseType"},
205
+ },
206
+ },
207
+ "DefinitionInfo": {
208
+ "type": BaseTypeName.s_object,
209
+ "properties": {
210
+ "inputs": {
211
+ "type": "ReadonlyArray<InputInfo>",
212
+ },
213
+ "outputs": {
214
+ "type": "ReadonlyArray<OutputInfo>",
215
+ },
216
+ },
217
+ },
218
+ }
219
+ ctx.namespace.prescan(query_index_type_data)
220
+ ctx.namespace.process(
221
+ builder=builder,
222
+ data=query_index_type_data,
223
+ )
224
+
225
+ defn_lookup_info = {}
226
+ for scope, defn in definitions.items():
227
+ inputs = []
228
+ outputs = []
229
+ for input in defn.inputs.values():
230
+ _validate_input(input)
231
+ inputs.append(
232
+ serialize_for_api({
233
+ "value_spec_var": input.vs_var_name,
234
+ "type": input.type,
235
+ "variable": input,
236
+ })
237
+ )
238
+ for name, output in defn.outputs.items():
239
+ outputs.append(
240
+ serialize_for_api({
241
+ "name": name,
242
+ "desc": output.description,
243
+ "type": output.vs_type,
244
+ })
245
+ )
246
+ defn_lookup_info[scope] = {"inputs": inputs, "outputs": outputs}
247
+
248
+ defn_lookup_out = f"export const DEFINITION_LOOKUP = {json.dumps(defn_lookup_info, sort_keys=True, indent=2)} as const\n\nexport const DEFINITION_LOOKUP_TYPED = DEFINITION_LOOKUP as Record<UiEntryActionsT.ActionScope, DefinitionInfo>\n"
249
+
250
+ for stype in ctx.namespace.types.values():
251
+ emit_typescript_util.emit_type_ts(
252
+ ctx=ctx,
253
+ stype=stype,
254
+ )
255
+
256
+ import_buffer = StringIO()
257
+ emit_typescript_util.emit_namespace_imports_from_root_ts(
258
+ namespaces=ctx.namespaces,
259
+ out=import_buffer,
260
+ root=_TYPES_ROOT,
261
+ )
262
+
263
+ return rewrite_file(
264
+ content=import_buffer.getvalue() + ctx.out.getvalue() + defn_lookup_out,
265
+ filename=str(index_path),
266
+ )
267
+
268
+
269
+ def generate_entry_actions_typescript(
270
+ *,
271
+ definitions: dict[
272
+ ui_entry_actions_t.ActionScope, ui_entry_actions_t.UiEntryActionDefinition
273
+ ],
274
+ destination_root: Path,
275
+ materials_type_spec_config: Config,
276
+ ) -> None:
277
+ builder = load_types(materials_type_spec_config)
278
+ assert builder is not None
279
+
280
+ definition_buffer = StringIO()
281
+ index_namespace = SpecNamespace(name="index")
282
+ ctx = emit_typescript_util.EmitTypescriptContext(
283
+ out=definition_buffer,
284
+ namespace=index_namespace,
285
+ api_endpoints={},
286
+ )
287
+ builder.namespaces[index_namespace.name] = index_namespace
288
+
289
+ defn_infos: list[EntryActionTypeInfo] = []
290
+
291
+ for action_scope, defn in definitions.items():
292
+ defn_infos.append(
293
+ emit_entry_action_definition(
294
+ action_scope=action_scope,
295
+ ctx=ctx,
296
+ defn=defn,
297
+ builder=builder,
298
+ )
299
+ )
300
+
301
+ index_path = _get_types_root(destination_root) / "index.ts"
302
+ emit_query_index(
303
+ ctx=ctx,
304
+ builder=builder,
305
+ defn_infos=defn_infos,
306
+ definitions=definitions,
307
+ index_path=index_path,
308
+ )
pkgs/type_spec/util.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import json
2
2
  import os
3
3
  from dataclasses import dataclass
4
- from typing import Optional, TypeVar, Union
4
+ from typing import TypeVar, Union
5
5
 
6
6
  import regex as re
7
7
 
@@ -29,8 +29,8 @@ LiteralTypeValue = Union[str, bool]
29
29
  class ParsedTypePart:
30
30
  name: str
31
31
  # An empty list is distinct from None
32
- parameters: Optional[list["ParsedTypePath"]] = None
33
- literal_value: Optional[LiteralTypeValue] = None
32
+ parameters: list["ParsedTypePath"] | None = None
33
+ literal_value: LiteralTypeValue | None = None
34
34
 
35
35
 
36
36
  ParsedTypePath = list[ParsedTypePart]
@@ -159,7 +159,7 @@ def is_valid_property_name(name: str) -> bool:
159
159
  def check_fields(data: dict[str, T], allowed: list[str]) -> None:
160
160
  for key in data:
161
161
  if key not in allowed:
162
- raise Exception(f"unexpected-field: {key}")
162
+ raise Exception(f"unexpected-field: {key}. Allowed: {allowed}")
163
163
 
164
164
 
165
165
  def split_any_name(name: str) -> list[str]: