@autorest/python 5.12.4 → 5.13.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 (47) hide show
  1. package/ChangeLog.md +173 -109
  2. package/autorest/black/__init__.py +7 -1
  3. package/autorest/codegen/__init__.py +12 -2
  4. package/autorest/codegen/models/__init__.py +2 -1
  5. package/autorest/codegen/models/client.py +22 -19
  6. package/autorest/codegen/models/constant_schema.py +0 -4
  7. package/autorest/codegen/models/credential_schema.py +3 -3
  8. package/autorest/codegen/models/dictionary_schema.py +1 -1
  9. package/autorest/codegen/models/enum_schema.py +2 -2
  10. package/autorest/codegen/models/imports.py +90 -50
  11. package/autorest/codegen/models/list_schema.py +1 -1
  12. package/autorest/codegen/models/lro_operation.py +15 -9
  13. package/autorest/codegen/models/object_schema.py +2 -2
  14. package/autorest/codegen/models/operation.py +39 -30
  15. package/autorest/codegen/models/operation_group.py +5 -14
  16. package/autorest/codegen/models/paging_operation.py +9 -9
  17. package/autorest/codegen/models/parameter.py +37 -11
  18. package/autorest/codegen/models/parameter_list.py +11 -4
  19. package/autorest/codegen/models/primitive_schemas.py +2 -2
  20. package/autorest/codegen/models/property.py +1 -1
  21. package/autorest/codegen/models/request_builder.py +7 -6
  22. package/autorest/codegen/models/request_builder_parameter.py +5 -0
  23. package/autorest/codegen/models/request_builder_parameter_list.py +1 -0
  24. package/autorest/codegen/models/schema_response.py +1 -1
  25. package/autorest/codegen/serializers/__init__.py +75 -71
  26. package/autorest/codegen/serializers/builder_serializer.py +68 -37
  27. package/autorest/codegen/serializers/client_serializer.py +14 -3
  28. package/autorest/codegen/serializers/general_serializer.py +7 -7
  29. package/autorest/codegen/serializers/import_serializer.py +44 -46
  30. package/autorest/codegen/serializers/metadata_serializer.py +12 -10
  31. package/autorest/codegen/serializers/utils.py +5 -1
  32. package/autorest/codegen/templates/config.py.jinja2 +2 -7
  33. package/autorest/codegen/templates/lro_operation.py.jinja2 +3 -1
  34. package/autorest/codegen/templates/lro_paging_operation.py.jinja2 +2 -0
  35. package/autorest/codegen/templates/operation.py.jinja2 +8 -2
  36. package/autorest/codegen/templates/operation_group.py.jinja2 +2 -1
  37. package/autorest/codegen/templates/operation_groups_container.py.jinja2 +1 -0
  38. package/autorest/codegen/templates/operation_tools.jinja2 +3 -2
  39. package/autorest/codegen/templates/paging_operation.py.jinja2 +3 -1
  40. package/autorest/codegen/templates/request_builder.py.jinja2 +2 -7
  41. package/autorest/codegen/templates/service_client.py.jinja2 +1 -1
  42. package/autorest/multiapi/models/imports.py +1 -1
  43. package/autorest/multiapi/serializers/import_serializer.py +1 -1
  44. package/autorest/namer/name_converter.py +1 -1
  45. package/package.json +2 -2
  46. package/run-python3.js +1 -7
  47. package/venvtools.py +2 -2
@@ -178,7 +178,7 @@ class EnumSchema(BaseSchema):
178
178
 
179
179
  def imports(self) -> FileImport:
180
180
  file_import = FileImport()
181
- file_import.add_from_import("typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL)
181
+ file_import.add_submodule_import("typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL)
182
182
  file_import.merge(self.enum_type.imports())
183
183
  return file_import
184
184
 
@@ -186,7 +186,7 @@ class EnumSchema(BaseSchema):
186
186
  imports = self.imports()
187
187
  # we import every enum since we can get extremely long imports
188
188
  # if we import my name
189
- imports.add_from_import("." + self.enum_file_name, "*", ImportType.LOCAL)
189
+ imports.add_submodule_import("." + self.enum_file_name, "*", ImportType.LOCAL)
190
190
  return imports
191
191
 
192
192
  class HiddenModelEnumSchema(EnumSchema):
@@ -4,8 +4,7 @@
4
4
  # license information.
5
5
  # --------------------------------------------------------------------------
6
6
  from enum import Enum
7
- from typing import Dict, Optional, Set, Tuple, Union
8
-
7
+ from typing import Dict, List, Optional, Tuple, Union, Set
9
8
 
10
9
  class ImportType(str, Enum):
11
10
  STDLIB = "stdlib"
@@ -18,81 +17,122 @@ class TypingSection(str, Enum):
18
17
  CONDITIONAL = "conditional" # is a typing import when we're dealing with files that py2 will use, else regular
19
18
  TYPING = "typing" # never a typing import
20
19
 
20
+ class ImportModel:
21
+ def __init__(
22
+ self,
23
+ typing_section: TypingSection,
24
+ import_type: ImportType,
25
+ module_name: str,
26
+ *,
27
+ submodule_name: Optional[str] = None,
28
+ alias: Optional[str] = None,
29
+ ):
30
+ self.typing_section = typing_section
31
+ self.import_type = import_type
32
+ self.module_name = module_name
33
+ self.submodule_name = submodule_name
34
+ self.alias = alias
35
+
36
+ def __eq__(self, other):
37
+ try:
38
+ return (
39
+ self.typing_section == other.typing_section and
40
+ self.import_type == other.import_type and
41
+ self.module_name == other.module_name and
42
+ self.submodule_name == other.submodule_name and
43
+ self.alias == other.alias
44
+ )
45
+ except AttributeError:
46
+ return False
47
+
48
+ def __hash__(self):
49
+ retval: int = 0
50
+ for attr in dir(self):
51
+ if attr[0] != "_":
52
+ retval += hash(getattr(self, attr))
53
+ return retval
21
54
 
22
55
  class FileImport:
23
56
  def __init__(
24
57
  self,
25
- imports: Dict[
26
- TypingSection,
27
- Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]]
28
- ] = None
58
+ imports: List[ImportModel] = None
29
59
  ) -> None:
30
- # Basic implementation
31
- # First level dict: TypingSection
32
- # Second level dict: ImportType
33
- # Third level dict: the package name.
34
- # Fourth level set: None if this import is a "import", the name to import if it's a "from"
35
- self._imports: Dict[
36
- TypingSection,
37
- Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]]
38
- ] = imports or dict()
60
+ self.imports = imports or []
39
61
  # has sync and async type definitions
40
62
  self.type_definitions: Dict[str, Tuple[str, str]] = {}
41
63
 
42
- def _add_import(
43
- self,
44
- from_section: str,
45
- import_type: ImportType,
46
- name_import: Optional[Union[str, Tuple[str, str]]] = None,
47
- typing_section: TypingSection = TypingSection.REGULAR
48
- ) -> None:
49
- self._imports.setdefault(
50
- typing_section, dict()
51
- ).setdefault(
52
- import_type, dict()
53
- ).setdefault(
54
- from_section, set()
55
- ).add(name_import)
64
+ def _append_import(self, import_model: ImportModel) -> None:
65
+ if not any(
66
+ i for i in self.imports
67
+ if all(
68
+ getattr(i, attr) == getattr(import_model, attr)
69
+ for attr in dir(i)
70
+ if attr[0] != "_"
71
+ )
72
+ ):
73
+ self.imports.append(import_model)
74
+
75
+ def get_imports_from_section(self, typing_section: TypingSection) -> List[ImportModel]:
76
+ return [i for i in self.imports if i.typing_section == typing_section]
56
77
 
57
- def add_from_import(
78
+ def add_submodule_import(
58
79
  self,
59
- from_section: str,
60
- name_import: str,
80
+ module_name: str,
81
+ submodule_name: str,
61
82
  import_type: ImportType,
62
83
  typing_section: TypingSection = TypingSection.REGULAR,
63
84
  alias: Optional[str] = None,
64
85
  ) -> None:
65
86
  """Add an import to this import block.
66
87
  """
67
- self._add_import(
68
- from_section, import_type, (name_import, alias) if alias else name_import, typing_section
69
- )
88
+ self._append_import(ImportModel(
89
+ typing_section=typing_section,
90
+ import_type=import_type,
91
+ module_name=module_name,
92
+ submodule_name=submodule_name,
93
+ alias=alias,
94
+ ))
70
95
 
71
96
  def add_import(
72
97
  self,
73
- name_import: str,
98
+ module_name: str,
74
99
  import_type: ImportType,
75
100
  typing_section: TypingSection = TypingSection.REGULAR
76
101
  ) -> None:
77
102
  # Implementation detail: a regular import is just a "from" with no from
78
- self._add_import(name_import, import_type, None, typing_section)
79
-
80
- @property
81
- def imports(self) -> Dict[
82
- TypingSection,
83
- Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]]
84
- ]:
85
- return self._imports
103
+ self._append_import(ImportModel(
104
+ typing_section=typing_section,
105
+ import_type=import_type,
106
+ module_name=module_name,
107
+ ))
86
108
 
87
109
  def define_mypy_type(self, type_name: str, type_value: str, async_type_value: Optional[str] = None):
88
- self._add_import("typing", ImportType.STDLIB, "TypeVar", TypingSection.CONDITIONAL)
110
+ self.add_submodule_import("typing", "TypeVar", ImportType.STDLIB, TypingSection.CONDITIONAL)
89
111
  self.type_definitions[type_name] = (type_value, async_type_value or type_value)
90
112
 
91
113
  def merge(self, file_import: "FileImport") -> None:
92
114
  """Merge the given file import format."""
93
- for typing_section, import_type_dict in file_import.imports.items():
94
- for import_type, package_list in import_type_dict.items():
95
- for package_name, module_list in package_list.items():
96
- for module_name in module_list:
97
- self._add_import(package_name, import_type, module_name, typing_section)
115
+ for i in file_import.imports:
116
+ self._append_import(i)
98
117
  self.type_definitions.update(file_import.type_definitions)
118
+
119
+ def to_dict(self) -> Dict[
120
+ TypingSection,
121
+ Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]]
122
+ ]:
123
+ retval: Dict[
124
+ TypingSection,
125
+ Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]]
126
+ ] = dict()
127
+ for i in self.imports:
128
+ name_import: Optional[Union[str, Tuple[str, str]]] = None
129
+ if i.submodule_name:
130
+ name_import = (i.submodule_name, i.alias) if i.alias else i.submodule_name
131
+ retval.setdefault(
132
+ i.typing_section, dict()
133
+ ).setdefault(
134
+ i.import_type, dict()
135
+ ).setdefault(
136
+ i.module_name, set()
137
+ ).add(name_import)
138
+ return retval
@@ -108,6 +108,6 @@ class ListSchema(BaseSchema):
108
108
 
109
109
  def imports(self) -> FileImport:
110
110
  file_import = FileImport()
111
- file_import.add_from_import("typing", "List", ImportType.STDLIB, TypingSection.CONDITIONAL)
111
+ file_import.add_submodule_import("typing", "List", ImportType.STDLIB, TypingSection.CONDITIONAL)
112
112
  file_import.merge(self.element_type.imports())
113
113
  return file_import
@@ -140,28 +140,30 @@ class LROOperation(Operation):
140
140
  file_import = super().imports_for_multiapi(async_mode)
141
141
  poller_import_path = ".".join(self.get_poller_path(async_mode).split(".")[:-1])
142
142
  poller = self.get_poller(async_mode)
143
- file_import.add_from_import(poller_import_path, poller, ImportType.AZURECORE, TypingSection.CONDITIONAL)
143
+ file_import.add_submodule_import(poller_import_path, poller, ImportType.AZURECORE, TypingSection.CONDITIONAL)
144
144
  return file_import
145
145
 
146
146
  def imports(self, async_mode: bool) -> FileImport:
147
147
  file_import = super().imports(async_mode)
148
- file_import.add_from_import("typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL)
148
+ file_import.add_submodule_import("typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL)
149
149
 
150
150
  poller_import_path = ".".join(self.get_poller_path(async_mode).split(".")[:-1])
151
151
  poller = self.get_poller(async_mode)
152
- file_import.add_from_import(poller_import_path, poller, ImportType.AZURECORE)
152
+ file_import.add_submodule_import(poller_import_path, poller, ImportType.AZURECORE)
153
153
 
154
154
  default_polling_method_import_path = ".".join(
155
155
  self.get_default_polling_method_path(async_mode, self.code_model.options['azure_arm']).split(".")[:-1]
156
156
  )
157
157
  default_polling_method = self.get_default_polling_method(async_mode, self.code_model.options['azure_arm'])
158
- file_import.add_from_import(default_polling_method_import_path, default_polling_method, ImportType.AZURECORE)
158
+ file_import.add_submodule_import(
159
+ default_polling_method_import_path, default_polling_method, ImportType.AZURECORE
160
+ )
159
161
 
160
162
  default_no_polling_method_import_path = ".".join(
161
163
  self.get_default_no_polling_method_path(async_mode).split(".")[:-1]
162
164
  )
163
165
  default_no_polling_method = self.get_default_no_polling_method(async_mode)
164
- file_import.add_from_import(
166
+ file_import.add_submodule_import(
165
167
  default_no_polling_method_import_path, default_no_polling_method, ImportType.AZURECORE
166
168
  )
167
169
 
@@ -169,10 +171,14 @@ class LROOperation(Operation):
169
171
  self.get_base_polling_method_path(async_mode).split(".")[:-1]
170
172
  )
171
173
  base_polling_method = self.get_base_polling_method(async_mode)
172
- file_import.add_from_import(base_polling_method_import_path, base_polling_method, ImportType.AZURECORE)
174
+ file_import.add_submodule_import(base_polling_method_import_path, base_polling_method, ImportType.AZURECORE)
173
175
 
174
176
  if async_mode:
175
- file_import.add_from_import("typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL)
176
- if self.lro_response and self.lro_response.has_body and not self.code_model.options["models_mode"]:
177
- file_import.add_from_import("json", "loads", import_type=ImportType.STDLIB, alias="_loads")
177
+ file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL)
178
+ if self.code_model.options["tracing"] and self.want_tracing:
179
+ file_import.add_submodule_import(
180
+ f"azure.core.tracing.decorator{'_async' if async_mode else ''}",
181
+ f"distributed_trace{'_async' if async_mode else ''}",
182
+ ImportType.AZURECORE,
183
+ )
178
184
  return file_import
@@ -213,7 +213,7 @@ class ObjectSchema(BaseSchema): # pylint: disable=too-many-instance-attributes
213
213
  def imports(self) -> FileImport:
214
214
  file_import = FileImport()
215
215
  if self.is_exception:
216
- file_import.add_from_import("azure.core.exceptions", "HttpResponseError", ImportType.AZURECORE)
216
+ file_import.add_submodule_import("azure.core.exceptions", "HttpResponseError", ImportType.AZURECORE)
217
217
  return file_import
218
218
 
219
219
  class HiddenModelObjectSchema(ObjectSchema):
@@ -240,7 +240,7 @@ class HiddenModelObjectSchema(ObjectSchema):
240
240
 
241
241
  def imports(self) -> FileImport:
242
242
  file_import = FileImport()
243
- file_import.add_from_import("typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL)
243
+ file_import.add_submodule_import("typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL)
244
244
  return file_import
245
245
 
246
246
  def get_object_schema(code_model) -> Type[ObjectSchema]:
@@ -147,7 +147,7 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
147
147
 
148
148
  def _imports_shared(self, async_mode: bool) -> FileImport: # pylint: disable=unused-argument
149
149
  file_import = FileImport()
150
- file_import.add_from_import("typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL)
150
+ file_import.add_submodule_import("typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL)
151
151
  for param in self.parameters.method:
152
152
  file_import.merge(param.imports())
153
153
 
@@ -159,11 +159,12 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
159
159
  if response.has_body:
160
160
  file_import.merge(cast(BaseSchema, response.schema).imports())
161
161
 
162
- if len([r for r in self.responses if r.has_body]) > 1:
163
- file_import.add_from_import("typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL)
162
+ response_types = [r.operation_type_annotation for r in self.responses if r.has_body]
163
+ if len(set(response_types)) > 1:
164
+ file_import.add_submodule_import("typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL)
164
165
 
165
166
  if self.is_stream_response:
166
- file_import.add_from_import("typing", "IO", ImportType.STDLIB, TypingSection.CONDITIONAL)
167
+ file_import.add_submodule_import("typing", "IO", ImportType.STDLIB, TypingSection.CONDITIONAL)
167
168
  return file_import
168
169
 
169
170
 
@@ -174,42 +175,37 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
174
175
  file_import = self._imports_shared(async_mode)
175
176
 
176
177
  # Exceptions
177
- file_import.add_from_import("azure.core.exceptions", "map_error", ImportType.AZURECORE)
178
+ file_import.add_submodule_import("azure.core.exceptions", "map_error", ImportType.AZURECORE)
178
179
  if self.code_model.options["azure_arm"]:
179
- file_import.add_from_import("azure.mgmt.core.exceptions", "ARMErrorFormat", ImportType.AZURECORE)
180
- file_import.add_from_import("azure.core.exceptions", "HttpResponseError", ImportType.AZURECORE)
181
-
182
-
183
- file_import.add_import("functools", ImportType.STDLIB)
184
- file_import.add_from_import("typing", "Callable", ImportType.STDLIB, TypingSection.CONDITIONAL)
185
- file_import.add_from_import("typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL)
186
- file_import.add_from_import("typing", "Dict", ImportType.STDLIB, TypingSection.CONDITIONAL)
187
- file_import.add_from_import("typing", "TypeVar", ImportType.STDLIB, TypingSection.CONDITIONAL)
188
- file_import.add_from_import("typing", "Generic", ImportType.STDLIB, TypingSection.CONDITIONAL)
189
- file_import.add_from_import("azure.core.pipeline", "PipelineResponse", ImportType.AZURECORE)
190
- file_import.add_from_import("azure.core.rest", "HttpRequest", ImportType.AZURECORE)
180
+ file_import.add_submodule_import("azure.mgmt.core.exceptions", "ARMErrorFormat", ImportType.AZURECORE)
181
+ file_import.add_submodule_import("azure.core.exceptions", "HttpResponseError", ImportType.AZURECORE)
182
+
183
+ file_import.add_submodule_import("typing", "Callable", ImportType.STDLIB, TypingSection.CONDITIONAL)
184
+ file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL)
185
+ file_import.add_submodule_import("typing", "Dict", ImportType.STDLIB, TypingSection.CONDITIONAL)
186
+ file_import.add_submodule_import("typing", "TypeVar", ImportType.STDLIB, TypingSection.CONDITIONAL)
187
+ file_import.add_submodule_import("azure.core.pipeline", "PipelineResponse", ImportType.AZURECORE)
188
+ file_import.add_submodule_import("azure.core.rest", "HttpRequest", ImportType.AZURECORE)
191
189
  if async_mode:
192
- file_import.add_from_import("azure.core.pipeline.transport", "AsyncHttpResponse", ImportType.AZURECORE)
190
+ file_import.add_submodule_import("azure.core.pipeline.transport", "AsyncHttpResponse", ImportType.AZURECORE)
193
191
  else:
194
- file_import.add_from_import("azure.core.pipeline.transport", "HttpResponse", ImportType.AZURECORE)
192
+ file_import.add_submodule_import("azure.core.pipeline.transport", "HttpResponse", ImportType.AZURECORE)
195
193
 
196
- # Deprecation
197
- # FIXME: Replace with "the YAML contains deprecated:true"
198
- if True: # pylint: disable=using-constant-test
194
+ if self.deprecated:
199
195
  file_import.add_import("warnings", ImportType.STDLIB)
200
196
 
201
197
  if self.code_model.options["builders_visibility"] != "embedded":
202
198
  builder_group_name = self.request_builder.builder_group_name
203
199
  rest_import_path = "..." if async_mode else ".."
204
200
  if builder_group_name:
205
- file_import.add_from_import(
201
+ file_import.add_submodule_import(
206
202
  f"{rest_import_path}{self.code_model.rest_layer_name}",
207
- name_import=builder_group_name,
203
+ builder_group_name,
208
204
  import_type=ImportType.LOCAL,
209
205
  alias=f"rest_{builder_group_name}"
210
206
  )
211
207
  else:
212
- file_import.add_from_import(
208
+ file_import.add_submodule_import(
213
209
  rest_import_path,
214
210
  self.code_model.rest_layer_name,
215
211
  import_type=ImportType.LOCAL,
@@ -219,7 +215,7 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
219
215
  file_import.merge(self.request_builder.imports())
220
216
  if self.code_model.need_request_converter:
221
217
  relative_path = "..." if async_mode else ".."
222
- file_import.add_from_import(
218
+ file_import.add_submodule_import(
223
219
  f"{relative_path}_vendor", "_convert_request", ImportType.LOCAL
224
220
  )
225
221
  if self.code_model.options["version_tolerant"] and (
@@ -227,6 +223,12 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
227
223
  any(r for r in self.responses if r.has_body)
228
224
  ):
229
225
  file_import.define_mypy_type("JSONType", "Any")
226
+ if self.code_model.options["tracing"] and self.want_tracing:
227
+ file_import.add_submodule_import(
228
+ f"azure.core.tracing.decorator{'_async' if async_mode else ''}",
229
+ f"distributed_trace{'_async' if async_mode else ''}",
230
+ ImportType.AZURECORE,
231
+ )
230
232
  return file_import
231
233
 
232
234
  def _get_body_param_from_body_kwarg(self, body_kwarg: Parameter) -> Parameter:
@@ -301,6 +303,15 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
301
303
  parameters, multiple_content_type_parameters = create_parameters(
302
304
  yaml_data, code_model, parameter_creator
303
305
  )
306
+ parameter_list = parameter_list_creator(code_model, parameters, schema_requests)
307
+ multiple_content_type_parameter_list = parameter_list_creator(
308
+ code_model, multiple_content_type_parameters, schema_requests
309
+ )
310
+
311
+ if len(parameter_list.content_types) > 1:
312
+ for p in parameter_list.parameters:
313
+ if p.rest_api_name == "Content-Type":
314
+ p.is_keyword_only = True
304
315
 
305
316
  return cls(
306
317
  code_model=code_model,
@@ -308,10 +319,8 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
308
319
  name=name,
309
320
  description=yaml_data["language"]["python"]["description"],
310
321
  api_versions=set(value_dict["version"] for value_dict in yaml_data["apiVersions"]),
311
- parameters=parameter_list_creator(code_model, parameters, schema_requests),
312
- multiple_content_type_parameters=parameter_list_creator(
313
- code_model, multiple_content_type_parameters, schema_requests
314
- ),
322
+ parameters=parameter_list,
323
+ multiple_content_type_parameters=multiple_content_type_parameter_list,
315
324
  schema_requests=schema_requests,
316
325
  summary=yaml_data["language"]["python"].get("summary"),
317
326
  responses=[SchemaResponse.from_yaml(yaml) for yaml in yaml_data.get("responses", [])],
@@ -58,23 +58,14 @@ class OperationGroup(BaseModel):
58
58
 
59
59
  def imports(self, async_mode: bool) -> FileImport:
60
60
  file_import = FileImport()
61
- file_import.add_from_import("azure.core.exceptions", "ClientAuthenticationError", ImportType.AZURECORE)
62
- file_import.add_from_import("azure.core.exceptions", "ResourceNotFoundError", ImportType.AZURECORE)
63
- file_import.add_from_import("azure.core.exceptions", "ResourceExistsError", ImportType.AZURECORE)
61
+ file_import.add_submodule_import("azure.core.exceptions", "ClientAuthenticationError", ImportType.AZURECORE)
62
+ file_import.add_submodule_import("azure.core.exceptions", "ResourceNotFoundError", ImportType.AZURECORE)
63
+ file_import.add_submodule_import("azure.core.exceptions", "ResourceExistsError", ImportType.AZURECORE)
64
64
  for operation in self.operations:
65
65
  file_import.merge(operation.imports(async_mode))
66
- if self.code_model.options["tracing"]:
67
- if async_mode:
68
- file_import.add_from_import(
69
- "azure.core.tracing.decorator_async", "distributed_trace_async", ImportType.AZURECORE,
70
- )
71
- else:
72
- file_import.add_from_import(
73
- "azure.core.tracing.decorator", "distributed_trace", ImportType.AZURECORE,
74
- )
75
66
  local_path = "..." if async_mode else ".."
76
67
  if self.code_model.has_schemas and self.code_model.options["models_mode"]:
77
- file_import.add_from_import(local_path, "models", ImportType.LOCAL, alias="_models")
68
+ file_import.add_submodule_import(local_path, "models", ImportType.LOCAL, alias="_models")
78
69
  if self.code_model.options["builders_visibility"] == "embedded" and async_mode:
79
70
  if not self.code_model.options["combine_operation_files"]:
80
71
  operation_group_name = "" if self.is_empty_operation_group else self.name
@@ -88,7 +79,7 @@ class OperationGroup(BaseModel):
88
79
  python3_only = self.code_model.options["python3_only"]
89
80
  typed_sync_operation_file = self.code_model.options["add_python3_operation_files"]
90
81
  suffix = "_py3" if typed_sync_operation_file and not python3_only else ""
91
- file_import.add_from_import(
82
+ file_import.add_submodule_import(
92
83
  f"...{self.code_model.operations_folder_name}.{self.filename}{suffix}",
93
84
  request_builder.name,
94
85
  import_type=ImportType.LOCAL
@@ -125,9 +125,9 @@ class PagingOperation(Operation):
125
125
  def _imports_shared(self, async_mode: bool) -> FileImport:
126
126
  file_import = super()._imports_shared(async_mode)
127
127
  if async_mode:
128
- file_import.add_from_import("typing", "AsyncIterable", ImportType.STDLIB, TypingSection.CONDITIONAL)
128
+ file_import.add_submodule_import("typing", "AsyncIterable", ImportType.STDLIB, TypingSection.CONDITIONAL)
129
129
  else:
130
- file_import.add_from_import("typing", "Iterable", ImportType.STDLIB, TypingSection.CONDITIONAL)
130
+ file_import.add_submodule_import("typing", "Iterable", ImportType.STDLIB, TypingSection.CONDITIONAL)
131
131
  if (
132
132
  self.next_request_builder and
133
133
  self.code_model.options["builders_visibility"] == "embedded"
@@ -141,26 +141,26 @@ class PagingOperation(Operation):
141
141
  pager_import_path = ".".join(self.get_pager_path(async_mode).split(".")[:-1])
142
142
  pager = self.get_pager(async_mode)
143
143
 
144
- file_import.add_from_import(pager_import_path, pager, ImportType.AZURECORE, TypingSection.CONDITIONAL)
144
+ file_import.add_submodule_import(pager_import_path, pager, ImportType.AZURECORE, TypingSection.CONDITIONAL)
145
145
 
146
146
  return file_import
147
147
 
148
148
  def imports(self, async_mode: bool) -> FileImport:
149
149
  file_import = super(PagingOperation, self).imports(async_mode)
150
+ # operation adds an import for distributed_trace_async, we don't want it
151
+ file_import.imports = [i for i in file_import.imports if not i.submodule_name == "distributed_trace_async"]
150
152
 
151
153
  pager_import_path = ".".join(self.get_pager_path(async_mode).split(".")[:-1])
152
154
  pager = self.get_pager(async_mode)
153
155
 
154
- file_import.add_from_import(pager_import_path, pager, ImportType.AZURECORE)
156
+ file_import.add_submodule_import(pager_import_path, pager, ImportType.AZURECORE)
155
157
 
156
158
  if async_mode:
157
- file_import.add_from_import("azure.core.async_paging", "AsyncList", ImportType.AZURECORE)
159
+ file_import.add_submodule_import("azure.core.async_paging", "AsyncList", ImportType.AZURECORE)
158
160
 
159
- if self.code_model.options["tracing"]:
160
- file_import.add_from_import(
161
+ if self.code_model.options["tracing"] and self.want_tracing:
162
+ file_import.add_submodule_import(
161
163
  "azure.core.tracing.decorator", "distributed_trace", ImportType.AZURECORE,
162
164
  )
163
- if not self.code_model.options["models_mode"]:
164
- file_import.add_from_import("json", "loads", ImportType.STDLIB, alias="_loads")
165
165
 
166
166
  return file_import
@@ -68,7 +68,7 @@ class Parameter(BaseModel): # pylint: disable=too-many-instance-attributes, too
68
68
  grouped_by: Optional["Parameter"] = None,
69
69
  original_parameter: Optional["Parameter"] = None,
70
70
  client_default_value: Optional[Any] = None,
71
- keyword_only: bool = False,
71
+ keyword_only: Optional[bool] = None,
72
72
  content_types: Optional[List[str]] = None,
73
73
  ) -> None:
74
74
  super().__init__(yaml_data)
@@ -98,6 +98,8 @@ class Parameter(BaseModel): # pylint: disable=too-many-instance-attributes, too
98
98
  self.content_types = content_types or []
99
99
  self.body_kwargs: List[Parameter] = []
100
100
  self.is_body_kwarg = False
101
+ self.need_import = True
102
+ self.is_kwarg = (self.rest_api_name == "Content-Type" or (self.constant and self.rest_api_name != "Accept"))
101
103
 
102
104
  def __hash__(self) -> int:
103
105
  return hash(self.serialized_name)
@@ -110,6 +112,14 @@ class Parameter(BaseModel): # pylint: disable=too-many-instance-attributes, too
110
112
  if description:
111
113
  description += " "
112
114
  description += f"{self.schema.extra_description_information}"
115
+ if isinstance(self.schema, ConstantSchema) and not self.constant:
116
+ if description:
117
+ description += " "
118
+ description += f"Possible values are {self.schema.get_declaration(self.schema.value)} or {None}."
119
+ if self.has_default_value and not any(
120
+ l for l in ["default value is", "default is"] if l in description.lower()
121
+ ):
122
+ description += f" Default value is {self.default_value_declaration}."
113
123
  if self.constant:
114
124
  description += " Note that overriding this default value may result in unsupported behavior."
115
125
  return description
@@ -231,7 +241,12 @@ class Parameter(BaseModel): # pylint: disable=too-many-instance-attributes, too
231
241
  default_value_declaration = "None"
232
242
  else:
233
243
  if isinstance(self.schema, ConstantSchema):
234
- default_value = self.schema.get_declaration(self.schema.value)
244
+ if (self.required or
245
+ self.is_content_type or
246
+ not self.code_model.options["default_optional_constants_to_none"]):
247
+ default_value = self.schema.get_declaration(self.schema.value)
248
+ else:
249
+ default_value = None
235
250
  default_value_declaration = default_value
236
251
  else:
237
252
  default_value = self.schema.default_value
@@ -297,22 +312,26 @@ class Parameter(BaseModel): # pylint: disable=too-many-instance-attributes, too
297
312
  origin_name = f"self._config.{self.serialized_name}"
298
313
  return origin_name
299
314
 
300
- @property
301
- def is_kwarg(self) -> bool:
302
- # this means "am I in **kwargs?"
303
- return self.rest_api_name == "Content-Type" or (self.constant and self.rest_api_name != "Accept")
304
-
305
315
  @property
306
316
  def is_keyword_only(self) -> bool:
307
317
  # this means in async mode, I am documented like def hello(positional_1, *, me!)
308
- return self._keyword_only
318
+ return self._keyword_only or False
319
+
320
+ @is_keyword_only.setter
321
+ def is_keyword_only(self, val: bool) -> None:
322
+ self._keyword_only = val
323
+ self.is_kwarg = False
309
324
 
310
325
  @property
311
326
  def is_hidden(self) -> bool:
312
- return self.serialized_name in _HIDDEN_KWARGS or (
327
+ return self.serialized_name in _HIDDEN_KWARGS and self.is_kwarg or (
313
328
  self.yaml_data["implementation"] == "Client" and self.constant
314
329
  )
315
330
 
331
+ @property
332
+ def is_content_type(self) -> bool:
333
+ return self.rest_api_name == "Content-Type" and self.location == ParameterLocation.Header
334
+
316
335
  @property
317
336
  def is_positional(self) -> bool:
318
337
  return self.in_method_signature and not (self.is_keyword_only or self.is_kwarg)
@@ -354,9 +373,9 @@ class Parameter(BaseModel): # pylint: disable=too-many-instance-attributes, too
354
373
  def imports(self) -> FileImport:
355
374
  file_import = self.schema.imports()
356
375
  if not self.required:
357
- file_import.add_from_import("typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL)
376
+ file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL)
358
377
  if self.has_multiple_content_types or self._is_io_json:
359
- file_import.add_from_import("typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL)
378
+ file_import.add_submodule_import("typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL)
360
379
 
361
380
  return file_import
362
381
 
@@ -364,6 +383,8 @@ class ParameterOnlyPathAndBodyPositional(Parameter):
364
383
 
365
384
  @property
366
385
  def is_keyword_only(self) -> bool:
386
+ if self._keyword_only is not None:
387
+ return self._keyword_only
367
388
  return self.in_method_signature and not (
368
389
  self.is_hidden or
369
390
  self.location == ParameterLocation.Path or
@@ -372,6 +393,11 @@ class ParameterOnlyPathAndBodyPositional(Parameter):
372
393
  self.is_kwarg
373
394
  )
374
395
 
396
+ @is_keyword_only.setter
397
+ def is_keyword_only(self, val: bool) -> None:
398
+ self._keyword_only = val
399
+ self.is_kwarg = False
400
+
375
401
  def get_parameter(code_model):
376
402
  if code_model.options["only_path_and_body_params_positional"]:
377
403
  return ParameterOnlyPathAndBodyPositional