@typespec/http-client-python 0.4.4 → 0.5.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 (137) hide show
  1. package/dist/emitter/emitter.d.ts.map +1 -1
  2. package/dist/emitter/emitter.js +85 -24
  3. package/dist/emitter/emitter.js.map +1 -1
  4. package/dist/emitter/lib.d.ts +1 -0
  5. package/dist/emitter/lib.d.ts.map +1 -1
  6. package/dist/emitter/lib.js +1 -0
  7. package/dist/emitter/lib.js.map +1 -1
  8. package/dist/emitter/run-python3.d.ts +2 -0
  9. package/dist/emitter/run-python3.d.ts.map +1 -0
  10. package/dist/emitter/run-python3.js +19 -0
  11. package/dist/emitter/run-python3.js.map +1 -0
  12. package/dist/emitter/system-requirements.d.ts +17 -0
  13. package/dist/emitter/system-requirements.d.ts.map +1 -0
  14. package/dist/emitter/system-requirements.js +167 -0
  15. package/dist/emitter/system-requirements.js.map +1 -0
  16. package/emitter/src/emitter.ts +88 -23
  17. package/emitter/src/lib.ts +2 -0
  18. package/emitter/src/run-python3.ts +20 -0
  19. package/emitter/src/system-requirements.ts +261 -0
  20. package/emitter/temp/tsconfig.tsbuildinfo +1 -1
  21. package/eng/scripts/ci/regenerate.ts +16 -4
  22. package/eng/scripts/setup/__pycache__/venvtools.cpython-38.pyc +0 -0
  23. package/eng/scripts/setup/build.ts +16 -0
  24. package/eng/scripts/setup/build_pygen_wheel.py +40 -0
  25. package/eng/scripts/setup/install.py +9 -3
  26. package/eng/scripts/setup/install.ts +32 -0
  27. package/eng/scripts/setup/prepare.py +3 -1
  28. package/eng/scripts/setup/prepare.ts +11 -0
  29. package/eng/scripts/setup/run-python3.ts +1 -6
  30. package/generator/build/lib/pygen/__init__.py +107 -0
  31. package/generator/build/lib/pygen/_version.py +7 -0
  32. package/generator/build/lib/pygen/black.py +71 -0
  33. package/generator/build/lib/pygen/codegen/__init__.py +357 -0
  34. package/generator/build/lib/pygen/codegen/_utils.py +17 -0
  35. package/generator/build/lib/pygen/codegen/models/__init__.py +204 -0
  36. package/generator/build/lib/pygen/codegen/models/base.py +186 -0
  37. package/generator/build/lib/pygen/codegen/models/base_builder.py +118 -0
  38. package/generator/build/lib/pygen/codegen/models/client.py +435 -0
  39. package/generator/build/lib/pygen/codegen/models/code_model.py +237 -0
  40. package/generator/build/lib/pygen/codegen/models/combined_type.py +149 -0
  41. package/generator/build/lib/pygen/codegen/models/constant_type.py +129 -0
  42. package/generator/build/lib/pygen/codegen/models/credential_types.py +214 -0
  43. package/generator/build/lib/pygen/codegen/models/dictionary_type.py +127 -0
  44. package/generator/build/lib/pygen/codegen/models/enum_type.py +238 -0
  45. package/generator/build/lib/pygen/codegen/models/imports.py +291 -0
  46. package/generator/build/lib/pygen/codegen/models/list_type.py +143 -0
  47. package/generator/build/lib/pygen/codegen/models/lro_operation.py +142 -0
  48. package/generator/build/lib/pygen/codegen/models/lro_paging_operation.py +32 -0
  49. package/generator/build/lib/pygen/codegen/models/model_type.py +357 -0
  50. package/generator/build/lib/pygen/codegen/models/operation.py +509 -0
  51. package/generator/build/lib/pygen/codegen/models/operation_group.py +184 -0
  52. package/generator/build/lib/pygen/codegen/models/paging_operation.py +155 -0
  53. package/generator/build/lib/pygen/codegen/models/parameter.py +412 -0
  54. package/generator/build/lib/pygen/codegen/models/parameter_list.py +387 -0
  55. package/generator/build/lib/pygen/codegen/models/primitive_types.py +659 -0
  56. package/generator/build/lib/pygen/codegen/models/property.py +170 -0
  57. package/generator/build/lib/pygen/codegen/models/request_builder.py +189 -0
  58. package/generator/build/lib/pygen/codegen/models/request_builder_parameter.py +115 -0
  59. package/generator/build/lib/pygen/codegen/models/response.py +348 -0
  60. package/generator/build/lib/pygen/codegen/models/utils.py +21 -0
  61. package/generator/build/lib/pygen/codegen/serializers/__init__.py +574 -0
  62. package/generator/build/lib/pygen/codegen/serializers/base_serializer.py +21 -0
  63. package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +1533 -0
  64. package/generator/build/lib/pygen/codegen/serializers/client_serializer.py +294 -0
  65. package/generator/build/lib/pygen/codegen/serializers/enum_serializer.py +15 -0
  66. package/generator/build/lib/pygen/codegen/serializers/general_serializer.py +213 -0
  67. package/generator/build/lib/pygen/codegen/serializers/import_serializer.py +126 -0
  68. package/generator/build/lib/pygen/codegen/serializers/metadata_serializer.py +198 -0
  69. package/generator/build/lib/pygen/codegen/serializers/model_init_serializer.py +33 -0
  70. package/generator/build/lib/pygen/codegen/serializers/model_serializer.py +335 -0
  71. package/generator/build/lib/pygen/codegen/serializers/operation_groups_serializer.py +89 -0
  72. package/generator/build/lib/pygen/codegen/serializers/operations_init_serializer.py +44 -0
  73. package/generator/build/lib/pygen/codegen/serializers/parameter_serializer.py +221 -0
  74. package/generator/build/lib/pygen/codegen/serializers/patch_serializer.py +19 -0
  75. package/generator/build/lib/pygen/codegen/serializers/request_builders_serializer.py +52 -0
  76. package/generator/build/lib/pygen/codegen/serializers/sample_serializer.py +168 -0
  77. package/generator/build/lib/pygen/codegen/serializers/test_serializer.py +292 -0
  78. package/generator/build/lib/pygen/codegen/serializers/types_serializer.py +31 -0
  79. package/generator/build/lib/pygen/codegen/serializers/utils.py +68 -0
  80. package/generator/build/lib/pygen/codegen/templates/client.py.jinja2 +37 -0
  81. package/generator/build/lib/pygen/codegen/templates/client_container.py.jinja2 +12 -0
  82. package/generator/build/lib/pygen/codegen/templates/config.py.jinja2 +73 -0
  83. package/generator/build/lib/pygen/codegen/templates/config_container.py.jinja2 +16 -0
  84. package/generator/build/lib/pygen/codegen/templates/conftest.py.jinja2 +28 -0
  85. package/generator/build/lib/pygen/codegen/templates/enum.py.jinja2 +13 -0
  86. package/generator/build/lib/pygen/codegen/templates/enum_container.py.jinja2 +10 -0
  87. package/generator/build/lib/pygen/codegen/templates/init.py.jinja2 +24 -0
  88. package/generator/build/lib/pygen/codegen/templates/keywords.jinja2 +27 -0
  89. package/generator/build/lib/pygen/codegen/templates/lro_operation.py.jinja2 +16 -0
  90. package/generator/build/lib/pygen/codegen/templates/lro_paging_operation.py.jinja2 +18 -0
  91. package/generator/build/lib/pygen/codegen/templates/macros.jinja2 +12 -0
  92. package/generator/build/lib/pygen/codegen/templates/metadata.json.jinja2 +167 -0
  93. package/generator/build/lib/pygen/codegen/templates/model_base.py.jinja2 +1174 -0
  94. package/generator/build/lib/pygen/codegen/templates/model_container.py.jinja2 +15 -0
  95. package/generator/build/lib/pygen/codegen/templates/model_dpg.py.jinja2 +97 -0
  96. package/generator/build/lib/pygen/codegen/templates/model_init.py.jinja2 +33 -0
  97. package/generator/build/lib/pygen/codegen/templates/model_msrest.py.jinja2 +92 -0
  98. package/generator/build/lib/pygen/codegen/templates/operation.py.jinja2 +21 -0
  99. package/generator/build/lib/pygen/codegen/templates/operation_group.py.jinja2 +75 -0
  100. package/generator/build/lib/pygen/codegen/templates/operation_groups_container.py.jinja2 +19 -0
  101. package/generator/build/lib/pygen/codegen/templates/operation_tools.jinja2 +81 -0
  102. package/generator/build/lib/pygen/codegen/templates/operations_folder_init.py.jinja2 +17 -0
  103. package/generator/build/lib/pygen/codegen/templates/packaging_templates/CHANGELOG.md.jinja2 +6 -0
  104. package/generator/build/lib/pygen/codegen/templates/packaging_templates/LICENSE.jinja2 +21 -0
  105. package/generator/build/lib/pygen/codegen/templates/packaging_templates/MANIFEST.in.jinja2 +8 -0
  106. package/generator/build/lib/pygen/codegen/templates/packaging_templates/README.md.jinja2 +107 -0
  107. package/generator/build/lib/pygen/codegen/templates/packaging_templates/dev_requirements.txt.jinja2 +9 -0
  108. package/generator/build/lib/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +108 -0
  109. package/generator/build/lib/pygen/codegen/templates/paging_operation.py.jinja2 +21 -0
  110. package/generator/build/lib/pygen/codegen/templates/patch.py.jinja2 +19 -0
  111. package/generator/build/lib/pygen/codegen/templates/pkgutil_init.py.jinja2 +1 -0
  112. package/generator/build/lib/pygen/codegen/templates/request_builder.py.jinja2 +28 -0
  113. package/generator/build/lib/pygen/codegen/templates/request_builders.py.jinja2 +10 -0
  114. package/generator/build/lib/pygen/codegen/templates/rest_init.py.jinja2 +12 -0
  115. package/generator/build/lib/pygen/codegen/templates/sample.py.jinja2 +44 -0
  116. package/generator/build/lib/pygen/codegen/templates/serialization.py.jinja2 +2117 -0
  117. package/generator/build/lib/pygen/codegen/templates/test.py.jinja2 +50 -0
  118. package/generator/build/lib/pygen/codegen/templates/testpreparer.py.jinja2 +26 -0
  119. package/generator/build/lib/pygen/codegen/templates/types.py.jinja2 +7 -0
  120. package/generator/build/lib/pygen/codegen/templates/validation.py.jinja2 +38 -0
  121. package/generator/build/lib/pygen/codegen/templates/vendor.py.jinja2 +96 -0
  122. package/generator/build/lib/pygen/codegen/templates/version.py.jinja2 +4 -0
  123. package/generator/build/lib/pygen/m2r.py +65 -0
  124. package/generator/build/lib/pygen/preprocess/__init__.py +515 -0
  125. package/generator/build/lib/pygen/preprocess/helpers.py +27 -0
  126. package/generator/build/lib/pygen/preprocess/python_mappings.py +226 -0
  127. package/generator/build/lib/pygen/utils.py +163 -0
  128. package/generator/component-detection-pip-report.json +134 -0
  129. package/generator/dev_requirements.txt +0 -1
  130. package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
  131. package/generator/pygen.egg-info/PKG-INFO +7 -4
  132. package/generator/pygen.egg-info/requires.txt +7 -4
  133. package/generator/requirements.txt +5 -10
  134. package/generator/setup.py +7 -4
  135. package/generator/test/azure/requirements.txt +1 -1
  136. package/generator/test/unbranded/requirements.txt +1 -1
  137. package/package.json +6 -5
@@ -0,0 +1,294 @@
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License. See License.txt in the project root for
4
+ # license information.
5
+ # --------------------------------------------------------------------------
6
+ from typing import List
7
+
8
+ from . import utils
9
+ from ..models import Client, ParameterMethodLocation
10
+ from .parameter_serializer import ParameterSerializer, PopKwargType
11
+ from ...utils import build_policies
12
+
13
+
14
+ class ClientSerializer:
15
+ def __init__(self, client: Client) -> None:
16
+ self.client = client
17
+ self.parameter_serializer = ParameterSerializer()
18
+
19
+ def _init_signature(self, async_mode: bool) -> str:
20
+ pylint_disable = ""
21
+ if not self.client.parameters.credential:
22
+ pylint_disable = " # pylint: disable=missing-client-constructor-parameter-credential"
23
+ return self.parameter_serializer.serialize_method(
24
+ function_def="def",
25
+ method_name="__init__",
26
+ need_self_param=True,
27
+ method_param_signatures=self.client.parameters.method_signature(async_mode),
28
+ pylint_disable=pylint_disable,
29
+ )
30
+
31
+ def init_signature_and_response_type_annotation(self, async_mode: bool) -> str:
32
+ init_signature = self._init_signature(async_mode)
33
+ return utils.method_signature_and_response_type_annotation_template(
34
+ method_signature=init_signature,
35
+ response_type_annotation="None",
36
+ )
37
+
38
+ def pop_kwargs_from_signature(self) -> List[str]:
39
+ return self.parameter_serializer.pop_kwargs_from_signature(
40
+ self.client.parameters.kwargs_to_pop,
41
+ check_kwarg_dict=False,
42
+ pop_headers_kwarg=PopKwargType.NO,
43
+ pop_params_kwarg=PopKwargType.NO,
44
+ )
45
+
46
+ def class_definition(self) -> str:
47
+ class_name = self.client.name
48
+ base_class = ""
49
+ if self.client.has_mixin:
50
+ base_class = f"{class_name}OperationsMixin"
51
+ pylint_disable = self.client.pylint_disable()
52
+ if base_class:
53
+ return f"class {class_name}({base_class}):{pylint_disable}"
54
+ return f"class {class_name}:{pylint_disable}"
55
+
56
+ def property_descriptions(self, async_mode: bool) -> List[str]:
57
+ retval: List[str] = []
58
+ operations_folder = ".aio.operations." if async_mode else ".operations."
59
+ for og in [og for og in self.client.operation_groups if not og.is_mixin]:
60
+ retval.append(f":ivar {og.property_name}: {og.class_name} operations")
61
+ property_type = f"{self.client.code_model.namespace}{operations_folder}{og.class_name}"
62
+ retval.append(f":vartype {og.property_name}: {property_type}")
63
+ for param in self.client.parameters.method:
64
+ retval.append(f":{param.description_keyword} {param.client_name}: {param.description}")
65
+ retval.append(
66
+ f":{param.docstring_type_keyword} {param.client_name}: {param.docstring_type(async_mode=async_mode)}"
67
+ )
68
+ if self.client.has_public_lro_operations:
69
+ retval.append(
70
+ ":keyword int polling_interval: Default waiting time between two polls for LRO operations "
71
+ "if no Retry-After header is present."
72
+ )
73
+ retval = [s.replace("\\", "\\\\") for s in retval]
74
+ retval.append('"""')
75
+ return retval
76
+
77
+ def initialize_config(self) -> str:
78
+ config_name = f"{self.client.name}Configuration"
79
+ config_call = ", ".join(
80
+ [
81
+ f"{p.client_name}={p.client_name}"
82
+ for p in self.client.config.parameters.method
83
+ if p.method_location != ParameterMethodLocation.KWARG
84
+ ]
85
+ + ["**kwargs"]
86
+ )
87
+ return f"self._config = {config_name}({config_call})"
88
+
89
+ @property
90
+ def host_variable_name(self) -> str:
91
+ try:
92
+ return next(p for p in self.client.parameters if p.is_host).client_name
93
+ except StopIteration:
94
+ return "_endpoint"
95
+
96
+ @property
97
+ def should_init_super(self) -> bool:
98
+ return any(og for og in self.client.operation_groups if og.is_mixin and og.has_abstract_operations)
99
+
100
+ def initialize_pipeline_client(self, async_mode: bool) -> List[str]:
101
+ result = []
102
+ pipeline_client_name = self.client.pipeline_class(async_mode)
103
+ endpoint_name = "base_url" if self.client.code_model.is_azure_flavor else "endpoint"
104
+ params = {
105
+ endpoint_name: self.host_variable_name,
106
+ "policies": "_policies",
107
+ }
108
+ if not self.client.code_model.is_legacy and self.client.request_id_header_name:
109
+ result.append(f'kwargs["request_id_header_name"] = "{self.client.request_id_header_name}"')
110
+ policies = build_policies(
111
+ self.client.code_model.options["azure_arm"],
112
+ async_mode,
113
+ is_azure_flavor=self.client.code_model.is_azure_flavor,
114
+ tracing=self.client.code_model.options["tracing"],
115
+ )
116
+ result.extend(
117
+ [
118
+ "_policies = kwargs.pop('policies', None)",
119
+ "if _policies is None:",
120
+ f' _policies = [{",".join(policies)}]',
121
+ f"self._client: {pipeline_client_name} = {pipeline_client_name}("
122
+ f"{', '.join(f'{k}={v}' for k, v in params.items())}, **kwargs)",
123
+ ]
124
+ )
125
+ return result
126
+
127
+ def serializers_and_operation_groups_properties(self) -> List[str]:
128
+ retval = []
129
+
130
+ def _get_client_models_value(models_dict_name: str) -> str:
131
+ if self.client.code_model.model_types:
132
+ return f"{{k: v for k, v in {models_dict_name}.__dict__.items() if isinstance(v, type)}}"
133
+ return "{}"
134
+
135
+ is_msrest_model = self.client.code_model.options["models_mode"] == "msrest"
136
+ if is_msrest_model:
137
+ add_private_models = len(self.client.code_model.model_types) != len(
138
+ self.client.code_model.public_model_types
139
+ )
140
+ model_dict_name = f"_models.{self.client.code_model.models_filename}" if add_private_models else "_models"
141
+ retval.append(
142
+ f"client_models{': Dict[str, Any]' if not self.client.code_model.model_types else ''}"
143
+ f" = {_get_client_models_value(model_dict_name)}"
144
+ )
145
+ if add_private_models and self.client.code_model.model_types:
146
+ update_dict = "{k: v for k, v in _models.__dict__.items() if isinstance(v, type)}"
147
+ retval.append(f"client_models.update({update_dict})")
148
+ client_models_str = "client_models" if is_msrest_model else ""
149
+ retval.append(f"self._serialize = Serializer({client_models_str})")
150
+ retval.append(f"self._deserialize = Deserializer({client_models_str})")
151
+ if not self.client.code_model.options["client_side_validation"]:
152
+ retval.append("self._serialize.client_side_validation = False")
153
+ operation_groups = [og for og in self.client.operation_groups if not og.is_mixin]
154
+ for og in operation_groups:
155
+ if og.code_model.options["multiapi"]:
156
+ api_version = f", '{og.api_versions[0]}'" if og.api_versions else ", None"
157
+ else:
158
+ api_version = ""
159
+ retval.extend(
160
+ [
161
+ f"self.{og.property_name} = {og.class_name}(",
162
+ f" self._client, self._config, self._serialize, self._deserialize{api_version}",
163
+ ")",
164
+ ]
165
+ )
166
+ return retval
167
+
168
+ def _send_request_signature(self) -> str:
169
+ send_request_signature = [
170
+ "request: HttpRequest, *, stream: bool = False,"
171
+ ] + self.client.parameters.method_signature_kwargs
172
+ return self.parameter_serializer.serialize_method(
173
+ function_def="def",
174
+ method_name=self.client.send_request_name,
175
+ need_self_param=True,
176
+ method_param_signatures=send_request_signature,
177
+ )
178
+
179
+ def send_request_signature_and_response_type_annotation(self, async_mode: bool) -> str:
180
+ send_request_signature = self._send_request_signature()
181
+ return utils.method_signature_and_response_type_annotation_template(
182
+ method_signature=send_request_signature,
183
+ response_type_annotation=("Awaitable[AsyncHttpResponse]" if async_mode else "HttpResponse"),
184
+ )
185
+
186
+ def _example_make_call(self, async_mode: bool) -> List[str]:
187
+ http_response = "AsyncHttpResponse" if async_mode else "HttpResponse"
188
+ retval = [f">>> response = {'await ' if async_mode else ''}client.{self.client.send_request_name}(request)"]
189
+ retval.append(f"<{http_response}: 200 OK>")
190
+ return retval
191
+
192
+ def _request_builder_example(self, async_mode: bool) -> List[str]:
193
+ retval = [
194
+ "We have helper methods to create requests specific to this service in "
195
+ + f"`{self.client.code_model.namespace}.{self.client.code_model.rest_layer_name}`."
196
+ ]
197
+ retval.append("Use these helper methods to create the request you pass to this method.")
198
+ retval.append("")
199
+
200
+ request_builder = self.client.request_builders[0]
201
+ request_builder_signature = ", ".join(request_builder.parameters.call)
202
+ if request_builder.group_name:
203
+ rest_imported = request_builder.group_name
204
+ request_builder_name = f"{request_builder.group_name}.{request_builder.name}"
205
+ else:
206
+ rest_imported = request_builder.name
207
+ request_builder_name = request_builder.name
208
+ full_path = f"{self.client.code_model.namespace}.{self.client.code_model.rest_layer_name}"
209
+ retval.append(f">>> from {full_path} import {rest_imported}")
210
+ retval.append(f">>> request = {request_builder_name}({request_builder_signature})")
211
+ retval.append(f"<HttpRequest [{request_builder.method}], url: '{request_builder.url}'>")
212
+ retval.extend(self._example_make_call(async_mode))
213
+ return retval
214
+
215
+ def _rest_request_example(self, async_mode: bool) -> List[str]:
216
+ retval = [f">>> from {self.client.code_model.core_library}.rest import HttpRequest"]
217
+ retval.append('>>> request = HttpRequest("GET", "https://www.example.org/")')
218
+ retval.append("<HttpRequest [GET], url: 'https://www.example.org/'>")
219
+ retval.extend(self._example_make_call(async_mode))
220
+ return retval
221
+
222
+ def send_request_description(self, async_mode: bool) -> List[str]:
223
+ rest_library = f"{self.client.code_model.core_library}.rest"
224
+ retval = ['"""Runs the network request through the client\'s chained policies.']
225
+ retval.append("")
226
+ if self.client.code_model.options["builders_visibility"] != "embedded":
227
+ retval.extend(self._request_builder_example(async_mode))
228
+ else:
229
+ retval.extend(self._rest_request_example(async_mode))
230
+ retval.append("")
231
+ retval.append("For more information on this code flow, see https://aka.ms/azsdk/dpcodegen/python/send_request")
232
+ retval.append("")
233
+ retval.append(":param request: The network request you want to make. Required.")
234
+ retval.append(f":type request: ~{rest_library}.HttpRequest")
235
+ retval.append(":keyword bool stream: Whether the response payload will be streamed. Defaults to False.")
236
+ retval.append(":return: The response of your network call. Does not do error handling on your response.")
237
+ http_response = "AsyncHttpResponse" if async_mode else "HttpResponse"
238
+ retval.append(f":rtype: ~{rest_library}.{http_response}")
239
+ retval.append('"""')
240
+ return retval
241
+
242
+ def serialize_path(self) -> List[str]:
243
+ return self.parameter_serializer.serialize_path(self.client.parameters.path, "self._serialize")
244
+
245
+
246
+ class ConfigSerializer:
247
+ def __init__(self, client: Client) -> None:
248
+ self.client = client
249
+ self.parameter_serializer = ParameterSerializer()
250
+
251
+ def _init_signature(self, async_mode: bool) -> str:
252
+ return self.parameter_serializer.serialize_method(
253
+ function_def="def",
254
+ method_name="__init__",
255
+ need_self_param=True,
256
+ method_param_signatures=self.client.config.parameters.method_signature(async_mode),
257
+ )
258
+
259
+ def init_signature_and_response_type_annotation(self, async_mode: bool) -> str:
260
+ init_signature = self._init_signature(async_mode)
261
+ return utils.method_signature_and_response_type_annotation_template(
262
+ method_signature=init_signature,
263
+ response_type_annotation="None",
264
+ )
265
+
266
+ def pop_kwargs_from_signature(self) -> List[str]:
267
+ return self.parameter_serializer.pop_kwargs_from_signature(
268
+ self.client.config.parameters.kwargs_to_pop,
269
+ check_kwarg_dict=False,
270
+ pop_headers_kwarg=PopKwargType.NO,
271
+ pop_params_kwarg=PopKwargType.NO,
272
+ )
273
+
274
+ def set_constants(self) -> List[str]:
275
+ return [
276
+ f"self.{p.client_name} = {p.client_default_value_declaration}"
277
+ for p in self.client.config.parameters.constant
278
+ if p not in self.client.config.parameters.method
279
+ ]
280
+
281
+ def check_required_parameters(self) -> List[str]:
282
+ return [
283
+ f"if {p.client_name} is None:\n" f" raise ValueError(\"Parameter '{p.client_name}' must not be None.\")"
284
+ for p in self.client.config.parameters.method
285
+ if not (p.optional or p.constant)
286
+ ]
287
+
288
+ def property_descriptions(self, async_mode: bool) -> List[str]:
289
+ retval: List[str] = []
290
+ for p in self.client.config.parameters.method:
291
+ retval.append(f":{p.description_keyword} {p.client_name}: {p.description}")
292
+ retval.append(f":{p.docstring_type_keyword} {p.client_name}: {p.docstring_type(async_mode=async_mode)}")
293
+ retval.append('"""')
294
+ return retval
@@ -0,0 +1,15 @@
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License. See License.txt in the project root for
4
+ # license information.
5
+ # --------------------------------------------------------------------------
6
+
7
+ from .base_serializer import BaseSerializer
8
+ from ..models import FileImport
9
+
10
+
11
+ class EnumSerializer(BaseSerializer):
12
+ def serialize(self) -> str:
13
+ # Generate the enum file
14
+ template = self.env.get_template("enum_container.py.jinja2")
15
+ return template.render(code_model=self.code_model, file_import=FileImport(self.code_model))
@@ -0,0 +1,213 @@
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License. See License.txt in the project root for
4
+ # license information.
5
+ # --------------------------------------------------------------------------
6
+ import json
7
+ from typing import Any, List
8
+ from jinja2 import Environment
9
+ from .import_serializer import FileImportSerializer, TypingSection
10
+ from ..models.imports import MsrestImportType, FileImport
11
+ from ..models import (
12
+ ImportType,
13
+ CodeModel,
14
+ TokenCredentialType,
15
+ Client,
16
+ )
17
+ from .client_serializer import ClientSerializer, ConfigSerializer
18
+ from .base_serializer import BaseSerializer
19
+
20
+
21
+ class GeneralSerializer(BaseSerializer):
22
+ """General serializer for SDK root level files"""
23
+
24
+ def __init__(self, code_model: CodeModel, env: Environment, async_mode: bool):
25
+ super().__init__(code_model, env)
26
+ self.async_mode = async_mode
27
+
28
+ def serialize_setup_file(self) -> str:
29
+ template = self.env.get_template("packaging_templates/setup.py.jinja2")
30
+ params = {}
31
+ params.update(self.code_model.options)
32
+ return template.render(code_model=self.code_model, **params)
33
+
34
+ def serialize_package_file(self, template_name: str, **kwargs: Any) -> str:
35
+ template = self.env.get_template(template_name)
36
+ package_parts = (self.code_model.options["package_name"] or "").split("-")[:-1]
37
+ token_credential = any(
38
+ c for c in self.code_model.clients if isinstance(getattr(c.credential, "type", None), TokenCredentialType)
39
+ )
40
+ version = self.code_model.options["package_version"]
41
+ if any(x in version for x in ["a", "b", "rc"]) or version[0] == "0":
42
+ dev_status = "4 - Beta"
43
+ else:
44
+ dev_status = "5 - Production/Stable"
45
+ params = {
46
+ "code_model": self.code_model,
47
+ "dev_status": dev_status,
48
+ "token_credential": token_credential,
49
+ "pkgutil_names": [".".join(package_parts[: i + 1]) for i in range(len(package_parts))],
50
+ "init_names": ["/".join(package_parts[: i + 1]) + "/__init__.py" for i in range(len(package_parts))],
51
+ "client_name": self.code_model.clients[0].name,
52
+ "namespace": self.code_model.namespace,
53
+ }
54
+ params.update(self.code_model.options)
55
+ params.update(kwargs)
56
+ return template.render(file_import=FileImport(self.code_model), **params)
57
+
58
+ def serialize_pkgutil_init_file(self) -> str:
59
+ template = self.env.get_template("pkgutil_init.py.jinja2")
60
+ return template.render()
61
+
62
+ def serialize_init_file(self, clients: List[Client]) -> str:
63
+ template = self.env.get_template("init.py.jinja2")
64
+ return template.render(
65
+ code_model=self.code_model,
66
+ clients=clients,
67
+ async_mode=self.async_mode,
68
+ )
69
+
70
+ def serialize_service_client_file(self, clients: List[Client]) -> str:
71
+ template = self.env.get_template("client_container.py.jinja2")
72
+
73
+ imports = FileImport(self.code_model)
74
+ for client in clients:
75
+ imports.merge(client.imports(self.async_mode))
76
+
77
+ return template.render(
78
+ code_model=self.code_model,
79
+ clients=clients,
80
+ async_mode=self.async_mode,
81
+ get_serializer=ClientSerializer,
82
+ imports=FileImportSerializer(imports),
83
+ )
84
+
85
+ def serialize_vendor_file(self, clients: List[Client]) -> str:
86
+ template = self.env.get_template("vendor.py.jinja2")
87
+
88
+ # configure imports
89
+ file_import = FileImport(self.code_model)
90
+ if self.code_model.need_mixin_abc:
91
+ file_import.add_submodule_import(
92
+ "abc",
93
+ "ABC",
94
+ ImportType.STDLIB,
95
+ )
96
+ file_import.add_submodule_import(
97
+ "" if self.code_model.is_azure_flavor else "runtime",
98
+ f"{'Async' if self.async_mode else ''}PipelineClient",
99
+ ImportType.SDKCORE,
100
+ TypingSection.TYPING,
101
+ )
102
+ file_import.add_msrest_import(
103
+ relative_path=".." if self.async_mode else ".",
104
+ msrest_import_type=MsrestImportType.SerializerDeserializer,
105
+ typing_section=TypingSection.TYPING,
106
+ )
107
+ for client in clients:
108
+ if client.has_mixin:
109
+ file_import.add_submodule_import(
110
+ "._configuration",
111
+ f"{client.name}Configuration",
112
+ ImportType.LOCAL,
113
+ )
114
+ if self.code_model.has_etag:
115
+ file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB)
116
+ file_import.add_submodule_import(
117
+ "",
118
+ "MatchConditions",
119
+ ImportType.SDKCORE,
120
+ )
121
+ if self.code_model.has_form_data and self.code_model.options["models_mode"] == "dpg" and not self.async_mode:
122
+ file_import.add_submodule_import("typing", "IO", ImportType.STDLIB)
123
+ file_import.add_submodule_import("typing", "Tuple", ImportType.STDLIB)
124
+ file_import.add_submodule_import("typing", "Union", ImportType.STDLIB)
125
+ file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB)
126
+ file_import.add_submodule_import("typing", "Mapping", ImportType.STDLIB)
127
+ file_import.add_submodule_import("typing", "Dict", ImportType.STDLIB)
128
+ file_import.add_submodule_import("typing", "Any", ImportType.STDLIB)
129
+ file_import.add_submodule_import("typing", "List", ImportType.STDLIB)
130
+ file_import.add_submodule_import(
131
+ "._model_base",
132
+ "SdkJSONEncoder",
133
+ ImportType.LOCAL,
134
+ )
135
+ file_import.add_submodule_import(
136
+ "._model_base",
137
+ "Model",
138
+ ImportType.LOCAL,
139
+ )
140
+ file_import.add_import("json", ImportType.STDLIB)
141
+
142
+ return template.render(
143
+ code_model=self.code_model,
144
+ imports=FileImportSerializer(
145
+ file_import,
146
+ ),
147
+ async_mode=self.async_mode,
148
+ clients=clients,
149
+ )
150
+
151
+ def serialize_config_file(self, clients: List[Client]) -> str:
152
+ template = self.env.get_template("config_container.py.jinja2")
153
+ imports = FileImport(self.code_model)
154
+ for client in self.code_model.clients:
155
+ imports.merge(client.config.imports(self.async_mode))
156
+ return template.render(
157
+ code_model=self.code_model,
158
+ async_mode=self.async_mode,
159
+ imports=FileImportSerializer(imports),
160
+ get_serializer=ConfigSerializer,
161
+ clients=clients,
162
+ )
163
+
164
+ def serialize_version_file(self) -> str:
165
+ template = self.env.get_template("version.py.jinja2")
166
+ return template.render(code_model=self.code_model)
167
+
168
+ def serialize_serialization_file(self) -> str:
169
+ template = self.env.get_template("serialization.py.jinja2")
170
+ return template.render(
171
+ code_model=self.code_model,
172
+ )
173
+
174
+ def serialize_model_base_file(self) -> str:
175
+ template = self.env.get_template("model_base.py.jinja2")
176
+ return template.render(code_model=self.code_model, file_import=FileImport(self.code_model))
177
+
178
+ def serialize_validation_file(self) -> str:
179
+ template = self.env.get_template("validation.py.jinja2")
180
+ return template.render(code_model=self.code_model)
181
+
182
+ def serialize_cross_language_definition_file(self) -> str:
183
+ cross_langauge_def_dict = {
184
+ f"{self.code_model.namespace}.models.{model.name}": model.cross_language_definition_id
185
+ for model in self.code_model.public_model_types
186
+ }
187
+ cross_langauge_def_dict.update(
188
+ {
189
+ f"{self.code_model.namespace}.models.{enum.name}": enum.cross_language_definition_id
190
+ for enum in self.code_model.enums
191
+ if not enum.internal
192
+ }
193
+ )
194
+ cross_langauge_def_dict.update(
195
+ {
196
+ (
197
+ f"{self.code_model.namespace}.{client.name}."
198
+ + ("" if operation_group.is_mixin else f"{operation_group.property_name}.")
199
+ + f"{operation.name}"
200
+ ): operation.cross_language_definition_id
201
+ for client in self.code_model.clients
202
+ for operation_group in client.operation_groups
203
+ for operation in operation_group.operations
204
+ if not operation.name.startswith("_")
205
+ }
206
+ )
207
+ return json.dumps(
208
+ {
209
+ "CrossLanguagePackageId": self.code_model.cross_language_package_id,
210
+ "CrossLanguageDefinitionId": cross_langauge_def_dict,
211
+ },
212
+ indent=4,
213
+ )
@@ -0,0 +1,126 @@
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License. See License.txt in the project root for
4
+ # license information.
5
+ # --------------------------------------------------------------------------
6
+ from copy import deepcopy
7
+ from typing import List
8
+ from ..models.imports import (
9
+ ImportType,
10
+ FileImport,
11
+ ImportModel,
12
+ TypingSection,
13
+ TypeDefinition,
14
+ )
15
+
16
+
17
+ def _serialize_package(imports: List[ImportModel], delimiter: str) -> str:
18
+ buffer = []
19
+ if any(i for i in imports if i.submodule_name is None):
20
+ buffer.append(f"import {imports[0].module_name}{f' as {imports[0].alias}' if imports[0].alias else ''}")
21
+ else:
22
+ import_str = ", ".join(
23
+ sorted(
24
+ set(
25
+ f"{i.submodule_name} as {i.alias}" if i.alias else i.submodule_name for i in imports # type: ignore
26
+ )
27
+ )
28
+ )
29
+ buffer.append(f"from {imports[0].module_name} import {import_str}")
30
+ return delimiter.join(buffer)
31
+
32
+
33
+ def _serialize_versioned_package(i: ImportModel, delimiter: str) -> str:
34
+ if not i.version_modules:
35
+ return ""
36
+ buffer = []
37
+ for n, (version, module_name, comment) in enumerate(i.version_modules):
38
+ buffer.append("{} sys.version_info >= {}:".format("if" if n == 0 else "elif", version))
39
+ buffer.append(
40
+ f" from {module_name} import {i.submodule_name}{f' as {i.alias}' if i.alias else ''}"
41
+ f"{f' # {comment}' if comment else ''}"
42
+ )
43
+ buffer.append("else:")
44
+ buffer.append(
45
+ f" from {i.module_name} import {i.submodule_name}{f' as {i.alias}' if i.alias else ''}" " # type: ignore"
46
+ )
47
+ return delimiter.join(buffer)
48
+
49
+
50
+ def _serialize_import_type(imports: List[ImportModel], delimiter: str) -> str:
51
+ """Serialize a given import type."""
52
+ import_list = []
53
+ for module_name in sorted(set(i.module_name for i in imports)):
54
+ normal_imports = [i for i in imports if i.module_name == module_name and not i.version_modules]
55
+ versioned_imports = [i for i in imports if i.module_name == module_name and i.version_modules]
56
+ if normal_imports:
57
+ import_list.append(_serialize_package(normal_imports, delimiter))
58
+ for i in versioned_imports:
59
+ import_list.append(_serialize_versioned_package(i, delimiter))
60
+ return delimiter.join(import_list)
61
+
62
+
63
+ def _get_import_clauses(imports: List[ImportModel], delimiter: str) -> List[str]:
64
+ import_clause = []
65
+ for import_type in ImportType:
66
+ imports_with_import_type = [i for i in imports if i.import_type == import_type]
67
+ if imports_with_import_type:
68
+ import_clause.append(_serialize_import_type(imports_with_import_type, delimiter))
69
+ return import_clause
70
+
71
+
72
+ class FileImportSerializer:
73
+ def __init__(self, file_import: FileImport, async_mode: bool = False) -> None:
74
+ self.file_import = file_import
75
+ self.async_mode = async_mode
76
+
77
+ def _get_imports_list(self, baseline_typing_section: TypingSection, add_conditional_typing: bool):
78
+ # If this is a python 3 file, our regular imports include the CONDITIONAL category
79
+ # If this is not a python 3 file, our typing imports include the CONDITIONAL category
80
+ file_import_copy = deepcopy(self.file_import)
81
+ if add_conditional_typing and any(self.file_import.get_imports_from_section(TypingSection.CONDITIONAL)):
82
+ # we switch the TypingSection key for the CONDITIONAL typing imports so we can merge
83
+ # the imports together
84
+ for i in file_import_copy.imports:
85
+ if i.typing_section == TypingSection.CONDITIONAL:
86
+ i.typing_section = baseline_typing_section
87
+ return file_import_copy.get_imports_from_section(baseline_typing_section)
88
+
89
+ def _add_type_checking_import(self):
90
+ if any(self.file_import.get_imports_from_section(TypingSection.TYPING)):
91
+ self.file_import.add_submodule_import("typing", "TYPE_CHECKING", ImportType.STDLIB)
92
+
93
+ def get_typing_definitions(self) -> str:
94
+ def declare_definition(type_name: str, type_definition: TypeDefinition) -> List[str]:
95
+ ret: List[str] = []
96
+ definition_value = type_definition.async_definition if self.async_mode else type_definition.sync_definition
97
+ ret.append("{} = {}".format(type_name, definition_value))
98
+ return ret
99
+
100
+ if not self.file_import.type_definitions:
101
+ return ""
102
+ declarations: List[str] = [""]
103
+ for type_name, value in self.file_import.type_definitions.items():
104
+ declarations.extend(declare_definition(type_name, value))
105
+ return "\n".join(declarations)
106
+
107
+ def __str__(self) -> str:
108
+ self._add_type_checking_import()
109
+ regular_imports = ""
110
+ regular_imports_list = self._get_imports_list(
111
+ baseline_typing_section=TypingSection.REGULAR,
112
+ add_conditional_typing=True,
113
+ )
114
+
115
+ if regular_imports_list:
116
+ regular_imports = "\n\n".join(_get_import_clauses(regular_imports_list, "\n"))
117
+
118
+ typing_imports = ""
119
+ typing_imports_list = self._get_imports_list(
120
+ baseline_typing_section=TypingSection.TYPING,
121
+ add_conditional_typing=False,
122
+ )
123
+ if typing_imports_list:
124
+ typing_imports += "\n\nif TYPE_CHECKING:\n "
125
+ typing_imports += "\n\n ".join(_get_import_clauses(typing_imports_list, "\n "))
126
+ return regular_imports + typing_imports + self.get_typing_definitions()