@autorest/python 5.10.0 → 5.12.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 (57) hide show
  1. package/ChangeLog.md +74 -0
  2. package/autorest/codegen/__init__.py +7 -7
  3. package/autorest/codegen/models/__init__.py +2 -1
  4. package/autorest/codegen/models/base_builder.py +16 -8
  5. package/autorest/codegen/models/client.py +5 -3
  6. package/autorest/codegen/models/code_model.py +19 -5
  7. package/autorest/codegen/models/imports.py +7 -0
  8. package/autorest/codegen/models/lro_operation.py +7 -3
  9. package/autorest/codegen/models/object_schema.py +3 -3
  10. package/autorest/codegen/models/operation.py +69 -38
  11. package/autorest/codegen/models/operation_group.py +13 -8
  12. package/autorest/codegen/models/paging_operation.py +5 -2
  13. package/autorest/codegen/models/parameter.py +46 -13
  14. package/autorest/codegen/models/parameter_list.py +62 -70
  15. package/autorest/codegen/models/primitive_schemas.py +11 -0
  16. package/autorest/codegen/models/request_builder.py +21 -8
  17. package/autorest/codegen/models/request_builder_parameter.py +9 -5
  18. package/autorest/codegen/models/request_builder_parameter_list.py +179 -77
  19. package/autorest/codegen/models/rest.py +3 -2
  20. package/autorest/codegen/models/schema_request.py +4 -17
  21. package/autorest/codegen/models/schema_response.py +4 -4
  22. package/autorest/codegen/serializers/__init__.py +57 -53
  23. package/autorest/codegen/serializers/builder_serializer.py +76 -46
  24. package/autorest/codegen/serializers/client_serializer.py +37 -9
  25. package/autorest/codegen/serializers/general_serializer.py +7 -5
  26. package/autorest/codegen/serializers/import_serializer.py +22 -7
  27. package/autorest/codegen/serializers/metadata_serializer.py +2 -2
  28. package/autorest/codegen/serializers/model_base_serializer.py +3 -3
  29. package/autorest/codegen/serializers/model_generic_serializer.py +1 -1
  30. package/autorest/codegen/serializers/model_python3_serializer.py +1 -1
  31. package/autorest/codegen/serializers/operation_groups_serializer.py +70 -0
  32. package/autorest/codegen/serializers/operations_init_serializer.py +34 -2
  33. package/autorest/codegen/serializers/patch_serializer.py +15 -0
  34. package/autorest/codegen/serializers/rest_serializer.py +9 -4
  35. package/autorest/codegen/serializers/utils.py +2 -2
  36. package/autorest/codegen/templates/config.py.jinja2 +1 -11
  37. package/autorest/codegen/templates/init.py.jinja2 +4 -7
  38. package/autorest/codegen/templates/metadata.json.jinja2 +2 -2
  39. package/autorest/codegen/templates/model_init.py.jinja2 +1 -1
  40. package/autorest/codegen/templates/{operations_class.py.jinja2 → operation_group.py.jinja2} +2 -0
  41. package/autorest/codegen/templates/operation_groups_container.py.jinja2 +26 -0
  42. package/autorest/codegen/templates/operation_tools.jinja2 +7 -0
  43. package/autorest/codegen/templates/operations_folder_init.py.jinja2 +13 -0
  44. package/autorest/codegen/templates/patch.py.jinja2 +31 -0
  45. package/autorest/codegen/templates/request_builder.py.jinja2 +7 -2
  46. package/autorest/codegen/templates/request_builders.py.jinja2 +3 -3
  47. package/autorest/codegen/templates/setup.py.jinja2 +1 -1
  48. package/autorest/multiapi/serializers/__init__.py +3 -3
  49. package/autorest/multiapi/serializers/import_serializer.py +5 -5
  50. package/autorest/namer/name_converter.py +48 -3
  51. package/package.json +2 -2
  52. package/setup.py +1 -0
  53. package/autorest/codegen/serializers/operation_group_serializer.py +0 -71
  54. package/autorest/codegen/templates/operations_class_mixin.py.jinja2 +0 -16
  55. package/autorest/codegen/templates/operations_container.py.jinja2 +0 -42
  56. package/autorest/codegen/templates/operations_container_init.py.jinja2 +0 -24
  57. package/autorest/codegen/templates/operations_container_mixin.py.jinja2 +0 -23
@@ -3,12 +3,13 @@
3
3
  # Licensed under the MIT License. See License.txt in the project root for
4
4
  # license information.
5
5
  # --------------------------------------------------------------------------
6
+ import re
6
7
  from copy import copy
7
- from typing import List, Optional, TypeVar, Dict
8
+ from typing import List, Optional, Tuple, TypeVar, Dict
8
9
  from .request_builder_parameter import RequestBuilderParameter
9
10
  from .parameter_list import ParameterList
10
- from .parameter import ParameterLocation, Parameter
11
- from .primitive_schemas import AnySchema
11
+ from .parameter import ParameterLocation, Parameter, ParameterStyle
12
+ from .primitive_schemas import AnySchema, JSONSchema
12
13
  from .dictionary_schema import DictionarySchema
13
14
  from .base_schema import BaseSchema
14
15
  from .schema_request import SchemaRequest
@@ -17,14 +18,25 @@ T = TypeVar('T')
17
18
  OrderedSet = Dict[T, None]
18
19
 
19
20
  _REQUEST_BUILDER_BODY_NAMES = ["files", "json", "content", "data"]
21
+ _JSON_REGEXP = re.compile(r'^(application|text)/([0-9a-z+.]+\+)?json$')
20
22
 
23
+ def _update_content_types(content_types_to_assign: List[str], param: Parameter):
24
+ return [
25
+ c for c in content_types_to_assign if c not in param.content_types
26
+ ]
27
+
28
+ def _kwarg_not_added(body_method_params, serialized_name: str) -> bool:
29
+ return not any(b for b in body_method_params if b.serialized_name == serialized_name)
21
30
 
22
31
  class RequestBuilderParameterList(ParameterList):
23
32
  def __init__(
24
- self, code_model, parameters: Optional[List[RequestBuilderParameter]] = None
33
+ self,
34
+ code_model,
35
+ parameters: Optional[List[RequestBuilderParameter]] = None,
36
+ schema_requests: Optional[List[SchemaRequest]] = None,
25
37
  ) -> None:
26
38
  super(RequestBuilderParameterList, self).__init__(
27
- code_model, parameters # type: ignore
39
+ code_model, parameters, schema_requests # type: ignore
28
40
  )
29
41
  self.body_kwarg_names: OrderedSet[str] = {}
30
42
  self.parameters: List[RequestBuilderParameter] = parameters or [] # type: ignore
@@ -32,90 +44,170 @@ class RequestBuilderParameterList(ParameterList):
32
44
  def _change_body_param_name(self, parameter: Parameter, name: str) -> None:
33
45
  self.body_kwarg_names[name] = None
34
46
  parameter.serialized_name = name
47
+ parameter.is_body_kwarg = True
35
48
 
36
- def add_body_kwargs(self, schema_requests: List[SchemaRequest]) -> None:
37
- try:
38
- body_kwargs_added = []
39
- body_method_param = next(
40
- p for p in self.parameters if p.location == ParameterLocation.Body
41
- )
42
- except StopIteration:
43
- pass
44
- else:
45
- serialized_name: str = ""
46
- if body_method_param.is_multipart:
47
- serialized_name = "files"
48
- file_kwarg = copy(body_method_param)
49
- self._change_body_param_name(file_kwarg, "files")
50
- file_kwarg.schema = DictionarySchema(
51
- namespace="",
52
- yaml_data={},
53
- element_type=AnySchema(namespace="", yaml_data={}),
54
- )
55
- file_kwarg.description = (
56
- "Multipart input for files. See the template in our example to find the input shape. " +
57
- file_kwarg.description
49
+ def _is_json(self, body_method_param: Parameter) -> bool:
50
+ if 'json' in body_method_param.serialization_formats:
51
+ return True
52
+ if not any(
53
+ flag for flag in ["version_tolerant", "low_level_client"]
54
+ if self.code_model.options.get(flag)
55
+ ):
56
+ if body_method_param.style == ParameterStyle.binary:
57
+ return False
58
+ if any(
59
+ sr for sr in self.schema_requests
60
+ if sr.yaml_data.get("protocol", {}).get('http', {}).get('knownMediaType') == "json"
61
+ ):
62
+ return True
63
+ return any(c for c in self.content_types if _JSON_REGEXP.match(c))
64
+
65
+ @property
66
+ def body_kwargs_to_get(self) -> List[Parameter]:
67
+ if not self.body_kwarg_names:
68
+ return []
69
+ return [b for b in self.body if b.content_types]
70
+
71
+ def _update_constant_params(self):
72
+ # we don't currently have a fully constant data or files input
73
+ # so we don't need to modify the body kwarg
74
+ constant_bodies = [
75
+ p for p in self.parameters
76
+ if p.location == ParameterLocation.Body
77
+ and p.constant
78
+ and not p.is_data_input
79
+ and not p.is_multipart
80
+ ]
81
+ for constant_body in constant_bodies:
82
+ if self._is_json(constant_body):
83
+ constant_body.serialized_name = "json"
84
+ else:
85
+ constant_body.serialized_name = "content"
86
+
87
+ def _add_files_kwarg(
88
+ self, content_types_to_assign, body_method_param
89
+ ) -> Tuple[List[str], RequestBuilderParameter]:
90
+ file_kwarg = copy(body_method_param)
91
+ self._change_body_param_name(file_kwarg, "files")
92
+ file_kwarg.schema = DictionarySchema(
93
+ namespace="",
94
+ yaml_data={},
95
+ element_type=AnySchema(namespace="", yaml_data={}),
96
+ )
97
+ file_kwarg.description = (
98
+ "Multipart input for files. See the template in our example to find the input shape. " +
99
+ file_kwarg.description
100
+ )
101
+ file_kwarg.content_types = [
102
+ c for c in content_types_to_assign
103
+ if c == "multipart/form-data"
104
+ ]
105
+ content_types_to_assign = _update_content_types(content_types_to_assign, file_kwarg)
106
+ return content_types_to_assign, file_kwarg
107
+
108
+ def _add_data_kwarg(
109
+ self, content_types_to_assign, body_method_param
110
+ ) -> Tuple[List[str], RequestBuilderParameter]:
111
+ data_kwarg = copy(body_method_param)
112
+ self._change_body_param_name(data_kwarg, "data")
113
+ data_kwarg.schema = DictionarySchema(
114
+ namespace="",
115
+ yaml_data={},
116
+ element_type=AnySchema(namespace="", yaml_data={}),
117
+ )
118
+ data_kwarg.description = (
119
+ "Pass in dictionary that contains form data to include in the body of the request. " +
120
+ data_kwarg.description
121
+ )
122
+ data_kwarg.content_types = [
123
+ c for c in content_types_to_assign
124
+ if c == "application/x-www-form-urlencoded"
125
+ ]
126
+ content_types_to_assign = _update_content_types(content_types_to_assign, data_kwarg)
127
+ return content_types_to_assign, data_kwarg
128
+
129
+ def _add_json_kwarg(
130
+ self, content_types_to_assign, body_method_param
131
+ ) -> Tuple[List[str], RequestBuilderParameter]:
132
+ json_kwarg = copy(body_method_param)
133
+ self._change_body_param_name(json_kwarg, "json")
134
+ json_kwarg.description = (
135
+ "Pass in a JSON-serializable object (usually a dictionary). "
136
+ "See the template in our example to find the input shape. " +
137
+ json_kwarg.description
138
+ )
139
+ json_kwarg.schema = JSONSchema(namespace="", yaml_data={})
140
+ json_kwarg.content_types = [
141
+ c for c in content_types_to_assign
142
+ if _JSON_REGEXP.match(c)
143
+ ]
144
+ content_types_to_assign = _update_content_types(content_types_to_assign, json_kwarg)
145
+ return content_types_to_assign, json_kwarg
146
+
147
+ def _add_content_kwarg(
148
+ self, content_types_to_assign, body_method_param
149
+ ) -> RequestBuilderParameter:
150
+ content_kwarg = copy(body_method_param)
151
+ self._change_body_param_name(content_kwarg, "content")
152
+ content_kwarg.schema = AnySchema(namespace="", yaml_data={})
153
+ content_kwarg.description = (
154
+ "Pass in binary content you want in the body of the request (typically bytes, "
155
+ "a byte iterator, or stream input). " +
156
+ content_kwarg.description
157
+ )
158
+ content_kwarg.is_data_input = False
159
+ content_kwarg.is_multipart = False
160
+ content_kwarg.content_types = content_types_to_assign
161
+ return content_kwarg
162
+
163
+ def add_body_kwargs(self) -> None:
164
+ self._update_constant_params()
165
+ body_kwargs_added: List[RequestBuilderParameter] = []
166
+ body_method_params = [
167
+ p for p in self.parameters
168
+ if p.location == ParameterLocation.Body and not p.constant
169
+ ]
170
+ if not body_method_params:
171
+ return
172
+ content_types_to_assign = copy(self.content_types)
173
+ for body_method_param in body_method_params:
174
+ if body_method_param.is_multipart and _kwarg_not_added(body_kwargs_added, "files"):
175
+ content_types_to_assign, file_kwarg = self._add_files_kwarg(
176
+ content_types_to_assign, body_method_param
58
177
  )
59
- file_kwarg.is_multipart = False
60
178
  body_kwargs_added.append(file_kwarg)
61
- if body_method_param.is_data_input:
62
- serialized_name = "data"
63
- data_kwarg = copy(body_method_param)
64
- self._change_body_param_name(data_kwarg, "data")
65
- data_kwarg.schema = DictionarySchema(
66
- namespace="",
67
- yaml_data={},
68
- element_type=AnySchema(namespace="", yaml_data={}),
69
- )
70
- data_kwarg.description = (
71
- "Pass in dictionary that contains form data to include in the body of the request. " +
72
- data_kwarg.description
179
+
180
+ elif body_method_param.is_data_input and _kwarg_not_added(body_kwargs_added, "data"):
181
+ content_types_to_assign, data_kwarg = self._add_data_kwarg(
182
+ content_types_to_assign, body_method_param
73
183
  )
74
- data_kwarg.is_data_input = False
75
184
  body_kwargs_added.append(data_kwarg)
76
- if body_method_param.constant:
77
- # we don't add body kwargs for constant bodies
78
- if not serialized_name:
79
- serialized_name = "json" if body_method_param.is_json_parameter else "content"
80
- body_method_param.serialized_name = serialized_name
81
- return
82
- if (
83
- any(sr for sr in schema_requests if not sr.is_stream_request) and
84
- any([ct for ct in self.content_types if "json" in ct])
85
- ):
86
- json_kwarg = copy(body_method_param)
87
- self._change_body_param_name(json_kwarg, "json")
88
- json_kwarg.description = (
89
- "Pass in a JSON-serializable object (usually a dictionary). "
90
- "See the template in our example to find the input shape. " +
91
- json_kwarg.description
185
+ elif self._is_json(body_method_param) and _kwarg_not_added(body_kwargs_added, "json"):
186
+ content_types_to_assign, json_kwarg = self._add_json_kwarg(
187
+ content_types_to_assign, body_method_param
92
188
  )
93
- json_kwarg.schema = AnySchema(namespace="", yaml_data={})
94
189
  body_kwargs_added.append(json_kwarg)
95
- content_kwarg = copy(body_method_param)
96
- self._change_body_param_name(content_kwarg, "content")
97
- content_kwarg.schema = AnySchema(namespace="", yaml_data={})
98
- content_kwarg.description = (
99
- "Pass in binary content you want in the body of the request (typically bytes, "
100
- "a byte iterator, or stream input). " +
101
- content_kwarg.description
190
+
191
+ first_body_param = body_method_params[0]
192
+ if _kwarg_not_added(body_kwargs_added, "content"):
193
+ # we always add a content kwarg so users can pass in input by stream
194
+ content_kwarg = self._add_content_kwarg(
195
+ content_types_to_assign, first_body_param
102
196
  )
103
- content_kwarg.is_data_input = False
104
- content_kwarg.is_multipart = False
105
197
  body_kwargs_added.append(content_kwarg)
106
- if len(body_kwargs_added) == 1:
107
- body_kwargs_added[0].required = body_method_param.required
108
- else:
109
- for kwarg in body_kwargs_added:
110
- kwarg.required = False
111
- self.parameters = body_kwargs_added + self.parameters
198
+ if len(body_kwargs_added) == 1:
199
+ body_kwargs_added[0].required = first_body_param.required
200
+ else:
201
+ for kwarg in body_kwargs_added:
202
+ kwarg.required = False
203
+ self.parameters = body_kwargs_added + self.parameters
112
204
 
113
205
  @property
114
206
  def json_body(self) -> BaseSchema:
115
207
  if not self._json_body:
116
208
  try:
117
209
  json_param = next(
118
- b for b in self.body if b.serialized_name not in _REQUEST_BUILDER_BODY_NAMES and
210
+ b for b in self.body if not b.is_body_kwarg and
119
211
  b.is_json_parameter
120
212
  )
121
213
  self._json_body = json_param.schema
@@ -124,10 +216,10 @@ class RequestBuilderParameterList(ParameterList):
124
216
  raise ValueError("There is no JSON body in these parameters")
125
217
  return self._json_body
126
218
 
127
- def kwargs_to_pop(self, is_python_3_file: bool) -> List[Parameter]:
219
+ def kwargs_to_pop(self, is_python3_file: bool) -> List[Parameter]:
128
220
  # we don't want to pop the body kwargs in py2.7. We send them straight to HttpRequest
129
221
  kwargs_to_pop = self.kwargs
130
- if not is_python_3_file:
222
+ if not is_python3_file:
131
223
  kwargs_to_pop += [k for k in self.keyword_only if not (k.is_body and not k.constant)]
132
224
  return kwargs_to_pop
133
225
 
@@ -147,9 +239,19 @@ class RequestBuilderParameterList(ParameterList):
147
239
  seen_content_type = False
148
240
 
149
241
  for parameter in parameters:
242
+
243
+ if (
244
+ parameter.location == ParameterLocation.Body and
245
+ (parameter.is_data_input or parameter.is_multipart) and
246
+ not parameter.is_body_kwarg
247
+ ):
248
+ # if i am a part of files or data, and i'm not the files or
249
+ # data kwarg, ignore me
250
+ continue
150
251
  if (
151
252
  parameter.location == ParameterLocation.Body and
152
- parameter.serialized_name not in _REQUEST_BUILDER_BODY_NAMES
253
+ not parameter.is_body_kwarg and
254
+ not parameter.constant
153
255
  ):
154
256
  # we keep the original body param from the swagger for documentation purposes
155
257
  # we don't want it in the method signature
@@ -19,10 +19,11 @@ class Rest(BaseModel):
19
19
  super(Rest, self). __init__(yaml_data=yaml_data)
20
20
  self.request_builders = request_builders
21
21
 
22
- def imports(self) -> FileImport:
22
+ def imports(self, builder_group_name: str) -> FileImport:
23
23
  file_import = FileImport()
24
24
  for request_builder in self.request_builders:
25
- file_import.merge(request_builder.imports())
25
+ if request_builder.builder_group_name == builder_group_name:
26
+ file_import.merge(request_builder.imports())
26
27
  return file_import
27
28
 
28
29
  @classmethod
@@ -13,26 +13,13 @@ class SchemaRequest(BaseModel):
13
13
  def __init__(
14
14
  self,
15
15
  yaml_data: Dict[str, Any],
16
- media_types: List[str],
16
+ content_types: List[str],
17
17
  parameters: ParameterList,
18
18
  ) -> None:
19
19
  super().__init__(yaml_data)
20
- self.media_types = media_types
20
+ self.content_types = content_types
21
21
  self.parameters = parameters
22
22
 
23
- @property
24
- def pre_semicolon_media_types(self) -> List[str]:
25
- """Splits on semicolon of media types and returns the first half.
26
- I.e. ["text/plain; encoding=UTF-8"] -> ["text/plain"]
27
- """
28
- return [media_type.split(";")[0] for media_type in self.media_types]
29
-
30
- @property
31
- def body_parameter_has_schema(self) -> bool:
32
- """Tell if that request has a parameter that defines a body.
33
- """
34
- return any([p for p in self.parameters if hasattr(p, 'schema') and p.schema])
35
-
36
23
  @property
37
24
  def is_stream_request(self) -> bool:
38
25
  """Is the request expected to be streamable, like a download."""
@@ -50,9 +37,9 @@ class SchemaRequest(BaseModel):
50
37
 
51
38
  return cls(
52
39
  yaml_data=yaml_data,
53
- media_types=yaml_data["protocol"]["http"].get("mediaTypes", []),
40
+ content_types=yaml_data["protocol"]["http"].get("mediaTypes", []),
54
41
  parameters=ParameterList(code_model, parameters)
55
42
  )
56
43
 
57
44
  def __repr__(self) -> str:
58
- return f"<{self.__class__.__name__} {self.media_types}>"
45
+ return f"<{self.__class__.__name__} {self.content_types}>"
@@ -26,14 +26,14 @@ class SchemaResponse(BaseModel):
26
26
  self,
27
27
  yaml_data: Dict[str, Any],
28
28
  schema: Optional[BaseSchema],
29
- media_types: List[str],
29
+ content_types: List[str],
30
30
  status_codes: List[Union[str, int]],
31
31
  headers: List[HeaderResponse],
32
32
  binary: bool,
33
33
  ) -> None:
34
34
  super().__init__(yaml_data)
35
35
  self.schema = schema
36
- self.media_types = media_types
36
+ self.content_types = content_types
37
37
  self.status_codes = status_codes
38
38
  self.headers = headers
39
39
  self.binary = binary
@@ -94,7 +94,7 @@ class SchemaResponse(BaseModel):
94
94
 
95
95
  @property
96
96
  def is_xml(self) -> bool:
97
- return any(["xml" in ct for ct in self.media_types])
97
+ return any(["xml" in ct for ct in self.content_types])
98
98
 
99
99
  def imports(self, code_model) -> FileImport:
100
100
  file_import = FileImport()
@@ -108,7 +108,7 @@ class SchemaResponse(BaseModel):
108
108
  return cls(
109
109
  yaml_data=yaml_data,
110
110
  schema=yaml_data.get("schema", None), # FIXME replace by operation model
111
- media_types=yaml_data["protocol"]["http"].get("mediaTypes", []),
111
+ content_types=yaml_data["protocol"]["http"].get("mediaTypes", []),
112
112
  status_codes=[
113
113
  int(code) if code != "default" else "default" for code in yaml_data["protocol"]["http"]["statusCodes"]
114
114
  ],
@@ -3,29 +3,32 @@
3
3
  # Licensed under the MIT License. See License.txt in the project root for
4
4
  # license information.
5
5
  # --------------------------------------------------------------------------
6
- from typing import List
6
+ from typing import List, Optional
7
7
  from pathlib import Path
8
8
  from jinja2 import PackageLoader, Environment
9
9
  from autorest.codegen.models.operation_group import OperationGroup
10
10
 
11
11
  from ...jsonrpc import AutorestAPI
12
- from ..models import CodeModel
13
- from ..models.request_builder import RequestBuilder
12
+ from ..models import (
13
+ CodeModel,
14
+ OperationGroup,
15
+ RequestBuilder,
16
+ )
14
17
  from .enum_serializer import EnumSerializer
15
18
  from .general_serializer import GeneralSerializer
16
19
  from .model_generic_serializer import ModelGenericSerializer
17
20
  from .model_init_serializer import ModelInitSerializer
18
21
  from .model_python3_serializer import ModelPython3Serializer
19
22
  from .operations_init_serializer import OperationsInitSerializer
20
- from .operation_group_serializer import OperationGroupSerializer
23
+ from .operation_groups_serializer import OperationGroupsSerializer
21
24
  from .metadata_serializer import MetadataSerializer
22
25
  from .rest_serializer import RestPython3Serializer, RestGenericSerializer, RestSerializer
26
+ from .patch_serializer import PatchSerializer
23
27
 
24
28
  __all__ = [
25
29
  "JinjaSerializer",
26
30
  ]
27
31
 
28
-
29
32
  class JinjaSerializer:
30
33
  def __init__(self, autorestapi: AutorestAPI) -> None:
31
34
  self._autorestapi = autorestapi
@@ -45,11 +48,8 @@ class JinjaSerializer:
45
48
  )
46
49
 
47
50
  # if there was a patch file before, we keep it
48
- if self._autorestapi.read_file(namespace_path / "_patch.py"):
49
- self._autorestapi.write_file(
50
- namespace_path / Path("_patch.py"),
51
- self._autorestapi.read_file(namespace_path / "_patch.py")
52
- )
51
+ self._keep_patch_file(namespace_path / Path("_patch.py"), env)
52
+ self._keep_patch_file(namespace_path / Path("aio") / Path("_patch.py"), env)
53
53
 
54
54
  self._serialize_and_write_top_level_folder(code_model=code_model, env=env, namespace_path=namespace_path)
55
55
 
@@ -72,11 +72,19 @@ class JinjaSerializer:
72
72
  self._serialize_and_write_models_folder(code_model=code_model, env=env, namespace_path=namespace_path)
73
73
 
74
74
 
75
+
76
+ def _keep_patch_file(self, path_file: Path, env: Environment):
77
+ if self._autorestapi.read_file(path_file):
78
+ self._autorestapi.write_file(path_file, self._autorestapi.read_file(path_file))
79
+ else:
80
+ self._autorestapi.write_file(path_file, PatchSerializer(env=env).serialize())
81
+
82
+
75
83
  def _serialize_and_write_models_folder(self, code_model: CodeModel, env: Environment, namespace_path: Path) -> None:
76
84
  # Write the models folder
77
85
  models_path = namespace_path / Path("models")
78
86
  if code_model.schemas:
79
- if not code_model.options['python_3_only']:
87
+ if not code_model.options['python3_only']:
80
88
  self._autorestapi.write_file(
81
89
  models_path / Path("_models.py"), ModelGenericSerializer(code_model=code_model, env=env).serialize()
82
90
  )
@@ -141,96 +149,92 @@ class JinjaSerializer:
141
149
  ).serialize_init()
142
150
  )
143
151
 
144
- def _serialize_and_write_operations_folder_process(
152
+ def _serialize_and_write_operations_file(
145
153
  self,
146
154
  code_model: CodeModel,
147
155
  env: Environment,
148
156
  namespace_path: Path,
149
- operation_groups: List[OperationGroup],
150
- filename: str
157
+ operation_group: Optional[OperationGroup] = None
151
158
  ) -> None:
152
- # write sync operation group and operation files
153
- if not code_model.options['python_3_only'] and not code_model.options["add_python_3_operation_files"]:
154
- operation_group_serializer = OperationGroupSerializer(
159
+ filename = operation_group.filename if operation_group else "_operations"
160
+ # write first sync file
161
+ operation_group_serializer = OperationGroupsSerializer(
162
+ code_model=code_model,
163
+ env=env,
164
+ async_mode=False,
165
+ is_python3_file=code_model.options['python3_only'],
166
+ operation_group=operation_group
167
+ )
168
+ self._autorestapi.write_file(
169
+ namespace_path / Path(code_model.operations_folder_name) / Path(f"{filename}.py"),
170
+ operation_group_serializer.serialize(),
171
+ )
172
+
173
+ if not code_model.options['python3_only'] and code_model.options["add_python3_operation_files"]:
174
+ # write typed second file if not python 3 only
175
+ operation_group_serializer = OperationGroupsSerializer(
155
176
  code_model=code_model,
156
177
  env=env,
157
- operation_groups=operation_groups,
158
178
  async_mode=False,
159
- is_python_3_file=False,
179
+ is_python3_file=True,
180
+
160
181
  )
161
182
  self._autorestapi.write_file(
162
- namespace_path / Path(f"operations") / Path(f"{filename}.py"),
183
+ namespace_path / Path(code_model.operations_folder_name) / Path(f"{filename}_py3.py"),
163
184
  operation_group_serializer.serialize(),
164
185
  )
165
186
 
166
187
  if not code_model.options["no_async"]:
167
188
  # write async operation group and operation files
168
- operation_group_async_serializer = OperationGroupSerializer(
189
+ operation_group_async_serializer = OperationGroupsSerializer(
169
190
  code_model=code_model,
170
191
  env=env,
171
- operation_groups=operation_groups,
172
192
  async_mode=True,
173
- is_python_3_file=True,
193
+ is_python3_file=True,
194
+ operation_group=operation_group
174
195
  )
175
196
  self._autorestapi.write_file(
176
197
  (
177
198
  namespace_path
178
199
  / Path("aio")
179
- / Path(f"operations")
200
+ / Path(code_model.operations_folder_name)
180
201
  / Path(f"{filename}.py")
181
202
  ),
182
203
  operation_group_async_serializer.serialize(),
183
204
  )
184
205
 
185
- if code_model.options["add_python_3_operation_files"]:
186
- # write typed sync operation files
187
- operation_group_serializer = OperationGroupSerializer(
188
- code_model=code_model,
189
- env=env,
190
- operation_groups=operation_groups,
191
- async_mode=False,
192
- is_python_3_file=True,
193
- )
194
- self._autorestapi.write_file(
195
- namespace_path / Path(f"operations") / Path(f"{filename}_py3.py"),
196
- operation_group_serializer.serialize(),
197
- )
198
-
199
206
  def _serialize_and_write_operations_folder(
200
207
  self, code_model: CodeModel, env: Environment, namespace_path: Path
201
208
  ) -> None:
202
209
  # write sync operations init file
203
210
  operations_init_serializer = OperationsInitSerializer(code_model=code_model, env=env, async_mode=False)
204
211
  self._autorestapi.write_file(
205
- namespace_path / Path(f"operations") / Path("__init__.py"), operations_init_serializer.serialize()
212
+ namespace_path / Path(code_model.operations_folder_name) / Path("__init__.py"),
213
+ operations_init_serializer.serialize(),
206
214
  )
207
215
 
208
216
  # write async operations init file
209
217
  if not code_model.options["no_async"]:
210
218
  operations_async_init_serializer = OperationsInitSerializer(code_model=code_model, env=env, async_mode=True)
211
219
  self._autorestapi.write_file(
212
- namespace_path / Path("aio") / Path(f"operations") / Path("__init__.py"),
220
+ namespace_path / Path("aio") / Path(code_model.operations_folder_name) / Path("__init__.py"),
213
221
  operations_async_init_serializer.serialize(),
214
222
  )
215
223
 
216
- if not code_model.options["combine_operation_files"]:
224
+ if code_model.options["combine_operation_files"]:
225
+ self._serialize_and_write_operations_file(
226
+ code_model=code_model,
227
+ env=env,
228
+ namespace_path=namespace_path,
229
+ )
230
+ else:
217
231
  for operation_group in code_model.operation_groups:
218
- self._serialize_and_write_operations_folder_process(
232
+ self._serialize_and_write_operations_file(
219
233
  code_model=code_model,
220
234
  env=env,
221
235
  namespace_path=namespace_path,
222
- operation_groups=[operation_group],
223
- filename=operation_group.filename
236
+ operation_group=operation_group,
224
237
  )
225
- else:
226
- self._serialize_and_write_operations_folder_process(
227
- code_model=code_model,
228
- env=env,
229
- namespace_path=namespace_path,
230
- operation_groups=code_model.operation_groups,
231
- filename="_operations"
232
- )
233
-
234
238
 
235
239
  def _serialize_and_write_version_file(
236
240
  self, code_model: CodeModel, namespace_path: Path, general_serializer: GeneralSerializer