@typespec/http-client-python 0.1.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 (334) hide show
  1. package/README.md +118 -0
  2. package/dist/emitter/code-model.d.ts +4 -0
  3. package/dist/emitter/code-model.d.ts.map +1 -0
  4. package/dist/emitter/code-model.js +195 -0
  5. package/dist/emitter/code-model.js.map +1 -0
  6. package/dist/emitter/emitter.d.ts +6 -0
  7. package/dist/emitter/emitter.d.ts.map +1 -0
  8. package/dist/emitter/emitter.js +104 -0
  9. package/dist/emitter/emitter.js.map +1 -0
  10. package/dist/emitter/external-process.d.ts +20 -0
  11. package/dist/emitter/external-process.d.ts.map +1 -0
  12. package/dist/emitter/external-process.js +44 -0
  13. package/dist/emitter/external-process.js.map +1 -0
  14. package/dist/emitter/http.d.ts +7 -0
  15. package/dist/emitter/http.d.ts.map +1 -0
  16. package/dist/emitter/http.js +268 -0
  17. package/dist/emitter/http.js.map +1 -0
  18. package/dist/emitter/index.d.ts +3 -0
  19. package/dist/emitter/index.d.ts.map +1 -0
  20. package/dist/emitter/index.js +3 -0
  21. package/dist/emitter/index.js.map +1 -0
  22. package/dist/emitter/lib.d.ts +30 -0
  23. package/dist/emitter/lib.d.ts.map +1 -0
  24. package/dist/emitter/lib.js +33 -0
  25. package/dist/emitter/lib.js.map +1 -0
  26. package/dist/emitter/types.d.ts +36 -0
  27. package/dist/emitter/types.d.ts.map +1 -0
  28. package/dist/emitter/types.js +491 -0
  29. package/dist/emitter/types.js.map +1 -0
  30. package/dist/emitter/utils.d.ts +26 -0
  31. package/dist/emitter/utils.d.ts.map +1 -0
  32. package/dist/emitter/utils.js +155 -0
  33. package/dist/emitter/utils.js.map +1 -0
  34. package/emitter/src/code-model.ts +272 -0
  35. package/emitter/src/emitter.ts +127 -0
  36. package/emitter/src/external-process.ts +52 -0
  37. package/emitter/src/http.ts +382 -0
  38. package/emitter/src/index.ts +2 -0
  39. package/emitter/src/lib.ts +59 -0
  40. package/emitter/src/types.ts +573 -0
  41. package/emitter/src/utils.ts +215 -0
  42. package/emitter/temp/tsconfig.tsbuildinfo +1 -0
  43. package/emitter/test/utils.test.ts +22 -0
  44. package/emitter/tsconfig.build.json +11 -0
  45. package/emitter/tsconfig.json +7 -0
  46. package/emitter/vitest.config.ts +4 -0
  47. package/eng/scripts/Build-Packages.ps1 +86 -0
  48. package/eng/scripts/Check-GitChanges.ps1 +22 -0
  49. package/eng/scripts/Functions.ps1 +26 -0
  50. package/eng/scripts/Generate.ps1 +11 -0
  51. package/eng/scripts/Generation.psm1 +22 -0
  52. package/eng/scripts/Initialize-Repository.ps1 +40 -0
  53. package/eng/scripts/Test-Packages.ps1 +65 -0
  54. package/eng/scripts/ci/format.ts +3 -0
  55. package/eng/scripts/ci/lint.ts +39 -0
  56. package/eng/scripts/ci/mypy.ini +38 -0
  57. package/eng/scripts/ci/pylintrc +59 -0
  58. package/eng/scripts/ci/pyproject.toml +18 -0
  59. package/eng/scripts/ci/pyrightconfig.json +6 -0
  60. package/eng/scripts/ci/regenerate.ts +299 -0
  61. package/eng/scripts/ci/run-ci.ts +88 -0
  62. package/eng/scripts/ci/run_apiview.py +40 -0
  63. package/eng/scripts/ci/run_mypy.py +49 -0
  64. package/eng/scripts/ci/run_pylint.py +50 -0
  65. package/eng/scripts/ci/run_pyright.py +58 -0
  66. package/eng/scripts/ci/util.py +72 -0
  67. package/eng/scripts/ci/utils.ts +48 -0
  68. package/eng/scripts/setup/__pycache__/venvtools.cpython-38.pyc +0 -0
  69. package/eng/scripts/setup/install.py +53 -0
  70. package/eng/scripts/setup/prepare.py +42 -0
  71. package/eng/scripts/setup/run-python3.ts +25 -0
  72. package/eng/scripts/setup/run_tsp.py +42 -0
  73. package/eng/scripts/setup/system-requirements.ts +261 -0
  74. package/eng/scripts/setup/venvtools.py +87 -0
  75. package/generator/LICENSE +21 -0
  76. package/generator/README.md +1 -0
  77. package/generator/dev_requirements.txt +13 -0
  78. package/generator/pygen/__init__.py +107 -0
  79. package/generator/pygen/_version.py +7 -0
  80. package/generator/pygen/black.py +71 -0
  81. package/generator/pygen/codegen/__init__.py +338 -0
  82. package/generator/pygen/codegen/_utils.py +17 -0
  83. package/generator/pygen/codegen/models/__init__.py +204 -0
  84. package/generator/pygen/codegen/models/base.py +186 -0
  85. package/generator/pygen/codegen/models/base_builder.py +118 -0
  86. package/generator/pygen/codegen/models/client.py +433 -0
  87. package/generator/pygen/codegen/models/code_model.py +237 -0
  88. package/generator/pygen/codegen/models/combined_type.py +149 -0
  89. package/generator/pygen/codegen/models/constant_type.py +129 -0
  90. package/generator/pygen/codegen/models/credential_types.py +214 -0
  91. package/generator/pygen/codegen/models/dictionary_type.py +127 -0
  92. package/generator/pygen/codegen/models/enum_type.py +238 -0
  93. package/generator/pygen/codegen/models/imports.py +291 -0
  94. package/generator/pygen/codegen/models/list_type.py +143 -0
  95. package/generator/pygen/codegen/models/lro_operation.py +142 -0
  96. package/generator/pygen/codegen/models/lro_paging_operation.py +32 -0
  97. package/generator/pygen/codegen/models/model_type.py +359 -0
  98. package/generator/pygen/codegen/models/operation.py +530 -0
  99. package/generator/pygen/codegen/models/operation_group.py +184 -0
  100. package/generator/pygen/codegen/models/paging_operation.py +155 -0
  101. package/generator/pygen/codegen/models/parameter.py +412 -0
  102. package/generator/pygen/codegen/models/parameter_list.py +387 -0
  103. package/generator/pygen/codegen/models/primitive_types.py +659 -0
  104. package/generator/pygen/codegen/models/property.py +170 -0
  105. package/generator/pygen/codegen/models/request_builder.py +189 -0
  106. package/generator/pygen/codegen/models/request_builder_parameter.py +115 -0
  107. package/generator/pygen/codegen/models/response.py +348 -0
  108. package/generator/pygen/codegen/models/utils.py +21 -0
  109. package/generator/pygen/codegen/serializers/__init__.py +574 -0
  110. package/generator/pygen/codegen/serializers/base_serializer.py +21 -0
  111. package/generator/pygen/codegen/serializers/builder_serializer.py +1507 -0
  112. package/generator/pygen/codegen/serializers/client_serializer.py +294 -0
  113. package/generator/pygen/codegen/serializers/enum_serializer.py +15 -0
  114. package/generator/pygen/codegen/serializers/general_serializer.py +213 -0
  115. package/generator/pygen/codegen/serializers/import_serializer.py +126 -0
  116. package/generator/pygen/codegen/serializers/metadata_serializer.py +198 -0
  117. package/generator/pygen/codegen/serializers/model_init_serializer.py +33 -0
  118. package/generator/pygen/codegen/serializers/model_serializer.py +317 -0
  119. package/generator/pygen/codegen/serializers/operation_groups_serializer.py +89 -0
  120. package/generator/pygen/codegen/serializers/operations_init_serializer.py +44 -0
  121. package/generator/pygen/codegen/serializers/parameter_serializer.py +221 -0
  122. package/generator/pygen/codegen/serializers/patch_serializer.py +19 -0
  123. package/generator/pygen/codegen/serializers/request_builders_serializer.py +52 -0
  124. package/generator/pygen/codegen/serializers/sample_serializer.py +168 -0
  125. package/generator/pygen/codegen/serializers/test_serializer.py +292 -0
  126. package/generator/pygen/codegen/serializers/types_serializer.py +31 -0
  127. package/generator/pygen/codegen/serializers/utils.py +68 -0
  128. package/generator/pygen/codegen/templates/client.py.jinja2 +37 -0
  129. package/generator/pygen/codegen/templates/client_container.py.jinja2 +12 -0
  130. package/generator/pygen/codegen/templates/config.py.jinja2 +73 -0
  131. package/generator/pygen/codegen/templates/config_container.py.jinja2 +16 -0
  132. package/generator/pygen/codegen/templates/conftest.py.jinja2 +28 -0
  133. package/generator/pygen/codegen/templates/enum.py.jinja2 +13 -0
  134. package/generator/pygen/codegen/templates/enum_container.py.jinja2 +10 -0
  135. package/generator/pygen/codegen/templates/init.py.jinja2 +24 -0
  136. package/generator/pygen/codegen/templates/keywords.jinja2 +19 -0
  137. package/generator/pygen/codegen/templates/lro_operation.py.jinja2 +16 -0
  138. package/generator/pygen/codegen/templates/lro_paging_operation.py.jinja2 +18 -0
  139. package/generator/pygen/codegen/templates/macros.jinja2 +12 -0
  140. package/generator/pygen/codegen/templates/metadata.json.jinja2 +167 -0
  141. package/generator/pygen/codegen/templates/model_base.py.jinja2 +1157 -0
  142. package/generator/pygen/codegen/templates/model_container.py.jinja2 +12 -0
  143. package/generator/pygen/codegen/templates/model_dpg.py.jinja2 +97 -0
  144. package/generator/pygen/codegen/templates/model_init.py.jinja2 +28 -0
  145. package/generator/pygen/codegen/templates/model_msrest.py.jinja2 +92 -0
  146. package/generator/pygen/codegen/templates/operation.py.jinja2 +21 -0
  147. package/generator/pygen/codegen/templates/operation_group.py.jinja2 +75 -0
  148. package/generator/pygen/codegen/templates/operation_groups_container.py.jinja2 +19 -0
  149. package/generator/pygen/codegen/templates/operation_tools.jinja2 +81 -0
  150. package/generator/pygen/codegen/templates/operations_folder_init.py.jinja2 +17 -0
  151. package/generator/pygen/codegen/templates/packaging_templates/CHANGELOG.md.jinja2 +6 -0
  152. package/generator/pygen/codegen/templates/packaging_templates/LICENSE.jinja2 +21 -0
  153. package/generator/pygen/codegen/templates/packaging_templates/MANIFEST.in.jinja2 +8 -0
  154. package/generator/pygen/codegen/templates/packaging_templates/README.md.jinja2 +107 -0
  155. package/generator/pygen/codegen/templates/packaging_templates/dev_requirements.txt.jinja2 +9 -0
  156. package/generator/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +108 -0
  157. package/generator/pygen/codegen/templates/paging_operation.py.jinja2 +21 -0
  158. package/generator/pygen/codegen/templates/patch.py.jinja2 +19 -0
  159. package/generator/pygen/codegen/templates/pkgutil_init.py.jinja2 +1 -0
  160. package/generator/pygen/codegen/templates/request_builder.py.jinja2 +28 -0
  161. package/generator/pygen/codegen/templates/request_builders.py.jinja2 +10 -0
  162. package/generator/pygen/codegen/templates/rest_init.py.jinja2 +12 -0
  163. package/generator/pygen/codegen/templates/sample.py.jinja2 +44 -0
  164. package/generator/pygen/codegen/templates/serialization.py.jinja2 +2114 -0
  165. package/generator/pygen/codegen/templates/test.py.jinja2 +50 -0
  166. package/generator/pygen/codegen/templates/testpreparer.py.jinja2 +26 -0
  167. package/generator/pygen/codegen/templates/types.py.jinja2 +7 -0
  168. package/generator/pygen/codegen/templates/validation.py.jinja2 +38 -0
  169. package/generator/pygen/codegen/templates/vendor.py.jinja2 +95 -0
  170. package/generator/pygen/codegen/templates/version.py.jinja2 +4 -0
  171. package/generator/pygen/m2r.py +65 -0
  172. package/generator/pygen/postprocess/__init__.py +183 -0
  173. package/generator/pygen/postprocess/get_all.py +19 -0
  174. package/generator/pygen/postprocess/venvtools.py +75 -0
  175. package/generator/pygen/preprocess/__init__.py +515 -0
  176. package/generator/pygen/preprocess/helpers.py +27 -0
  177. package/generator/pygen/preprocess/python_mappings.py +224 -0
  178. package/generator/pygen/utils.py +163 -0
  179. package/generator/pygen.egg-info/PKG-INFO +25 -0
  180. package/generator/pygen.egg-info/SOURCES.txt +66 -0
  181. package/generator/pygen.egg-info/dependency_links.txt +1 -0
  182. package/generator/pygen.egg-info/requires.txt +4 -0
  183. package/generator/pygen.egg-info/top_level.txt +1 -0
  184. package/generator/requirements.txt +12 -0
  185. package/generator/setup.py +55 -0
  186. package/generator/test/azure/mock_api_tests/asynctests/test_azure_arm_models_common_types_managed_identity_async.py +63 -0
  187. package/generator/test/azure/mock_api_tests/asynctests/test_azure_arm_models_resource_async.py +284 -0
  188. package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_access_async.py +101 -0
  189. package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_flatten_async.py +93 -0
  190. package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_usage_async.py +31 -0
  191. package/generator/test/azure/mock_api_tests/asynctests/test_azure_core_basic_async.py +76 -0
  192. package/generator/test/azure/mock_api_tests/asynctests/test_azure_core_lro_rpc_async.py +22 -0
  193. package/generator/test/azure/mock_api_tests/asynctests/test_azure_core_lro_standard_async.py +39 -0
  194. package/generator/test/azure/mock_api_tests/asynctests/test_azure_core_model_async.py +33 -0
  195. package/generator/test/azure/mock_api_tests/asynctests/test_azure_core_page_async.py +58 -0
  196. package/generator/test/azure/mock_api_tests/asynctests/test_azure_core_scalar_async.py +41 -0
  197. package/generator/test/azure/mock_api_tests/asynctests/test_azure_core_traits_async.py +87 -0
  198. package/generator/test/azure/mock_api_tests/asynctests/test_azure_example_basic_async.py +30 -0
  199. package/generator/test/azure/mock_api_tests/asynctests/test_azure_special_headers_client_request_id_async.py +30 -0
  200. package/generator/test/azure/mock_api_tests/conftest.py +150 -0
  201. package/generator/test/azure/mock_api_tests/test_azure_arm_models_common_types_managed_identity.py +60 -0
  202. package/generator/test/azure/mock_api_tests/test_azure_arm_models_resource.py +254 -0
  203. package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_access.py +92 -0
  204. package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_flatten.py +84 -0
  205. package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_usage.py +28 -0
  206. package/generator/test/azure/mock_api_tests/test_azure_core_basic.py +70 -0
  207. package/generator/test/azure/mock_api_tests/test_azure_core_lro_rpc.py +20 -0
  208. package/generator/test/azure/mock_api_tests/test_azure_core_lro_standard.py +32 -0
  209. package/generator/test/azure/mock_api_tests/test_azure_core_model.py +30 -0
  210. package/generator/test/azure/mock_api_tests/test_azure_core_page.py +51 -0
  211. package/generator/test/azure/mock_api_tests/test_azure_core_scalar.py +35 -0
  212. package/generator/test/azure/mock_api_tests/test_azure_core_traits.py +85 -0
  213. package/generator/test/azure/mock_api_tests/test_azure_example_basic.py +29 -0
  214. package/generator/test/azure/mock_api_tests/test_azure_special_headers_client_request_id.py +29 -0
  215. package/generator/test/azure/requirements.txt +89 -0
  216. package/generator/test/azure/tox.ini +56 -0
  217. package/generator/test/generic_mock_api_tests/asynctests/test_authentication_async.py +121 -0
  218. package/generator/test/generic_mock_api_tests/asynctests/test_client_naming_async.py +69 -0
  219. package/generator/test/generic_mock_api_tests/asynctests/test_client_structure_async.py +62 -0
  220. package/generator/test/generic_mock_api_tests/asynctests/test_encode_bytes_async.py +133 -0
  221. package/generator/test/generic_mock_api_tests/asynctests/test_encode_datetime_async.py +127 -0
  222. package/generator/test/generic_mock_api_tests/asynctests/test_encode_duration_async.py +63 -0
  223. package/generator/test/generic_mock_api_tests/asynctests/test_encode_numeric_async.py +35 -0
  224. package/generator/test/generic_mock_api_tests/asynctests/test_headasboolean_async.py +35 -0
  225. package/generator/test/generic_mock_api_tests/asynctests/test_parameters_basic_async.py +24 -0
  226. package/generator/test/generic_mock_api_tests/asynctests/test_parameters_body_optionality_async.py +30 -0
  227. package/generator/test/generic_mock_api_tests/asynctests/test_parameters_collection_format_async.py +44 -0
  228. package/generator/test/generic_mock_api_tests/asynctests/test_parameters_spread_async.py +76 -0
  229. package/generator/test/generic_mock_api_tests/asynctests/test_payload_content_negotiation_async.py +37 -0
  230. package/generator/test/generic_mock_api_tests/asynctests/test_payload_json_merge_patch_async.py +98 -0
  231. package/generator/test/generic_mock_api_tests/asynctests/test_payload_media_type_async.py +27 -0
  232. package/generator/test/generic_mock_api_tests/asynctests/test_payload_multipart_async.py +153 -0
  233. package/generator/test/generic_mock_api_tests/asynctests/test_payload_pageable_async.py +19 -0
  234. package/generator/test/generic_mock_api_tests/asynctests/test_payload_xml_async.py +103 -0
  235. package/generator/test/generic_mock_api_tests/asynctests/test_resiliency_srv_driven_async.py +128 -0
  236. package/generator/test/generic_mock_api_tests/asynctests/test_routes_async.py +331 -0
  237. package/generator/test/generic_mock_api_tests/asynctests/test_serialization_encoded_name_json_async.py +24 -0
  238. package/generator/test/generic_mock_api_tests/asynctests/test_server_endpoint_not_defined_async.py +18 -0
  239. package/generator/test/generic_mock_api_tests/asynctests/test_server_path_multiple_async.py +25 -0
  240. package/generator/test/generic_mock_api_tests/asynctests/test_server_path_single_async.py +18 -0
  241. package/generator/test/generic_mock_api_tests/asynctests/test_server_versions_not_versioned_async.py +28 -0
  242. package/generator/test/generic_mock_api_tests/asynctests/test_server_versions_versioned_async.py +34 -0
  243. package/generator/test/generic_mock_api_tests/asynctests/test_special_headers_conditional_request_async.py +38 -0
  244. package/generator/test/generic_mock_api_tests/asynctests/test_special_headers_repeatability_async.py +19 -0
  245. package/generator/test/generic_mock_api_tests/asynctests/test_special_words_async.py +42 -0
  246. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_array_async.py +118 -0
  247. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_dictionary_async.py +98 -0
  248. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_enum_extensible_async.py +25 -0
  249. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_enum_fixed_async.py +27 -0
  250. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_model_empty_async.py +32 -0
  251. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_model_inheritance_enum_discriminator_async.py +70 -0
  252. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_model_inheritance_nested_discriminator_async.py +85 -0
  253. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_model_inheritance_not_discriminated_async.py +34 -0
  254. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_model_inheritance_recursive_async.py +34 -0
  255. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_model_inheritance_single_discriminator_async.py +67 -0
  256. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_model_usage_async.py +32 -0
  257. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_model_visibility_async.py +47 -0
  258. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_property_additionalproperties_async.py +352 -0
  259. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_property_nullable_async.py +110 -0
  260. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_property_optional_async.py +197 -0
  261. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_property_valuetypes_async.py +315 -0
  262. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_scalar_async.py +60 -0
  263. package/generator/test/generic_mock_api_tests/asynctests/test_typetest_union_async.py +90 -0
  264. package/generator/test/generic_mock_api_tests/asynctests/test_versioning_added_async.py +36 -0
  265. package/generator/test/generic_mock_api_tests/asynctests/test_versioning_made_optional_async.py +21 -0
  266. package/generator/test/generic_mock_api_tests/asynctests/test_versioning_removed_async.py +21 -0
  267. package/generator/test/generic_mock_api_tests/asynctests/test_versioning_renamed_from_async.py +29 -0
  268. package/generator/test/generic_mock_api_tests/asynctests/test_versioning_return_type_changed_from_async.py +18 -0
  269. package/generator/test/generic_mock_api_tests/asynctests/test_versioning_type_changed_from_async.py +22 -0
  270. package/generator/test/generic_mock_api_tests/conftest.py +113 -0
  271. package/generator/test/generic_mock_api_tests/data/image.jpg +0 -0
  272. package/generator/test/generic_mock_api_tests/data/image.png +0 -0
  273. package/generator/test/generic_mock_api_tests/test_authentication.py +113 -0
  274. package/generator/test/generic_mock_api_tests/test_client_naming.py +57 -0
  275. package/generator/test/generic_mock_api_tests/test_client_structure.py +57 -0
  276. package/generator/test/generic_mock_api_tests/test_encode_bytes.py +128 -0
  277. package/generator/test/generic_mock_api_tests/test_encode_datetime.py +123 -0
  278. package/generator/test/generic_mock_api_tests/test_encode_duration.py +60 -0
  279. package/generator/test/generic_mock_api_tests/test_encode_numeric.py +31 -0
  280. package/generator/test/generic_mock_api_tests/test_headasboolean.py +33 -0
  281. package/generator/test/generic_mock_api_tests/test_parameters_basic.py +22 -0
  282. package/generator/test/generic_mock_api_tests/test_parameters_body_optionality.py +27 -0
  283. package/generator/test/generic_mock_api_tests/test_parameters_collection_format.py +37 -0
  284. package/generator/test/generic_mock_api_tests/test_parameters_spread.py +66 -0
  285. package/generator/test/generic_mock_api_tests/test_payload_content_negotiation.py +33 -0
  286. package/generator/test/generic_mock_api_tests/test_payload_json_merge_patch.py +93 -0
  287. package/generator/test/generic_mock_api_tests/test_payload_media_type.py +25 -0
  288. package/generator/test/generic_mock_api_tests/test_payload_multipart.py +140 -0
  289. package/generator/test/generic_mock_api_tests/test_payload_pageable.py +18 -0
  290. package/generator/test/generic_mock_api_tests/test_payload_xml.py +93 -0
  291. package/generator/test/generic_mock_api_tests/test_resiliency_srv_driven.py +122 -0
  292. package/generator/test/generic_mock_api_tests/test_routes.py +285 -0
  293. package/generator/test/generic_mock_api_tests/test_serialization_encoded_name_json.py +21 -0
  294. package/generator/test/generic_mock_api_tests/test_server_endpoint_not_defined.py +17 -0
  295. package/generator/test/generic_mock_api_tests/test_server_path_multiple.py +21 -0
  296. package/generator/test/generic_mock_api_tests/test_server_path_single.py +17 -0
  297. package/generator/test/generic_mock_api_tests/test_server_versions_not_versioned.py +25 -0
  298. package/generator/test/generic_mock_api_tests/test_server_versions_versioned.py +30 -0
  299. package/generator/test/generic_mock_api_tests/test_special_headers_conditional_request.py +34 -0
  300. package/generator/test/generic_mock_api_tests/test_special_headers_repeatability.py +18 -0
  301. package/generator/test/generic_mock_api_tests/test_special_words.py +37 -0
  302. package/generator/test/generic_mock_api_tests/test_typetest_array.py +103 -0
  303. package/generator/test/generic_mock_api_tests/test_typetest_dictionary.py +86 -0
  304. package/generator/test/generic_mock_api_tests/test_typetest_enum_extensible.py +23 -0
  305. package/generator/test/generic_mock_api_tests/test_typetest_enum_fixed.py +25 -0
  306. package/generator/test/generic_mock_api_tests/test_typetest_model_empty.py +29 -0
  307. package/generator/test/generic_mock_api_tests/test_typetest_model_inheritance_enum_discriminator.py +58 -0
  308. package/generator/test/generic_mock_api_tests/test_typetest_model_inheritance_nested_discriminator.py +79 -0
  309. package/generator/test/generic_mock_api_tests/test_typetest_model_inheritance_not_discriminated.py +31 -0
  310. package/generator/test/generic_mock_api_tests/test_typetest_model_inheritance_recursive.py +32 -0
  311. package/generator/test/generic_mock_api_tests/test_typetest_model_inheritance_single_discriminator.py +60 -0
  312. package/generator/test/generic_mock_api_tests/test_typetest_model_usage.py +28 -0
  313. package/generator/test/generic_mock_api_tests/test_typetest_model_visibility.py +40 -0
  314. package/generator/test/generic_mock_api_tests/test_typetest_property_additionalproperties.py +313 -0
  315. package/generator/test/generic_mock_api_tests/test_typetest_property_nullable.py +102 -0
  316. package/generator/test/generic_mock_api_tests/test_typetest_property_optional.py +174 -0
  317. package/generator/test/generic_mock_api_tests/test_typetest_property_valuetypes.py +286 -0
  318. package/generator/test/generic_mock_api_tests/test_typetest_scalar.py +53 -0
  319. package/generator/test/generic_mock_api_tests/test_typetest_union.py +80 -0
  320. package/generator/test/generic_mock_api_tests/test_versioning_added.py +33 -0
  321. package/generator/test/generic_mock_api_tests/test_versioning_made_optional.py +20 -0
  322. package/generator/test/generic_mock_api_tests/test_versioning_removed.py +20 -0
  323. package/generator/test/generic_mock_api_tests/test_versioning_renamed_from.py +27 -0
  324. package/generator/test/generic_mock_api_tests/test_versioning_return_type_changed_from.py +17 -0
  325. package/generator/test/generic_mock_api_tests/test_versioning_type_changed_from.py +21 -0
  326. package/generator/test/generic_mock_api_tests/unittests/test_model_base_serialization.py +4067 -0
  327. package/generator/test/generic_mock_api_tests/unittests/test_model_base_xml_serialization.py +1001 -0
  328. package/generator/test/unbranded/mock_api_tests/asynctests/test_unbranded_async.py +24 -0
  329. package/generator/test/unbranded/mock_api_tests/cadl-ranch-config.yaml +27 -0
  330. package/generator/test/unbranded/mock_api_tests/conftest.py +35 -0
  331. package/generator/test/unbranded/mock_api_tests/test_unbranded.py +57 -0
  332. package/generator/test/unbranded/requirements.txt +72 -0
  333. package/generator/test/unbranded/tox.ini +56 -0
  334. package/package.json +93 -0
@@ -0,0 +1,1507 @@
1
+ # pylint: disable=too-many-lines
2
+ # -------------------------------------------------------------------------
3
+ # Copyright (c) Microsoft Corporation. All rights reserved.
4
+ # Licensed under the MIT License. See License.txt in the project root for
5
+ # license information.
6
+ # --------------------------------------------------------------------------
7
+ from abc import abstractmethod
8
+ from collections import defaultdict
9
+ from typing import Generic, List, Type, TypeVar, Dict, Union, Optional, cast
10
+
11
+ from ..models import (
12
+ Operation,
13
+ PagingOperation,
14
+ CodeModel,
15
+ LROOperation,
16
+ LROPagingOperation,
17
+ ModelType,
18
+ DictionaryType,
19
+ ListType,
20
+ RequestBuilder,
21
+ ParameterLocation,
22
+ Response,
23
+ BinaryType,
24
+ BodyParameter,
25
+ ParameterMethodLocation,
26
+ OverloadedRequestBuilder,
27
+ Property,
28
+ RequestBuilderType,
29
+ CombinedType,
30
+ JSONModelType,
31
+ DPGModelType,
32
+ ParameterListType,
33
+ ByteArraySchema,
34
+ )
35
+ from .parameter_serializer import ParameterSerializer, PopKwargType
36
+ from ..models.parameter_list import ParameterType
37
+ from . import utils
38
+ from ...utils import xml_serializable, json_serializable
39
+
40
+ T = TypeVar("T")
41
+ OrderedSet = Dict[T, None]
42
+
43
+ BuilderType = TypeVar(
44
+ "BuilderType",
45
+ bound=Union[
46
+ RequestBuilder,
47
+ Operation,
48
+ PagingOperation,
49
+ LROOperation,
50
+ LROPagingOperation,
51
+ OverloadedRequestBuilder,
52
+ ],
53
+ )
54
+ OperationType = TypeVar(
55
+ "OperationType",
56
+ bound=Union[Operation, PagingOperation, LROOperation, LROPagingOperation],
57
+ )
58
+
59
+
60
+ def _all_same(data: List[List[str]]) -> bool:
61
+ return len(data) > 1 and all(sorted(data[0]) == sorted(data[i]) for i in range(1, len(data)))
62
+
63
+
64
+ def _need_type_ignore(builder: OperationType) -> bool:
65
+ for e in builder.non_default_errors:
66
+ for status_code in e.status_codes:
67
+ if status_code in (401, 404, 409, 304):
68
+ return True
69
+ return False
70
+
71
+
72
+ def _xml_config(send_xml: bool, content_types: List[str]) -> str:
73
+ if not (send_xml and "xml" in str(content_types)):
74
+ return ""
75
+ if len(content_types) == 1:
76
+ return ", is_xml=True"
77
+ return ", is_xml='xml' in str(content_type)"
78
+
79
+
80
+ def _escape_str(input_str: str) -> str:
81
+ replace = input_str.replace("'", "\\'")
82
+ return f'"{replace}"'
83
+
84
+
85
+ def _get_polymorphic_subtype_template(polymorphic_subtype: ModelType) -> List[str]:
86
+ retval: List[str] = []
87
+ retval.append("")
88
+ retval.append(f'# JSON input template for discriminator value "{polymorphic_subtype.discriminator_value}":')
89
+ subtype_template = utils.json_dumps_template(
90
+ polymorphic_subtype.get_json_template_representation(),
91
+ )
92
+
93
+ def _get_polymorphic_parent(
94
+ polymorphic_subtype: Optional[ModelType],
95
+ ) -> Optional[ModelType]:
96
+ if not polymorphic_subtype:
97
+ return None
98
+ try:
99
+ return next(p for p in polymorphic_subtype.parents if p.discriminated_subtypes)
100
+ except StopIteration:
101
+ return None
102
+
103
+ polymorphic_parent = _get_polymorphic_parent(polymorphic_subtype)
104
+ while _get_polymorphic_parent(polymorphic_parent):
105
+ polymorphic_parent = _get_polymorphic_parent(polymorphic_parent)
106
+ retval.extend(f"{cast(ModelType, polymorphic_parent).snake_case_name} = {subtype_template}".splitlines())
107
+ return retval
108
+
109
+
110
+ def _serialize_grouped_body(builder: BuilderType) -> List[str]:
111
+ retval: List[str] = []
112
+ for grouped_parameter in builder.parameters.grouped:
113
+ retval.append(f"{grouped_parameter.client_name} = None")
114
+ groupers = [p for p in builder.parameters if p.grouper]
115
+ for grouper in groupers:
116
+ retval.append(f"if {grouper.client_name} is not None:")
117
+ retval.extend(
118
+ [
119
+ f" {parameter} = {grouper.client_name}.{property}"
120
+ for property, parameter in grouper.property_to_parameter_name.items()
121
+ ]
122
+ )
123
+ return retval
124
+
125
+
126
+ def _serialize_flattened_body(body_parameter: BodyParameter) -> List[str]:
127
+ retval: List[str] = []
128
+ if not body_parameter.property_to_parameter_name:
129
+ raise ValueError("This method can't be called if the operation doesn't need parameter flattening")
130
+
131
+ parameter_string = ", ".join(
132
+ f"{property_name}={parameter_name}"
133
+ for property_name, parameter_name in body_parameter.property_to_parameter_name.items()
134
+ )
135
+ model_type = cast(ModelType, body_parameter.type)
136
+ retval.append(f"{body_parameter.client_name} = _models.{model_type.name}({parameter_string})")
137
+ return retval
138
+
139
+
140
+ def _serialize_json_model_body(body_parameter: BodyParameter, parameters: List[ParameterType]) -> List[str]:
141
+ retval: List[str] = []
142
+ if not body_parameter.property_to_parameter_name:
143
+ raise ValueError("This method can't be called if the operation doesn't need parameter flattening")
144
+
145
+ retval.append(f"if {body_parameter.client_name} is _Unset:")
146
+ for p in parameters:
147
+ if p.client_default_value is None and not p.optional and p.default_to_unset_sentinel:
148
+ retval.append(f" if {p.client_name} is _Unset:")
149
+ retval.append(f" raise TypeError('missing required argument: {p.client_name}')")
150
+ parameter_string = ", \n".join(
151
+ f'"{property_name}": {parameter_name}'
152
+ for property_name, parameter_name in body_parameter.property_to_parameter_name.items()
153
+ )
154
+ model_type = cast(ModelType, body_parameter.type)
155
+ if isinstance(model_type, CombinedType) and model_type.target_model_subtype((JSONModelType,)):
156
+ model_type = model_type.target_model_subtype((JSONModelType,))
157
+ retval.append(f" {body_parameter.client_name} = {{{parameter_string}}}")
158
+ retval.append(f" {body_parameter.client_name} = {{")
159
+ retval.append(f" k: v for k, v in {body_parameter.client_name}.items() if v is not None")
160
+ retval.append(" }")
161
+ return retval
162
+
163
+
164
+ def _serialize_multipart_body(builder: BuilderType) -> List[str]:
165
+ retval: List[str] = []
166
+ body_param = builder.parameters.body_parameter
167
+ # we have to construct our form data before passing to the request as well
168
+ retval.append("# Construct form data")
169
+ retval.append(f"_{body_param.client_name} = {{")
170
+ for param in body_param.entries:
171
+ retval.append(f' "{param.wire_name}": {param.client_name},')
172
+ retval.append("}")
173
+ return retval
174
+
175
+
176
+ def _get_json_response_template_to_status_codes(
177
+ builder: OperationType,
178
+ ) -> Dict[str, List[str]]:
179
+ retval = defaultdict(list)
180
+ for response in builder.responses:
181
+ json_template = response.get_json_template_representation()
182
+ if not json_template:
183
+ continue
184
+ status_codes = [str(status_code) for status_code in response.status_codes]
185
+ response_json = utils.json_dumps_template(json_template)
186
+ retval[response_json].extend(status_codes)
187
+ return retval
188
+
189
+
190
+ def is_json_model_type(parameters: ParameterListType) -> bool:
191
+ return (
192
+ parameters.has_body
193
+ and parameters.body_parameter.has_json_model_type
194
+ and any(p.in_flattened_body for p in parameters.parameters)
195
+ )
196
+
197
+
198
+ class _BuilderBaseSerializer(Generic[BuilderType]):
199
+ def __init__(self, code_model: CodeModel, async_mode: bool) -> None:
200
+ self.code_model = code_model
201
+ self.async_mode = async_mode
202
+ self.parameter_serializer = ParameterSerializer()
203
+
204
+ @property
205
+ @abstractmethod
206
+ def _need_self_param(self) -> bool: ...
207
+
208
+ @property
209
+ @abstractmethod
210
+ def _function_def(self) -> str:
211
+ """The def keyword for the builder we're serializing, i.e. 'def' or 'async def'"""
212
+
213
+ @property
214
+ @abstractmethod
215
+ def _call_method(self) -> str:
216
+ """How to call network calls. Await if we have to await network calls"""
217
+
218
+ @property
219
+ @abstractmethod
220
+ def serializer_name(self) -> str:
221
+ """Name of serializer"""
222
+
223
+ @abstractmethod
224
+ def response_docstring(self, builder: BuilderType) -> List[str]:
225
+ """Response portion of the docstring"""
226
+
227
+ def decorators(self, builder: BuilderType) -> List[str]:
228
+ """Decorators for the method"""
229
+ retval: List[str] = []
230
+ if builder.is_overload:
231
+ return ["@overload"]
232
+ if self.code_model.options["tracing"] and builder.want_tracing:
233
+ retval.append(f"@distributed_trace{'_async' if self.async_mode else ''}")
234
+ return retval
235
+
236
+ def _method_signature(self, builder: BuilderType) -> str:
237
+ return self.parameter_serializer.serialize_method(
238
+ function_def=self._function_def,
239
+ method_name=builder.name,
240
+ need_self_param=self._need_self_param,
241
+ method_param_signatures=builder.method_signature(self.async_mode),
242
+ pylint_disable=builder.pylint_disable(self.async_mode),
243
+ )
244
+
245
+ def method_signature_and_response_type_annotation(
246
+ self, builder: BuilderType, *, want_decorators: Optional[bool] = True
247
+ ) -> str:
248
+ response_type_annotation = builder.response_type_annotation(async_mode=self.async_mode)
249
+ method_signature = self._method_signature(builder)
250
+ decorators = self.decorators(builder)
251
+ decorators_str = ""
252
+ if decorators and want_decorators:
253
+ decorators_str = "\n".join(decorators) + "\n"
254
+ return decorators_str + utils.method_signature_and_response_type_annotation_template(
255
+ method_signature=method_signature,
256
+ response_type_annotation=response_type_annotation,
257
+ )
258
+
259
+ def description_and_summary(self, builder: BuilderType) -> List[str]:
260
+ description_list: List[str] = []
261
+ description_list.append(f"{builder.summary.strip() if builder.summary else builder.description.strip()}")
262
+ if builder.summary and builder.description:
263
+ description_list.append("")
264
+ description_list.append(builder.description.strip())
265
+ description_list.append("")
266
+ return description_list
267
+
268
+ @staticmethod
269
+ def line_too_long(docs: List[str], indentation: int = 0) -> bool:
270
+ return any(len(line) > (120 - indentation) for line in docs)
271
+
272
+ def example_template(self, builder: BuilderType) -> List[str]:
273
+ template = []
274
+ if builder.abstract:
275
+ return []
276
+ if self._json_input_example_template(builder):
277
+ template.append("")
278
+ template += self._json_input_example_template(builder)
279
+ return template
280
+
281
+ def param_description(self, builder: BuilderType) -> List[str]:
282
+ description_list: List[str] = []
283
+ for param in builder.parameters.method:
284
+ if (
285
+ not param.in_docstring
286
+ or param.hide_in_operation_signature
287
+ or param.method_location == ParameterMethodLocation.KWARG
288
+ ):
289
+ continue
290
+ description_list.extend(
291
+ f":{param.description_keyword} {param.client_name}: {param.description}".replace("\n", "\n ").split(
292
+ "\n"
293
+ )
294
+ )
295
+ docstring_type = param.docstring_type(
296
+ async_mode=self.async_mode,
297
+ )
298
+ description_list.append(f":{param.docstring_type_keyword} {param.client_name}: {docstring_type}")
299
+ return description_list
300
+
301
+ def param_description_and_response_docstring(self, builder: BuilderType) -> List[str]:
302
+ if builder.abstract:
303
+ return []
304
+ return self.param_description(builder) + self.response_docstring(builder)
305
+
306
+ @property
307
+ @abstractmethod
308
+ def _json_response_template_name(self) -> str: ...
309
+
310
+ def _json_input_example_template(self, builder: BuilderType) -> List[str]:
311
+ template: List[str] = []
312
+ if not builder.parameters.has_body or builder.parameters.body_parameter.flattened:
313
+ # No input template if now body parameter
314
+ return template
315
+
316
+ body_param = builder.parameters.body_parameter
317
+ if not isinstance(body_param.type, (ListType, DictionaryType, ModelType, CombinedType)):
318
+ return template
319
+
320
+ if (
321
+ isinstance(body_param.type, (ListType, DictionaryType))
322
+ and self.code_model.options["models_mode"] == "msrest"
323
+ ):
324
+ return template
325
+
326
+ if isinstance(body_param.type, ModelType) and body_param.type.base == "msrest":
327
+ return template
328
+
329
+ json_type = body_param.type
330
+ if isinstance(body_param.type, CombinedType):
331
+ target_model_type = body_param.type.target_model_subtype((JSONModelType, DPGModelType))
332
+ if target_model_type is None:
333
+ return template
334
+ json_type = target_model_type
335
+
336
+ polymorphic_subtypes: List[ModelType] = []
337
+ json_type.get_polymorphic_subtypes(polymorphic_subtypes)
338
+ if polymorphic_subtypes:
339
+ # we just assume one kind of polymorphic body for input
340
+ discriminator_name = cast(Property, polymorphic_subtypes[0].discriminator).wire_name
341
+ template.append(
342
+ "# The input is polymorphic. The following are possible polymorphic "
343
+ f'inputs based off discriminator "{discriminator_name}":'
344
+ )
345
+ for idx in range(
346
+ min(
347
+ self.code_model.options["polymorphic_examples"],
348
+ len(polymorphic_subtypes),
349
+ )
350
+ ):
351
+ template.extend(_get_polymorphic_subtype_template(polymorphic_subtypes[idx]))
352
+ template.append("")
353
+ template.append("# JSON input template you can fill out and use as your body input.")
354
+ json_template = utils.json_dumps_template(
355
+ json_type.get_json_template_representation(),
356
+ )
357
+ template.extend(f"{builder.parameters.body_parameter.client_name} = {json_template}".splitlines())
358
+ return template
359
+
360
+ def serialize_path(self, builder: BuilderType) -> List[str]:
361
+ return self.parameter_serializer.serialize_path(builder.parameters.path, self.serializer_name)
362
+
363
+ @property
364
+ def pipeline_name(self) -> str:
365
+ return f"{'_' if self.code_model.is_azure_flavor else ''}pipeline"
366
+
367
+
368
+ ############################## REQUEST BUILDERS ##############################
369
+
370
+
371
+ class RequestBuilderSerializer(_BuilderBaseSerializer[RequestBuilderType]):
372
+ def description_and_summary(self, builder: RequestBuilderType) -> List[str]:
373
+ retval = super().description_and_summary(builder)
374
+ retval += [
375
+ "See https://aka.ms/azsdk/dpcodegen/python/send_request for how to incorporate this "
376
+ "request builder into your code flow.",
377
+ "",
378
+ ]
379
+ return retval
380
+
381
+ @property
382
+ def _call_method(self) -> str:
383
+ return ""
384
+
385
+ @property
386
+ def serializer_name(self) -> str:
387
+ return "_SERIALIZER"
388
+
389
+ @property
390
+ def _json_response_template_name(self) -> str:
391
+ return "response.json()"
392
+
393
+ @staticmethod
394
+ def declare_non_inputtable_headers_queries(
395
+ builder: RequestBuilderType,
396
+ ) -> List[str]:
397
+ def _get_value(param):
398
+ declaration = param.get_declaration() if param.constant else None
399
+ if param.location in [ParameterLocation.HEADER, ParameterLocation.QUERY]:
400
+ kwarg_dict = "headers" if param.location == ParameterLocation.HEADER else "params"
401
+ return f"_{kwarg_dict}.pop('{param.wire_name}', {declaration})"
402
+ return declaration
403
+
404
+ return [
405
+ f"{p.client_name} = {_get_value(p)}"
406
+ for p in (builder.parameters.headers + builder.parameters.query)
407
+ if not p.in_method_signature
408
+ ]
409
+
410
+ @property
411
+ def _function_def(self) -> str:
412
+ return "def"
413
+
414
+ @property
415
+ def _need_self_param(self) -> bool:
416
+ return False
417
+
418
+ def response_docstring(self, builder: RequestBuilderType) -> List[str]:
419
+ request_full_path = f"{self.code_model.core_library}.rest.HttpRequest"
420
+ response_str = (
421
+ f":return: Returns an :class:`~{request_full_path}` that you will pass to the client's "
422
+ + "`send_request` method. See https://aka.ms/azsdk/dpcodegen/python/send_request for how to "
423
+ + "incorporate this response into your code flow."
424
+ )
425
+ rtype_str = f":rtype: ~{request_full_path}"
426
+ return [response_str, rtype_str]
427
+
428
+ def pop_kwargs_from_signature(self, builder: RequestBuilderType) -> List[str]:
429
+ return self.parameter_serializer.pop_kwargs_from_signature(
430
+ builder.parameters.kwargs_to_pop,
431
+ check_kwarg_dict=True,
432
+ pop_headers_kwarg=(PopKwargType.CASE_INSENSITIVE if bool(builder.parameters.headers) else PopKwargType.NO),
433
+ pop_params_kwarg=(PopKwargType.CASE_INSENSITIVE if bool(builder.parameters.query) else PopKwargType.NO),
434
+ )
435
+
436
+ @staticmethod
437
+ def create_http_request(builder: RequestBuilderType) -> List[str]:
438
+ retval = ["return HttpRequest("]
439
+ retval.append(f' method="{builder.method}",')
440
+ retval.append(" url=_url,")
441
+ if builder.parameters.query:
442
+ retval.append(" params=_params,")
443
+ if builder.parameters.headers:
444
+ retval.append(" headers=_headers,")
445
+ if builder.parameters.has_body and builder.parameters.body_parameter.in_method_signature:
446
+ body_param = builder.parameters.body_parameter
447
+ if body_param.constant or body_param.method_location != ParameterMethodLocation.KWARG:
448
+ # we only need to pass it through if it's not a kwarg or it's a popped kwarg
449
+ retval.append(
450
+ f" {builder.parameters.body_parameter.client_name}="
451
+ f"{builder.parameters.body_parameter.client_name},"
452
+ )
453
+ retval.append(" **kwargs")
454
+ retval.append(")")
455
+ return retval
456
+
457
+ def serialize_headers(self, builder: RequestBuilderType) -> List[str]:
458
+ headers = [
459
+ h
460
+ for h in builder.parameters.headers
461
+ if not builder.has_form_data_body or h.wire_name.lower() != "content-type"
462
+ ]
463
+ retval = ["# Construct headers"] if headers else []
464
+ for header in headers:
465
+ retval.extend(
466
+ self.parameter_serializer.serialize_query_header(
467
+ header,
468
+ "headers",
469
+ self.serializer_name,
470
+ self.code_model.is_legacy,
471
+ )
472
+ )
473
+ return retval
474
+
475
+ def serialize_query(self, builder: RequestBuilderType) -> List[str]:
476
+ retval = ["# Construct parameters"]
477
+ for parameter in builder.parameters.query:
478
+ retval.extend(
479
+ self.parameter_serializer.serialize_query_header(
480
+ parameter,
481
+ "params",
482
+ self.serializer_name,
483
+ self.code_model.is_legacy,
484
+ )
485
+ )
486
+ return retval
487
+
488
+ def construct_url(self, builder: RequestBuilderType) -> str:
489
+ if any(o for o in ["low_level_client", "version_tolerant"] if self.code_model.options.get(o)):
490
+ url_value = _escape_str(builder.url)
491
+ else:
492
+ url_value = f'kwargs.pop("template_url", {_escape_str(builder.url)})'
493
+ return f"_url = {url_value}{' # pylint: disable=line-too-long' if len(url_value) > 114 else ''}"
494
+
495
+
496
+ ############################## NORMAL OPERATIONS ##############################
497
+
498
+
499
+ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
500
+ def description_and_summary(self, builder: OperationType) -> List[str]:
501
+ retval = super().description_and_summary(builder)
502
+ if builder.deprecated:
503
+ retval.append(".. warning::")
504
+ retval.append(" This method is deprecated")
505
+ retval.append("")
506
+ if builder.external_docs and builder.external_docs.get("url"):
507
+ retval.append(".. seealso::")
508
+ retval.append(f" - {builder.external_docs['url']}")
509
+ retval.append("")
510
+ return retval
511
+
512
+ @property
513
+ def _json_response_template_name(self) -> str:
514
+ return "response"
515
+
516
+ def example_template(self, builder: OperationType) -> List[str]:
517
+ if self.code_model.options["models_mode"] in ("msrest", "dpg"):
518
+ return []
519
+ retval = super().example_template(builder)
520
+ for response in builder.responses:
521
+ polymorphic_subtypes: List[ModelType] = []
522
+ if not response.type:
523
+ continue
524
+ response.get_polymorphic_subtypes(polymorphic_subtypes)
525
+ if polymorphic_subtypes:
526
+ # we just assume one kind of polymorphic body for input
527
+ discriminator_name = cast(Property, polymorphic_subtypes[0].discriminator).wire_name
528
+ retval.append("")
529
+ retval.append(
530
+ "# The response is polymorphic. The following are possible polymorphic "
531
+ f'responses based off discriminator "{discriminator_name}":'
532
+ )
533
+ for idx in range(
534
+ min(
535
+ self.code_model.options["polymorphic_examples"],
536
+ len(polymorphic_subtypes),
537
+ )
538
+ ):
539
+ retval.extend(_get_polymorphic_subtype_template(polymorphic_subtypes[idx]))
540
+
541
+ if _get_json_response_template_to_status_codes(builder):
542
+ retval.append("")
543
+ for (
544
+ response_body,
545
+ status_codes,
546
+ ) in _get_json_response_template_to_status_codes(builder).items():
547
+ retval.append("# response body for status code(s): {}".format(", ".join(status_codes)))
548
+ retval.extend(f"{self._json_response_template_name} == {response_body}".splitlines())
549
+ return retval
550
+
551
+ def make_pipeline_call(self, builder: OperationType) -> List[str]:
552
+ retval = []
553
+ type_ignore = self.async_mode and builder.group_name == "" # is in a mixin
554
+ if builder.stream_value is True and not self.code_model.options["version_tolerant"]:
555
+ retval.append("_decompress = kwargs.pop('decompress', True)")
556
+ retval.extend(
557
+ [
558
+ f"_stream = {builder.stream_value}",
559
+ f"pipeline_response: PipelineResponse = {self._call_method}self._client.{self.pipeline_name}.run( "
560
+ + f"{'# type: ignore' if type_ignore else ''} # pylint: disable=protected-access",
561
+ " _request,",
562
+ " stream=_stream,",
563
+ " **kwargs",
564
+ ")",
565
+ ]
566
+ )
567
+ return retval
568
+
569
+ @property
570
+ def _function_def(self) -> str:
571
+ return "async def" if self.async_mode else "def"
572
+
573
+ @property
574
+ def _need_self_param(self) -> bool:
575
+ return True
576
+
577
+ @property
578
+ def serializer_name(self) -> str:
579
+ return "self._serialize"
580
+
581
+ def decorators(self, builder: OperationType) -> List[str]:
582
+ """Decorators for the method"""
583
+ retval = super().decorators(builder)
584
+ if self._api_version_validation(builder):
585
+ retval.append(self._api_version_validation(builder))
586
+ return retval
587
+
588
+ def _api_version_validation(self, builder: OperationType) -> str:
589
+ if builder.is_overload:
590
+ return ""
591
+ retval: List[str] = []
592
+ if builder.added_on:
593
+ retval.append(f' method_added_on="{builder.added_on}",')
594
+ params_added_on = defaultdict(list)
595
+ for parameter in builder.parameters:
596
+ if parameter.added_on:
597
+ params_added_on[parameter.added_on].append(parameter.client_name)
598
+ if params_added_on:
599
+ retval.append(f" params_added_on={dict(params_added_on)},")
600
+ if retval:
601
+ retval_str = "\n".join(retval)
602
+ return f"@api_version_validation(\n{retval_str}\n){builder.pylint_disable(self.async_mode)}"
603
+ return ""
604
+
605
+ def pop_kwargs_from_signature(self, builder: OperationType) -> List[str]:
606
+ kwargs_to_pop = builder.parameters.kwargs_to_pop
607
+ kwargs = self.parameter_serializer.pop_kwargs_from_signature(
608
+ kwargs_to_pop,
609
+ check_kwarg_dict=True,
610
+ pop_headers_kwarg=(
611
+ PopKwargType.CASE_INSENSITIVE
612
+ if builder.has_kwargs_to_pop_with_default(kwargs_to_pop, ParameterLocation.HEADER) # type: ignore
613
+ else PopKwargType.SIMPLE
614
+ ),
615
+ pop_params_kwarg=(
616
+ PopKwargType.CASE_INSENSITIVE
617
+ if builder.has_kwargs_to_pop_with_default(kwargs_to_pop, ParameterLocation.QUERY) # type: ignore
618
+ else PopKwargType.SIMPLE
619
+ ),
620
+ check_client_input=not self.code_model.options["multiapi"],
621
+ operation_name=f"('{builder.name}')" if builder.group_name == "" else "",
622
+ )
623
+ for p in builder.parameters.parameters:
624
+ if p.hide_in_operation_signature:
625
+ kwargs.append(f'{p.client_name} = kwargs.pop("{p.client_name}", None)')
626
+ cls_annotation = builder.cls_type_annotation(async_mode=self.async_mode)
627
+ kwargs.append(f"cls: {cls_annotation} = kwargs.pop(\n 'cls', None\n)")
628
+ return kwargs
629
+
630
+ def response_docstring(self, builder: OperationType) -> List[str]:
631
+ response_str = f":return: {builder.response_docstring_text(async_mode=self.async_mode)}"
632
+ rtype_str = f":rtype: {builder.response_docstring_type(async_mode=self.async_mode)}"
633
+ return [
634
+ response_str,
635
+ rtype_str,
636
+ f":raises ~{self.code_model.core_library}.exceptions.HttpResponseError:",
637
+ ]
638
+
639
+ def _serialize_body_parameter(self, builder: OperationType) -> List[str]:
640
+ """We need to serialize params if they're not meant to be streamed in.
641
+
642
+ This function serializes the body params that need to be serialized.
643
+ """
644
+ retval: List[str] = []
645
+ body_param = builder.parameters.body_parameter
646
+ if body_param.is_form_data:
647
+ model_type = cast(
648
+ ModelType,
649
+ (
650
+ body_param.type.target_model_subtype((JSONModelType, DPGModelType))
651
+ if isinstance(body_param.type, CombinedType)
652
+ else body_param.type
653
+ ),
654
+ )
655
+ file_fields = [p.wire_name for p in model_type.properties if p.is_multipart_file_input]
656
+ data_fields = [p.wire_name for p in model_type.properties if not p.is_multipart_file_input]
657
+ retval.extend(
658
+ [
659
+ "_body = (",
660
+ f" {body_param.client_name}.as_dict()",
661
+ f" if isinstance({body_param.client_name}, _model_base.Model) else",
662
+ f" {body_param.client_name}",
663
+ ")",
664
+ f"_file_fields: List[str] = {file_fields}",
665
+ f"_data_fields: List[str] = {data_fields}",
666
+ "_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)",
667
+ ]
668
+ )
669
+ return retval
670
+
671
+ body_kwarg_name = builder.request_builder.parameters.body_parameter.client_name
672
+ send_xml = builder.parameters.body_parameter.type.is_xml
673
+ xml_serialization_ctxt = body_param.type.xml_serialization_ctxt if send_xml else None
674
+ ser_ctxt_name = "serialization_ctxt"
675
+ if xml_serialization_ctxt and self.code_model.options["models_mode"]:
676
+ retval.append(f'{ser_ctxt_name} = {{"xml": {{{xml_serialization_ctxt}}}}}')
677
+ if self.code_model.options["models_mode"] == "msrest":
678
+ is_xml_cmd = _xml_config(send_xml, builder.parameters.body_parameter.content_types)
679
+ serialization_ctxt_cmd = f", {ser_ctxt_name}={ser_ctxt_name}" if xml_serialization_ctxt else ""
680
+ create_body_call = (
681
+ f"_{body_kwarg_name} = self._serialize.body({body_param.client_name}, "
682
+ f"'{body_param.type.serialization_type}'{is_xml_cmd}{serialization_ctxt_cmd})"
683
+ )
684
+ elif self.code_model.options["models_mode"] == "dpg":
685
+ if json_serializable(body_param.default_content_type):
686
+ if hasattr(body_param.type, "encode") and body_param.type.encode: # type: ignore
687
+ create_body_call = (
688
+ f"_{body_kwarg_name} = json.dumps({body_param.client_name}, "
689
+ "cls=SdkJSONEncoder, exclude_readonly=True, "
690
+ f"format='{body_param.type.encode}') # type: ignore" # type: ignore
691
+ )
692
+ else:
693
+ create_body_call = (
694
+ f"_{body_kwarg_name} = json.dumps({body_param.client_name}, "
695
+ "cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore"
696
+ )
697
+ elif xml_serializable(body_param.default_content_type):
698
+ create_body_call = f"_{body_kwarg_name} = _get_element({body_param.client_name})"
699
+ else:
700
+ create_body_call = f"_{body_kwarg_name} = {body_param.client_name}"
701
+ else:
702
+ create_body_call = f"_{body_kwarg_name} = {body_param.client_name}"
703
+ if body_param.optional:
704
+ retval.append(f"if {body_param.client_name} is not None:")
705
+ retval.append(" " + create_body_call)
706
+ retval.append("else:")
707
+ retval.append(f" _{body_kwarg_name} = None")
708
+ else:
709
+ retval.append(create_body_call)
710
+ return retval
711
+
712
+ def _create_body_parameter(
713
+ self,
714
+ builder: OperationType,
715
+ ) -> List[str]:
716
+ """Create the body parameter before we pass it as either json or content to the request builder"""
717
+ retval = []
718
+ body_param = builder.parameters.body_parameter
719
+ if body_param.entries:
720
+ return _serialize_multipart_body(builder)
721
+ body_kwarg_name = builder.request_builder.parameters.body_parameter.client_name
722
+ body_param_type = body_param.type
723
+ if isinstance(body_param_type, BinaryType) or (
724
+ isinstance(body_param.type, ByteArraySchema) and body_param.default_content_type != "application/json"
725
+ ):
726
+ retval.append(f"_{body_kwarg_name} = {body_param.client_name}")
727
+ if (
728
+ not body_param.default_content_type
729
+ and not next(p for p in builder.parameters if p.wire_name.lower() == "content-type").optional
730
+ ):
731
+ content_types = "'" + "', '".join(body_param.content_types) + "'"
732
+ retval.extend(
733
+ [
734
+ "if not content_type:",
735
+ f' raise TypeError("Missing required keyword-only argument: content_type. '
736
+ f'Known values are:" + "{content_types}")',
737
+ ]
738
+ )
739
+ else:
740
+ retval.extend(self._serialize_body_parameter(builder))
741
+ return retval
742
+
743
+ def _initialize_overloads(self, builder: OperationType, is_paging: bool = False) -> List[str]:
744
+ retval: List[str] = []
745
+ # For paging, we put body parameter in local place outside `prepare_request`
746
+ if is_paging:
747
+ return retval
748
+ same_content_type = len(set(o.parameters.body_parameter.default_content_type for o in builder.overloads)) == 1
749
+ if same_content_type:
750
+ default_content_type = builder.overloads[0].parameters.body_parameter.default_content_type
751
+ retval.append(f'content_type = content_type or "{default_content_type}"')
752
+ client_names = [
753
+ overload.request_builder.parameters.body_parameter.client_name for overload in builder.overloads
754
+ ]
755
+ for v in sorted(set(client_names), key=client_names.index):
756
+ retval.append(f"_{v} = None")
757
+ try:
758
+ # if there is a binary overload, we do a binary check first.
759
+ binary_overload = cast(
760
+ OperationType,
761
+ next((o for o in builder.overloads if isinstance(o.parameters.body_parameter.type, BinaryType))),
762
+ )
763
+ binary_body_param = binary_overload.parameters.body_parameter
764
+ retval.append(f"if {binary_body_param.type.instance_check_template.format(binary_body_param.client_name)}:")
765
+ if binary_body_param.default_content_type and not same_content_type:
766
+ retval.append(f' content_type = content_type or "{binary_body_param.default_content_type}"')
767
+ retval.extend(f" {l}" for l in self._create_body_parameter(binary_overload))
768
+ retval.append("else:")
769
+ other_overload = cast(
770
+ OperationType,
771
+ next((o for o in builder.overloads if not isinstance(o.parameters.body_parameter.type, BinaryType))),
772
+ )
773
+ retval.extend(f" {l}" for l in self._create_body_parameter(other_overload))
774
+ if other_overload.parameters.body_parameter.default_content_type and not same_content_type:
775
+ retval.append(
776
+ " content_type = content_type or "
777
+ f'"{other_overload.parameters.body_parameter.default_content_type}"'
778
+ )
779
+ except StopIteration:
780
+ for idx, overload in enumerate(builder.overloads):
781
+ if_statement = "if" if idx == 0 else "elif"
782
+ body_param = overload.parameters.body_parameter
783
+ retval.append(
784
+ f"{if_statement} {body_param.type.instance_check_template.format(body_param.client_name)}:"
785
+ )
786
+ if body_param.default_content_type and not same_content_type:
787
+ retval.append(f' content_type = content_type or "{body_param.default_content_type}"')
788
+ retval.extend(f" {l}" for l in self._create_body_parameter(cast(OperationType, overload)))
789
+ return retval
790
+
791
+ def _create_request_builder_call(
792
+ self,
793
+ builder: OperationType,
794
+ request_builder: RequestBuilderType,
795
+ is_next_request: bool = False,
796
+ ) -> List[str]:
797
+ retval: List[str] = []
798
+ if self.code_model.options["builders_visibility"] == "embedded":
799
+ request_path_name = request_builder.name
800
+ else:
801
+ group_name = request_builder.group_name
802
+ request_path_name = "rest{}.{}".format(
803
+ ("_" + group_name) if group_name else "",
804
+ request_builder.name,
805
+ )
806
+ retval.append(f"_request = {request_path_name}(")
807
+ for parameter in request_builder.parameters.method:
808
+ if parameter.location == ParameterLocation.BODY:
809
+ # going to pass in body later based off of overloads
810
+ continue
811
+ if (
812
+ is_next_request
813
+ and builder.operation_type == "paging"
814
+ and not bool(builder.next_request_builder) # type: ignore
815
+ and parameter.location == ParameterLocation.QUERY
816
+ ):
817
+ # if we don't want to reformat query parameters for next link calls
818
+ # in paging operations with a single swagger operation defintion,
819
+ # we skip passing query params when building the next request
820
+ continue
821
+ type_ignore = (
822
+ parameter.grouped_by
823
+ and parameter.client_default_value is not None
824
+ and next(p for p in builder.parameters if p.grouper and p.client_name == parameter.grouped_by).optional
825
+ )
826
+ retval.append(
827
+ f" {parameter.client_name}={parameter.name_in_high_level_operation},"
828
+ f"{' # type: ignore' if type_ignore else ''}"
829
+ )
830
+ if builder.parameters.has_body and builder.parameters.body_parameter.entries:
831
+ # this is for legacy
832
+ client_name = builder.parameters.body_parameter.client_name
833
+ retval.append(f" {client_name}=_{client_name},")
834
+ elif request_builder.has_form_data_body:
835
+ retval.append(" files=_files,")
836
+ retval.append(" data=_data,")
837
+ elif request_builder.overloads:
838
+ seen_body_params = set()
839
+ for overload in request_builder.overloads:
840
+ body_param = overload.parameters.body_parameter
841
+ if body_param.client_name in seen_body_params:
842
+ continue
843
+ seen_body_params.add(body_param.client_name)
844
+
845
+ retval.append(f" {body_param.client_name}={body_param.name_in_high_level_operation},")
846
+ elif request_builder.parameters.has_body:
847
+ body_param = request_builder.parameters.body_parameter
848
+ retval.append(f" {body_param.client_name}={body_param.name_in_high_level_operation},")
849
+ retval.append(" headers=_headers,")
850
+ retval.append(" params=_params,")
851
+ retval.append(")")
852
+ return retval
853
+
854
+ def _postprocess_http_request(self, builder: OperationType, template_url: Optional[str] = None) -> List[str]:
855
+ retval: List[str] = []
856
+ if builder.parameters.path:
857
+ retval.extend(self.serialize_path(builder))
858
+ url_to_format = "_request.url"
859
+ if self.code_model.options["version_tolerant"] and template_url:
860
+ url_to_format = template_url
861
+ retval.append(
862
+ "_request.url = self._client.format_url({}{})".format(
863
+ url_to_format,
864
+ ", **path_format_arguments" if builder.parameters.path else "",
865
+ )
866
+ )
867
+ return retval
868
+
869
+ def _call_request_builder_helper(
870
+ self,
871
+ builder: OperationType,
872
+ request_builder: RequestBuilderType,
873
+ template_url: Optional[str] = None,
874
+ is_next_request: bool = False,
875
+ is_paging: bool = False,
876
+ ) -> List[str]:
877
+ retval = []
878
+ if builder.parameters.grouped:
879
+ # request builders don't allow grouped parameters, so we group them before making the call
880
+ retval.extend(_serialize_grouped_body(builder))
881
+ if builder.parameters.has_body and builder.parameters.body_parameter.flattened:
882
+ # serialize flattened body before passing to request builder as well
883
+ retval.extend(_serialize_flattened_body(builder.parameters.body_parameter))
884
+ if is_json_model_type(builder.parameters):
885
+ retval.extend(_serialize_json_model_body(builder.parameters.body_parameter, builder.parameters.parameters))
886
+ if builder.has_form_data_body:
887
+ retval.extend(self._create_body_parameter(builder))
888
+ elif builder.overloads:
889
+ # we are only dealing with two overloads. If there are three, we generate an abstract operation
890
+ retval.extend(self._initialize_overloads(builder, is_paging=is_paging))
891
+ elif builder.parameters.has_body:
892
+ # non-overloaded body
893
+ retval.extend(self._create_body_parameter(builder))
894
+ retval.append("")
895
+ retval.extend(self._create_request_builder_call(builder, request_builder, is_next_request))
896
+ retval.extend(self._postprocess_http_request(builder, template_url))
897
+ return retval
898
+
899
+ def call_request_builder(self, builder: OperationType, is_paging: bool = False) -> List[str]:
900
+ return self._call_request_builder_helper(builder, builder.request_builder, is_paging=is_paging)
901
+
902
+ def response_headers_and_deserialization(
903
+ self,
904
+ builder: OperationType,
905
+ response: Response,
906
+ ) -> List[str]:
907
+ return self.response_headers(response) + self.response_deserialization(builder, response)
908
+
909
+ def response_headers(self, response: Response) -> List[str]:
910
+ retval: List[str] = [
911
+ (
912
+ f"response_headers['{response_header.wire_name}']=self._deserialize("
913
+ f"'{response_header.serialization_type}', response.headers.get('{response_header.wire_name}'))"
914
+ )
915
+ for response_header in response.headers
916
+ ]
917
+ if response.headers:
918
+ retval.append("")
919
+ return retval
920
+
921
+ def response_deserialization(
922
+ self,
923
+ builder: OperationType,
924
+ response: Response,
925
+ ) -> List[str]:
926
+ retval: List[str] = []
927
+ deserialize_code: List[str] = []
928
+ stream_logic = True
929
+ if builder.has_stream_response:
930
+ if isinstance(response.type, ByteArraySchema):
931
+ deserialized = f"{'await ' if self.async_mode else ''}response.read()"
932
+ else:
933
+ stream_logic = False
934
+ if self.code_model.options["version_tolerant"]:
935
+ deserialized = "response.iter_bytes()"
936
+ else:
937
+ deserialized = (
938
+ f"response.stream_download(self._client.{self.pipeline_name}, decompress=_decompress)"
939
+ )
940
+ deserialize_code.append(f"deserialized = {deserialized}")
941
+ elif response.type:
942
+ pylint_disable = ""
943
+ if isinstance(response.type, ModelType) and response.type.internal:
944
+ pylint_disable = " # pylint: disable=protected-access"
945
+ if self.code_model.options["models_mode"] == "msrest":
946
+ deserialize_code.append("deserialized = self._deserialize(")
947
+ deserialize_code.append(f" '{response.serialization_type}',{pylint_disable}")
948
+ deserialize_code.append(" pipeline_response.http_response")
949
+ deserialize_code.append(")")
950
+ elif self.code_model.options["models_mode"] == "dpg":
951
+ if builder.has_stream_response:
952
+ deserialize_code.append("deserialized = response.content")
953
+ else:
954
+ format_filed = (
955
+ f', format="{response.type.encode}"'
956
+ if isinstance(response.type, ByteArraySchema)
957
+ and response.default_content_type == "application/json"
958
+ else ""
959
+ )
960
+ response_attr = "json" if json_serializable(str(response.default_content_type)) else "text"
961
+ deserialize_func = "_deserialize"
962
+ if xml_serializable(str(response.default_content_type)):
963
+ deserialize_func = "_deserialize_xml"
964
+ deserialize_code.append(f"deserialized = {deserialize_func}(")
965
+ deserialize_code.append(
966
+ f" {response.type.type_annotation(is_operation_file=True)},{pylint_disable}"
967
+ )
968
+ deserialize_code.append(f" response.{response_attr}(){response.result_property}{format_filed}")
969
+ deserialize_code.append(")")
970
+
971
+ else:
972
+ deserialized_value = "ET.fromstring(response.text())" if response.type.is_xml else "response.json()"
973
+ deserialize_code.append("if response.content:")
974
+ deserialize_code.append(f" deserialized = {deserialized_value}")
975
+ deserialize_code.append("else:")
976
+ deserialize_code.append(" deserialized = None")
977
+ if len(deserialize_code) > 0:
978
+ if builder.expose_stream_keyword and stream_logic:
979
+ retval.append("if _stream:")
980
+ retval.append(" deserialized = response.iter_bytes()")
981
+ retval.append("else:")
982
+ retval.extend([f" {dc}" for dc in deserialize_code])
983
+ else:
984
+ retval.extend(deserialize_code)
985
+ return retval
986
+
987
+ def handle_error_response(self, builder: OperationType) -> List[str]:
988
+ async_await = "await " if self.async_mode else ""
989
+ retval = [f"if response.status_code not in {str(builder.success_status_codes)}:"]
990
+ response_read = [
991
+ " try:",
992
+ f" {async_await}response.read() # Load the body in memory and close the socket",
993
+ " except (StreamConsumedError, StreamClosedError):",
994
+ " pass",
995
+ ]
996
+ if builder.stream_value is True: # _stream is True so no need to judge it
997
+ retval.extend(response_read)
998
+ elif isinstance(builder.stream_value, str): # _stream is not sure, so we need to judge it
999
+ retval.append(" if _stream:")
1000
+ retval.extend([f" {l}" for l in response_read])
1001
+ type_ignore = " # type: ignore" if _need_type_ignore(builder) else ""
1002
+ retval.append(
1003
+ f" map_error(status_code=response.status_code, response=response, error_map=error_map){type_ignore}"
1004
+ )
1005
+ error_model = ""
1006
+ if builder.default_error_deserialization and self.code_model.options["models_mode"]:
1007
+ if self.code_model.options["models_mode"] == "dpg":
1008
+ retval.append(f" error = _deserialize({builder.default_error_deserialization}, response.json())")
1009
+ else:
1010
+ retval.append(
1011
+ f" error = self._deserialize.failsafe_deserialize({builder.default_error_deserialization}, "
1012
+ "pipeline_response)"
1013
+ )
1014
+ error_model = ", model=error"
1015
+ retval.append(
1016
+ " raise HttpResponseError(response=response{}{})".format(
1017
+ error_model,
1018
+ (", error_format=ARMErrorFormat" if self.code_model.options["azure_arm"] else ""),
1019
+ )
1020
+ )
1021
+ return retval
1022
+
1023
+ def handle_response(self, builder: OperationType) -> List[str]:
1024
+ retval: List[str] = ["response = pipeline_response.http_response"]
1025
+ retval.append("")
1026
+ retval.extend(self.handle_error_response(builder))
1027
+ retval.append("")
1028
+ if builder.has_optional_return_type:
1029
+ retval.append("deserialized = None")
1030
+ if builder.any_response_has_headers:
1031
+ retval.append("response_headers = {}")
1032
+ if builder.has_response_body or builder.any_response_has_headers: # pylint: disable=too-many-nested-blocks
1033
+ if len(builder.responses) > 1:
1034
+ status_codes, res_headers, res_deserialization = [], [], []
1035
+ for status_code in builder.success_status_codes:
1036
+ response = builder.get_response_from_status(status_code)
1037
+ if response.headers or response.type:
1038
+ status_codes.append(status_code)
1039
+ res_headers.append(self.response_headers(response))
1040
+ res_deserialization.append(self.response_deserialization(builder, response))
1041
+
1042
+ is_headers_same = _all_same(res_headers)
1043
+ is_deserialization_same = _all_same(res_deserialization)
1044
+ if is_deserialization_same:
1045
+ if is_headers_same:
1046
+ retval.extend(res_headers[0])
1047
+ retval.extend(res_deserialization[0])
1048
+ retval.append("")
1049
+ else:
1050
+ for status_code, headers in zip(status_codes, res_headers):
1051
+ if headers:
1052
+ retval.append(f"if response.status_code == {status_code}:")
1053
+ retval.extend([f" {line}" for line in headers])
1054
+ retval.append("")
1055
+ retval.extend(res_deserialization[0])
1056
+ retval.append("")
1057
+ else:
1058
+ for status_code, headers, deserialization in zip(status_codes, res_headers, res_deserialization):
1059
+ retval.append(f"if response.status_code == {status_code}:")
1060
+ retval.extend([f" {line}" for line in headers])
1061
+ retval.extend([f" {line}" for line in deserialization])
1062
+ retval.append("")
1063
+ else:
1064
+ retval.extend(self.response_headers_and_deserialization(builder, builder.responses[0]))
1065
+ retval.append("")
1066
+ if builder.has_optional_return_type or self.code_model.options["models_mode"]:
1067
+ deserialized = "deserialized"
1068
+ else:
1069
+ deserialized = f"cast({builder.response_type_annotation(async_mode=self.async_mode)}, deserialized)"
1070
+ retval.append("if cls:")
1071
+ retval.append(
1072
+ " return cls(pipeline_response, {}, {}){}".format(
1073
+ deserialized if builder.has_response_body else "None",
1074
+ "response_headers" if builder.any_response_has_headers else "{}",
1075
+ " # type: ignore",
1076
+ )
1077
+ )
1078
+ if builder.has_response_body and any(
1079
+ response.is_stream_response or response.type for response in builder.responses
1080
+ ):
1081
+ retval.append("")
1082
+ retval.append(f"return {deserialized} # type: ignore")
1083
+ if builder.request_builder.method == "HEAD" and self.code_model.options["head_as_boolean"]:
1084
+ retval.append("return 200 <= response.status_code <= 299")
1085
+ return retval
1086
+
1087
+ def error_map(self, builder: OperationType) -> List[str]:
1088
+ retval = ["error_map: MutableMapping = {"]
1089
+ if builder.non_default_errors:
1090
+ if not 401 in builder.non_default_error_status_codes:
1091
+ retval.append(" 401: ClientAuthenticationError,")
1092
+ if not 404 in builder.non_default_error_status_codes:
1093
+ retval.append(" 404: ResourceNotFoundError,")
1094
+ if not 409 in builder.non_default_error_status_codes:
1095
+ retval.append(" 409: ResourceExistsError,")
1096
+ if not 304 in builder.non_default_error_status_codes:
1097
+ retval.append(" 304: ResourceNotModifiedError,")
1098
+ for e in builder.non_default_errors:
1099
+ error_model_str = ""
1100
+ if isinstance(e.type, ModelType):
1101
+ if self.code_model.options["models_mode"] == "msrest":
1102
+ error_model_str = (
1103
+ f", model=self._deserialize(" f"_models.{e.type.serialization_type}, response)"
1104
+ )
1105
+ elif self.code_model.options["models_mode"] == "dpg":
1106
+ error_model_str = f", model=_deserialize(_models.{e.type.name}, response.json())"
1107
+ error_format_str = ", error_format=ARMErrorFormat" if self.code_model.options["azure_arm"] else ""
1108
+ for status_code in e.status_codes:
1109
+ if status_code == 401:
1110
+ retval.append(
1111
+ " 401: cast(Type[HttpResponseError], "
1112
+ "lambda response: ClientAuthenticationError(response=response"
1113
+ f"{error_model_str}{error_format_str})),"
1114
+ )
1115
+ elif status_code == 404:
1116
+ retval.append(
1117
+ " 404: cast(Type[HttpResponseError], "
1118
+ "lambda response: ResourceNotFoundError(response=response"
1119
+ f"{error_model_str}{error_format_str})),"
1120
+ )
1121
+ elif status_code == 409:
1122
+ retval.append(
1123
+ " 409: cast(Type[HttpResponseError], "
1124
+ "lambda response: ResourceExistsError(response=response"
1125
+ f"{error_model_str}{error_format_str})),"
1126
+ )
1127
+ elif status_code == 304:
1128
+ retval.append(
1129
+ " 304: cast(Type[HttpResponseError], "
1130
+ "lambda response: ResourceNotModifiedError(response=response"
1131
+ f"{error_model_str}{error_format_str})),"
1132
+ )
1133
+ elif not error_model_str and not error_format_str:
1134
+ retval.append(f" {status_code}: HttpResponseError,")
1135
+ else:
1136
+ retval.append(
1137
+ f" {status_code}: cast(Type[HttpResponseError], "
1138
+ "lambda response: HttpResponseError(response=response"
1139
+ f"{error_model_str}{error_format_str})),"
1140
+ )
1141
+ else:
1142
+ retval.append(
1143
+ " 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, "
1144
+ "304: ResourceNotModifiedError"
1145
+ )
1146
+ retval.append("}")
1147
+ if builder.has_etag:
1148
+ retval.extend(
1149
+ [
1150
+ "if match_condition == MatchConditions.IfNotModified:",
1151
+ " error_map[412] = ResourceModifiedError",
1152
+ "elif match_condition == MatchConditions.IfPresent:",
1153
+ " error_map[412] = ResourceNotFoundError",
1154
+ "elif match_condition == MatchConditions.IfMissing:",
1155
+ " error_map[412] = ResourceExistsError",
1156
+ ]
1157
+ )
1158
+ retval.append("error_map.update(kwargs.pop('error_map', {}) or {})")
1159
+ return retval
1160
+
1161
+ @property
1162
+ def _call_method(self) -> str:
1163
+ return "await " if self.async_mode else ""
1164
+
1165
+
1166
+ class OperationSerializer(_OperationSerializer[Operation]): ...
1167
+
1168
+
1169
+ ############################## PAGING OPERATIONS ##############################
1170
+
1171
+ PagingOperationType = TypeVar("PagingOperationType", bound=Union[PagingOperation, LROPagingOperation])
1172
+
1173
+
1174
+ class _PagingOperationSerializer(_OperationSerializer[PagingOperationType]):
1175
+ def __init__(self, code_model: CodeModel, async_mode: bool) -> None:
1176
+ # for pylint reasons need to redefine init
1177
+ # probably because inheritance is going too deep
1178
+ super().__init__(code_model, async_mode)
1179
+ self.code_model = code_model
1180
+ self.async_mode = async_mode
1181
+ self.parameter_serializer = ParameterSerializer()
1182
+
1183
+ def serialize_path(self, builder: PagingOperationType) -> List[str]:
1184
+ return self.parameter_serializer.serialize_path(builder.parameters.path, self.serializer_name)
1185
+
1186
+ def decorators(self, builder: PagingOperationType) -> List[str]:
1187
+ """Decorators for the method"""
1188
+ retval: List[str] = []
1189
+ if builder.is_overload:
1190
+ return ["@overload"]
1191
+ if self.code_model.options["tracing"] and builder.want_tracing:
1192
+ retval.append("@distributed_trace")
1193
+ if self._api_version_validation(builder):
1194
+ retval.append(self._api_version_validation(builder))
1195
+ return retval
1196
+
1197
+ def call_next_link_request_builder(self, builder: PagingOperationType) -> List[str]:
1198
+ if builder.next_request_builder:
1199
+ request_builder = builder.next_request_builder
1200
+ template_url = None
1201
+ else:
1202
+ request_builder = builder.request_builder
1203
+ template_url = "next_link"
1204
+
1205
+ request_builder = builder.next_request_builder or builder.request_builder
1206
+ if builder.next_request_builder:
1207
+ return self._call_request_builder_helper(
1208
+ builder,
1209
+ request_builder,
1210
+ template_url=template_url,
1211
+ is_next_request=True,
1212
+ )
1213
+ retval: List[str] = []
1214
+ query_str = ""
1215
+ next_link_str = "next_link"
1216
+ try:
1217
+ api_version_param = next(
1218
+ p for p in builder.client.parameters if p.is_api_version and p.location == ParameterLocation.QUERY
1219
+ )
1220
+ retval.append("# make call to next link with the client's api-version")
1221
+ retval.append("_parsed_next_link = urllib.parse.urlparse(next_link)")
1222
+ retval.extend(
1223
+ [
1224
+ "_next_request_params = case_insensitive_dict({",
1225
+ " key: [urllib.parse.quote(v) for v in value]"
1226
+ " for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items()"
1227
+ "})",
1228
+ ]
1229
+ )
1230
+ api_version = (
1231
+ "self._api_version"
1232
+ if self.code_model.options["multiapi"] and builder.group_name
1233
+ else api_version_param.full_client_name
1234
+ )
1235
+ retval.append(f'_next_request_params["api-version"] = {api_version}')
1236
+ query_str = ", params=_next_request_params"
1237
+ next_link_str = "urllib.parse.urljoin(next_link, _parsed_next_link.path)"
1238
+ except StopIteration:
1239
+ pass
1240
+
1241
+ retval.append(f'_request = HttpRequest("GET", {next_link_str}{query_str})')
1242
+ retval.extend(self._postprocess_http_request(builder, "_request.url"))
1243
+
1244
+ return retval
1245
+
1246
+ def _prepare_request_callback(self, builder: PagingOperationType) -> List[str]:
1247
+ retval = self._initialize_overloads(builder)
1248
+ retval.append("def prepare_request(next_link=None):")
1249
+ retval.append(" if not next_link:")
1250
+ retval.extend([f" {line}" for line in self.call_request_builder(builder, is_paging=True)])
1251
+ retval.append("")
1252
+ retval.append(" else:")
1253
+ retval.extend([f" {line}" for line in self.call_next_link_request_builder(builder)])
1254
+ if not builder.next_request_builder and self.code_model.is_legacy:
1255
+ retval.append(' _request.method = "GET"')
1256
+ else:
1257
+ retval.append("")
1258
+ retval.append(" return _request")
1259
+ return retval
1260
+
1261
+ @property
1262
+ def _function_def(self) -> str:
1263
+ return "def"
1264
+
1265
+ def _extract_data_callback(self, builder: PagingOperationType) -> List[str]:
1266
+ retval = [f"{'async ' if self.async_mode else ''}def extract_data(pipeline_response):"]
1267
+ response = builder.responses[0]
1268
+ deserialized = "pipeline_response.http_response.json()"
1269
+ if self.code_model.options["models_mode"] == "msrest":
1270
+ suffix = ".http_response" if hasattr(builder, "initial_operation") else ""
1271
+ deserialize_type = response.serialization_type
1272
+ pylint_disable = " # pylint: disable=protected-access"
1273
+ if isinstance(response.type, ModelType) and not response.type.internal:
1274
+ deserialize_type = f'"{response.serialization_type}"'
1275
+ pylint_disable = ""
1276
+ deserialized = (
1277
+ f"self._deserialize(\n {deserialize_type},{pylint_disable}\n pipeline_response{suffix}\n)"
1278
+ )
1279
+ retval.append(f" deserialized = {deserialized}")
1280
+ elif self.code_model.options["models_mode"] == "dpg":
1281
+ # we don't want to generate paging models for DPG
1282
+ retval.append(f" deserialized = {deserialized}")
1283
+ else:
1284
+ retval.append(f" deserialized = {deserialized}")
1285
+ item_name = builder.item_name
1286
+ access = f".{item_name}" if self.code_model.options["models_mode"] == "msrest" else f'["{item_name}"]'
1287
+ list_of_elem_deserialized = ""
1288
+ if self.code_model.options["models_mode"] == "dpg":
1289
+ item_type = builder.item_type.type_annotation(is_operation_file=True)
1290
+ list_of_elem_deserialized = f"_deserialize({item_type}, deserialized{access})"
1291
+ else:
1292
+ list_of_elem_deserialized = f"deserialized{access}"
1293
+ retval.append(f" list_of_elem = {list_of_elem_deserialized}")
1294
+ retval.append(" if cls:")
1295
+ retval.append(" list_of_elem = cls(list_of_elem) # type: ignore")
1296
+
1297
+ continuation_token_name = builder.continuation_token_name
1298
+ if not continuation_token_name:
1299
+ cont_token_property = "None"
1300
+ elif self.code_model.options["models_mode"] == "msrest":
1301
+ cont_token_property = f"deserialized.{continuation_token_name} or None"
1302
+ else:
1303
+ cont_token_property = f'deserialized.get("{continuation_token_name}") or None'
1304
+ list_type = "AsyncList" if self.async_mode else "iter"
1305
+ retval.append(f" return {cont_token_property}, {list_type}(list_of_elem)")
1306
+ return retval
1307
+
1308
+ def _get_next_callback(self, builder: PagingOperationType) -> List[str]:
1309
+ retval = [f"{'async ' if self.async_mode else ''}def get_next(next_link=None):"]
1310
+ retval.append(" _request = prepare_request(next_link)")
1311
+ retval.append("")
1312
+ retval.extend([f" {l}" for l in self.make_pipeline_call(builder)])
1313
+ retval.append(" response = pipeline_response.http_response")
1314
+ retval.append("")
1315
+ retval.extend([f" {line}" for line in self.handle_error_response(builder)])
1316
+ retval.append("")
1317
+ retval.append(" return pipeline_response")
1318
+ return retval
1319
+
1320
+ def set_up_params_for_pager(self, builder: PagingOperationType) -> List[str]:
1321
+ retval = []
1322
+ retval.extend(self.error_map(builder))
1323
+ retval.extend(self._prepare_request_callback(builder))
1324
+ retval.append("")
1325
+ retval.extend(self._extract_data_callback(builder))
1326
+ retval.append("")
1327
+ retval.extend(self._get_next_callback(builder))
1328
+ return retval
1329
+
1330
+
1331
+ class PagingOperationSerializer(_PagingOperationSerializer[PagingOperation]): ...
1332
+
1333
+
1334
+ ############################## LRO OPERATIONS ##############################
1335
+
1336
+ LROOperationType = TypeVar("LROOperationType", bound=Union[LROOperation, LROPagingOperation])
1337
+
1338
+
1339
+ class _LROOperationSerializer(_OperationSerializer[LROOperationType]):
1340
+ def __init__(self, code_model: CodeModel, async_mode: bool) -> None:
1341
+ # for pylint reasons need to redefine init
1342
+ # probably because inheritance is going too deep
1343
+ super().__init__(code_model, async_mode)
1344
+ self.code_model = code_model
1345
+ self.async_mode = async_mode
1346
+ self.parameter_serializer = ParameterSerializer()
1347
+
1348
+ def serialize_path(self, builder: LROOperationType) -> List[str]:
1349
+ return self.parameter_serializer.serialize_path(builder.parameters.path, self.serializer_name)
1350
+
1351
+ def initial_call(self, builder: LROOperationType) -> List[str]:
1352
+ retval = [
1353
+ f"polling: Union[bool, {builder.get_base_polling_method(self.async_mode)}] = kwargs.pop('polling', True)",
1354
+ ]
1355
+ retval.append("lro_delay = kwargs.pop(")
1356
+ retval.append(" 'polling_interval',")
1357
+ retval.append(" self._config.polling_interval")
1358
+ retval.append(")")
1359
+ retval.append("cont_token: Optional[str] = kwargs.pop('continuation_token', None)")
1360
+ retval.append("if cont_token is None:")
1361
+ retval.append(
1362
+ f" raw_result = {self._call_method}self.{builder.initial_operation.name}("
1363
+ f"{'' if any(rsp.type for rsp in builder.initial_operation.responses) else ' # type: ignore'}"
1364
+ )
1365
+ retval.extend(
1366
+ [f" {parameter.client_name}={parameter.client_name}," for parameter in builder.parameters.method]
1367
+ )
1368
+ retval.append(" cls=lambda x,y,z: x,")
1369
+ retval.append(" headers=_headers,")
1370
+ retval.append(" params=_params,")
1371
+ retval.append(" **kwargs")
1372
+ retval.append(" )")
1373
+ retval.append(f" {'await ' if self.async_mode else ''}raw_result.http_response.read() # type: ignore")
1374
+
1375
+ retval.append("kwargs.pop('error_map', None)")
1376
+ return retval
1377
+
1378
+ def return_lro_poller(self, builder: LROOperationType) -> List[str]:
1379
+ retval = []
1380
+ lro_options_str = (
1381
+ "lro_options={'final-state-via': '" + builder.lro_options["final-state-via"] + "'},"
1382
+ if builder.lro_options
1383
+ else ""
1384
+ )
1385
+ path_format_arguments_str = ""
1386
+ if builder.parameters.path:
1387
+ path_format_arguments_str = "path_format_arguments=path_format_arguments,"
1388
+ retval.extend(self.serialize_path(builder))
1389
+ retval.append("")
1390
+ retval.extend(
1391
+ [
1392
+ "if polling is True:",
1393
+ f" polling_method: {builder.get_base_polling_method(self.async_mode)} "
1394
+ + f"= cast({builder.get_base_polling_method(self.async_mode)}, "
1395
+ f"{builder.get_polling_method(self.async_mode)}(",
1396
+ " lro_delay,",
1397
+ f" {lro_options_str}",
1398
+ f" {path_format_arguments_str}",
1399
+ " **kwargs",
1400
+ "))",
1401
+ ]
1402
+ )
1403
+ retval.append(
1404
+ f"elif polling is False: polling_method = cast({builder.get_base_polling_method(self.async_mode)}, "
1405
+ f"{builder.get_no_polling_method(self.async_mode)}())"
1406
+ )
1407
+ retval.append("else: polling_method = polling")
1408
+ retval.append("if cont_token:")
1409
+ retval.append(f" return {builder.get_poller_with_response_type(self.async_mode)}.from_continuation_token(")
1410
+ retval.append(" polling_method=polling_method,")
1411
+ retval.append(" continuation_token=cont_token,")
1412
+ retval.append(" client=self._client,")
1413
+ retval.append(" deserialization_callback=get_long_running_output")
1414
+ retval.append(" )")
1415
+ retval.append(f"return {builder.get_poller_with_response_type(self.async_mode)}(")
1416
+ retval.append(" self._client, raw_result, get_long_running_output, polling_method # type: ignore")
1417
+ retval.append(" )")
1418
+ return retval
1419
+
1420
+ def get_long_running_output(self, builder: LROOperationType) -> List[str]:
1421
+ pylint_disable = ""
1422
+ if not builder.lro_response:
1423
+ pylint_disable = " # pylint: disable=inconsistent-return-statements"
1424
+ retval = [f"def get_long_running_output(pipeline_response):{pylint_disable}"]
1425
+ if builder.lro_response:
1426
+ if builder.lro_response.headers:
1427
+ retval.append(" response_headers = {}")
1428
+ if (
1429
+ not self.code_model.options["models_mode"]
1430
+ or self.code_model.options["models_mode"] == "dpg"
1431
+ or builder.lro_response.headers
1432
+ ):
1433
+ retval.append(" response = pipeline_response.http_response")
1434
+ retval.extend(
1435
+ [f" {line}" for line in self.response_headers_and_deserialization(builder, builder.lro_response)]
1436
+ )
1437
+ retval.append(" if cls:")
1438
+ retval.append(
1439
+ " return cls(pipeline_response, {}, {}){}".format(
1440
+ ("deserialized" if builder.lro_response and builder.lro_response.type else "None"),
1441
+ ("response_headers" if builder.lro_response and builder.lro_response.headers else "{}"),
1442
+ " # type: ignore",
1443
+ )
1444
+ )
1445
+ if builder.lro_response and builder.lro_response.type:
1446
+ retval.append(" return deserialized")
1447
+ return retval
1448
+
1449
+
1450
+ class LROOperationSerializer(_LROOperationSerializer[LROOperation]): ...
1451
+
1452
+
1453
+ ############################## LRO PAGING OPERATIONS ##############################
1454
+
1455
+
1456
+ class LROPagingOperationSerializer(
1457
+ _LROOperationSerializer[LROPagingOperation],
1458
+ _PagingOperationSerializer[LROPagingOperation],
1459
+ ):
1460
+ @property
1461
+ def _call_method(self) -> str:
1462
+ return "await " if self.async_mode else ""
1463
+
1464
+ @property
1465
+ def _function_def(self) -> str:
1466
+ return "async def" if self.async_mode else "def"
1467
+
1468
+ def get_long_running_output(self, builder: LROPagingOperation) -> List[str]:
1469
+ retval = ["def get_long_running_output(pipeline_response):"]
1470
+ retval.append(f" {self._function_def} internal_get_next(next_link=None):")
1471
+ retval.append(" if next_link is None:")
1472
+ retval.append(" return pipeline_response")
1473
+ retval.append(f" return {self._call_method}get_next(next_link)")
1474
+ retval.append("")
1475
+ retval.append(f" return {builder.get_pager(self.async_mode)}(")
1476
+ retval.append(" internal_get_next, extract_data")
1477
+ retval.append(" )")
1478
+ return retval
1479
+
1480
+ def decorators(self, builder: LROPagingOperation) -> List[str]:
1481
+ """Decorators for the method"""
1482
+ return _LROOperationSerializer.decorators(self, builder) # type: ignore
1483
+
1484
+
1485
+ def get_operation_serializer(
1486
+ builder: Operation,
1487
+ code_model,
1488
+ async_mode: bool,
1489
+ ) -> Union[
1490
+ OperationSerializer,
1491
+ PagingOperationSerializer,
1492
+ LROOperationSerializer,
1493
+ LROPagingOperationSerializer,
1494
+ ]:
1495
+ ret_cls: Union[
1496
+ Type[OperationSerializer],
1497
+ Type[PagingOperationSerializer],
1498
+ Type[LROOperationSerializer],
1499
+ Type[LROPagingOperationSerializer],
1500
+ ] = OperationSerializer
1501
+ if builder.operation_type == "lropaging":
1502
+ ret_cls = LROPagingOperationSerializer
1503
+ elif builder.operation_type == "lro":
1504
+ ret_cls = LROOperationSerializer
1505
+ elif builder.operation_type == "paging":
1506
+ ret_cls = PagingOperationSerializer
1507
+ return ret_cls(code_model, async_mode)