@autorest/python 5.16.0 → 5.19.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 (96) hide show
  1. package/ChangeLog.md +79 -4
  2. package/README.md +30 -4
  3. package/autorest/__init__.py +1 -1
  4. package/autorest/codegen/__init__.py +55 -211
  5. package/autorest/codegen/models/__init__.py +116 -83
  6. package/autorest/codegen/models/base_builder.py +49 -88
  7. package/autorest/codegen/models/base_model.py +1 -1
  8. package/autorest/codegen/models/{base_schema.py → base_type.py} +61 -39
  9. package/autorest/codegen/models/client.py +165 -53
  10. package/autorest/codegen/models/code_model.py +122 -257
  11. package/autorest/codegen/models/combined_type.py +107 -0
  12. package/autorest/codegen/models/{constant_schema.py → constant_type.py} +49 -40
  13. package/autorest/codegen/models/credential_types.py +224 -0
  14. package/autorest/codegen/models/dictionary_type.py +131 -0
  15. package/autorest/codegen/models/enum_type.py +195 -0
  16. package/autorest/codegen/models/imports.py +80 -2
  17. package/autorest/codegen/models/list_type.py +149 -0
  18. package/autorest/codegen/models/lro_operation.py +79 -156
  19. package/autorest/codegen/models/lro_paging_operation.py +28 -11
  20. package/autorest/codegen/models/model_type.py +262 -0
  21. package/autorest/codegen/models/operation.py +331 -298
  22. package/autorest/codegen/models/operation_group.py +54 -91
  23. package/autorest/codegen/models/paging_operation.py +82 -123
  24. package/autorest/codegen/models/parameter.py +289 -396
  25. package/autorest/codegen/models/parameter_list.py +355 -360
  26. package/autorest/codegen/models/primitive_types.py +544 -0
  27. package/autorest/codegen/models/property.py +123 -139
  28. package/autorest/codegen/models/request_builder.py +130 -102
  29. package/autorest/codegen/models/request_builder_parameter.py +112 -100
  30. package/autorest/codegen/models/response.py +325 -0
  31. package/autorest/codegen/models/utils.py +12 -19
  32. package/autorest/codegen/serializers/__init__.py +55 -37
  33. package/autorest/codegen/serializers/builder_serializer.py +695 -1144
  34. package/autorest/codegen/serializers/client_serializer.py +92 -89
  35. package/autorest/codegen/serializers/general_serializer.py +15 -69
  36. package/autorest/codegen/serializers/import_serializer.py +7 -4
  37. package/autorest/codegen/serializers/metadata_serializer.py +15 -104
  38. package/autorest/codegen/serializers/model_base_serializer.py +49 -36
  39. package/autorest/codegen/serializers/model_generic_serializer.py +8 -6
  40. package/autorest/codegen/serializers/model_init_serializer.py +2 -4
  41. package/autorest/codegen/serializers/model_python3_serializer.py +22 -16
  42. package/autorest/codegen/serializers/operation_groups_serializer.py +7 -13
  43. package/autorest/codegen/serializers/parameter_serializer.py +174 -0
  44. package/autorest/codegen/serializers/request_builders_serializer.py +13 -30
  45. package/autorest/codegen/serializers/utils.py +0 -140
  46. package/autorest/codegen/templates/MANIFEST.in.jinja2 +1 -0
  47. package/autorest/codegen/templates/{service_client.py.jinja2 → client.py.jinja2} +10 -7
  48. package/autorest/codegen/templates/config.py.jinja2 +13 -13
  49. package/autorest/codegen/templates/enum.py.jinja2 +4 -4
  50. package/autorest/codegen/templates/enum_container.py.jinja2 +1 -1
  51. package/autorest/codegen/templates/init.py.jinja2 +2 -2
  52. package/autorest/codegen/templates/lro_operation.py.jinja2 +4 -1
  53. package/autorest/codegen/templates/lro_paging_operation.py.jinja2 +4 -1
  54. package/autorest/codegen/templates/metadata.json.jinja2 +33 -33
  55. package/autorest/codegen/templates/model.py.jinja2 +23 -24
  56. package/autorest/codegen/templates/model_container.py.jinja2 +2 -1
  57. package/autorest/codegen/templates/model_init.py.jinja2 +3 -5
  58. package/autorest/codegen/templates/operation.py.jinja2 +6 -8
  59. package/autorest/codegen/templates/operation_group.py.jinja2 +21 -8
  60. package/autorest/codegen/templates/operation_groups_container.py.jinja2 +2 -2
  61. package/autorest/codegen/templates/operation_tools.jinja2 +11 -3
  62. package/autorest/codegen/templates/paging_operation.py.jinja2 +2 -2
  63. package/autorest/codegen/templates/request_builder.py.jinja2 +10 -15
  64. package/autorest/codegen/templates/request_builders.py.jinja2 +1 -1
  65. package/autorest/codegen/templates/serialization.py.jinja2 +2006 -0
  66. package/autorest/codegen/templates/setup.py.jinja2 +13 -3
  67. package/autorest/codegen/templates/vendor.py.jinja2 +11 -1
  68. package/autorest/jsonrpc/server.py +15 -3
  69. package/autorest/m4reformatter/__init__.py +1126 -0
  70. package/autorest/multiapi/models/client.py +12 -2
  71. package/autorest/multiapi/models/code_model.py +1 -1
  72. package/autorest/multiapi/serializers/__init__.py +18 -4
  73. package/autorest/multiapi/templates/multiapi_config.py.jinja2 +3 -3
  74. package/autorest/multiapi/templates/multiapi_init.py.jinja2 +2 -2
  75. package/autorest/multiapi/templates/multiapi_operations_mixin.py.jinja2 +4 -4
  76. package/autorest/multiapi/templates/multiapi_service_client.py.jinja2 +9 -9
  77. package/autorest/postprocess/__init__.py +202 -0
  78. package/autorest/postprocess/get_all.py +19 -0
  79. package/autorest/postprocess/venvtools.py +73 -0
  80. package/autorest/preprocess/__init__.py +210 -0
  81. package/autorest/preprocess/helpers.py +54 -0
  82. package/autorest/{namer → preprocess}/python_mappings.py +21 -16
  83. package/package.json +2 -2
  84. package/autorest/codegen/models/credential_model.py +0 -55
  85. package/autorest/codegen/models/credential_schema.py +0 -95
  86. package/autorest/codegen/models/credential_schema_policy.py +0 -73
  87. package/autorest/codegen/models/dictionary_schema.py +0 -106
  88. package/autorest/codegen/models/enum_schema.py +0 -225
  89. package/autorest/codegen/models/list_schema.py +0 -135
  90. package/autorest/codegen/models/object_schema.py +0 -303
  91. package/autorest/codegen/models/primitive_schemas.py +0 -495
  92. package/autorest/codegen/models/request_builder_parameter_list.py +0 -249
  93. package/autorest/codegen/models/schema_request.py +0 -55
  94. package/autorest/codegen/models/schema_response.py +0 -141
  95. package/autorest/namer/__init__.py +0 -23
  96. package/autorest/namer/name_converter.py +0 -509
@@ -3,218 +3,141 @@
3
3
  # Licensed under the MIT License. See License.txt in the project root for
4
4
  # license information.
5
5
  # --------------------------------------------------------------------------
6
- import logging
7
- from typing import Dict, List, Any, Optional, Set, cast, TYPE_CHECKING
6
+ from typing import Any, Dict, Optional, List, TYPE_CHECKING, TypeVar, Union
8
7
  from .imports import FileImport
9
- from .operation import Operation
10
- from .parameter_list import ParameterList
11
- from .schema_response import SchemaResponse
8
+ from .operation import OperationBase, Operation
9
+ from .response import LROPagingResponse, LROResponse, Response
12
10
  from .imports import ImportType, TypingSection
13
- from .base_schema import BaseSchema
14
- from .schema_request import SchemaRequest
15
11
  from .request_builder import RequestBuilder
12
+ from .parameter_list import ParameterList
16
13
 
17
14
  if TYPE_CHECKING:
18
15
  from .code_model import CodeModel
19
16
 
20
- _LOGGER = logging.getLogger(__name__)
17
+ LROResponseType = TypeVar(
18
+ "LROResponseType", bound=Union[LROResponse, LROPagingResponse]
19
+ )
21
20
 
22
21
 
23
- class LROOperation(Operation):
22
+ class LROOperationBase(OperationBase[LROResponseType]):
24
23
  def __init__(
25
24
  self,
26
25
  yaml_data: Dict[str, Any],
27
26
  code_model: "CodeModel",
28
- request_builder: RequestBuilder,
29
27
  name: str,
30
- description: str,
31
- api_versions: Set[str],
28
+ request_builder: RequestBuilder,
32
29
  parameters: ParameterList,
33
- multiple_content_type_parameters: ParameterList,
34
- schema_requests: List[SchemaRequest],
35
- summary: Optional[str] = None,
36
- responses: Optional[List[SchemaResponse]] = None,
37
- exceptions: Optional[List[SchemaResponse]] = None,
38
- want_description_docstring: bool = True,
39
- want_tracing: bool = True,
30
+ responses: List[LROResponseType],
31
+ exceptions: List[Response],
40
32
  *,
33
+ overloads: Optional[List[Operation]] = None,
34
+ public: bool = True,
35
+ want_tracing: bool = True,
41
36
  abstract: bool = False,
42
37
  ) -> None:
43
38
  super().__init__(
44
- yaml_data,
45
- code_model,
46
- request_builder,
47
- name,
48
- description,
49
- api_versions,
50
- parameters,
51
- multiple_content_type_parameters,
52
- schema_requests,
53
- summary,
54
- responses,
55
- exceptions,
56
- want_description_docstring,
39
+ code_model=code_model,
40
+ yaml_data=yaml_data,
41
+ name=name,
42
+ request_builder=request_builder,
43
+ parameters=parameters,
44
+ responses=responses,
45
+ exceptions=exceptions,
46
+ overloads=overloads,
47
+ public=public,
57
48
  want_tracing=want_tracing,
58
49
  abstract=abstract,
59
50
  )
60
- self.lro_options = yaml_data.get("extensions", {}).get(
61
- "x-ms-long-running-operation-options", {}
62
- )
63
51
  self.name = "begin_" + self.name
52
+ self.lro_options: Dict[str, Any] = self.yaml_data.get("lroOptions", {})
64
53
 
65
54
  @property
66
- def lro_response(self) -> Optional[SchemaResponse]:
67
- if not self.responses:
68
- return None
69
- responses_with_bodies = [r for r in self.responses if r.has_body]
70
- num_response_schemas = {r.schema for r in responses_with_bodies}
55
+ def operation_type(self) -> str:
56
+ return "lro"
57
+
58
+ @property
59
+ def has_optional_return_type(self) -> bool:
60
+ return False
61
+
62
+ @property
63
+ def lro_response(self) -> Optional[LROResponseType]:
64
+ responses_with_bodies = [r for r in self.responses if r.type]
65
+ num_response_schemas = {
66
+ id(r.type.yaml_data) for r in responses_with_bodies if r.type
67
+ }
71
68
  response = None
72
69
  if len(num_response_schemas) > 1:
73
70
  # choose the response that has a status code of 200
74
- responses_with_200_status_codes = [
75
- r for r in responses_with_bodies if 200 in r.status_codes
76
- ]
77
71
  try:
78
- response = responses_with_200_status_codes[0]
79
- schema_types = {r.schema for r in responses_with_bodies}
80
- response_schema = cast(BaseSchema, response.schema).serialization_type
81
- _LOGGER.warning(
82
- "Multiple schema types in responses: %s. Choosing: %s",
83
- schema_types,
84
- response_schema,
72
+ response = next(
73
+ r for r in responses_with_bodies if 200 in r.status_codes
85
74
  )
86
- except IndexError:
75
+ except StopIteration:
87
76
  raise ValueError(
88
77
  f"Your swagger is invalid because you have multiple response schemas for LRO"
89
- + f" method {self.python_name} and none of them have a 200 status code."
78
+ + f" method {self.name} and none of them have a 200 status code."
90
79
  )
91
80
 
92
81
  elif num_response_schemas:
93
82
  response = responses_with_bodies[0]
94
83
  return response
95
84
 
85
+ def cls_type_annotation(self, *, async_mode: bool) -> str:
86
+ """We don't want the poller to show up in ClsType, so we call super() on resposne type annotation"""
87
+ return f"ClsType[{Response.type_annotation(self.responses[0], async_mode=async_mode)}]"
88
+
96
89
  @property
97
90
  def initial_operation(self) -> Operation:
98
- operation = Operation(
99
- yaml_data={},
91
+ """Initial operation that creates the first call for LRO polling"""
92
+ return Operation(
93
+ yaml_data=self.yaml_data,
100
94
  code_model=self.code_model,
101
95
  request_builder=self.code_model.lookup_request_builder(id(self.yaml_data)),
102
96
  name=self.name[5:] + "_initial",
103
- description="",
104
- api_versions=self.api_versions,
97
+ overloads=self.overloads,
105
98
  parameters=self.parameters,
106
- schema_requests=self.schema_requests,
107
- multiple_content_type_parameters=self.multiple_content_type_parameters,
108
- summary=self.summary,
109
- responses=self.responses,
110
- want_description_docstring=False,
99
+ responses=[
100
+ Response(r.yaml_data, self.code_model, headers=r.headers, type=r.type)
101
+ for r in self.responses
102
+ ],
103
+ exceptions=self.exceptions,
104
+ public=False,
111
105
  want_tracing=False,
112
106
  )
113
- operation.request_builder = self.request_builder
114
- return operation
115
-
116
- @property
117
- def has_optional_return_type(self) -> bool:
118
- """An LROOperation will never have an optional return type, we will always return a poller"""
119
- return False
120
-
121
- def _get_lro_extension(self, extension_base, async_mode, *, azure_arm=None):
122
- extension_name = extension_base + ("-async" if async_mode else "-sync")
123
- extension = self.yaml_data["extensions"][extension_name]
124
- arm_extension = None
125
- if azure_arm is not None:
126
- arm_extension = "azure-arm" if azure_arm else "data-plane"
127
- return extension[arm_extension] if arm_extension else extension
128
-
129
- def get_poller_path(self, async_mode: bool) -> str:
130
- return self._get_lro_extension("poller", async_mode)
131
107
 
132
108
  def get_poller(self, async_mode: bool) -> str:
133
- return self.get_poller_path(async_mode).split(".")[-1]
134
-
135
- def get_default_polling_method_path(self, async_mode: bool, azure_arm: bool) -> str:
136
- return self._get_lro_extension(
137
- "default-polling-method", async_mode, azure_arm=azure_arm
138
- )
109
+ return self.responses[0].get_poller(async_mode)
139
110
 
140
- def get_default_polling_method(self, async_mode: bool, azure_arm: bool) -> str:
141
- return self.get_default_polling_method_path(async_mode, azure_arm).split(".")[
142
- -1
143
- ]
144
-
145
- def get_default_no_polling_method_path(self, async_mode: bool) -> str:
146
- return self._get_lro_extension("default-no-polling-method", async_mode)
147
-
148
- def get_default_no_polling_method(self, async_mode: bool) -> str:
149
- return self.get_default_no_polling_method_path(async_mode).split(".")[-1]
150
-
151
- def get_base_polling_method_path(self, async_mode: bool) -> str:
152
- return self._get_lro_extension("base-polling-method", async_mode)
111
+ def get_polling_method(self, async_mode: bool) -> str:
112
+ return self.responses[0].get_polling_method(async_mode)
153
113
 
154
114
  def get_base_polling_method(self, async_mode: bool) -> str:
155
- return self.get_base_polling_method_path(async_mode).split(".")[-1]
115
+ return self.responses[0].get_base_polling_method(async_mode)
156
116
 
157
- def imports_for_multiapi(self, async_mode: bool) -> FileImport:
158
- file_import = super().imports_for_multiapi(async_mode)
159
- poller_import_path = ".".join(self.get_poller_path(async_mode).split(".")[:-1])
160
- poller = self.get_poller(async_mode)
161
- file_import.add_submodule_import(
162
- poller_import_path, poller, ImportType.AZURECORE, TypingSection.CONDITIONAL
163
- )
164
- return file_import
165
-
166
- def imports(self, async_mode: bool, is_python3_file: bool) -> FileImport:
167
- file_import = self._imports_base(async_mode, is_python3_file)
168
- file_import.add_submodule_import(
169
- "typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL
170
- )
171
-
172
- poller_import_path = ".".join(self.get_poller_path(async_mode).split(".")[:-1])
173
- poller = self.get_poller(async_mode)
174
- file_import.add_submodule_import(
175
- poller_import_path, poller, ImportType.AZURECORE
176
- )
177
-
178
- default_polling_method_import_path = ".".join(
179
- self.get_default_polling_method_path(
180
- async_mode, self.code_model.options["azure_arm"]
181
- ).split(".")[:-1]
182
- )
183
- default_polling_method = self.get_default_polling_method(
184
- async_mode, self.code_model.options["azure_arm"]
185
- )
186
- file_import.add_submodule_import(
187
- default_polling_method_import_path,
188
- default_polling_method,
189
- ImportType.AZURECORE,
190
- )
117
+ def get_base_polling_method_path(self, async_mode: bool) -> str:
118
+ return self.responses[0].get_base_polling_method_path(async_mode)
191
119
 
192
- default_no_polling_method_import_path = ".".join(
193
- self.get_default_no_polling_method_path(async_mode).split(".")[:-1]
194
- )
195
- default_no_polling_method = self.get_default_no_polling_method(async_mode)
196
- file_import.add_submodule_import(
197
- default_no_polling_method_import_path,
198
- default_no_polling_method,
199
- ImportType.AZURECORE,
200
- )
120
+ def get_no_polling_method(self, async_mode: bool) -> str:
121
+ return self.responses[0].get_no_polling_method(async_mode)
201
122
 
202
- base_polling_method_import_path = ".".join(
203
- self.get_base_polling_method_path(async_mode).split(".")[:-1]
204
- )
205
- base_polling_method = self.get_base_polling_method(async_mode)
206
- file_import.add_submodule_import(
207
- base_polling_method_import_path, base_polling_method, ImportType.AZURECORE
208
- )
209
- file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
123
+ def imports(
124
+ self, async_mode: bool, is_python3_file: bool, **kwargs: Any
125
+ ) -> FileImport:
126
+ file_import = super().imports(async_mode, is_python3_file, **kwargs)
127
+ if self.abstract:
128
+ return file_import
210
129
  if async_mode:
211
130
  file_import.add_submodule_import(
212
- "typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL
213
- )
214
- if self.code_model.options["tracing"] and self.want_tracing:
215
- file_import.add_submodule_import(
216
- f"azure.core.tracing.decorator{'_async' if async_mode else ''}",
217
- f"distributed_trace{'_async' if async_mode else ''}",
131
+ f"azure.core.tracing.decorator_async",
132
+ f"distributed_trace_async",
218
133
  ImportType.AZURECORE,
219
134
  )
135
+ file_import.add_submodule_import(
136
+ "typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL
137
+ )
138
+ file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
220
139
  return file_import
140
+
141
+
142
+ class LROOperation(LROOperationBase[LROResponse]):
143
+ ...
@@ -3,21 +3,38 @@
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 Any
6
7
  from .imports import FileImport
7
- from .lro_operation import LROOperation
8
- from .paging_operation import PagingOperation
8
+ from .lro_operation import LROOperationBase
9
+ from .paging_operation import PagingOperationBase
10
+ from .response import LROPagingResponse, Response
9
11
 
10
12
 
11
- class LROPagingOperation(PagingOperation, LROOperation):
12
- def imports(self, async_mode: bool, is_python3_file: bool) -> FileImport:
13
- lro_imports = LROOperation.imports(self, async_mode, is_python3_file)
14
- paging_imports = PagingOperation.imports(self, async_mode, is_python3_file)
13
+ class LROPagingOperation(
14
+ LROOperationBase[LROPagingResponse], PagingOperationBase[LROPagingResponse]
15
+ ):
16
+ @property
17
+ def success_status_codes(self):
18
+ """The list of all successfull status code."""
19
+ return [200]
20
+
21
+ @property
22
+ def operation_type(self) -> str:
23
+ return "lropaging"
24
+
25
+ def cls_type_annotation(self, *, async_mode: bool) -> str:
26
+ return f"ClsType[{Response.type_annotation(self.responses[0], async_mode=async_mode)}]" # pylint: disable=no-member
27
+
28
+ def imports(
29
+ self, async_mode: bool, is_python3_file: bool, **kwargs: Any
30
+ ) -> FileImport:
31
+ lro_imports = LROOperationBase.imports(
32
+ self, async_mode, is_python3_file, **kwargs
33
+ )
34
+ paging_imports = PagingOperationBase.imports(
35
+ self, async_mode, is_python3_file, **kwargs
36
+ )
15
37
 
16
38
  file_import = lro_imports
17
39
  file_import.merge(paging_imports)
18
40
  return file_import
19
-
20
- @property
21
- def success_status_code(self):
22
- """The list of all successfull status code."""
23
- return [200]
@@ -0,0 +1,262 @@
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 Any, Dict, List, Optional, TYPE_CHECKING, cast
7
+
8
+ from autorest.codegen.models.utils import add_to_pylint_disable
9
+ from .base_type import BaseType
10
+ from .property import Property
11
+ from .imports import FileImport, ImportType, TypingSection
12
+
13
+ if TYPE_CHECKING:
14
+ from .code_model import CodeModel
15
+
16
+
17
+ def _get_properties(type: "ModelType", properties: List[Property]) -> List[Property]:
18
+ for parent in type.parents:
19
+ # here we're adding the properties from our parents
20
+
21
+ # need to make sure that the properties we choose from our parent also don't contain
22
+ # any of our own properties
23
+ property_names = set(
24
+ [p.client_name for p in properties]
25
+ + [p.client_name for p in type.properties]
26
+ )
27
+ chosen_parent_properties = [
28
+ p for p in parent.properties if p.client_name not in property_names
29
+ ]
30
+ properties = _get_properties(parent, chosen_parent_properties) + properties
31
+ return properties
32
+
33
+
34
+ class ModelType(BaseType): # pylint: disable=too-many-instance-attributes
35
+ """Represents a class ready to be serialized in Python.
36
+
37
+ :param str name: The name of the class.
38
+ :param str description: The description of the class.
39
+ :param properties: the optional properties of the class.
40
+ :type properties: dict(str, str)
41
+ """
42
+
43
+ def __init__(
44
+ self,
45
+ yaml_data: Dict[str, Any],
46
+ code_model: "CodeModel",
47
+ *,
48
+ properties: Optional[List[Property]] = None,
49
+ parents: Optional[List["ModelType"]] = None,
50
+ discriminated_subtypes: Optional[Dict[str, "ModelType"]] = None,
51
+ ) -> None:
52
+ super().__init__(yaml_data=yaml_data, code_model=code_model)
53
+ self.name: str = self.yaml_data["name"]
54
+ self.max_properties: Optional[int] = self.yaml_data.get("maxProperties")
55
+ self.min_properties: Optional[int] = self.yaml_data.get("minProperties")
56
+ self.properties = properties or []
57
+ self.parents = parents or []
58
+ self.discriminated_subtypes = discriminated_subtypes or {}
59
+ self.discriminator_value: Optional[str] = self.yaml_data.get(
60
+ "discriminatorValue"
61
+ )
62
+ self._created_json_template_representation = False
63
+ self.is_public: bool = self.yaml_data.get("isPublic", True)
64
+ self.snake_case_name: str = self.yaml_data["snakeCaseName"]
65
+
66
+ @property
67
+ def is_xml(self) -> bool:
68
+ return self.yaml_data.get("isXml", False)
69
+
70
+ @property
71
+ def serialization_type(self) -> str:
72
+ if self.code_model.options["models_mode"]:
73
+ return self.name
74
+ return "object"
75
+
76
+ def type_annotation(self, **kwargs: Any) -> str:
77
+ if self.code_model.options["models_mode"]:
78
+ is_operation_file = kwargs.pop("is_operation_file", False)
79
+ if self.is_public:
80
+ retval = f"_models.{self.name}"
81
+ return retval if is_operation_file else f'"{retval}"'
82
+ return self.name if is_operation_file else f'"{self.name}"'
83
+ return "ET.Element" if self.is_xml else "JSON"
84
+
85
+ def docstring_type(self, **kwargs: Any) -> str:
86
+ if self.code_model.options["models_mode"]:
87
+ return f"~{self.code_model.namespace}.models.{self.name}"
88
+ return "ET.Element" if self.is_xml else "JSON"
89
+
90
+ def description(self, *, is_operation_file: bool = False) -> str:
91
+ return "" if is_operation_file else self.yaml_data.get("description", self.name)
92
+
93
+ def docstring_text(self, **kwargs: Any) -> str:
94
+ if self.code_model.options["models_mode"]:
95
+ return self.name
96
+ return "XML Element" if self.is_xml else "JSON object"
97
+
98
+ def get_declaration(self, value: Any) -> str:
99
+ return f"{self.name}()"
100
+
101
+ def __repr__(self) -> str:
102
+ return f"<{self.__class__.__name__} {self.name}>"
103
+
104
+ @property
105
+ def xml_serialization_ctxt(self) -> Optional[str]:
106
+ # object schema contains _xml_map, they don't need serialization context
107
+ return ""
108
+
109
+ @property
110
+ def xml_map_content(self) -> Optional[str]:
111
+ # This is NOT an error on the super call, we use the serialization context for "xml_map",
112
+ # but we don't want to write a serialization context for an object.
113
+ return super().xml_serialization_ctxt
114
+
115
+ @property
116
+ def discriminated_subtypes_name_mapping(self) -> Dict[str, str]:
117
+ return {k: v.name for k, v in self.discriminated_subtypes.items()}
118
+
119
+ def get_json_template_representation(
120
+ self,
121
+ *,
122
+ optional: bool = True,
123
+ client_default_value_declaration: Optional[str] = None,
124
+ description: Optional[str] = None,
125
+ ) -> Any:
126
+ if self._created_json_template_representation:
127
+ return "..." # do this to avoid loop
128
+ self._created_json_template_representation = True
129
+ if self.discriminated_subtypes:
130
+ # we will instead print the discriminated subtypes
131
+ self._created_json_template_representation = False
132
+ return self.snake_case_name
133
+
134
+ # don't add additional properties, because there's not really a concept of
135
+ # additional properties in the template
136
+ representation = {
137
+ f'"{prop.rest_api_name}"': prop.get_json_template_representation(
138
+ optional=optional,
139
+ client_default_value_declaration=client_default_value_declaration,
140
+ description=description,
141
+ )
142
+ for prop in [
143
+ p
144
+ for p in self.properties
145
+ if not (p.is_discriminator or p.client_name == "additional_properties")
146
+ ]
147
+ }
148
+ if self.discriminator and self.discriminator_value:
149
+ representation[
150
+ f'"{self.discriminator.rest_api_name}"'
151
+ ] = f'"{self.discriminator_value}"'
152
+
153
+ # once we've finished, we want to reset created_json_template_representation to false
154
+ # so we can call it again
155
+ self._created_json_template_representation = False
156
+ return representation
157
+
158
+ def get_polymorphic_subtypes(self, polymorphic_subtypes: List["ModelType"]) -> None:
159
+ is_polymorphic_subtype = (
160
+ self.discriminator_value and not self.discriminated_subtypes
161
+ )
162
+ if (
163
+ self.name not in (m.name for m in polymorphic_subtypes)
164
+ and is_polymorphic_subtype
165
+ ):
166
+ polymorphic_subtypes.append(self)
167
+ for discriminated_subtype in self.discriminated_subtypes.values():
168
+ discriminated_subtype.get_polymorphic_subtypes(polymorphic_subtypes)
169
+ for property in self.properties:
170
+ property.get_polymorphic_subtypes(polymorphic_subtypes)
171
+
172
+ @classmethod
173
+ def from_yaml(
174
+ cls, yaml_data: Dict[str, Any], code_model: "CodeModel"
175
+ ) -> "ModelType":
176
+ raise ValueError(
177
+ "You shouldn't call from_yaml for ModelType to avoid recursion. "
178
+ "Please initial a blank ModelType, then call .fill_instance_from_yaml on the created type."
179
+ )
180
+
181
+ def fill_instance_from_yaml(
182
+ self, yaml_data: Dict[str, Any], code_model: "CodeModel"
183
+ ) -> None:
184
+ from . import build_type
185
+
186
+ self.parents = [
187
+ cast(ModelType, build_type(bm, code_model))
188
+ for bm in yaml_data.get("parents", [])
189
+ ]
190
+ properties = [
191
+ Property.from_yaml(p, code_model) for p in yaml_data["properties"]
192
+ ]
193
+ self.properties = _get_properties(self, properties)
194
+ # checking to see if this is a polymorphic class
195
+ self.discriminated_subtypes = {
196
+ k: cast(ModelType, build_type(v, code_model))
197
+ for k, v in self.yaml_data.get("discriminatedSubtypes", {}).items()
198
+ }
199
+
200
+ @property
201
+ def has_readonly_or_constant_property(self) -> bool:
202
+ return any(x.readonly or x.constant for x in self.properties)
203
+
204
+ @property
205
+ def discriminator(self) -> Optional[Property]:
206
+ try:
207
+ return next(p for p in self.properties if p.is_discriminator)
208
+ except StopIteration:
209
+ return None
210
+
211
+ @property
212
+ def instance_check_template(self) -> str:
213
+ if self.code_model.options["models_mode"]:
214
+ return "isinstance({}, msrest.Model)"
215
+ return "isinstance({}, MutableMapping)"
216
+
217
+ @property
218
+ def pylint_disable(self) -> str:
219
+ retval: str = ""
220
+ if len(self.properties) > 10:
221
+ retval = add_to_pylint_disable(retval, "too-many-instance-attributes")
222
+ return retval
223
+
224
+ @property
225
+ def init_pylint_disable(self) -> str:
226
+ retval: str = ""
227
+ if len(self.properties) > 23:
228
+ retval = add_to_pylint_disable(retval, "too-many-locals")
229
+ return retval
230
+
231
+ def imports(self, **kwargs: Any) -> FileImport:
232
+ file_import = FileImport()
233
+ relative_path = kwargs.pop("relative_path", None)
234
+ if self.code_model.options["models_mode"] and relative_path:
235
+ # add import for models in operations file
236
+ if self.is_public:
237
+ file_import.add_submodule_import(
238
+ relative_path, "models", ImportType.LOCAL, alias="_models"
239
+ )
240
+ else:
241
+ # a little hacky, but we only do this for version tolerant
242
+ # models files, which are all python3 only
243
+ models_filename = self.code_model.get_models_filename(
244
+ is_python3_file=True
245
+ )
246
+ file_import.add_submodule_import(
247
+ f"{relative_path}models.{models_filename}",
248
+ self.name,
249
+ ImportType.LOCAL,
250
+ )
251
+ if self.code_model.options["models_mode"]:
252
+ return file_import
253
+ file_import.add_submodule_import(
254
+ "typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL
255
+ )
256
+ file_import.add_import("sys", ImportType.STDLIB)
257
+ file_import.define_mutable_mapping_type()
258
+ if self.is_xml:
259
+ file_import.add_submodule_import(
260
+ "xml.etree", "ElementTree", ImportType.STDLIB, alias="ET"
261
+ )
262
+ return file_import