UncountablePythonSDK 0.0.8__py3-none-any.whl → 0.0.92__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 (312) hide show
  1. UncountablePythonSDK-0.0.92.dist-info/METADATA +61 -0
  2. UncountablePythonSDK-0.0.92.dist-info/RECORD +301 -0
  3. {UncountablePythonSDK-0.0.8.dist-info → UncountablePythonSDK-0.0.92.dist-info}/WHEEL +1 -1
  4. {UncountablePythonSDK-0.0.8.dist-info → UncountablePythonSDK-0.0.92.dist-info}/top_level.txt +1 -1
  5. docs/.gitignore +1 -0
  6. docs/conf.py +57 -0
  7. docs/index.md +13 -0
  8. docs/justfile +12 -0
  9. docs/quickstart.md +19 -0
  10. docs/requirements.txt +7 -0
  11. docs/static/favicons/android-chrome-192x192.png +0 -0
  12. docs/static/favicons/android-chrome-512x512.png +0 -0
  13. docs/static/favicons/apple-touch-icon.png +0 -0
  14. docs/static/favicons/browserconfig.xml +9 -0
  15. docs/static/favicons/favicon-16x16.png +0 -0
  16. docs/static/favicons/favicon-32x32.png +0 -0
  17. docs/static/favicons/manifest.json +18 -0
  18. docs/static/favicons/mstile-150x150.png +0 -0
  19. docs/static/favicons/safari-pinned-tab.svg +32 -0
  20. docs/static/logo_blue.png +0 -0
  21. examples/async_batch.py +35 -0
  22. examples/create_entity.py +22 -17
  23. examples/download_files.py +26 -0
  24. examples/edit_recipe_inputs.py +50 -0
  25. examples/integration-server/jobs/materials_auto/example_cron.py +18 -0
  26. examples/integration-server/jobs/materials_auto/example_wh.py +15 -0
  27. examples/integration-server/jobs/materials_auto/profile.yaml +43 -0
  28. examples/integration-server/pyproject.toml +224 -0
  29. examples/invoke_uploader.py +26 -0
  30. examples/set_recipe_metadata_file.py +40 -0
  31. examples/set_recipe_output_file_sdk.py +26 -0
  32. examples/upload_files.py +18 -0
  33. pkgs/argument_parser/__init__.py +5 -0
  34. pkgs/argument_parser/_is_enum.py +1 -6
  35. pkgs/argument_parser/argument_parser.py +232 -76
  36. pkgs/argument_parser/case_convert.py +4 -3
  37. pkgs/filesystem_utils/__init__.py +20 -0
  38. pkgs/filesystem_utils/_blob_session.py +137 -0
  39. pkgs/filesystem_utils/_gdrive_session.py +309 -0
  40. pkgs/filesystem_utils/_local_session.py +69 -0
  41. pkgs/filesystem_utils/_s3_session.py +117 -0
  42. pkgs/filesystem_utils/_sftp_session.py +147 -0
  43. pkgs/filesystem_utils/file_type_utils.py +91 -0
  44. pkgs/filesystem_utils/filesystem_session.py +39 -0
  45. pkgs/py.typed +0 -0
  46. pkgs/serialization/__init__.py +8 -1
  47. pkgs/serialization/annotation.py +64 -0
  48. pkgs/serialization/missing_sentry.py +1 -1
  49. pkgs/serialization/opaque_key.py +1 -1
  50. pkgs/serialization/serial_alias.py +47 -0
  51. pkgs/serialization/serial_class.py +65 -50
  52. pkgs/serialization/serial_generic.py +16 -0
  53. pkgs/serialization/serial_union.py +84 -0
  54. pkgs/serialization/yaml.py +57 -0
  55. pkgs/serialization_util/__init__.py +7 -7
  56. pkgs/serialization_util/_get_type_for_serialization.py +1 -3
  57. pkgs/serialization_util/convert_to_snakecase.py +27 -0
  58. pkgs/serialization_util/dataclasses.py +14 -0
  59. pkgs/serialization_util/serialization_helpers.py +116 -74
  60. pkgs/strenum_compat/strenum_compat.py +1 -9
  61. pkgs/type_spec/actions_registry/__init__.py +0 -0
  62. pkgs/type_spec/actions_registry/__main__.py +126 -0
  63. pkgs/type_spec/actions_registry/emit_typescript.py +182 -0
  64. pkgs/type_spec/builder.py +475 -89
  65. pkgs/type_spec/config.py +24 -19
  66. pkgs/type_spec/emit_io_ts.py +5 -2
  67. pkgs/type_spec/emit_open_api.py +266 -32
  68. pkgs/type_spec/emit_open_api_util.py +32 -13
  69. pkgs/type_spec/emit_python.py +599 -151
  70. pkgs/type_spec/emit_typescript.py +74 -273
  71. pkgs/type_spec/emit_typescript_util.py +239 -5
  72. pkgs/type_spec/load_types.py +55 -10
  73. pkgs/type_spec/open_api_util.py +30 -41
  74. pkgs/type_spec/parts/base.py.prepart +4 -3
  75. pkgs/type_spec/type_info/emit_type_info.py +178 -16
  76. pkgs/type_spec/util.py +11 -11
  77. pkgs/type_spec/value_spec/__main__.py +3 -3
  78. pkgs/type_spec/value_spec/convert_type.py +8 -1
  79. pkgs/type_spec/value_spec/emit_python.py +13 -4
  80. uncountable/__init__.py +1 -2
  81. uncountable/core/__init__.py +12 -2
  82. uncountable/core/async_batch.py +37 -0
  83. uncountable/core/client.py +293 -43
  84. uncountable/core/environment.py +41 -0
  85. uncountable/core/file_upload.py +135 -0
  86. uncountable/core/types.py +17 -0
  87. uncountable/integration/__init__.py +0 -0
  88. uncountable/integration/cli.py +49 -0
  89. uncountable/integration/construct_client.py +51 -0
  90. uncountable/integration/cron.py +29 -0
  91. uncountable/integration/db/__init__.py +0 -0
  92. uncountable/integration/db/connect.py +18 -0
  93. uncountable/integration/db/session.py +25 -0
  94. uncountable/integration/entrypoint.py +13 -0
  95. uncountable/integration/executors/__init__.py +0 -0
  96. uncountable/integration/executors/executors.py +148 -0
  97. uncountable/integration/executors/generic_upload_executor.py +284 -0
  98. uncountable/integration/executors/script_executor.py +25 -0
  99. uncountable/integration/job.py +87 -0
  100. uncountable/integration/queue_runner/__init__.py +0 -0
  101. uncountable/integration/queue_runner/command_server/__init__.py +24 -0
  102. uncountable/integration/queue_runner/command_server/command_client.py +68 -0
  103. uncountable/integration/queue_runner/command_server/command_server.py +64 -0
  104. uncountable/integration/queue_runner/command_server/protocol/__init__.py +0 -0
  105. uncountable/integration/queue_runner/command_server/protocol/command_server.proto +22 -0
  106. uncountable/integration/queue_runner/command_server/protocol/command_server_pb2.py +40 -0
  107. uncountable/integration/queue_runner/command_server/protocol/command_server_pb2.pyi +38 -0
  108. uncountable/integration/queue_runner/command_server/protocol/command_server_pb2_grpc.py +129 -0
  109. uncountable/integration/queue_runner/command_server/types.py +52 -0
  110. uncountable/integration/queue_runner/datastore/__init__.py +3 -0
  111. uncountable/integration/queue_runner/datastore/datastore_sqlite.py +93 -0
  112. uncountable/integration/queue_runner/datastore/interface.py +19 -0
  113. uncountable/integration/queue_runner/datastore/model.py +17 -0
  114. uncountable/integration/queue_runner/job_scheduler.py +163 -0
  115. uncountable/integration/queue_runner/queue_runner.py +26 -0
  116. uncountable/integration/queue_runner/types.py +7 -0
  117. uncountable/integration/queue_runner/worker.py +119 -0
  118. uncountable/integration/scan_profiles.py +67 -0
  119. uncountable/integration/scheduler.py +150 -0
  120. uncountable/integration/secret_retrieval/__init__.py +3 -0
  121. uncountable/integration/secret_retrieval/retrieve_secret.py +93 -0
  122. uncountable/integration/server.py +117 -0
  123. uncountable/integration/telemetry.py +209 -0
  124. uncountable/integration/webhook_server/entrypoint.py +170 -0
  125. uncountable/types/__init__.py +136 -20
  126. uncountable/types/api/batch/execute_batch.py +15 -7
  127. uncountable/types/api/batch/execute_batch_load_async.py +42 -0
  128. uncountable/types/api/chemical/__init__.py +1 -0
  129. uncountable/types/api/chemical/convert_chemical_formats.py +63 -0
  130. uncountable/types/api/entity/create_entities.py +23 -11
  131. uncountable/types/api/entity/create_entity.py +21 -12
  132. uncountable/types/api/entity/get_entities_data.py +18 -8
  133. uncountable/types/api/entity/grant_entity_permissions.py +48 -0
  134. uncountable/types/api/entity/list_entities.py +27 -12
  135. uncountable/types/api/entity/lock_entity.py +45 -0
  136. uncountable/types/api/entity/resolve_entity_ids.py +17 -7
  137. uncountable/types/api/entity/set_entity_field_values.py +44 -0
  138. uncountable/types/api/entity/set_values.py +14 -7
  139. uncountable/types/api/entity/transition_entity_phase.py +80 -0
  140. uncountable/types/api/entity/unlock_entity.py +44 -0
  141. uncountable/types/api/equipment/__init__.py +1 -0
  142. uncountable/types/api/equipment/associate_equipment_input.py +44 -0
  143. uncountable/types/api/field_options/__init__.py +1 -0
  144. uncountable/types/api/field_options/upsert_field_options.py +55 -0
  145. uncountable/types/api/files/__init__.py +1 -0
  146. uncountable/types/api/files/download_file.py +77 -0
  147. uncountable/types/api/id_source/__init__.py +1 -0
  148. uncountable/types/api/id_source/list_id_source.py +56 -0
  149. uncountable/types/api/id_source/match_id_source.py +54 -0
  150. uncountable/types/api/input_groups/get_input_group_names.py +16 -6
  151. uncountable/types/api/inputs/create_inputs.py +24 -11
  152. uncountable/types/api/inputs/get_input_data.py +32 -13
  153. uncountable/types/api/inputs/get_input_names.py +18 -8
  154. uncountable/types/api/inputs/get_inputs_data.py +29 -10
  155. uncountable/types/api/inputs/set_input_attribute_values.py +16 -9
  156. uncountable/types/api/inputs/set_input_category.py +44 -0
  157. uncountable/types/api/inputs/set_input_subcategories.py +45 -0
  158. uncountable/types/api/inputs/set_intermediate_type.py +50 -0
  159. uncountable/types/api/material_families/__init__.py +1 -0
  160. uncountable/types/api/material_families/update_entity_material_families.py +48 -0
  161. uncountable/types/api/outputs/get_output_data.py +32 -16
  162. uncountable/types/api/outputs/get_output_names.py +18 -8
  163. uncountable/types/api/outputs/resolve_output_conditions.py +23 -10
  164. uncountable/types/api/permissions/__init__.py +1 -0
  165. uncountable/types/api/permissions/set_core_permissions.py +105 -0
  166. uncountable/types/api/project/get_projects.py +17 -7
  167. uncountable/types/api/project/get_projects_data.py +21 -11
  168. uncountable/types/api/recipe_links/__init__.py +1 -0
  169. uncountable/types/api/recipe_links/create_recipe_link.py +46 -0
  170. uncountable/types/api/recipe_links/remove_recipe_link.py +45 -0
  171. uncountable/types/api/recipe_metadata/get_recipe_metadata_data.py +18 -8
  172. uncountable/types/api/recipes/add_recipe_to_project.py +42 -0
  173. uncountable/types/api/recipes/archive_recipes.py +42 -0
  174. uncountable/types/api/recipes/associate_recipe_as_input.py +44 -0
  175. uncountable/types/api/recipes/associate_recipe_as_lot.py +43 -0
  176. uncountable/types/api/recipes/clear_recipe_outputs.py +42 -0
  177. uncountable/types/api/recipes/create_recipe.py +51 -0
  178. uncountable/types/api/recipes/create_recipes.py +25 -12
  179. uncountable/types/api/recipes/disassociate_recipe_as_input.py +42 -0
  180. uncountable/types/api/recipes/edit_recipe_inputs.py +283 -0
  181. uncountable/types/api/recipes/get_column_calculation_values.py +58 -0
  182. uncountable/types/api/recipes/get_curve.py +15 -7
  183. uncountable/types/api/recipes/get_recipe_calculations.py +17 -10
  184. uncountable/types/api/recipes/get_recipe_links.py +13 -6
  185. uncountable/types/api/recipes/get_recipe_names.py +16 -6
  186. uncountable/types/api/recipes/get_recipe_output_metadata.py +14 -7
  187. uncountable/types/api/recipes/get_recipes_data.py +63 -38
  188. uncountable/types/api/recipes/lock_recipes.py +63 -0
  189. uncountable/types/api/recipes/remove_recipe_from_project.py +42 -0
  190. uncountable/types/api/recipes/set_recipe_inputs.py +19 -10
  191. uncountable/types/api/recipes/set_recipe_metadata.py +43 -0
  192. uncountable/types/api/recipes/set_recipe_output_annotations.py +115 -0
  193. uncountable/types/api/recipes/set_recipe_output_file.py +56 -0
  194. uncountable/types/api/recipes/set_recipe_outputs.py +26 -12
  195. uncountable/types/api/recipes/set_recipe_tags.py +109 -0
  196. uncountable/types/api/recipes/unarchive_recipes.py +41 -0
  197. uncountable/types/api/recipes/unlock_recipes.py +50 -0
  198. uncountable/types/api/triggers/__init__.py +1 -0
  199. uncountable/types/api/triggers/run_trigger.py +43 -0
  200. uncountable/types/api/uploader/__init__.py +1 -0
  201. uncountable/types/api/uploader/invoke_uploader.py +47 -0
  202. uncountable/types/async_batch.py +13 -0
  203. uncountable/types/async_batch_processor.py +384 -0
  204. uncountable/types/async_batch_t.py +97 -0
  205. uncountable/types/async_jobs.py +9 -0
  206. uncountable/types/async_jobs_t.py +53 -0
  207. uncountable/types/auth_retrieval.py +12 -0
  208. uncountable/types/auth_retrieval_t.py +75 -0
  209. uncountable/types/base.py +5 -78
  210. uncountable/types/base_t.py +85 -0
  211. uncountable/types/calculations.py +3 -18
  212. uncountable/types/calculations_t.py +27 -0
  213. uncountable/types/chemical_structure.py +8 -0
  214. uncountable/types/chemical_structure_t.py +28 -0
  215. uncountable/types/client_base.py +1093 -54
  216. uncountable/types/client_config.py +8 -0
  217. uncountable/types/client_config_t.py +26 -0
  218. uncountable/types/curves.py +5 -42
  219. uncountable/types/curves_t.py +51 -0
  220. uncountable/types/entity.py +8 -269
  221. uncountable/types/entity_t.py +393 -0
  222. uncountable/types/experiment_groups.py +3 -18
  223. uncountable/types/experiment_groups_t.py +27 -0
  224. uncountable/types/field_values.py +17 -60
  225. uncountable/types/field_values_t.py +204 -0
  226. uncountable/types/fields.py +3 -19
  227. uncountable/types/fields_t.py +28 -0
  228. uncountable/types/generic_upload.py +15 -0
  229. uncountable/types/generic_upload_t.py +119 -0
  230. uncountable/types/id_source.py +12 -0
  231. uncountable/types/id_source_t.py +68 -0
  232. uncountable/types/identifier.py +11 -0
  233. uncountable/types/identifier_t.py +63 -0
  234. uncountable/types/input_attributes.py +3 -24
  235. uncountable/types/input_attributes_t.py +30 -0
  236. uncountable/types/inputs.py +6 -56
  237. uncountable/types/inputs_t.py +83 -0
  238. uncountable/types/integration_server.py +9 -0
  239. uncountable/types/integration_server_t.py +42 -0
  240. uncountable/types/job_definition.py +27 -0
  241. uncountable/types/job_definition_t.py +260 -0
  242. uncountable/types/outputs.py +3 -21
  243. uncountable/types/outputs_t.py +30 -0
  244. uncountable/types/overrides.py +10 -0
  245. uncountable/types/overrides_t.py +49 -0
  246. uncountable/types/permissions.py +8 -0
  247. uncountable/types/permissions_t.py +46 -0
  248. uncountable/types/phases.py +3 -18
  249. uncountable/types/phases_t.py +27 -0
  250. uncountable/types/post_base.py +8 -0
  251. uncountable/types/post_base_t.py +30 -0
  252. uncountable/types/queued_job.py +16 -0
  253. uncountable/types/queued_job_t.py +123 -0
  254. uncountable/types/recipe_identifiers.py +12 -0
  255. uncountable/types/recipe_identifiers_t.py +76 -0
  256. uncountable/types/recipe_inputs.py +9 -0
  257. uncountable/types/recipe_inputs_t.py +30 -0
  258. uncountable/types/recipe_links.py +4 -45
  259. uncountable/types/recipe_links_t.py +54 -0
  260. uncountable/types/recipe_metadata.py +5 -45
  261. uncountable/types/recipe_metadata_t.py +58 -0
  262. uncountable/types/recipe_output_metadata.py +3 -19
  263. uncountable/types/recipe_output_metadata_t.py +28 -0
  264. uncountable/types/recipe_tags.py +3 -18
  265. uncountable/types/recipe_tags_t.py +27 -0
  266. uncountable/types/recipe_workflow_steps.py +14 -0
  267. uncountable/types/recipe_workflow_steps_t.py +95 -0
  268. uncountable/types/recipes.py +8 -0
  269. uncountable/types/recipes_t.py +25 -0
  270. uncountable/types/response.py +3 -20
  271. uncountable/types/response_t.py +26 -0
  272. uncountable/types/secret_retrieval.py +12 -0
  273. uncountable/types/secret_retrieval_t.py +75 -0
  274. uncountable/types/units.py +3 -18
  275. uncountable/types/units_t.py +27 -0
  276. uncountable/types/users.py +3 -19
  277. uncountable/types/users_t.py +28 -0
  278. uncountable/types/webhook_job.py +9 -0
  279. uncountable/types/webhook_job_t.py +37 -0
  280. uncountable/types/workflows.py +4 -27
  281. uncountable/types/workflows_t.py +39 -0
  282. UncountablePythonSDK-0.0.8.dist-info/METADATA +0 -27
  283. UncountablePythonSDK-0.0.8.dist-info/RECORD +0 -134
  284. examples/recipe-import/importer.py +0 -39
  285. type_spec/external/api/batch/execute_batch.yaml +0 -56
  286. type_spec/external/api/entity/create_entities.yaml +0 -33
  287. type_spec/external/api/entity/create_entity.yaml +0 -39
  288. type_spec/external/api/entity/get_entities_data.yaml +0 -29
  289. type_spec/external/api/entity/list_entities.yaml +0 -52
  290. type_spec/external/api/entity/resolve_entity_ids.yaml +0 -29
  291. type_spec/external/api/entity/set_values.yaml +0 -18
  292. type_spec/external/api/input_groups/get_input_group_names.yaml +0 -29
  293. type_spec/external/api/inputs/create_inputs.yaml +0 -48
  294. type_spec/external/api/inputs/get_input_data.yaml +0 -95
  295. type_spec/external/api/inputs/get_input_names.yaml +0 -38
  296. type_spec/external/api/inputs/get_inputs_data.yaml +0 -82
  297. type_spec/external/api/inputs/set_input_attribute_values.yaml +0 -33
  298. type_spec/external/api/outputs/get_output_data.yaml +0 -92
  299. type_spec/external/api/outputs/get_output_names.yaml +0 -35
  300. type_spec/external/api/outputs/resolve_output_conditions.yaml +0 -50
  301. type_spec/external/api/project/get_projects.yaml +0 -42
  302. type_spec/external/api/project/get_projects_data.yaml +0 -50
  303. type_spec/external/api/recipe_metadata/get_recipe_metadata_data.yaml +0 -41
  304. type_spec/external/api/recipes/create_recipes.yaml +0 -47
  305. type_spec/external/api/recipes/get_curve.yaml +0 -18
  306. type_spec/external/api/recipes/get_recipe_calculations.yaml +0 -39
  307. type_spec/external/api/recipes/get_recipe_links.yaml +0 -26
  308. type_spec/external/api/recipes/get_recipe_names.yaml +0 -29
  309. type_spec/external/api/recipes/get_recipe_output_metadata.yaml +0 -36
  310. type_spec/external/api/recipes/get_recipes_data.yaml +0 -238
  311. type_spec/external/api/recipes/set_recipe_inputs.yaml +0 -36
  312. type_spec/external/api/recipes/set_recipe_outputs.yaml +0 -52
@@ -1,82 +1,21 @@
1
1
  import io
2
2
  import os
3
- from typing import Any, Tuple
4
3
 
5
4
  from . import builder, util
6
- from .builder import SpecTypeDefnObject
7
5
  from .config import TypeScriptConfig
8
6
  from .emit_io_ts import emit_type_io_ts
9
7
  from .emit_typescript_util import (
10
- INDENT,
11
8
  MODIFY_NOTICE,
12
9
  EmitTypescriptContext,
10
+ emit_namespace_imports_ts,
11
+ emit_type_ts,
12
+ emit_value_ts,
13
+ resolve_namespace_name,
13
14
  resolve_namespace_ref,
14
- ts_name,
15
15
  ts_type_name,
16
16
  )
17
17
 
18
18
 
19
- def ts_enum_name(name: str, name_case: builder.NameCase) -> str:
20
- if name_case == builder.NameCase.js_upper:
21
- return name.upper()
22
- return ts_name(name, name_case)
23
-
24
-
25
- def _resolve_namespace_name(namespace: builder.SpecNamespace) -> str:
26
- return namespace.name
27
-
28
-
29
- def _emit_value(ctx: EmitTypescriptContext, stype: builder.SpecType, value: Any) -> str:
30
- """Mimics emit_python even if not all types are used in TypeScript yet"""
31
- literal = builder.unwrap_literal_type(stype)
32
- if literal is not None:
33
- return _emit_value(ctx, literal.value_type, literal.value)
34
-
35
- if stype.is_base_type(builder.BaseTypeName.s_string):
36
- assert isinstance(value, str)
37
- return util.encode_common_string(value)
38
- elif stype.is_base_type(builder.BaseTypeName.s_integer):
39
- assert isinstance(value, int)
40
- return str(value)
41
- elif stype.is_base_type(builder.BaseTypeName.s_boolean):
42
- assert isinstance(value, bool)
43
- return "true" if value else "false"
44
- elif stype.is_base_type(builder.BaseTypeName.s_lossy_decimal):
45
- return str(value)
46
- elif stype.is_base_type(builder.BaseTypeName.s_decimal):
47
- return f"'{value}'"
48
- elif isinstance(stype, builder.SpecTypeInstance):
49
- if stype.defn_type.is_base_type(builder.BaseTypeName.s_list):
50
- sub_type = stype.parameters[0]
51
- return "[" + ", ".join([_emit_value(ctx, sub_type, x) for x in value]) + "]"
52
-
53
- if stype.defn_type.is_base_type(builder.BaseTypeName.s_dict):
54
- key_type = stype.parameters[0]
55
- value_type = stype.parameters[1]
56
- return (
57
- "{\n\t"
58
- + ",\n\t".join(
59
- "["
60
- + _emit_value(ctx, key_type, dkey)
61
- + "]: "
62
- + _emit_value(ctx, value_type, dvalue)
63
- for dkey, dvalue in value.items()
64
- )
65
- + "\n}"
66
- )
67
-
68
- if stype.defn_type.is_base_type(builder.BaseTypeName.s_optional):
69
- sub_type = stype.parameters[0]
70
- if value is None:
71
- return "null"
72
- return _emit_value(ctx, sub_type, value)
73
-
74
- elif isinstance(stype, builder.SpecTypeDefnStringEnum):
75
- return f"{refer_to(ctx, stype)}.{ts_enum_name(value, stype.name_case)}"
76
-
77
- raise Exception("invalid constant type", value, stype)
78
-
79
-
80
19
  def emit_typescript(builder: builder.SpecBuilder, config: TypeScriptConfig) -> None:
81
20
  _emit_types(builder, config)
82
21
  _emit_id_source(builder, config)
@@ -90,11 +29,11 @@ def _emit_types(builder: builder.SpecBuilder, config: TypeScriptConfig) -> None:
90
29
 
91
30
  for namespace in sorted(
92
31
  builder.namespaces.values(),
93
- key=lambda ns: _resolve_namespace_name(ns),
32
+ key=lambda ns: resolve_namespace_name(ns),
94
33
  ):
95
- ctx = EmitTypescriptContext(out=io.StringIO(), namespace=namespace, config=config)
34
+ ctx = EmitTypescriptContext(out=io.StringIO(), namespace=namespace)
96
35
 
97
- _emit_namespace(ctx, namespace)
36
+ _emit_namespace(ctx, config, namespace)
98
37
 
99
38
  prepart = builder.preparts["typescript"].get(namespace.name)
100
39
  part = builder.parts["typescript"].get(namespace.name)
@@ -121,16 +60,7 @@ def _emit_types(builder: builder.SpecBuilder, config: TypeScriptConfig) -> None:
121
60
  full.write(f"// === END section from {namespace.name}.ts.prepart ===\n")
122
61
  full.write("\n")
123
62
 
124
- for ns in sorted(
125
- ctx.namespaces,
126
- key=lambda name: _resolve_namespace_name(name),
127
- ):
128
- import_as = resolve_namespace_ref(ns)
129
- import_path = (
130
- "./" if len(namespace.path) == 1 else "../" * (len(namespace.path) - 1)
131
- )
132
- import_from = f"{import_path}{_resolve_namespace_name(ns)}"
133
- full.write(f'import * as {import_as} from "{import_from}"\n') # noqa: E501
63
+ emit_namespace_imports_ts(ctx.namespaces, out=full, current_namespace=namespace)
134
64
  if namespace.emit_io_ts:
135
65
  full.write("import * as IO from 'io-ts';")
136
66
  full.write(ctx.out.getvalue())
@@ -150,7 +80,7 @@ def _emit_types(builder: builder.SpecBuilder, config: TypeScriptConfig) -> None:
150
80
 
151
81
  if len(namespace.path) == 1:
152
82
  index_out.write(
153
- f"import * as {resolve_namespace_ref(namespace)} from './{_resolve_namespace_name(namespace)}'\n"
83
+ f"import * as {resolve_namespace_ref(namespace)} from './{resolve_namespace_name(namespace)}'\n"
154
84
  ) # noqa: E501
155
85
  index_out_end.write(f"export {{{resolve_namespace_ref(namespace)}}}\n")
156
86
 
@@ -161,22 +91,27 @@ def _emit_types(builder: builder.SpecBuilder, config: TypeScriptConfig) -> None:
161
91
  util.rewrite_file(f"{config.types_output}/index.ts", index_out.getvalue())
162
92
 
163
93
 
164
- def _emit_namespace(ctx: EmitTypescriptContext, namespace: builder.SpecNamespace) -> None:
94
+ def _emit_namespace(
95
+ ctx: EmitTypescriptContext,
96
+ config: TypeScriptConfig,
97
+ namespace: builder.SpecNamespace,
98
+ ) -> None:
165
99
  for stype in namespace.types.values():
166
100
  if namespace.emit_io_ts:
167
101
  emit_type_io_ts(ctx, stype, namespace.derive_types_from_io_ts)
168
102
  if not namespace.emit_io_ts or not namespace.derive_types_from_io_ts:
169
- _emit_type(ctx, stype)
103
+ emit_type_ts(ctx, stype)
170
104
 
171
105
  for sconst in namespace.constants.values():
172
106
  _emit_constant(ctx, sconst)
173
107
 
174
108
  if namespace.endpoint is not None:
175
- _emit_endpoint(ctx, namespace, namespace.endpoint)
109
+ _emit_endpoint(ctx, config, namespace, namespace.endpoint)
176
110
 
177
111
 
178
112
  def _emit_endpoint(
179
113
  ctx: EmitTypescriptContext,
114
+ config: TypeScriptConfig,
180
115
  namespace: builder.SpecNamespace,
181
116
  endpoint: builder.SpecEndpoint,
182
117
  ) -> None:
@@ -188,6 +123,7 @@ def _emit_endpoint(
188
123
  has_data = "Data" in namespace.types
189
124
  has_deprecated_result = "DeprecatedResult" in namespace.types
190
125
  is_binary = endpoint.result_type == builder.ResultType.binary
126
+ has_multiple_endpoints = len(endpoint.path_per_api_endpoint) > 1
191
127
 
192
128
  result_type_count = sum([has_data, has_deprecated_result, is_binary])
193
129
  assert result_type_count < 2
@@ -222,51 +158,90 @@ def _emit_endpoint(
222
158
  wrap_call = (
223
159
  f"{wrap_name}<Arguments>" if is_binary else f"{wrap_name}<Arguments, Response>"
224
160
  )
225
- type_path = f"unc_mat/types/{'/'.join(namespace.path)}"
226
161
 
227
- if is_binary:
228
- tsx_response_part = f"""import {{ {wrap_name} }} from "unc_base/api"
229
- import {{ Arguments }} from "{type_path}"
162
+ unc_base_api_imports = (
163
+ f"appSpecificApiPath, {wrap_name}" if has_multiple_endpoints else wrap_name
164
+ )
165
+ unc_types_imports = (
166
+ 'import { ApplicationT } from "unc_types"\n' if has_multiple_endpoints else ""
167
+ )
230
168
 
169
+ type_path = f"unc_types/{'/'.join(namespace.path)}"
170
+
171
+ if is_binary:
172
+ tsx_response_part = f"""import {{ {unc_base_api_imports} }} from "unc_base/api"
173
+ import type {{ Arguments }} from "{type_path}"
174
+ {unc_types_imports}
231
175
  export type {{ Arguments }}
232
176
  """
233
177
  elif has_data and endpoint.has_attachment:
234
- tsx_response_part = f"""import {{ {wrap_name}, AttachmentResponse }} from "unc_base/api"
235
- import {{ Arguments, Data }} from "{type_path}"
236
-
178
+ tsx_response_part = f"""import {{ {unc_base_api_imports}, type AttachmentResponse }} from "unc_base/api"
179
+ import type {{ Arguments, Data }} from "{type_path}"
180
+ {unc_types_imports}
237
181
  export type {{ Arguments, Data }}
238
182
  export type Response = AttachmentResponse<Data>
239
183
  """
240
184
  elif has_data:
241
- tsx_response_part = f"""import {{ {wrap_name}, JsonResponse }} from "unc_base/api"
242
- import {{ Arguments, Data }} from "{type_path}"
243
-
185
+ tsx_response_part = f"""import {{ {unc_base_api_imports}, type JsonResponse }} from "unc_base/api"
186
+ import type {{ Arguments, Data }} from "{type_path}"
187
+ {unc_types_imports}
244
188
  export type {{ Arguments, Data }}
245
189
  export type Response = JsonResponse<Data>
246
190
  """
247
191
 
248
192
  else:
249
193
  assert has_deprecated_result
250
- tsx_response_part = f"""import {{ {wrap_name} }} from "unc_base/api"
251
- import {{ Arguments, DeprecatedResult }} from "{type_path}"
252
-
194
+ tsx_response_part = f"""import {{ {unc_base_api_imports} }} from "unc_base/api"
195
+ import type {{ Arguments, DeprecatedResult }} from "{type_path}"
196
+ {unc_types_imports}
253
197
  export type {{ Arguments }}
254
198
  export type Response = DeprecatedResult
255
199
  """
256
200
 
201
+ """
202
+
203
+ export const apiCall = buildWrappedGetCall<Arguments, Response>(
204
+ appSpecificApiPath({
205
+ [ApplicationT.FrontendApplication.materials]: "api/materials/common/list_id_source",
206
+ }),
207
+ )
208
+
209
+
210
+ """
211
+
212
+ endpoint_path_part = (
213
+ f'"{endpoint.path_root}/{endpoint.path_dirname}/{endpoint.path_basename}",'
214
+ )
215
+
216
+ if has_multiple_endpoints:
217
+ path_lookup_map = ""
218
+ for (
219
+ api_endpoint_key,
220
+ endpoint_specific_path,
221
+ ) in endpoint.path_per_api_endpoint.items():
222
+ full_path = f"{endpoint_specific_path.path_root}/{endpoint_specific_path.path_dirname}/{endpoint_specific_path.path_basename}"
223
+ frontend_app_value = config.endpoint_to_frontend_app_type[api_endpoint_key]
224
+
225
+ path_lookup_map += (
226
+ f'\n [ApplicationT.{frontend_app_value}]: "{full_path}",'
227
+ )
228
+
229
+ endpoint_path_part = f"""appSpecificApiPath({{{path_lookup_map}
230
+ }}),"""
231
+
257
232
  tsx_api = f"""{MODIFY_NOTICE}
258
233
  {data_loader_head}{tsx_response_part}
259
234
  export const apiCall = {wrap_call}(
260
- "{endpoint.path_root}/{endpoint.path_dirname}/{endpoint.path_basename}",
235
+ {endpoint_path_part}
261
236
  )
262
237
  {data_loader_body}"""
263
238
 
264
- output = f"{ctx.config.routes_output}/{'/'.join(namespace.path)}.tsx"
239
+ output = f"{config.routes_output}/{'/'.join(namespace.path)}.tsx"
265
240
  util.rewrite_file(output, tsx_api)
266
241
 
267
242
  # Hacky index support, until enough is migrated to regen entirely
268
243
  # Emits the import into the UI API index file
269
- index_path = f"{ctx.config.routes_output}/{'/'.join(namespace.path[0:-1])}/index.tsx"
244
+ index_path = f"{config.routes_output}/{'/'.join(namespace.path[0:-1])}/index.tsx"
270
245
  api_name = f"Api{ts_type_name(namespace.path[0 - 1])}"
271
246
  if os.path.exists(index_path):
272
247
  with open(index_path) as index:
@@ -278,192 +253,18 @@ export const apiCall = {wrap_call}(
278
253
  if need_index:
279
254
  with open(index_path, "a") as index:
280
255
  print(f"Updated API Index {index_path}")
281
- index.write("\n// eslint-disable-next-line import/first\n")
282
256
  index.write(f'import * as {api_name} from "./{namespace.path[-1]}"\n\n')
283
257
  index.write(f"export {{ {api_name} }}\n")
284
258
 
285
259
 
286
- MARKER_BEGIN = "### BEGIN:TYPE_SPEC"
287
- MARKER_END = "### END:TYPE_SPEC"
288
-
289
-
290
- def _patch_file_line(filename: str, line: str) -> None:
291
- """
292
- Adds a line into a file inside a marked region. The file section is
293
- kept ordered. The rest of the file is untouched.
294
- """
295
- with open(filename) as ignore_in:
296
- ignore_data = ignore_in.read()
297
- need_ignore = ignore_data.find(line) == -1
298
- if not need_ignore:
299
- return
300
-
301
- begin = ignore_data.find(MARKER_BEGIN)
302
- end = ignore_data.find(MARKER_END)
303
- if begin == -1 or end == -1:
304
- predata = ignore_data
305
- postdata = ""
306
- linedata = ""
307
- else:
308
- predata = ignore_data[:begin]
309
- postdata = ignore_data[(end + len(MARKER_END)) :]
310
- linedata = ignore_data[begin + len(MARKER_BEGIN) : end]
311
-
312
- lines = [y for y in [x.strip() for x in linedata.split("\n")] if len(y) > 0]
313
- lines.append(line)
314
-
315
- with open(filename, "w") as ignore_out:
316
- ignore_out.write(f"{predata}{MARKER_BEGIN}\n")
317
- ignore_out.write("\n".join(sorted(lines)))
318
- ignore_out.write(f"\n{MARKER_END}{postdata}")
319
-
320
-
321
- def _emit_type(ctx: EmitTypescriptContext, stype: builder.SpecType) -> None:
322
- if not isinstance(stype, builder.SpecTypeDefn):
323
- return
324
-
325
- if stype.is_base or stype.is_predefined:
326
- return
327
-
328
- ctx.out.write("\n")
329
- ctx.out.write(MODIFY_NOTICE)
330
-
331
- if isinstance(stype, builder.SpecTypeDefnExternal):
332
- assert not stype.is_exported, "expecting private names"
333
- ctx.out.write(stype.external_map["ts"])
334
- ctx.out.write("\n")
335
- return
336
-
337
- assert stype.is_exported, "expecting exported names"
338
- if isinstance(stype, builder.SpecTypeDefnAlias):
339
- ctx.out.write(f"export type {stype.name} = {refer_to(ctx, stype.alias)}\n")
340
- return
341
-
342
- if isinstance(stype, builder.SpecTypeDefnStringEnum):
343
- ctx.out.write(f"export enum {stype.name} {{\n")
344
- assert stype.values
345
- for name, entry in stype.values.items():
346
- ctx.out.write(
347
- f'{INDENT}{ts_enum_name(name, stype.name_case)} = "{entry.value}",\n'
348
- )
349
- ctx.out.write("}\n")
350
- return
351
-
352
- assert isinstance(stype, builder.SpecTypeDefnObject)
353
- assert stype.base is not None
354
-
355
- base_type = ""
356
- if not stype.base.is_base:
357
- base_type = f"{refer_to(ctx, stype.base)} & "
358
-
359
- if stype.properties is None and base_type == "":
360
- ctx.out.write(f"export type {stype.name} = TEmpty\n")
361
- elif stype.properties is None:
362
- ctx.out.write(f"export type {stype.name} = {base_type}{{}}\n")
363
- else:
364
- if isinstance(stype, SpecTypeDefnObject) and len(stype.parameters) > 0:
365
- full_type_name = f'{stype.name}<{", ".join(stype.parameters)}>'
366
- else:
367
- full_type_name = stype.name
368
- ctx.out.write(f"export type {full_type_name} = {base_type}{{")
369
- ctx.out.write("\n")
370
- for prop in stype.properties.values():
371
- ref_type = refer_to(ctx, prop.spec_type)
372
- prop_name = ts_name(prop.name, prop.name_case)
373
- if prop.has_default and not prop.parse_require:
374
- # For now, we'll assume the generated types with defaults are meant as
375
- # arguments, thus treat like extant==missing
376
- # IMPROVE: if we can decide they are meant as output instead, then
377
- # they should be marked as required
378
- ctx.out.write(f"{INDENT}{prop_name}?: {ref_type}")
379
- elif prop.extant == builder.PropertyExtant.missing:
380
- # Unlike optional below, missing does not imply null is possible. They
381
- # treated distinctly.
382
- ctx.out.write(f"{INDENT}{prop_name}?: {ref_type}")
383
- elif prop.extant == builder.PropertyExtant.optional:
384
- # Need to add in |null since Python side can produce null's right now
385
- # IMPROVE: It would be better if the serializer could instead omit the None's
386
- # Dropping the null should be forward compatible
387
- ctx.out.write(f"{INDENT}{prop_name}?: {ref_type} | null")
388
- else:
389
- ctx.out.write(f"{INDENT}{prop_name}: {ref_type}")
390
- ctx.out.write("\n")
391
- ctx.out.write("}\n")
392
-
393
-
394
260
  def _emit_constant(ctx: EmitTypescriptContext, sconst: builder.SpecConstant) -> None:
395
261
  ctx.out.write("\n\n")
396
262
  ctx.out.write(MODIFY_NOTICE)
397
- value = _emit_value(ctx, sconst.value_type, sconst.value)
263
+ value = emit_value_ts(ctx, sconst.value_type, sconst.value)
398
264
  const_name = sconst.name.upper()
399
265
  ctx.out.write(f"export const {const_name} = {value}\n")
400
266
 
401
267
 
402
- base_name_map = {
403
- builder.BaseTypeName.s_boolean: "boolean",
404
- builder.BaseTypeName.s_date: "string", # IMPROVE: Aliased DateStr
405
- builder.BaseTypeName.s_date_time: "string", # IMPROVE: Aliased DateTimeStr
406
- # Decimal's are marked as to_string_values thus are strings in the front-end
407
- builder.BaseTypeName.s_decimal: "string",
408
- builder.BaseTypeName.s_dict: "PartialRecord",
409
- builder.BaseTypeName.s_integer: "number",
410
- builder.BaseTypeName.s_lossy_decimal: "number",
411
- builder.BaseTypeName.s_opaque_key: "string",
412
- builder.BaseTypeName.s_none: "null",
413
- builder.BaseTypeName.s_string: "string",
414
- # UNC: global types
415
- builder.BaseTypeName.s_json_value: "JsonValue",
416
- }
417
-
418
-
419
- def refer_to(ctx: EmitTypescriptContext, stype: builder.SpecType) -> str:
420
- return refer_to_impl(ctx, stype)[0]
421
-
422
-
423
- def refer_to_impl(
424
- ctx: EmitTypescriptContext, stype: builder.SpecType
425
- ) -> Tuple[str, bool]:
426
- """
427
- @return (string-specific, multiple-types)
428
- """
429
- if isinstance(stype, builder.SpecTypeInstance):
430
- if stype.defn_type.name == builder.BaseTypeName.s_list:
431
- spec, multi = refer_to_impl(ctx, stype.parameters[0])
432
- return f"({spec})[]" if multi else f"{spec}[]", False
433
- if stype.defn_type.name == builder.BaseTypeName.s_union:
434
- return f'({" | ".join([refer_to(ctx, p) for p in stype.parameters])})', False
435
- if stype.defn_type.name == builder.BaseTypeName.s_literal:
436
- parts = []
437
- for parameter in stype.parameters:
438
- assert isinstance(parameter, builder.SpecTypeLiteralWrapper)
439
- parts.append(refer_to(ctx, parameter))
440
- return f'({" | ".join(parts)})', False
441
- if stype.defn_type.name == builder.BaseTypeName.s_optional:
442
- return f"{refer_to(ctx, stype.parameters[0])} | null", True
443
- if stype.defn_type.name == builder.BaseTypeName.s_tuple:
444
- return f"[{', '.join([refer_to(ctx, p) for p in stype.parameters])}]", False
445
- params = ", ".join([refer_to(ctx, p) for p in stype.parameters])
446
- return f"{refer_to(ctx, stype.defn_type)}<{params}>", False
447
-
448
- if isinstance(stype, builder.SpecTypeLiteralWrapper):
449
- return _emit_value(ctx, stype.value_type, stype.value), False
450
-
451
- if isinstance(stype, builder.SpecTypeGenericParameter):
452
- return stype.name, False
453
-
454
- assert isinstance(stype, builder.SpecTypeDefn)
455
- if stype.is_base: # assume correct namespace
456
- if stype.name == builder.BaseTypeName.s_list:
457
- return "any[]", False # TODO: generic type
458
- return base_name_map[builder.BaseTypeName(stype.name)], False
459
-
460
- if stype.namespace == ctx.namespace:
461
- return stype.name, False
462
-
463
- ctx.namespaces.add(stype.namespace)
464
- return f"{resolve_namespace_ref(stype.namespace)}.{stype.name}", False
465
-
466
-
467
268
  def _emit_id_source(builder: builder.SpecBuilder, config: TypeScriptConfig) -> None:
468
269
  id_source_output = config.id_source_output
469
270
  if id_source_output is None: