@typespec/http-client-python 0.28.2 → 0.29.0

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.
Files changed (368) hide show
  1. package/dist/emitter/code-model.d.ts.map +1 -1
  2. package/dist/emitter/code-model.js +7 -6
  3. package/dist/emitter/code-model.js.map +1 -1
  4. package/dist/emitter/constants.d.ts +6 -0
  5. package/dist/emitter/constants.d.ts.map +1 -0
  6. package/dist/emitter/constants.js +27 -0
  7. package/dist/emitter/constants.js.map +1 -0
  8. package/dist/emitter/emitter.d.ts.map +1 -1
  9. package/dist/emitter/emitter.js +193 -119
  10. package/dist/emitter/emitter.js.map +1 -1
  11. package/dist/emitter/http.d.ts.map +1 -1
  12. package/dist/emitter/http.js +33 -1
  13. package/dist/emitter/http.js.map +1 -1
  14. package/dist/emitter/lib.d.ts +37 -3
  15. package/dist/emitter/lib.d.ts.map +1 -1
  16. package/dist/emitter/lib.js +17 -0
  17. package/dist/emitter/lib.js.map +1 -1
  18. package/dist/emitter/run-python3.js +1 -1
  19. package/dist/emitter/run-python3.js.map +1 -1
  20. package/dist/emitter/system-requirements.js +6 -4
  21. package/dist/emitter/system-requirements.js.map +1 -1
  22. package/dist/emitter/types.d.ts +2 -5
  23. package/dist/emitter/types.d.ts.map +1 -1
  24. package/dist/emitter/types.js +86 -63
  25. package/dist/emitter/types.js.map +1 -1
  26. package/dist/emitter/utils.d.ts.map +1 -1
  27. package/dist/emitter/utils.js +16 -17
  28. package/dist/emitter/utils.js.map +1 -1
  29. package/emitter/src/code-model.ts +7 -13
  30. package/emitter/src/constants.ts +27 -0
  31. package/emitter/src/emitter.ts +241 -123
  32. package/emitter/src/http.ts +29 -1
  33. package/emitter/src/lib.ts +24 -0
  34. package/emitter/src/run-python3.ts +1 -1
  35. package/emitter/src/system-requirements.ts +4 -4
  36. package/emitter/src/types.ts +102 -62
  37. package/emitter/src/utils.ts +16 -18
  38. package/emitter/temp/tsconfig.tsbuildinfo +1 -1
  39. package/emitter/test/utils.test.ts +3 -0
  40. package/emitter/tsconfig.build.json +2 -1
  41. package/emitter/tsconfig.json +2 -1
  42. package/eng/scripts/Build-Packages.ps1 +62 -37
  43. package/eng/scripts/Check-GitChanges.ps1 +30 -3
  44. package/eng/scripts/Functions.ps1 +54 -15
  45. package/eng/scripts/Generate.ps1 +42 -8
  46. package/eng/scripts/Generation.psm1 +44 -15
  47. package/eng/scripts/Initialize-Repository.ps1 +29 -11
  48. package/eng/scripts/Test-Packages.ps1 +47 -31
  49. package/eng/scripts/ci/config/eslint-ci.config.mjs +64 -0
  50. package/eng/scripts/ci/{mypy.ini → config/mypy.ini} +1 -1
  51. package/eng/scripts/ci/{pylintrc → config/pylintrc} +1 -1
  52. package/eng/scripts/ci/{pyrightconfig.json → config/pyrightconfig.json} +1 -1
  53. package/eng/scripts/ci/dev_requirements.txt +2 -1
  54. package/eng/scripts/ci/format.ts +232 -2
  55. package/eng/scripts/ci/lint.ts +223 -20
  56. package/eng/scripts/ci/regenerate-common.ts +411 -136
  57. package/eng/scripts/ci/regenerate.ts +247 -101
  58. package/eng/scripts/ci/run-tests.ts +507 -0
  59. package/eng/scripts/ci/run_apiview.py +22 -16
  60. package/eng/scripts/ci/run_mypy.py +34 -23
  61. package/eng/scripts/ci/run_pylint.py +27 -19
  62. package/eng/scripts/ci/run_pyright.py +9 -5
  63. package/eng/scripts/ci/run_sphinx_build.py +24 -9
  64. package/eng/scripts/ci/typecheck.ts +225 -0
  65. package/eng/scripts/ci/util.py +61 -25
  66. package/eng/scripts/ci/utils.ts +5 -5
  67. package/eng/scripts/setup/__pycache__/package_manager.cpython-311.pyc +0 -0
  68. package/eng/scripts/setup/__pycache__/venvtools.cpython-311.pyc +0 -0
  69. package/eng/scripts/setup/build.ts +1 -1
  70. package/eng/scripts/setup/build_pygen_wheel.py +4 -3
  71. package/eng/scripts/setup/install.py +4 -3
  72. package/eng/scripts/setup/install.ts +1 -1
  73. package/eng/scripts/setup/prepare.py +3 -2
  74. package/eng/scripts/setup/prepare.ts +1 -1
  75. package/eng/scripts/setup/run-python3.ts +1 -1
  76. package/eng/scripts/setup/run_batch.py +197 -0
  77. package/eng/scripts/setup/run_tsp.py +3 -3
  78. package/eng/scripts/setup/system-requirements.ts +8 -4
  79. package/eng/scripts/setup/venvtools.py +1 -1
  80. package/generator/build/lib/pygen/__init__.py +1 -3
  81. package/generator/build/lib/pygen/codegen/__init__.py +0 -1
  82. package/generator/build/lib/pygen/codegen/models/base.py +0 -1
  83. package/generator/build/lib/pygen/codegen/models/client.py +2 -1
  84. package/generator/build/lib/pygen/codegen/models/code_model.py +1 -0
  85. package/generator/build/lib/pygen/codegen/models/enum_type.py +0 -1
  86. package/generator/build/lib/pygen/codegen/models/model_type.py +1 -7
  87. package/generator/build/lib/pygen/codegen/models/parameter.py +16 -14
  88. package/generator/build/lib/pygen/codegen/serializers/__init__.py +27 -12
  89. package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +12 -3
  90. package/generator/build/lib/pygen/codegen/serializers/general_serializer.py +6 -2
  91. package/generator/build/lib/pygen/codegen/serializers/import_serializer.py +17 -4
  92. package/generator/build/lib/pygen/codegen/serializers/parameter_serializer.py +17 -11
  93. package/generator/build/lib/pygen/codegen/templates/model_base.py.jinja2 +176 -71
  94. package/generator/build/lib/pygen/codegen/templates/packaging_templates/README.md.jinja2 +11 -3
  95. package/generator/build/lib/pygen/codegen/templates/packaging_templates/pyproject.toml.jinja2 +1 -1
  96. package/generator/build/lib/pygen/codegen/templates/serialization.py.jinja2 +5 -1
  97. package/generator/build/lib/pygen/preprocess/__init__.py +37 -30
  98. package/generator/component-detection-pip-report.json +7 -7
  99. package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
  100. package/generator/pygen/__init__.py +1 -3
  101. package/generator/pygen/codegen/__init__.py +0 -1
  102. package/generator/pygen/codegen/models/base.py +0 -1
  103. package/generator/pygen/codegen/models/client.py +2 -1
  104. package/generator/pygen/codegen/models/code_model.py +1 -0
  105. package/generator/pygen/codegen/models/enum_type.py +0 -1
  106. package/generator/pygen/codegen/models/model_type.py +1 -7
  107. package/generator/pygen/codegen/models/parameter.py +16 -14
  108. package/generator/pygen/codegen/serializers/__init__.py +27 -12
  109. package/generator/pygen/codegen/serializers/builder_serializer.py +12 -3
  110. package/generator/pygen/codegen/serializers/general_serializer.py +6 -2
  111. package/generator/pygen/codegen/serializers/import_serializer.py +17 -4
  112. package/generator/pygen/codegen/serializers/parameter_serializer.py +17 -11
  113. package/generator/pygen/codegen/templates/model_base.py.jinja2 +176 -71
  114. package/generator/pygen/codegen/templates/packaging_templates/README.md.jinja2 +11 -3
  115. package/generator/pygen/codegen/templates/packaging_templates/pyproject.toml.jinja2 +1 -1
  116. package/generator/pygen/codegen/templates/serialization.py.jinja2 +5 -1
  117. package/generator/pygen/preprocess/__init__.py +37 -30
  118. package/generator/pygen.egg-info/PKG-INFO +1 -2
  119. package/generator/pygen.egg-info/requires.txt +1 -1
  120. package/generator/setup.py +1 -2
  121. package/package.json +63 -42
  122. package/eng/scripts/ci/run-ci.ts +0 -89
  123. package/generator/test/azure/mock_api_tests/asynctests/test_azure_arm_commonproperties_async.py +0 -94
  124. package/generator/test/azure/mock_api_tests/asynctests/test_azure_arm_largeheader_async.py +0 -30
  125. package/generator/test/azure/mock_api_tests/asynctests/test_azure_arm_nonresource_async.py +0 -36
  126. package/generator/test/azure/mock_api_tests/asynctests/test_azure_arm_operationtemplates_async.py +0 -205
  127. package/generator/test/azure/mock_api_tests/asynctests/test_azure_arm_resource_async.py +0 -478
  128. package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_access_async.py +0 -101
  129. package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_api_version_header_async.py +0 -18
  130. package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_api_version_path_async.py +0 -18
  131. package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_api_version_query_async.py +0 -18
  132. package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_client_default_value_async.py +0 -46
  133. package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_client_initialization_async.py +0 -58
  134. package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_client_location_async.py +0 -82
  135. package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_deserialize_empty_string_as_null_async.py +0 -20
  136. package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_flatten_async.py +0 -115
  137. package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_hierrarchy_building_async.py +0 -53
  138. package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_next_link_verb_async.py +0 -28
  139. package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_override_async.py +0 -106
  140. package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_usage_async.py +0 -38
  141. package/generator/test/azure/mock_api_tests/asynctests/test_azure_core_basic_async.py +0 -76
  142. package/generator/test/azure/mock_api_tests/asynctests/test_azure_core_lro_rpc_async.py +0 -22
  143. package/generator/test/azure/mock_api_tests/asynctests/test_azure_core_lro_standard_async.py +0 -39
  144. package/generator/test/azure/mock_api_tests/asynctests/test_azure_core_model_async.py +0 -33
  145. package/generator/test/azure/mock_api_tests/asynctests/test_azure_core_page_async.py +0 -80
  146. package/generator/test/azure/mock_api_tests/asynctests/test_azure_core_scalar_async.py +0 -41
  147. package/generator/test/azure/mock_api_tests/asynctests/test_azure_core_traits_async.py +0 -87
  148. package/generator/test/azure/mock_api_tests/asynctests/test_azure_encode_duration_async.py +0 -19
  149. package/generator/test/azure/mock_api_tests/asynctests/test_azure_example_basic_async.py +0 -30
  150. package/generator/test/azure/mock_api_tests/asynctests/test_azure_payload_pageable_async.py +0 -19
  151. package/generator/test/azure/mock_api_tests/asynctests/test_azure_resource_manager_method_subscription_id_async.py +0 -248
  152. package/generator/test/azure/mock_api_tests/asynctests/test_azure_resource_manager_multi_service_async.py +0 -110
  153. package/generator/test/azure/mock_api_tests/asynctests/test_azure_resource_manager_multi_service_shared_models_async.py +0 -132
  154. package/generator/test/azure/mock_api_tests/asynctests/test_azure_special_headers_client_request_id_async.py +0 -30
  155. package/generator/test/azure/mock_api_tests/asynctests/test_azure_versioning_previewversion_async.py +0 -53
  156. package/generator/test/azure/mock_api_tests/asynctests/test_client_namespace_async.py +0 -34
  157. package/generator/test/azure/mock_api_tests/asynctests/test_client_naming_async.py +0 -69
  158. package/generator/test/azure/mock_api_tests/asynctests/test_client_naming_enum_conflict_async.py +0 -37
  159. package/generator/test/azure/mock_api_tests/asynctests/test_client_overload_async.py +0 -27
  160. package/generator/test/azure/mock_api_tests/asynctests/test_client_structure_async.py +0 -64
  161. package/generator/test/azure/mock_api_tests/asynctests/test_client_structure_clientoperationgroup_async.py +0 -31
  162. package/generator/test/azure/mock_api_tests/asynctests/test_encode_duration_async.py +0 -63
  163. package/generator/test/azure/mock_api_tests/asynctests/test_encode_numeric_async.py +0 -35
  164. package/generator/test/azure/mock_api_tests/asynctests/test_parameters_basic_async.py +0 -24
  165. package/generator/test/azure/mock_api_tests/asynctests/test_parameters_spread_async.py +0 -76
  166. package/generator/test/azure/mock_api_tests/asynctests/test_payload_content_negotiation_async.py +0 -37
  167. package/generator/test/azure/mock_api_tests/asynctests/test_payload_multipart_async.py +0 -216
  168. package/generator/test/azure/mock_api_tests/asynctests/test_resiliency_srv_driven_async.py +0 -130
  169. package/generator/test/azure/mock_api_tests/asynctests/test_serialization_encoded_name_json_async.py +0 -24
  170. package/generator/test/azure/mock_api_tests/asynctests/test_service_multi_service_async.py +0 -31
  171. package/generator/test/azure/mock_api_tests/asynctests/test_special_words_async.py +0 -71
  172. package/generator/test/azure/mock_api_tests/conftest.py +0 -207
  173. package/generator/test/azure/mock_api_tests/data/image.jpg +0 -0
  174. package/generator/test/azure/mock_api_tests/data/image.png +0 -0
  175. package/generator/test/azure/mock_api_tests/test_azure_arm_commonproperties.py +0 -89
  176. package/generator/test/azure/mock_api_tests/test_azure_arm_largeheader.py +0 -27
  177. package/generator/test/azure/mock_api_tests/test_azure_arm_nonresource.py +0 -34
  178. package/generator/test/azure/mock_api_tests/test_azure_arm_operationtemplates.py +0 -180
  179. package/generator/test/azure/mock_api_tests/test_azure_arm_resource.py +0 -436
  180. package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_access.py +0 -92
  181. package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_api_version_header.py +0 -17
  182. package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_api_version_path.py +0 -17
  183. package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_api_version_query.py +0 -17
  184. package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_client_default_value.py +0 -42
  185. package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_client_initialization.py +0 -51
  186. package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_client_location.py +0 -70
  187. package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_deserialize_empty_string_as_null.py +0 -19
  188. package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_flatten.py +0 -104
  189. package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_hierrarchy_building.py +0 -45
  190. package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_next_link_verb.py +0 -27
  191. package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_override.py +0 -102
  192. package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_usage.py +0 -32
  193. package/generator/test/azure/mock_api_tests/test_azure_core_basic.py +0 -70
  194. package/generator/test/azure/mock_api_tests/test_azure_core_lro_rpc.py +0 -20
  195. package/generator/test/azure/mock_api_tests/test_azure_core_lro_standard.py +0 -32
  196. package/generator/test/azure/mock_api_tests/test_azure_core_model.py +0 -30
  197. package/generator/test/azure/mock_api_tests/test_azure_core_page.py +0 -71
  198. package/generator/test/azure/mock_api_tests/test_azure_core_scalar.py +0 -35
  199. package/generator/test/azure/mock_api_tests/test_azure_core_traits.py +0 -85
  200. package/generator/test/azure/mock_api_tests/test_azure_encode_duration.py +0 -18
  201. package/generator/test/azure/mock_api_tests/test_azure_example_basic.py +0 -29
  202. package/generator/test/azure/mock_api_tests/test_azure_payload_pageable.py +0 -18
  203. package/generator/test/azure/mock_api_tests/test_azure_resource_manager_method_subscription_id.py +0 -235
  204. package/generator/test/azure/mock_api_tests/test_azure_resource_manager_multi_service.py +0 -104
  205. package/generator/test/azure/mock_api_tests/test_azure_resource_manager_multi_service_shared_models.py +0 -128
  206. package/generator/test/azure/mock_api_tests/test_azure_special_headers_client_request_id.py +0 -29
  207. package/generator/test/azure/mock_api_tests/test_azure_versioning_previewversion.py +0 -50
  208. package/generator/test/azure/mock_api_tests/test_clear_output_folder.py +0 -23
  209. package/generator/test/azure/mock_api_tests/test_client_namespace.py +0 -32
  210. package/generator/test/azure/mock_api_tests/test_client_naming.py +0 -57
  211. package/generator/test/azure/mock_api_tests/test_client_naming_enum_conflict.py +0 -35
  212. package/generator/test/azure/mock_api_tests/test_client_overload.py +0 -25
  213. package/generator/test/azure/mock_api_tests/test_client_structure.py +0 -60
  214. package/generator/test/azure/mock_api_tests/test_client_structure_clientoperationgroup.py +0 -29
  215. package/generator/test/azure/mock_api_tests/test_encode_duration.py +0 -60
  216. package/generator/test/azure/mock_api_tests/test_encode_numeric.py +0 -31
  217. package/generator/test/azure/mock_api_tests/test_model_base_flatten_compatibility.py +0 -251
  218. package/generator/test/azure/mock_api_tests/test_parameters_basic.py +0 -22
  219. package/generator/test/azure/mock_api_tests/test_parameters_spread.py +0 -66
  220. package/generator/test/azure/mock_api_tests/test_payload_content_negotiation.py +0 -33
  221. package/generator/test/azure/mock_api_tests/test_payload_multipart.py +0 -198
  222. package/generator/test/azure/mock_api_tests/test_resiliency_srv_driven.py +0 -124
  223. package/generator/test/azure/mock_api_tests/test_serialization_encoded_name_json.py +0 -21
  224. package/generator/test/azure/mock_api_tests/test_service_multi_service.py +0 -29
  225. package/generator/test/azure/mock_api_tests/test_special_words.py +0 -63
  226. package/generator/test/azure/requirements.txt +0 -125
  227. package/generator/test/azure/tox.ini +0 -64
  228. package/generator/test/data/image.jpg +0 -0
  229. package/generator/test/data/image.png +0 -0
  230. package/generator/test/dev_requirements.txt +0 -8
  231. package/generator/test/generic_mock_api_tests/asynctests/test_authentication_async.py +0 -140
  232. package/generator/test/generic_mock_api_tests/asynctests/test_encode_array_async.py +0 -139
  233. package/generator/test/generic_mock_api_tests/asynctests/test_encode_bytes_async.py +0 -132
  234. package/generator/test/generic_mock_api_tests/asynctests/test_encode_datetime_async.py +0 -127
  235. package/generator/test/generic_mock_api_tests/asynctests/test_headasboolean_async.py +0 -35
  236. package/generator/test/generic_mock_api_tests/asynctests/test_parameters_body_optionality_async.py +0 -30
  237. package/generator/test/generic_mock_api_tests/asynctests/test_parameters_collection_format_async.py +0 -38
  238. package/generator/test/generic_mock_api_tests/asynctests/test_parameters_path_async.py +0 -24
  239. package/generator/test/generic_mock_api_tests/asynctests/test_parameters_query_async.py +0 -18
  240. package/generator/test/generic_mock_api_tests/asynctests/test_payload_json_merge_patch_async.py +0 -98
  241. package/generator/test/generic_mock_api_tests/asynctests/test_payload_media_type_async.py +0 -27
  242. package/generator/test/generic_mock_api_tests/asynctests/test_payload_pageable_async.py +0 -134
  243. package/generator/test/generic_mock_api_tests/asynctests/test_payload_xml_async.py +0 -150
  244. package/generator/test/generic_mock_api_tests/asynctests/test_response_status_code_range_async.py +0 -38
  245. package/generator/test/generic_mock_api_tests/asynctests/test_routes_async.py +0 -331
  246. package/generator/test/generic_mock_api_tests/asynctests/test_server_endpoint_not_defined_async.py +0 -18
  247. package/generator/test/generic_mock_api_tests/asynctests/test_server_path_multiple_async.py +0 -25
  248. package/generator/test/generic_mock_api_tests/asynctests/test_server_path_single_async.py +0 -18
  249. package/generator/test/generic_mock_api_tests/asynctests/test_server_versions_not_versioned_async.py +0 -28
  250. package/generator/test/generic_mock_api_tests/asynctests/test_server_versions_versioned_async.py +0 -34
  251. package/generator/test/generic_mock_api_tests/asynctests/test_special_headers_conditional_request_async.py +0 -38
  252. package/generator/test/generic_mock_api_tests/asynctests/test_special_headers_repeatability_async.py +0 -19
  253. package/generator/test/generic_mock_api_tests/asynctests/test_specs_documentation_async.py +0 -59
  254. package/generator/test/generic_mock_api_tests/asynctests/test_streaming_jsonl_async.py +0 -27
  255. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_array_async.py +0 -127
  256. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_dictionary_async.py +0 -98
  257. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_enum_extensible_async.py +0 -25
  258. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_enum_fixed_async.py +0 -27
  259. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_file_async.py +0 -59
  260. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_model_empty_async.py +0 -32
  261. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_model_inheritance_enum_discriminator_async.py +0 -70
  262. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_model_inheritance_nested_discriminator_async.py +0 -85
  263. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_model_inheritance_not_discriminated_async.py +0 -34
  264. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_model_inheritance_recursive_async.py +0 -34
  265. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_model_inheritance_single_discriminator_async.py +0 -67
  266. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_model_usage_async.py +0 -32
  267. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_model_visibility_async.py +0 -47
  268. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_property_additionalproperties_async.py +0 -353
  269. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_property_nullable_async.py +0 -110
  270. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_property_optional_async.py +0 -197
  271. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_property_valuetypes_async.py +0 -315
  272. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_scalar_async.py +0 -60
  273. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_union_async.py +0 -90
  274. package/generator/test/generic_mock_api_tests/asynctests/test_versioning_added_async.py +0 -36
  275. package/generator/test/generic_mock_api_tests/asynctests/test_versioning_made_optional_async.py +0 -21
  276. package/generator/test/generic_mock_api_tests/asynctests/test_versioning_removed_async.py +0 -39
  277. package/generator/test/generic_mock_api_tests/asynctests/test_versioning_renamed_from_async.py +0 -29
  278. package/generator/test/generic_mock_api_tests/asynctests/test_versioning_return_type_changed_from_async.py +0 -18
  279. package/generator/test/generic_mock_api_tests/asynctests/test_versioning_type_changed_from_async.py +0 -22
  280. package/generator/test/generic_mock_api_tests/conftest.py +0 -75
  281. package/generator/test/generic_mock_api_tests/data/image.jpg +0 -0
  282. package/generator/test/generic_mock_api_tests/data/image.png +0 -0
  283. package/generator/test/generic_mock_api_tests/test_authentication.py +0 -130
  284. package/generator/test/generic_mock_api_tests/test_encode_array.py +0 -126
  285. package/generator/test/generic_mock_api_tests/test_encode_bytes.py +0 -128
  286. package/generator/test/generic_mock_api_tests/test_encode_datetime.py +0 -123
  287. package/generator/test/generic_mock_api_tests/test_headasboolean.py +0 -33
  288. package/generator/test/generic_mock_api_tests/test_parameters_body_optionality.py +0 -27
  289. package/generator/test/generic_mock_api_tests/test_parameters_collection_format.py +0 -33
  290. package/generator/test/generic_mock_api_tests/test_parameters_path.py +0 -22
  291. package/generator/test/generic_mock_api_tests/test_parameters_query.py +0 -17
  292. package/generator/test/generic_mock_api_tests/test_payload_json_merge_patch.py +0 -93
  293. package/generator/test/generic_mock_api_tests/test_payload_media_type.py +0 -25
  294. package/generator/test/generic_mock_api_tests/test_payload_pageable.py +0 -99
  295. package/generator/test/generic_mock_api_tests/test_payload_xml.py +0 -135
  296. package/generator/test/generic_mock_api_tests/test_response_status_code_range.py +0 -36
  297. package/generator/test/generic_mock_api_tests/test_routes.py +0 -285
  298. package/generator/test/generic_mock_api_tests/test_server_endpoint_not_defined.py +0 -17
  299. package/generator/test/generic_mock_api_tests/test_server_path_multiple.py +0 -21
  300. package/generator/test/generic_mock_api_tests/test_server_path_single.py +0 -17
  301. package/generator/test/generic_mock_api_tests/test_server_versions_not_versioned.py +0 -25
  302. package/generator/test/generic_mock_api_tests/test_server_versions_versioned.py +0 -30
  303. package/generator/test/generic_mock_api_tests/test_special_headers_conditional_request.py +0 -34
  304. package/generator/test/generic_mock_api_tests/test_special_headers_repeatability.py +0 -18
  305. package/generator/test/generic_mock_api_tests/test_specs_documentation.py +0 -51
  306. package/generator/test/generic_mock_api_tests/test_streaming_jsonl.py +0 -25
  307. package/generator/test/generic_mock_api_tests/test_typetest_array.py +0 -111
  308. package/generator/test/generic_mock_api_tests/test_typetest_dictionary.py +0 -86
  309. package/generator/test/generic_mock_api_tests/test_typetest_enum_extensible.py +0 -23
  310. package/generator/test/generic_mock_api_tests/test_typetest_enum_fixed.py +0 -25
  311. package/generator/test/generic_mock_api_tests/test_typetest_file.py +0 -52
  312. package/generator/test/generic_mock_api_tests/test_typetest_model_empty.py +0 -29
  313. package/generator/test/generic_mock_api_tests/test_typetest_model_inheritance_enum_discriminator.py +0 -58
  314. package/generator/test/generic_mock_api_tests/test_typetest_model_inheritance_nested_discriminator.py +0 -79
  315. package/generator/test/generic_mock_api_tests/test_typetest_model_inheritance_not_discriminated.py +0 -31
  316. package/generator/test/generic_mock_api_tests/test_typetest_model_inheritance_recursive.py +0 -32
  317. package/generator/test/generic_mock_api_tests/test_typetest_model_inheritance_single_discriminator.py +0 -60
  318. package/generator/test/generic_mock_api_tests/test_typetest_model_usage.py +0 -28
  319. package/generator/test/generic_mock_api_tests/test_typetest_model_visibility.py +0 -40
  320. package/generator/test/generic_mock_api_tests/test_typetest_property_additionalproperties.py +0 -314
  321. package/generator/test/generic_mock_api_tests/test_typetest_property_nullable.py +0 -102
  322. package/generator/test/generic_mock_api_tests/test_typetest_property_optional.py +0 -174
  323. package/generator/test/generic_mock_api_tests/test_typetest_property_valuetypes.py +0 -286
  324. package/generator/test/generic_mock_api_tests/test_typetest_scalar.py +0 -53
  325. package/generator/test/generic_mock_api_tests/test_typetest_union.py +0 -80
  326. package/generator/test/generic_mock_api_tests/test_typetest_union_discriminated.py +0 -290
  327. package/generator/test/generic_mock_api_tests/test_versioning_added.py +0 -33
  328. package/generator/test/generic_mock_api_tests/test_versioning_made_optional.py +0 -20
  329. package/generator/test/generic_mock_api_tests/test_versioning_removed.py +0 -37
  330. package/generator/test/generic_mock_api_tests/test_versioning_renamed_from.py +0 -27
  331. package/generator/test/generic_mock_api_tests/test_versioning_return_type_changed_from.py +0 -17
  332. package/generator/test/generic_mock_api_tests/test_versioning_type_changed_from.py +0 -21
  333. package/generator/test/unbranded/mock_api_tests/asynctests/test_auth_flow_async.py +0 -19
  334. package/generator/test/unbranded/mock_api_tests/asynctests/test_encode_duration_async.py +0 -63
  335. package/generator/test/unbranded/mock_api_tests/asynctests/test_encode_numeric_async.py +0 -35
  336. package/generator/test/unbranded/mock_api_tests/asynctests/test_parameters_basic_async.py +0 -24
  337. package/generator/test/unbranded/mock_api_tests/asynctests/test_parameters_spread_async.py +0 -76
  338. package/generator/test/unbranded/mock_api_tests/asynctests/test_payload_content_negotiation_async.py +0 -37
  339. package/generator/test/unbranded/mock_api_tests/asynctests/test_payload_multipart_async.py +0 -218
  340. package/generator/test/unbranded/mock_api_tests/asynctests/test_serialization_encoded_name_json_async.py +0 -24
  341. package/generator/test/unbranded/mock_api_tests/asynctests/test_special_words_async.py +0 -73
  342. package/generator/test/unbranded/mock_api_tests/asynctests/test_unbranded_async.py +0 -24
  343. package/generator/test/unbranded/mock_api_tests/conftest.py +0 -91
  344. package/generator/test/unbranded/mock_api_tests/data/image.jpg +0 -0
  345. package/generator/test/unbranded/mock_api_tests/data/image.png +0 -0
  346. package/generator/test/unbranded/mock_api_tests/test_auth_flow.py +0 -17
  347. package/generator/test/unbranded/mock_api_tests/test_encode_duration.py +0 -60
  348. package/generator/test/unbranded/mock_api_tests/test_encode_numeric.py +0 -32
  349. package/generator/test/unbranded/mock_api_tests/test_parameters_basic.py +0 -22
  350. package/generator/test/unbranded/mock_api_tests/test_parameters_spread.py +0 -66
  351. package/generator/test/unbranded/mock_api_tests/test_payload_content_negotiation.py +0 -33
  352. package/generator/test/unbranded/mock_api_tests/test_payload_multipart.py +0 -200
  353. package/generator/test/unbranded/mock_api_tests/test_serialization_encoded_name_json.py +0 -22
  354. package/generator/test/unbranded/mock_api_tests/test_special_words.py +0 -66
  355. package/generator/test/unbranded/mock_api_tests/test_unbranded.py +0 -65
  356. package/generator/test/unbranded/requirements.txt +0 -69
  357. package/generator/test/unbranded/tox.ini +0 -64
  358. package/generator/test/unittests/conftest.py +0 -15
  359. package/generator/test/unittests/requirements.txt +0 -3
  360. package/generator/test/unittests/test_enums.py +0 -89
  361. package/generator/test/unittests/test_model_base_serialization.py +0 -4906
  362. package/generator/test/unittests/test_model_base_xml_serialization.py +0 -1239
  363. package/generator/test/unittests/test_name_converter.py +0 -35
  364. package/generator/test/unittests/test_optional_return_type.py +0 -268
  365. package/generator/test/unittests/test_parameter_ordering.py +0 -104
  366. package/generator/test/unittests/test_sort_schema.py +0 -93
  367. package/generator/test/unittests/tox.ini +0 -5
  368. /package/eng/scripts/ci/{pyproject.toml → config/pyproject.toml} +0 -0
@@ -25,14 +25,7 @@ import {
25
25
  emitPagingHttpMethod,
26
26
  } from "./http.js";
27
27
  import { PythonSdkContext } from "./lib.js";
28
- import {
29
- KnownTypes,
30
- disableGenerationMap,
31
- emitEndpointType,
32
- getType,
33
- simpleTypesMap,
34
- typesMap,
35
- } from "./types.js";
28
+ import { KnownTypes, emitEndpointType, getType } from "./types.js";
36
29
  import { emitParamBase, getClientNamespace, getImplementation, getRootNamespace } from "./utils.js";
37
30
 
38
31
  function emitBasicMethod<TServiceOperation extends SdkServiceOperation>(
@@ -263,7 +256,7 @@ function emitOperationGroups<TServiceOperation extends SdkServiceOperation>(
263
256
  // operation has same clientNamespace as the operation group
264
257
  for (const og of operationGroups) {
265
258
  for (const op of og.operations) {
266
- op.clientNamespace = getClientNamespace(context, og.clientNamespace);
259
+ op.clientNamespace = og.clientNamespace;
267
260
  }
268
261
  }
269
262
 
@@ -366,7 +359,7 @@ export function emitCodeModel(sdkContext: PythonSdkContext) {
366
359
  continue;
367
360
  }
368
361
  // filter out specific models not used in python, e.g., pageable models
369
- if (disableGenerationMap.has(model)) {
362
+ if (sdkContext.__disableGenerationMap.has(model)) {
370
363
  continue;
371
364
  }
372
365
  // filter out core models
@@ -391,7 +384,7 @@ export function emitCodeModel(sdkContext: PythonSdkContext) {
391
384
  }
392
385
 
393
386
  // clear usage when a model is only used by paging
394
- for (const type of typesMap.values()) {
387
+ for (const type of sdkContext.__typesMap.values()) {
395
388
  if (
396
389
  type["type"] === "model" &&
397
390
  type["referredByOperationType"] === ReferredByOperationTypes.PagingOnly &&
@@ -402,11 +395,12 @@ export function emitCodeModel(sdkContext: PythonSdkContext) {
402
395
  }
403
396
 
404
397
  codeModel["types"] = [
405
- ...typesMap.values(),
398
+ ...sdkContext.__typesMap.values(),
406
399
  ...Object.values(KnownTypes),
407
- ...simpleTypesMap.values(),
400
+ ...sdkContext.__simpleTypesMap.values(),
408
401
  ];
409
402
  codeModel["crossLanguagePackageId"] = ignoreDiagnostics(getCrossLanguagePackageId(sdkContext));
403
+ codeModel["crossLanguageVersion"] = sdkContext.sdkPackage.crossLanguageVersion;
410
404
  if ((sdkContext.emitContext.options as any).flavor === "azure") {
411
405
  const metadata = { ...sdkPackage.metadata } as any;
412
406
  if (metadata.apiVersions) {
@@ -0,0 +1,27 @@
1
+ export const PYODIDE_VERSION = "0.26.2";
2
+ export const PYGEN_WHEEL_FILENAME = "pygen-0.1.0-py3-none-any.whl";
3
+ export const BLOB_STORAGE_BASE_URL = "https://typespec.blob.core.windows.net/pkgs";
4
+ export const PACKAGE_NAME = "@typespec/http-client-python";
5
+
6
+ export const blackExcludeDirs = [
7
+ "__pycache__/",
8
+ "node_modules/",
9
+ "venv/",
10
+ "env/",
11
+ ".direnv",
12
+ ".eggs",
13
+ ".git",
14
+ ".hg",
15
+ ".tox",
16
+ ".venv",
17
+ ".eggs",
18
+ ".mypy_cache",
19
+ ".pytest_cache",
20
+ ".vscode",
21
+ ".*_build/",
22
+ "/build/",
23
+ "dist",
24
+ ".nox",
25
+ ".svn",
26
+ "TempTypeSpecFiles/",
27
+ ];
@@ -1,18 +1,30 @@
1
1
  import { createSdkContext } from "@azure-tools/typespec-client-generator-core";
2
- import { EmitContext, NoTarget } from "@typespec/compiler";
2
+ import { EmitContext, emitFile, joinPaths, NoTarget } from "@typespec/compiler";
3
3
  import { execSync } from "child_process";
4
4
  import fs from "fs";
5
+ import jsyaml from "js-yaml";
5
6
  import os from "os";
6
7
  import path, { dirname } from "path";
7
- import { loadPyodide } from "pyodide";
8
+ import { loadPyodide, PyodideInterface } from "pyodide";
8
9
  import { fileURLToPath } from "url";
10
+ import pkgJson from "../../package.json" with { type: "json" };
9
11
  import { emitCodeModel } from "./code-model.js";
12
+ import {
13
+ blackExcludeDirs,
14
+ BLOB_STORAGE_BASE_URL,
15
+ PACKAGE_NAME,
16
+ PYGEN_WHEEL_FILENAME,
17
+ PYODIDE_VERSION,
18
+ } from "./constants.js";
10
19
  import { saveCodeModelAsYaml } from "./external-process.js";
11
20
  import { PythonEmitterOptions, PythonSdkContext, reportDiagnostic } from "./lib.js";
12
21
  import { runPython3 } from "./run-python3.js";
13
- import { disableGenerationMap, simpleTypesMap, typesMap } from "./types.js";
14
22
  import { getRootNamespace, md2Rst } from "./utils.js";
15
23
 
24
+ function getBrowserPygenWheelUrl(): string {
25
+ return `${BLOB_STORAGE_BASE_URL}/${PACKAGE_NAME}/${pkgJson.version}/generator/dist/${PYGEN_WHEEL_FILENAME}`;
26
+ }
27
+
16
28
  function addDefaultOptions(sdkContext: PythonSdkContext) {
17
29
  const defaultOptions = {
18
30
  "package-version": "1.0.0b1",
@@ -30,21 +42,24 @@ function addDefaultOptions(sdkContext: PythonSdkContext) {
30
42
  const packageName = namespace.replace(/\./g, "-");
31
43
  options["package-name"] = packageName;
32
44
  }
33
- if ((options as any).flavor !== "azure") {
34
- // if they pass in a flavor other than azure, we want to ignore the value
35
- (options as any).flavor = undefined;
36
- }
45
+ // Set flavor based on namespace or passed option
37
46
  if (getRootNamespace(sdkContext).toLowerCase().includes("azure")) {
38
47
  (options as any).flavor = "azure";
48
+ } else if ((options as any).flavor !== "azure") {
49
+ // Explicitly set unbranded flavor when not azure
50
+ (options as any).flavor = "unbranded";
39
51
  }
40
52
 
41
53
  if (
42
54
  options["package-pprint-name"] !== undefined &&
43
55
  !options["package-pprint-name"].startsWith('"')
44
56
  ) {
45
- options["package-pprint-name"] = options["use-pyodide"]
46
- ? `${options["package-pprint-name"]}`
47
- : `"${options["package-pprint-name"]}"`;
57
+ // Only add quotes for shell compatibility when NOT using emit-yaml-only mode
58
+ // (emit-yaml-only passes options via JSON config files, not shell)
59
+ const needsShellQuoting = !options["use-pyodide"] && !options["emit-yaml-only"];
60
+ options["package-pprint-name"] = needsShellQuoting
61
+ ? `"${options["package-pprint-name"]}"`
62
+ : `${options["package-pprint-name"]}`;
48
63
  }
49
64
  }
50
65
 
@@ -59,6 +74,9 @@ async function createPythonSdkContext(
59
74
  return {
60
75
  ...sdkContext,
61
76
  __endpointPathParameters: [],
77
+ __typesMap: new Map(),
78
+ __simpleTypesMap: new Map(),
79
+ __disableGenerationMap: new Set(),
62
80
  };
63
81
  }
64
82
 
@@ -100,10 +118,58 @@ function walkThroughNodes(yamlMap: Record<string, any>): Record<string, any> {
100
118
  return yamlMap;
101
119
  }
102
120
 
103
- function cleanAllCache() {
104
- typesMap.clear();
105
- simpleTypesMap.clear();
106
- disableGenerationMap.clear();
121
+ const pyodideGenerationCode = `
122
+ async def main():
123
+ import warnings
124
+ with warnings.catch_warnings():
125
+ from pygen import preprocess, codegen, black
126
+ preprocess.PreProcessPlugin(output_folder=outputFolder, tsp_file=yamlFile, **commandArgs).process()
127
+ codegen.CodeGenerator(output_folder=outputFolder, tsp_file=yamlFile, **commandArgs).process()
128
+ black.BlackScriptPlugin(output_folder=outputFolder, **commandArgs).process()
129
+
130
+ await main()`;
131
+
132
+ async function runPyodideGeneration(
133
+ pyodide: PyodideInterface,
134
+ outputFolder: string,
135
+ yamlFile: string,
136
+ commandArgs: Record<string, string>,
137
+ ) {
138
+ const globals = pyodide.toPy({
139
+ outputFolder,
140
+ yamlFile,
141
+ commandArgs,
142
+ });
143
+
144
+ await pyodide.runPythonAsync(pyodideGenerationCode, { globals });
145
+ }
146
+
147
+ async function copyPyodideOutputToHost(
148
+ context: EmitContext<PythonEmitterOptions>,
149
+ pyodide: PyodideInterface,
150
+ memfsDir: string,
151
+ relativeDir: string = "",
152
+ ) {
153
+ const entries = pyodide.FS.readdir(memfsDir).filter(
154
+ (entry: string) => entry !== "." && entry !== "..",
155
+ );
156
+
157
+ for (const entry of entries) {
158
+ const memfsPath = `${memfsDir}/${entry}`;
159
+ const relativePath = relativeDir ? `${relativeDir}/${entry}` : entry;
160
+ const stats = pyodide.FS.stat(memfsPath);
161
+
162
+ if (pyodide.FS.isDir(stats.mode)) {
163
+ await copyPyodideOutputToHost(context, pyodide, memfsPath, relativePath);
164
+ continue;
165
+ }
166
+
167
+ const content = pyodide.FS.readFile(memfsPath, { encoding: "utf8" });
168
+ await emitFile(context.program, {
169
+ path: joinPaths(context.emitterOutputDir, relativePath),
170
+ content,
171
+ });
172
+ }
107
173
  }
108
174
 
109
175
  export async function $onEmit(context: EmitContext<PythonEmitterOptions>) {
@@ -124,18 +190,23 @@ export async function $onEmit(context: EmitContext<PythonEmitterOptions>) {
124
190
  }
125
191
 
126
192
  async function onEmitMain(context: EmitContext<PythonEmitterOptions>) {
127
- // clean all cache to make sure emitter could work in watch mode
128
- cleanAllCache();
129
-
130
193
  const program = context.program;
131
194
  const sdkContext = await createPythonSdkContext(context);
132
- const root = path.join(dirname(fileURLToPath(import.meta.url)), "..", "..");
195
+
133
196
  const outputDir = context.emitterOutputDir;
134
197
  addDefaultOptions(sdkContext);
135
198
  const yamlMap = emitCodeModel(sdkContext);
136
199
  const parsedYamlMap = walkThroughNodes(yamlMap);
137
200
 
138
- const yamlPath = await saveCodeModelAsYaml("python-yaml-path", parsedYamlMap);
201
+ // Python emitter requires an SDK client in the TypeSpec
202
+ if (sdkContext.sdkPackage.clients.length === 0) {
203
+ reportDiagnostic(program, {
204
+ code: "no-sdk-clients",
205
+ target: NoTarget,
206
+ });
207
+ return;
208
+ }
209
+
139
210
  const resolvedOptions = sdkContext.emitContext.options;
140
211
  const commandArgs: Record<string, string> = {};
141
212
  if (resolvedOptions["packaging-files-config"]) {
@@ -162,99 +233,141 @@ async function onEmitMain(context: EmitContext<PythonEmitterOptions>) {
162
233
  commandArgs["from-typespec"] = "true";
163
234
  commandArgs["models-mode"] = (resolvedOptions as any)["models-mode"] ?? "dpg";
164
235
 
165
- if (!program.compilerOptions.noEmit && !program.hasError()) {
166
- // if not using pyodide and there's no venv, we try to create venv
167
- if (!resolvedOptions["use-pyodide"] && !fs.existsSync(path.join(root, "venv"))) {
168
- try {
169
- await runPython3(path.join(root, "/eng/scripts/setup/install.py"));
170
- await runPython3(path.join(root, "/eng/scripts/setup/prepare.py"));
171
- } catch (error) {
172
- // if the python env is not ready, we use pyodide instead
173
- resolvedOptions["use-pyodide"] = true;
174
- }
236
+ if (typeof window !== "undefined") {
237
+ // Running in browser with Pyodide - fileURLToPath and other filesystem operations are browser-incompatible
238
+ const pyodide = await browserPyodidePromise;
239
+
240
+ if (!pyodide) {
241
+ reportDiagnostic(program, {
242
+ code: "browser-runtime-load-failed",
243
+ target: NoTarget,
244
+ format: { details: "" },
245
+ });
246
+ return;
175
247
  }
176
248
 
177
- if (resolvedOptions["use-pyodide"]) {
178
- // here we run with pyodide
179
- const pyodide = await setupPyodideCall(root);
180
- // create the output folder if not exists
181
- if (!fs.existsSync(outputDir)) {
182
- fs.mkdirSync(outputDir, { recursive: true });
249
+ const yamlFilePath = "/yaml/python-yaml-path.yaml";
250
+ pyodide.FS.mkdirTree("/yaml");
251
+ pyodide.FS.mkdirTree("/output");
252
+ clearMemfsDirectory(pyodide, "/output");
253
+ pyodide.FS.writeFile(yamlFilePath, jsyaml.dump(parsedYamlMap));
254
+
255
+ await runPyodideGeneration(pyodide, "/output", yamlFilePath, commandArgs);
256
+ await copyPyodideOutputToHost(context, pyodide, "/output");
257
+ } else {
258
+ const root = path.join(dirname(fileURLToPath(import.meta.url)), "..", "..");
259
+ const yamlPath = await saveCodeModelAsYaml("python-yaml-path", parsedYamlMap);
260
+
261
+ if (!program.compilerOptions.noEmit && !program.hasError()) {
262
+ // If emit-yaml-only mode, just copy YAML to output dir for batch processing
263
+ if (resolvedOptions["emit-yaml-only"]) {
264
+ if (!fs.existsSync(outputDir)) {
265
+ fs.mkdirSync(outputDir, { recursive: true });
266
+ }
267
+ // Copy YAML to output dir with command args embedded
268
+ // Use unique filename to avoid conflicts when multiple specs share output dir
269
+ const configId = path.basename(yamlPath, ".yaml");
270
+ const batchConfig = { yamlPath, commandArgs, outputDir };
271
+ fs.writeFileSync(
272
+ path.join(outputDir, `.tsp-codegen-${configId}.json`),
273
+ JSON.stringify(batchConfig, null, 2),
274
+ );
275
+ return;
183
276
  }
184
- // mount output folder to pyodide
185
- pyodide.FS.mkdirTree("/output");
186
- pyodide.FS.mount(pyodide.FS.filesystems.NODEFS, { root: outputDir }, "/output");
187
- // mount yaml file to pyodide
188
- pyodide.FS.mkdirTree("/yaml");
189
- pyodide.FS.mount(pyodide.FS.filesystems.NODEFS, { root: path.dirname(yamlPath) }, "/yaml");
190
- const globals = pyodide.toPy({
191
- outputFolder: "/output",
192
- yamlFile: `/yaml/${path.basename(yamlPath)}`,
193
- commandArgs,
194
- });
195
- const pythonCode = `
196
- async def main():
197
- import warnings
198
- with warnings.catch_warnings():
199
- from pygen import preprocess, codegen, black
200
- preprocess.PreProcessPlugin(output_folder=outputFolder, tsp_file=yamlFile, **commandArgs).process()
201
- codegen.CodeGenerator(output_folder=outputFolder, tsp_file=yamlFile, **commandArgs).process()
202
- black.BlackScriptPlugin(output_folder=outputFolder, **commandArgs).process()
203
-
204
- await main()`;
205
- await pyodide.runPythonAsync(pythonCode, { globals });
206
- } else {
207
- // here we run with native python
208
- let venvPath = path.join(root, "venv");
209
- if (fs.existsSync(path.join(venvPath, "bin"))) {
210
- venvPath = path.join(venvPath, "bin", "python");
211
- } else if (fs.existsSync(path.join(venvPath, "Scripts"))) {
212
- venvPath = path.join(venvPath, "Scripts", "python.exe");
277
+ // if not using pyodide and there's no venv, we try to create venv
278
+ if (!resolvedOptions["use-pyodide"] && !fs.existsSync(path.join(root, "venv"))) {
279
+ try {
280
+ await runPython3(path.join(root, "/eng/scripts/setup/install.py"));
281
+ await runPython3(path.join(root, "/eng/scripts/setup/prepare.py"));
282
+ } catch {
283
+ // if the python env is not ready, we use pyodide instead
284
+ resolvedOptions["use-pyodide"] = true;
285
+ }
286
+ }
287
+
288
+ if (resolvedOptions["use-pyodide"]) {
289
+ // here we run with pyodide
290
+ const pyodide = await setupPyodideCall(root);
291
+ // create the output folder if not exists
292
+ if (!fs.existsSync(outputDir)) {
293
+ fs.mkdirSync(outputDir, { recursive: true });
294
+ }
295
+ // mount output folder to pyodide
296
+ pyodide.FS.mkdirTree("/output");
297
+ pyodide.FS.mount(pyodide.FS.filesystems.NODEFS, { root: outputDir }, "/output");
298
+ // mount yaml file to pyodide
299
+ pyodide.FS.mkdirTree("/yaml");
300
+ pyodide.FS.mount(pyodide.FS.filesystems.NODEFS, { root: path.dirname(yamlPath) }, "/yaml");
301
+ await runPyodideGeneration(
302
+ pyodide,
303
+ "/output",
304
+ `/yaml/${path.basename(yamlPath)}`,
305
+ commandArgs,
306
+ );
213
307
  } else {
214
- reportDiagnostic(program, {
215
- code: "pyodide-flag-conflict",
216
- target: NoTarget,
217
- });
308
+ // here we run with native python
309
+ let venvPath = path.join(root, "venv");
310
+ if (fs.existsSync(path.join(venvPath, "bin"))) {
311
+ venvPath = path.join(venvPath, "bin", "python");
312
+ } else if (fs.existsSync(path.join(venvPath, "Scripts"))) {
313
+ venvPath = path.join(venvPath, "Scripts", "python.exe");
314
+ } else {
315
+ reportDiagnostic(program, {
316
+ code: "pyodide-flag-conflict",
317
+ target: NoTarget,
318
+ });
319
+ }
320
+ commandArgs["output-folder"] = outputDir;
321
+ commandArgs["tsp-file"] = yamlPath;
322
+ const commandFlags = Object.entries(commandArgs)
323
+ .map(([key, value]) => `--${key}=${value}`)
324
+ .join(" ");
325
+ const command = `${venvPath} ${root}/eng/scripts/setup/run_tsp.py ${commandFlags}`;
326
+ execSync(command);
327
+
328
+ const excludePattern = blackExcludeDirs.join("|");
329
+ execSync(
330
+ `${venvPath} -m black --line-length=120 --quiet --fast ${outputDir} --exclude "${excludePattern}"`,
331
+ );
332
+ await checkForPylintIssues(outputDir, excludePattern);
218
333
  }
219
- commandArgs["output-folder"] = outputDir;
220
- commandArgs["tsp-file"] = yamlPath;
221
- const commandFlags = Object.entries(commandArgs)
222
- .map(([key, value]) => `--${key}=${value}`)
223
- .join(" ");
224
- const command = `${venvPath} ${root}/eng/scripts/setup/run_tsp.py ${commandFlags}`;
225
- execSync(command);
226
-
227
- const blackExcludeDirs = [
228
- "__pycache__/",
229
- "node_modules/",
230
- "venv/",
231
- "env/",
232
- ".direnv",
233
- ".eggs",
234
- ".git",
235
- ".hg",
236
- ".tox",
237
- ".venv",
238
- ".eggs",
239
- ".mypy_cache",
240
- ".pytest_cache",
241
- ".vscode",
242
- ".*_build/",
243
- "/build/",
244
- "dist",
245
- ".nox",
246
- ".svn",
247
- "TempTypeSpecFiles/",
248
- ];
249
- const excludePattern = blackExcludeDirs.join("|");
250
- execSync(
251
- `${venvPath} -m black --line-length=120 --quiet --fast ${outputDir} --exclude "${excludePattern}"`,
252
- );
253
- checkForPylintIssues(outputDir, excludePattern);
254
334
  }
255
335
  }
256
336
  }
257
337
 
338
+ const browserPyodidePromise: Promise<PyodideInterface> | null =
339
+ typeof window !== "undefined" ? setupPyodideCallBrowser() : null;
340
+
341
+ function clearMemfsDirectory(pyodide: PyodideInterface, dir: string): void {
342
+ const entries: string[] = pyodide.FS.readdir(dir).filter(
343
+ (entry: string) => entry !== "." && entry !== "..",
344
+ );
345
+ for (const entry of entries) {
346
+ const fullPath = `${dir}/${entry}`;
347
+ const stats = pyodide.FS.stat(fullPath);
348
+ if (pyodide.FS.isDir(stats.mode)) {
349
+ clearMemfsDirectory(pyodide, fullPath);
350
+ pyodide.FS.rmdir(fullPath);
351
+ } else {
352
+ pyodide.FS.unlink(fullPath);
353
+ }
354
+ }
355
+ }
356
+
357
+ async function setupPyodideCallBrowser() {
358
+ const pyodide = await loadPyodide({
359
+ indexURL: `https://cdn.jsdelivr.net/pyodide/v${PYODIDE_VERSION}/full/`,
360
+ });
361
+
362
+ // use default MEMFS for browser, since NODEFS is not supported
363
+ pyodide.FS.mkdirTree("/generator");
364
+ await pyodide.loadPackage("micropip");
365
+ const micropip = pyodide.pyimport("micropip");
366
+ await micropip.install(getBrowserPygenWheelUrl());
367
+
368
+ return pyodide;
369
+ }
370
+
258
371
  async function setupPyodideCall(root: string) {
259
372
  const pyodide = await loadPyodide({
260
373
  indexURL: path.dirname(fileURLToPath(import.meta.resolve("pyodide"))),
@@ -269,7 +382,7 @@ async function setupPyodideCall(root: string) {
269
382
  if (lockAge > 300) {
270
383
  fs.unlinkSync(micropipLockPath);
271
384
  }
272
- } catch (err) {
385
+ } catch {
273
386
  // ignore
274
387
  }
275
388
  }
@@ -284,18 +397,18 @@ async function setupPyodideCall(root: string) {
284
397
  );
285
398
  await pyodide.loadPackage("micropip");
286
399
  const micropip = pyodide.pyimport("micropip");
287
- await micropip.install("emfs:/generator/dist/pygen-0.1.0-py3-none-any.whl");
400
+ await micropip.install(`emfs:/generator/dist/${PYGEN_WHEEL_FILENAME}`);
288
401
  fs.closeSync(fd);
289
402
  fs.unlinkSync(micropipLockPath);
290
403
  break;
291
- } catch (err) {
404
+ } catch {
292
405
  await new Promise((resolve) => setTimeout(resolve, 1000));
293
406
  }
294
407
  }
295
408
  return pyodide;
296
409
  }
297
410
 
298
- function checkForPylintIssues(outputDir: string, excludePattern: string) {
411
+ async function checkForPylintIssues(outputDir: string, excludePattern: string) {
299
412
  const excludeRegex = new RegExp(excludePattern);
300
413
 
301
414
  const shouldExcludePath = (filePath: string): boolean => {
@@ -304,9 +417,8 @@ function checkForPylintIssues(outputDir: string, excludePattern: string) {
304
417
  return excludeRegex.test(normalizedPath);
305
418
  };
306
419
 
307
- const processFile = (filePath: string) => {
308
- let fileContent;
309
- fileContent = fs.readFileSync(filePath, "utf-8");
420
+ const processFile = async (filePath: string) => {
421
+ let fileContent = await fs.promises.readFile(filePath, "utf-8");
310
422
  const pylintDisables: string[] = [];
311
423
  const lineEnding = fileContent.includes("\r\n") && os.platform() === "win32" ? "\r\n" : "\n";
312
424
  const lines: string[] = fileContent.split(lineEnding);
@@ -321,32 +433,38 @@ function checkForPylintIssues(outputDir: string, excludePattern: string) {
321
433
  fileContent = lines[0].includes("pylint: disable=")
322
434
  ? [lines[0] + "," + pylintDisables.join(",")].concat(lines.slice(1)).join(lineEnding)
323
435
  : `# pylint: disable=${pylintDisables.join(",")}${lineEnding}` + fileContent;
436
+ await fs.promises.writeFile(filePath, fileContent);
324
437
  }
325
438
  }
326
-
327
- fs.writeFileSync(filePath, fileContent);
328
439
  };
329
440
 
330
- const walkDir = (dir: string) => {
441
+ const collectPythonFiles = async (dir: string): Promise<string[]> => {
331
442
  if (shouldExcludePath(dir)) {
332
- return;
443
+ return [];
333
444
  }
334
445
 
335
- const files = fs.readdirSync(dir);
336
- files.forEach((file) => {
337
- const filePath = path.join(dir, file);
446
+ const entries = await fs.promises.readdir(dir, { withFileTypes: true });
447
+
448
+ const promises = entries.map(async (entry) => {
449
+ const filePath = path.join(dir, entry.name);
338
450
 
339
451
  if (shouldExcludePath(filePath)) {
340
- return;
452
+ return [];
341
453
  }
342
454
 
343
- if (fs.statSync(filePath).isDirectory()) {
344
- walkDir(filePath);
345
- } else if (file.endsWith(".py")) {
346
- processFile(filePath);
455
+ if (entry.isDirectory()) {
456
+ return collectPythonFiles(filePath);
457
+ } else if (entry.name.endsWith(".py")) {
458
+ return [filePath];
347
459
  }
460
+ return [];
348
461
  });
462
+
463
+ const results = await Promise.all(promises);
464
+ return results.flat();
349
465
  };
350
466
 
351
- walkDir(outputDir);
467
+ // Collect all Python files first, then process in parallel
468
+ const pythonFiles = await collectPythonFiles(outputDir);
469
+ await Promise.all(pythonFiles.map(processFile));
352
470
  }
@@ -1,4 +1,4 @@
1
- import { NoTarget } from "@typespec/compiler";
1
+ import { getNamespaceFullName, NoTarget } from "@typespec/compiler";
2
2
 
3
3
  import {
4
4
  getHttpOperationParameter,
@@ -19,6 +19,7 @@ import {
19
19
  SdkQueryParameter,
20
20
  SdkServiceMethod,
21
21
  SdkServiceResponseHeader,
22
+ SdkType,
22
23
  UsageFlags,
23
24
  } from "@azure-tools/typespec-client-generator-core";
24
25
  import { HttpStatusCodeRange } from "@typespec/http";
@@ -41,6 +42,32 @@ export enum ReferredByOperationTypes {
41
42
  NonPagingOnly = 2,
42
43
  }
43
44
 
45
+ function isEtagType(type: SdkType): boolean {
46
+ if (type.kind === "nullable") return isEtagType(type.type);
47
+ const raw = type.__raw;
48
+ if (!raw || raw.kind !== "Scalar") return false;
49
+ return (
50
+ raw.name === "eTag" &&
51
+ raw.namespace !== undefined &&
52
+ getNamespaceFullName(raw.namespace) === "Azure.Core"
53
+ );
54
+ }
55
+
56
+ function getEtagRole(parameter: SdkHeaderParameter): string | undefined {
57
+ const name = parameter.name.toLowerCase();
58
+ const wire = parameter.serializedName.toLowerCase();
59
+ // Standard If-Match / If-None-Match headers work with any type
60
+ if (wire === "if-match") return "ifMatch";
61
+ if (wire === "if-none-match") return "ifNoneMatch";
62
+ // Non-standard headers require Azure.Core.eTag type
63
+ if (!isEtagType(parameter.type)) return undefined;
64
+ if (name.includes("nonematch") || name.includes("none_match")) return "ifNoneMatch";
65
+ if (name.includes("match")) return "ifMatch";
66
+ if (wire.endsWith("-if-none-match")) return "ifNoneMatch";
67
+ if (wire.endsWith("-if-match")) return "ifMatch";
68
+ return undefined;
69
+ }
70
+
44
71
  function isContentTypeParameter(parameter: SdkHeaderParameter) {
45
72
  return parameter.serializedName.toLowerCase() === "content-type";
46
73
  }
@@ -496,6 +523,7 @@ function emitHttpHeaderParameter(
496
523
  delimiter,
497
524
  explode,
498
525
  clientDefaultValue,
526
+ etagRole: getEtagRole(parameter),
499
527
  };
500
528
  }
501
529