@azure-tools/typespec-python 0.24.3 → 0.25.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 (132) hide show
  1. package/dist/src/code-model.d.ts.map +1 -1
  2. package/dist/src/code-model.js +1 -4
  3. package/dist/src/code-model.js.map +1 -1
  4. package/dist/src/emitter.d.ts.map +1 -1
  5. package/dist/src/emitter.js +5 -4
  6. package/dist/src/emitter.js.map +1 -1
  7. package/dist/src/external-process.d.ts +0 -9
  8. package/dist/src/external-process.d.ts.map +1 -1
  9. package/dist/src/external-process.js +1 -25
  10. package/dist/src/external-process.js.map +1 -1
  11. package/dist/src/types.d.ts.map +1 -1
  12. package/dist/src/types.js +2 -0
  13. package/dist/src/types.js.map +1 -1
  14. package/generator/LICENSE +21 -0
  15. package/generator/README.md +1 -0
  16. package/generator/dev_requirements.txt +5 -0
  17. package/generator/pygen/__init__.py +107 -0
  18. package/generator/pygen/_version.py +7 -0
  19. package/generator/pygen/black.py +71 -0
  20. package/generator/pygen/codegen/__init__.py +334 -0
  21. package/generator/pygen/codegen/_utils.py +16 -0
  22. package/generator/pygen/codegen/models/__init__.py +202 -0
  23. package/generator/pygen/codegen/models/base.py +186 -0
  24. package/generator/pygen/codegen/models/base_builder.py +119 -0
  25. package/generator/pygen/codegen/models/client.py +429 -0
  26. package/generator/pygen/codegen/models/code_model.py +239 -0
  27. package/generator/pygen/codegen/models/combined_type.py +149 -0
  28. package/generator/pygen/codegen/models/constant_type.py +129 -0
  29. package/generator/pygen/codegen/models/credential_types.py +221 -0
  30. package/generator/pygen/codegen/models/dictionary_type.py +127 -0
  31. package/generator/pygen/codegen/models/enum_type.py +238 -0
  32. package/generator/pygen/codegen/models/imports.py +291 -0
  33. package/generator/pygen/codegen/models/list_type.py +143 -0
  34. package/generator/pygen/codegen/models/lro_operation.py +143 -0
  35. package/generator/pygen/codegen/models/lro_paging_operation.py +32 -0
  36. package/generator/pygen/codegen/models/model_type.py +361 -0
  37. package/generator/pygen/codegen/models/operation.py +518 -0
  38. package/generator/pygen/codegen/models/operation_group.py +184 -0
  39. package/generator/pygen/codegen/models/paging_operation.py +156 -0
  40. package/generator/pygen/codegen/models/parameter.py +402 -0
  41. package/generator/pygen/codegen/models/parameter_list.py +390 -0
  42. package/generator/pygen/codegen/models/primitive_types.py +626 -0
  43. package/generator/pygen/codegen/models/property.py +175 -0
  44. package/generator/pygen/codegen/models/request_builder.py +189 -0
  45. package/generator/pygen/codegen/models/request_builder_parameter.py +115 -0
  46. package/generator/pygen/codegen/models/response.py +348 -0
  47. package/generator/pygen/codegen/models/utils.py +23 -0
  48. package/generator/pygen/codegen/serializers/__init__.py +570 -0
  49. package/generator/pygen/codegen/serializers/base_serializer.py +21 -0
  50. package/generator/pygen/codegen/serializers/builder_serializer.py +1454 -0
  51. package/generator/pygen/codegen/serializers/client_serializer.py +295 -0
  52. package/generator/pygen/codegen/serializers/enum_serializer.py +15 -0
  53. package/generator/pygen/codegen/serializers/general_serializer.py +212 -0
  54. package/generator/pygen/codegen/serializers/import_serializer.py +127 -0
  55. package/generator/pygen/codegen/serializers/metadata_serializer.py +198 -0
  56. package/generator/pygen/codegen/serializers/model_init_serializer.py +33 -0
  57. package/generator/pygen/codegen/serializers/model_serializer.py +287 -0
  58. package/generator/pygen/codegen/serializers/operation_groups_serializer.py +89 -0
  59. package/generator/pygen/codegen/serializers/operations_init_serializer.py +44 -0
  60. package/generator/pygen/codegen/serializers/parameter_serializer.py +221 -0
  61. package/generator/pygen/codegen/serializers/patch_serializer.py +19 -0
  62. package/generator/pygen/codegen/serializers/request_builders_serializer.py +52 -0
  63. package/generator/pygen/codegen/serializers/sample_serializer.py +163 -0
  64. package/generator/pygen/codegen/serializers/test_serializer.py +287 -0
  65. package/generator/pygen/codegen/serializers/types_serializer.py +31 -0
  66. package/generator/pygen/codegen/serializers/utils.py +68 -0
  67. package/generator/pygen/codegen/templates/client.py.jinja2 +37 -0
  68. package/generator/pygen/codegen/templates/client_container.py.jinja2 +12 -0
  69. package/generator/pygen/codegen/templates/config.py.jinja2 +73 -0
  70. package/generator/pygen/codegen/templates/config_container.py.jinja2 +16 -0
  71. package/generator/pygen/codegen/templates/conftest.py.jinja2 +28 -0
  72. package/generator/pygen/codegen/templates/enum.py.jinja2 +13 -0
  73. package/generator/pygen/codegen/templates/enum_container.py.jinja2 +10 -0
  74. package/generator/pygen/codegen/templates/init.py.jinja2 +24 -0
  75. package/generator/pygen/codegen/templates/keywords.jinja2 +19 -0
  76. package/generator/pygen/codegen/templates/lro_operation.py.jinja2 +16 -0
  77. package/generator/pygen/codegen/templates/lro_paging_operation.py.jinja2 +18 -0
  78. package/generator/pygen/codegen/templates/macros.jinja2 +12 -0
  79. package/generator/pygen/codegen/templates/metadata.json.jinja2 +167 -0
  80. package/generator/pygen/codegen/templates/model_base.py.jinja2 +899 -0
  81. package/generator/pygen/codegen/templates/model_container.py.jinja2 +13 -0
  82. package/generator/pygen/codegen/templates/model_dpg.py.jinja2 +92 -0
  83. package/generator/pygen/codegen/templates/model_init.py.jinja2 +28 -0
  84. package/generator/pygen/codegen/templates/model_msrest.py.jinja2 +92 -0
  85. package/generator/pygen/codegen/templates/operation.py.jinja2 +21 -0
  86. package/generator/pygen/codegen/templates/operation_group.py.jinja2 +75 -0
  87. package/generator/pygen/codegen/templates/operation_groups_container.py.jinja2 +20 -0
  88. package/generator/pygen/codegen/templates/operation_tools.jinja2 +74 -0
  89. package/generator/pygen/codegen/templates/operations_folder_init.py.jinja2 +17 -0
  90. package/generator/pygen/codegen/templates/packaging_templates/CHANGELOG.md.jinja2 +6 -0
  91. package/generator/pygen/codegen/templates/packaging_templates/LICENSE.jinja2 +21 -0
  92. package/generator/pygen/codegen/templates/packaging_templates/MANIFEST.in.jinja2 +8 -0
  93. package/generator/pygen/codegen/templates/packaging_templates/README.md.jinja2 +107 -0
  94. package/generator/pygen/codegen/templates/packaging_templates/dev_requirements.txt.jinja2 +9 -0
  95. package/generator/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +108 -0
  96. package/generator/pygen/codegen/templates/paging_operation.py.jinja2 +21 -0
  97. package/generator/pygen/codegen/templates/patch.py.jinja2 +19 -0
  98. package/generator/pygen/codegen/templates/pkgutil_init.py.jinja2 +1 -0
  99. package/generator/pygen/codegen/templates/request_builder.py.jinja2 +28 -0
  100. package/generator/pygen/codegen/templates/request_builders.py.jinja2 +10 -0
  101. package/generator/pygen/codegen/templates/rest_init.py.jinja2 +12 -0
  102. package/generator/pygen/codegen/templates/sample.py.jinja2 +44 -0
  103. package/generator/pygen/codegen/templates/serialization.py.jinja2 +2006 -0
  104. package/generator/pygen/codegen/templates/test.py.jinja2 +50 -0
  105. package/generator/pygen/codegen/templates/testpreparer.py.jinja2 +26 -0
  106. package/generator/pygen/codegen/templates/types.py.jinja2 +8 -0
  107. package/generator/pygen/codegen/templates/validation.py.jinja2 +38 -0
  108. package/generator/pygen/codegen/templates/vendor.py.jinja2 +98 -0
  109. package/generator/pygen/codegen/templates/version.py.jinja2 +4 -0
  110. package/generator/pygen/m2r.py +65 -0
  111. package/generator/pygen/postprocess/__init__.py +183 -0
  112. package/generator/pygen/postprocess/get_all.py +19 -0
  113. package/generator/pygen/postprocess/venvtools.py +77 -0
  114. package/generator/pygen/preprocess/__init__.py +503 -0
  115. package/generator/pygen/preprocess/helpers.py +27 -0
  116. package/generator/pygen/preprocess/python_mappings.py +222 -0
  117. package/generator/pygen/utils.py +149 -0
  118. package/generator/pygen.egg-info/PKG-INFO +25 -0
  119. package/generator/pygen.egg-info/SOURCES.txt +66 -0
  120. package/generator/pygen.egg-info/dependency_links.txt +1 -0
  121. package/generator/pygen.egg-info/requires.txt +4 -0
  122. package/generator/pygen.egg-info/top_level.txt +1 -0
  123. package/generator/requirements.txt +12 -0
  124. package/generator/setup.py +55 -0
  125. package/package.json +10 -7
  126. package/scripts/__pycache__/venvtools.cpython-38.pyc +0 -0
  127. package/scripts/install.py +49 -0
  128. package/scripts/prepare.py +38 -0
  129. package/scripts/run-python3.cjs +22 -0
  130. package/scripts/run_tsp.py +40 -0
  131. package/scripts/system-requirements.cjs +180 -0
  132. package/scripts/venvtools.py +81 -0
@@ -0,0 +1,143 @@
1
+ # pylint: disable=multiple-statements
2
+ # -------------------------------------------------------------------------
3
+ # Copyright (c) Microsoft Corporation. All rights reserved.
4
+ # Licensed under the MIT License. See License.txt in the project root for
5
+ # license information.
6
+ # --------------------------------------------------------------------------
7
+ from typing import Any, Dict, Optional, List, TYPE_CHECKING, TypeVar, Union
8
+ from .imports import FileImport
9
+ from .operation import OperationBase, Operation
10
+ from .response import LROPagingResponse, LROResponse, Response
11
+ from .imports import ImportType, TypingSection
12
+ from .request_builder import RequestBuilder
13
+ from .parameter_list import ParameterList
14
+
15
+ if TYPE_CHECKING:
16
+ from .code_model import CodeModel
17
+ from .client import Client
18
+ from . import OperationType
19
+
20
+ LROResponseType = TypeVar("LROResponseType", bound=Union[LROResponse, LROPagingResponse])
21
+
22
+
23
+ class LROOperationBase(OperationBase[LROResponseType]):
24
+ def __init__(
25
+ self,
26
+ yaml_data: Dict[str, Any],
27
+ code_model: "CodeModel",
28
+ client: "Client",
29
+ name: str,
30
+ request_builder: RequestBuilder,
31
+ parameters: ParameterList,
32
+ responses: List[LROResponseType],
33
+ exceptions: List[Response],
34
+ *,
35
+ overloads: Optional[List[Operation]] = None,
36
+ ) -> None:
37
+ super().__init__(
38
+ code_model=code_model,
39
+ client=client,
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
+ )
48
+ if not self.name.lstrip("_").startswith("begin"):
49
+ self.name = ("_begin" if self.internal else "begin_") + self.name
50
+ self.lro_options: Dict[str, Any] = self.yaml_data.get("lroOptions", {})
51
+ self._initial_operation: Optional["OperationType"] = None
52
+
53
+ @property
54
+ def initial_operation(self) -> "OperationType":
55
+ if not self._initial_operation:
56
+ raise ValueError("You need to first call client.link_lro_initial_operations before accessing")
57
+ return self._initial_operation
58
+
59
+ @initial_operation.setter
60
+ def initial_operation(self, val: "OperationType") -> None:
61
+ self._initial_operation = val
62
+
63
+ @property
64
+ def operation_type(self) -> str:
65
+ return "lro"
66
+
67
+ @property
68
+ def has_optional_return_type(self) -> bool:
69
+ return False
70
+
71
+ @property
72
+ def lro_response(self) -> Optional[LROResponseType]:
73
+ responses_with_bodies = [r for r in self.responses if r.type]
74
+ num_response_schemas = {id(r.type.yaml_data) for r in responses_with_bodies if r.type}
75
+ response = None
76
+ if len(num_response_schemas) > 1:
77
+ # choose the response that has a status code of 200
78
+ try:
79
+ response = next(r for r in responses_with_bodies if 200 in r.status_codes)
80
+ except StopIteration as exc:
81
+ raise ValueError(
82
+ "Your swagger is invalid because you have multiple response schemas for LRO"
83
+ + f" method {self.name} and none of them have a 200 status code."
84
+ ) from exc
85
+
86
+ elif num_response_schemas:
87
+ response = responses_with_bodies[0]
88
+ return response
89
+
90
+ def response_type_annotation(self, **kwargs) -> str:
91
+ lro_response = self.lro_response or next(iter(self.responses), None)
92
+ if lro_response:
93
+ return lro_response.type_annotation(**kwargs)
94
+ return "None"
95
+
96
+ def cls_type_annotation(self, *, async_mode: bool) -> str:
97
+ """We don't want the poller to show up in ClsType, so we call super() on resposne type annotation"""
98
+ return f"ClsType[{Response.type_annotation(self.responses[0], async_mode=async_mode)}]"
99
+
100
+ def get_poller_with_response_type(self, async_mode: bool) -> str:
101
+ return self.response_type_annotation(async_mode=async_mode)
102
+
103
+ def get_poller(self, async_mode: bool) -> str:
104
+ return self.responses[0].get_poller(async_mode)
105
+
106
+ def get_polling_method(self, async_mode: bool) -> str:
107
+ return self.responses[0].get_polling_method(async_mode)
108
+
109
+ def get_base_polling_method(self, async_mode: bool) -> str:
110
+ return self.responses[0].get_base_polling_method(async_mode)
111
+
112
+ def get_base_polling_method_path(self, async_mode: bool) -> str:
113
+ return self.responses[0].get_base_polling_method_path(async_mode)
114
+
115
+ def get_no_polling_method(self, async_mode: bool) -> str:
116
+ return self.responses[0].get_no_polling_method(async_mode)
117
+
118
+ def imports(self, async_mode: bool, **kwargs: Any) -> FileImport:
119
+ file_import = super().imports(async_mode, **kwargs)
120
+ if self.abstract:
121
+ return file_import
122
+ if async_mode and self.code_model.options["tracing"] and self.want_tracing:
123
+ file_import.add_submodule_import(
124
+ "azure.core.tracing.decorator_async",
125
+ "distributed_trace_async",
126
+ ImportType.SDKCORE,
127
+ )
128
+ if (
129
+ self.code_model.options["models_mode"] == "dpg"
130
+ and self.lro_response
131
+ and self.lro_response.type
132
+ and self.lro_response.type.type == "model"
133
+ ):
134
+ # used in the case if initial operation returns none
135
+ # but final call returns a model
136
+ relative_path = "..." if async_mode else ".."
137
+ file_import.add_submodule_import(f"{relative_path}_model_base", "_deserialize", ImportType.LOCAL)
138
+ file_import.add_submodule_import("typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL)
139
+ file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
140
+ return file_import
141
+
142
+
143
+ class LROOperation(LROOperationBase[LROResponse]): ...
@@ -0,0 +1,32 @@
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
7
+ from .imports import FileImport
8
+ from .lro_operation import LROOperationBase
9
+ from .paging_operation import PagingOperationBase
10
+ from .response import LROPagingResponse, Response
11
+
12
+
13
+ class LROPagingOperation(LROOperationBase[LROPagingResponse], PagingOperationBase[LROPagingResponse]):
14
+ @property
15
+ def success_status_codes(self):
16
+ """The list of all successfull status code."""
17
+ return [200]
18
+
19
+ @property
20
+ def operation_type(self) -> str:
21
+ return "lropaging"
22
+
23
+ def cls_type_annotation(self, *, async_mode: bool) -> str:
24
+ return f"ClsType[{Response.type_annotation(self.responses[0], async_mode=async_mode)}]" # pylint: disable=no-member
25
+
26
+ def imports(self, async_mode: bool, **kwargs: Any) -> FileImport:
27
+ lro_imports = LROOperationBase.imports(self, async_mode, **kwargs)
28
+ paging_imports = PagingOperationBase.imports(self, async_mode, **kwargs)
29
+
30
+ file_import = lro_imports
31
+ file_import.merge(paging_imports)
32
+ return file_import
@@ -0,0 +1,361 @@
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 enum import Enum
7
+ from collections import OrderedDict
8
+ from typing import Any, Dict, List, Optional, TYPE_CHECKING, cast
9
+ import sys
10
+ from .utils import (
11
+ add_to_pylint_disable,
12
+ NAME_LENGTH_LIMIT,
13
+ )
14
+ from .base import BaseType
15
+ from .constant_type import ConstantType
16
+ from .property import Property
17
+ from .imports import FileImport, ImportType, TypingSection
18
+
19
+ if sys.version_info >= (3, 8):
20
+ from typing import Literal # pylint: disable=no-name-in-module, ungrouped-imports
21
+ else:
22
+ from typing_extensions import Literal # type: ignore # pylint: disable=ungrouped-imports
23
+
24
+ if TYPE_CHECKING:
25
+ from .code_model import CodeModel
26
+
27
+
28
+ class UsageFlags(Enum):
29
+ Default = 0
30
+ Input = 2
31
+ Output = 4
32
+ ApiVersionEnum = 8
33
+ JsonMergePatch = 16
34
+ MultipartFormData = 32
35
+
36
+
37
+ def _get_properties(type: "ModelType", properties: List[Property]) -> List[Property]:
38
+ for parent in type.parents:
39
+ # here we're adding the properties from our parents
40
+
41
+ # need to make sure that the properties we choose from our parent also don't contain
42
+ # any of our own properties
43
+ property_names = set([p.client_name for p in properties] + [p.client_name for p in type.properties])
44
+ chosen_parent_properties = [p for p in parent.properties if p.client_name not in property_names]
45
+ properties = _get_properties(parent, chosen_parent_properties) + properties
46
+ return properties
47
+
48
+
49
+ class ModelType( # pylint: disable=abstract-method
50
+ BaseType
51
+ ): # pylint: disable=too-many-instance-attributes, too-many-public-methods
52
+ """Represents a class ready to be serialized in Python.
53
+
54
+ :param str name: The name of the class.
55
+ :param str description: The description of the class.
56
+ :param properties: the optional properties of the class.
57
+ :type properties: dict(str, str)
58
+ """
59
+
60
+ base: Literal["msrest", "dpg", "json"]
61
+
62
+ def __init__(
63
+ self,
64
+ yaml_data: Dict[str, Any],
65
+ code_model: "CodeModel",
66
+ *,
67
+ properties: Optional[List[Property]] = None,
68
+ parents: Optional[List["ModelType"]] = None,
69
+ discriminated_subtypes: Optional[Dict[str, "ModelType"]] = None,
70
+ ) -> None:
71
+ super().__init__(yaml_data=yaml_data, code_model=code_model)
72
+ self.name: str = self.yaml_data["name"]
73
+ self.max_properties: Optional[int] = self.yaml_data.get("maxProperties")
74
+ self.min_properties: Optional[int] = self.yaml_data.get("minProperties")
75
+ self.properties = properties or []
76
+ self.parents = parents or []
77
+ self.discriminated_subtypes = discriminated_subtypes or {}
78
+ self.discriminator_value: Optional[str] = self.yaml_data.get("discriminatorValue")
79
+ self._created_json_template_representation = False
80
+ self._got_polymorphic_subtypes = False
81
+ self.internal: bool = self.yaml_data.get("internal", False)
82
+ self.snake_case_name: str = self.yaml_data["snakeCaseName"]
83
+ self.page_result_model: bool = self.yaml_data.get("pageResultModel", False)
84
+ self.cross_language_definition_id: Optional[str] = self.yaml_data.get("crossLanguageDefinitionId")
85
+ self.usage: int = self.yaml_data.get("usage", 0)
86
+
87
+ @property
88
+ def is_usage_output(self) -> bool:
89
+ return self.usage == UsageFlags.Output.value
90
+
91
+ @property
92
+ def flattened_property(self) -> Optional[Property]:
93
+ try:
94
+ return next(p for p in self.properties if p.flatten)
95
+ except StopIteration:
96
+ return None
97
+
98
+ @property
99
+ def flattened_items(self) -> List[str]:
100
+ return [
101
+ item.client_name
102
+ for prop in self.properties
103
+ if isinstance(prop.type, ModelType) and prop.flatten
104
+ for item in prop.type.properties
105
+ ]
106
+
107
+ @property
108
+ def is_form_data(self) -> bool:
109
+ return any(p.is_multipart_file_input for p in self.properties)
110
+
111
+ @property
112
+ def is_xml(self) -> bool:
113
+ return self.yaml_data.get("isXml", False)
114
+
115
+ @property
116
+ def msrest_deserialization_key(self) -> str:
117
+ return self.name
118
+
119
+ @property
120
+ def is_polymorphic(self) -> bool:
121
+ return any(p.is_polymorphic for p in self.properties)
122
+
123
+ def description(self, *, is_operation_file: bool = False) -> str:
124
+ return "" if is_operation_file else self.yaml_data.get("description", self.name)
125
+
126
+ def get_declaration(self, value: Any) -> str:
127
+ return f"{self.name}()"
128
+
129
+ def __repr__(self) -> str:
130
+ return f"<{self.__class__.__name__} {self.name}>"
131
+
132
+ @property
133
+ def xml_serialization_ctxt(self) -> Optional[str]:
134
+ # object schema contains _xml_map, they don't need serialization context
135
+ return ""
136
+
137
+ @property
138
+ def xml_map_content(self) -> Optional[str]:
139
+ # This is NOT an error on the super call, we use the serialization context for "xml_map",
140
+ # but we don't want to write a serialization context for an object.
141
+ return super().xml_serialization_ctxt
142
+
143
+ @property
144
+ def discriminated_subtypes_name_mapping(self) -> Dict[str, str]:
145
+ return {k: v.name for k, v in self.discriminated_subtypes.items()}
146
+
147
+ def get_json_template_representation(
148
+ self,
149
+ *,
150
+ client_default_value_declaration: Optional[str] = None,
151
+ ) -> Any:
152
+ if self._created_json_template_representation:
153
+ return "..." # do this to avoid loop
154
+ self._created_json_template_representation = True
155
+ if self.discriminated_subtypes:
156
+ # we will instead print the discriminated subtypes
157
+ self._created_json_template_representation = False
158
+ return f'"{self.snake_case_name}"' if self.code_model.for_test else self.snake_case_name
159
+
160
+ # don't add additional properties, because there's not really a concept of
161
+ # additional properties in the template
162
+ representation = {
163
+ f'"{prop.wire_name}"': prop.get_json_template_representation(
164
+ client_default_value_declaration=client_default_value_declaration,
165
+ )
166
+ for prop in [
167
+ p for p in self.properties if not (p.is_discriminator or p.client_name == "additional_properties")
168
+ ]
169
+ }
170
+ if self.discriminator and self.discriminator_value:
171
+ representation[f'"{self.discriminator.wire_name}"'] = f'"{self.discriminator_value}"'
172
+
173
+ # once we've finished, we want to reset created_json_template_representation to false
174
+ # so we can call it again
175
+ self._created_json_template_representation = False
176
+ optional_keys = [f'"{p.wire_name}"' for p in self.properties if getattr(p, "optional", False)]
177
+ return OrderedDict(
178
+ sorted(
179
+ representation.items(),
180
+ key=lambda item: f"{1 if item[0] in optional_keys else 0}{item[0]}",
181
+ )
182
+ )
183
+
184
+ def get_polymorphic_subtypes(self, polymorphic_subtypes: List["ModelType"]) -> None:
185
+ is_polymorphic_subtype = self.discriminator_value and not self.discriminated_subtypes
186
+ if self._got_polymorphic_subtypes:
187
+ return
188
+ self._got_polymorphic_subtypes = True
189
+ if self.name not in (m.name for m in polymorphic_subtypes) and is_polymorphic_subtype:
190
+ polymorphic_subtypes.append(self)
191
+ for discriminated_subtype in self.discriminated_subtypes.values():
192
+ discriminated_subtype.get_polymorphic_subtypes(polymorphic_subtypes)
193
+ for property in self.properties:
194
+ property.get_polymorphic_subtypes(polymorphic_subtypes)
195
+ self._got_polymorphic_subtypes = False
196
+
197
+ @classmethod
198
+ def from_yaml(cls, yaml_data: Dict[str, Any], code_model: "CodeModel") -> "ModelType":
199
+ raise ValueError(
200
+ "You shouldn't call from_yaml for ModelType to avoid recursion. "
201
+ "Please initial a blank ModelType, then call .fill_instance_from_yaml on the created type."
202
+ )
203
+
204
+ def fill_instance_from_yaml(self, yaml_data: Dict[str, Any], code_model: "CodeModel") -> None:
205
+ from . import build_type
206
+
207
+ self.parents = [cast(ModelType, build_type(bm, code_model)) for bm in yaml_data.get("parents", [])]
208
+ properties = [Property.from_yaml(p, code_model) for p in yaml_data["properties"]]
209
+ self.properties = _get_properties(self, properties)
210
+ # checking to see if this is a polymorphic class
211
+ self.discriminated_subtypes = {
212
+ k: cast(ModelType, build_type(v, code_model))
213
+ for k, v in self.yaml_data.get("discriminatedSubtypes", {}).items()
214
+ }
215
+
216
+ @property
217
+ def has_readonly_or_constant_property(self) -> bool:
218
+ return any(x.readonly or x.constant or x.visibility == ["read"] for x in self.properties)
219
+
220
+ @property
221
+ def discriminator(self) -> Optional[Property]:
222
+ try:
223
+ return next(p for p in self.properties if p.is_discriminator)
224
+ except StopIteration:
225
+ return None
226
+
227
+ @property
228
+ def discriminator_property(self) -> Optional[Property]:
229
+ try:
230
+ return next(
231
+ p
232
+ for p in self.properties
233
+ if p.is_discriminator and isinstance(p.type, ConstantType) and p.type.value == self.discriminator_value
234
+ )
235
+ except StopIteration:
236
+ return None
237
+
238
+ @property
239
+ def pylint_disable(self) -> str:
240
+ retval: str = ""
241
+ if len(self.properties) > 10:
242
+ retval = add_to_pylint_disable(retval, "too-many-instance-attributes")
243
+ if len(self.name) > NAME_LENGTH_LIMIT:
244
+ retval = add_to_pylint_disable(retval, "name-too-long")
245
+ return retval
246
+
247
+ @property
248
+ def init_pylint_disable(self) -> str:
249
+ retval: str = ""
250
+ if len(self.properties) > 23:
251
+ retval = add_to_pylint_disable(retval, "too-many-locals")
252
+ return retval
253
+
254
+
255
+ class JSONModelType(ModelType):
256
+ base = "json"
257
+
258
+ def type_annotation(self, **kwargs: Any) -> str:
259
+ return "ET.Element" if self.is_xml else "JSON"
260
+
261
+ @property
262
+ def serialization_type(self) -> str:
263
+ return "object"
264
+
265
+ def docstring_type(self, **kwargs: Any) -> str:
266
+ return "ET.Element" if self.is_xml else "JSON"
267
+
268
+ def docstring_text(self, **kwargs: Any) -> str:
269
+ return "XML Element" if self.is_xml else "JSON object"
270
+
271
+ @property
272
+ def instance_check_template(self) -> str:
273
+ return "isinstance({}, MutableMapping)"
274
+
275
+ def imports(self, **kwargs: Any) -> FileImport:
276
+ file_import = FileImport(self.code_model)
277
+ file_import.add_submodule_import("typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL)
278
+ file_import.define_mutable_mapping_type()
279
+ if self.is_xml:
280
+ file_import.add_submodule_import("xml.etree", "ElementTree", ImportType.STDLIB, alias="ET")
281
+ return file_import
282
+
283
+
284
+ class GeneratedModelType(ModelType): # pylint: disable=abstract-method
285
+ def type_annotation(self, **kwargs: Any) -> str:
286
+ is_operation_file = kwargs.pop("is_operation_file", False)
287
+ skip_quote = kwargs.get("skip_quote", False)
288
+ module_name = "_models." if kwargs.get("need_module_name", True) else ""
289
+ file_name = f"{self.code_model.models_filename}." if self.internal else ""
290
+ retval = module_name + file_name + self.name
291
+ return retval if is_operation_file or skip_quote else f'"{retval}"'
292
+
293
+ def docstring_type(self, **kwargs: Any) -> str:
294
+ return f"~{self.code_model.namespace}.models.{self.type_annotation(need_module_name=False, skip_quote=True)}"
295
+
296
+ def docstring_text(self, **kwargs: Any) -> str:
297
+ return self.name
298
+
299
+ @property
300
+ def type_description(self) -> str:
301
+ return self.name
302
+
303
+ def imports(self, **kwargs: Any) -> FileImport:
304
+ file_import = super().imports(**kwargs)
305
+ relative_path = kwargs.pop("relative_path", None)
306
+ if relative_path:
307
+ # add import for models in operations or _types file
308
+ file_import.add_submodule_import(
309
+ relative_path,
310
+ "models",
311
+ ImportType.LOCAL,
312
+ alias="_models",
313
+ typing_section=(TypingSection.TYPING if kwargs.get("model_typing") else TypingSection.REGULAR),
314
+ )
315
+ if self.is_form_data:
316
+ file_import.add_submodule_import(
317
+ relative_path,
318
+ "_model_base",
319
+ ImportType.LOCAL,
320
+ typing_section=(TypingSection.TYPING if kwargs.get("model_typing") else TypingSection.REGULAR),
321
+ )
322
+ return file_import
323
+
324
+
325
+ class MsrestModelType(GeneratedModelType):
326
+ base = "msrest"
327
+
328
+ @property
329
+ def serialization_type(self) -> str:
330
+ return self.type_annotation(skip_quote=True) if self.internal else self.name
331
+
332
+ @property
333
+ def instance_check_template(self) -> str:
334
+ return "isinstance({}, msrest.Model)"
335
+
336
+ def imports(self, **kwargs: Any) -> FileImport:
337
+ file_import = super().imports(**kwargs)
338
+ file_import.add_submodule_import("typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL)
339
+ return file_import
340
+
341
+
342
+ class DPGModelType(GeneratedModelType):
343
+ base = "dpg"
344
+
345
+ @property
346
+ def serialization_type(self) -> str:
347
+ return (
348
+ self.type_annotation(skip_quote=True)
349
+ if self.internal
350
+ else self.type_annotation(need_module_name=False, skip_quote=True)
351
+ )
352
+
353
+ @property
354
+ def instance_check_template(self) -> str:
355
+ return "isinstance({}, _model_base.Model)"
356
+
357
+ def imports(self, **kwargs: Any) -> FileImport:
358
+ file_import = super().imports(**kwargs)
359
+ if self.flattened_property:
360
+ file_import.add_submodule_import("typing", "Any", ImportType.STDLIB)
361
+ return file_import