@typespec/http-client-python 0.4.3 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/dist/emitter/emitter.d.ts.map +1 -1
  2. package/dist/emitter/emitter.js +85 -24
  3. package/dist/emitter/emitter.js.map +1 -1
  4. package/dist/emitter/lib.d.ts +1 -0
  5. package/dist/emitter/lib.d.ts.map +1 -1
  6. package/dist/emitter/lib.js +1 -0
  7. package/dist/emitter/lib.js.map +1 -1
  8. package/dist/emitter/run-python3.d.ts +2 -0
  9. package/dist/emitter/run-python3.d.ts.map +1 -0
  10. package/dist/emitter/run-python3.js +19 -0
  11. package/dist/emitter/run-python3.js.map +1 -0
  12. package/dist/emitter/system-requirements.d.ts +17 -0
  13. package/dist/emitter/system-requirements.d.ts.map +1 -0
  14. package/dist/emitter/system-requirements.js +167 -0
  15. package/dist/emitter/system-requirements.js.map +1 -0
  16. package/emitter/src/emitter.ts +88 -23
  17. package/emitter/src/lib.ts +2 -0
  18. package/emitter/src/run-python3.ts +20 -0
  19. package/emitter/src/system-requirements.ts +261 -0
  20. package/emitter/temp/tsconfig.tsbuildinfo +1 -1
  21. package/eng/scripts/ci/regenerate.ts +16 -4
  22. package/eng/scripts/setup/__pycache__/venvtools.cpython-38.pyc +0 -0
  23. package/eng/scripts/setup/build.ts +16 -0
  24. package/eng/scripts/setup/build_pygen_wheel.py +40 -0
  25. package/eng/scripts/setup/install.py +9 -3
  26. package/eng/scripts/setup/install.ts +32 -0
  27. package/eng/scripts/setup/prepare.py +3 -1
  28. package/eng/scripts/setup/prepare.ts +11 -0
  29. package/eng/scripts/setup/run-python3.ts +1 -6
  30. package/generator/build/lib/pygen/__init__.py +107 -0
  31. package/generator/build/lib/pygen/_version.py +7 -0
  32. package/generator/build/lib/pygen/black.py +71 -0
  33. package/generator/build/lib/pygen/codegen/__init__.py +357 -0
  34. package/generator/build/lib/pygen/codegen/_utils.py +17 -0
  35. package/generator/build/lib/pygen/codegen/models/__init__.py +204 -0
  36. package/generator/build/lib/pygen/codegen/models/base.py +186 -0
  37. package/generator/build/lib/pygen/codegen/models/base_builder.py +118 -0
  38. package/generator/build/lib/pygen/codegen/models/client.py +435 -0
  39. package/generator/build/lib/pygen/codegen/models/code_model.py +237 -0
  40. package/generator/build/lib/pygen/codegen/models/combined_type.py +149 -0
  41. package/generator/build/lib/pygen/codegen/models/constant_type.py +129 -0
  42. package/generator/build/lib/pygen/codegen/models/credential_types.py +214 -0
  43. package/generator/build/lib/pygen/codegen/models/dictionary_type.py +127 -0
  44. package/generator/build/lib/pygen/codegen/models/enum_type.py +238 -0
  45. package/generator/build/lib/pygen/codegen/models/imports.py +291 -0
  46. package/generator/build/lib/pygen/codegen/models/list_type.py +143 -0
  47. package/generator/build/lib/pygen/codegen/models/lro_operation.py +142 -0
  48. package/generator/build/lib/pygen/codegen/models/lro_paging_operation.py +32 -0
  49. package/generator/build/lib/pygen/codegen/models/model_type.py +357 -0
  50. package/generator/build/lib/pygen/codegen/models/operation.py +509 -0
  51. package/generator/build/lib/pygen/codegen/models/operation_group.py +184 -0
  52. package/generator/build/lib/pygen/codegen/models/paging_operation.py +155 -0
  53. package/generator/build/lib/pygen/codegen/models/parameter.py +412 -0
  54. package/generator/build/lib/pygen/codegen/models/parameter_list.py +387 -0
  55. package/generator/build/lib/pygen/codegen/models/primitive_types.py +659 -0
  56. package/generator/build/lib/pygen/codegen/models/property.py +170 -0
  57. package/generator/build/lib/pygen/codegen/models/request_builder.py +189 -0
  58. package/generator/build/lib/pygen/codegen/models/request_builder_parameter.py +115 -0
  59. package/generator/build/lib/pygen/codegen/models/response.py +348 -0
  60. package/generator/build/lib/pygen/codegen/models/utils.py +21 -0
  61. package/generator/build/lib/pygen/codegen/serializers/__init__.py +574 -0
  62. package/generator/build/lib/pygen/codegen/serializers/base_serializer.py +21 -0
  63. package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +1533 -0
  64. package/generator/build/lib/pygen/codegen/serializers/client_serializer.py +294 -0
  65. package/generator/build/lib/pygen/codegen/serializers/enum_serializer.py +15 -0
  66. package/generator/build/lib/pygen/codegen/serializers/general_serializer.py +213 -0
  67. package/generator/build/lib/pygen/codegen/serializers/import_serializer.py +126 -0
  68. package/generator/build/lib/pygen/codegen/serializers/metadata_serializer.py +198 -0
  69. package/generator/build/lib/pygen/codegen/serializers/model_init_serializer.py +33 -0
  70. package/generator/build/lib/pygen/codegen/serializers/model_serializer.py +335 -0
  71. package/generator/build/lib/pygen/codegen/serializers/operation_groups_serializer.py +89 -0
  72. package/generator/build/lib/pygen/codegen/serializers/operations_init_serializer.py +44 -0
  73. package/generator/build/lib/pygen/codegen/serializers/parameter_serializer.py +221 -0
  74. package/generator/build/lib/pygen/codegen/serializers/patch_serializer.py +19 -0
  75. package/generator/build/lib/pygen/codegen/serializers/request_builders_serializer.py +52 -0
  76. package/generator/build/lib/pygen/codegen/serializers/sample_serializer.py +168 -0
  77. package/generator/build/lib/pygen/codegen/serializers/test_serializer.py +292 -0
  78. package/generator/build/lib/pygen/codegen/serializers/types_serializer.py +31 -0
  79. package/generator/build/lib/pygen/codegen/serializers/utils.py +68 -0
  80. package/generator/build/lib/pygen/codegen/templates/client.py.jinja2 +37 -0
  81. package/generator/build/lib/pygen/codegen/templates/client_container.py.jinja2 +12 -0
  82. package/generator/build/lib/pygen/codegen/templates/config.py.jinja2 +73 -0
  83. package/generator/build/lib/pygen/codegen/templates/config_container.py.jinja2 +16 -0
  84. package/generator/build/lib/pygen/codegen/templates/conftest.py.jinja2 +28 -0
  85. package/generator/build/lib/pygen/codegen/templates/enum.py.jinja2 +13 -0
  86. package/generator/build/lib/pygen/codegen/templates/enum_container.py.jinja2 +10 -0
  87. package/generator/build/lib/pygen/codegen/templates/init.py.jinja2 +24 -0
  88. package/generator/build/lib/pygen/codegen/templates/keywords.jinja2 +27 -0
  89. package/generator/build/lib/pygen/codegen/templates/lro_operation.py.jinja2 +16 -0
  90. package/generator/build/lib/pygen/codegen/templates/lro_paging_operation.py.jinja2 +18 -0
  91. package/generator/build/lib/pygen/codegen/templates/macros.jinja2 +12 -0
  92. package/generator/build/lib/pygen/codegen/templates/metadata.json.jinja2 +167 -0
  93. package/generator/build/lib/pygen/codegen/templates/model_base.py.jinja2 +1174 -0
  94. package/generator/build/lib/pygen/codegen/templates/model_container.py.jinja2 +15 -0
  95. package/generator/build/lib/pygen/codegen/templates/model_dpg.py.jinja2 +97 -0
  96. package/generator/build/lib/pygen/codegen/templates/model_init.py.jinja2 +33 -0
  97. package/generator/build/lib/pygen/codegen/templates/model_msrest.py.jinja2 +92 -0
  98. package/generator/build/lib/pygen/codegen/templates/operation.py.jinja2 +21 -0
  99. package/generator/build/lib/pygen/codegen/templates/operation_group.py.jinja2 +75 -0
  100. package/generator/build/lib/pygen/codegen/templates/operation_groups_container.py.jinja2 +19 -0
  101. package/generator/build/lib/pygen/codegen/templates/operation_tools.jinja2 +81 -0
  102. package/generator/build/lib/pygen/codegen/templates/operations_folder_init.py.jinja2 +17 -0
  103. package/generator/build/lib/pygen/codegen/templates/packaging_templates/CHANGELOG.md.jinja2 +6 -0
  104. package/generator/build/lib/pygen/codegen/templates/packaging_templates/LICENSE.jinja2 +21 -0
  105. package/generator/build/lib/pygen/codegen/templates/packaging_templates/MANIFEST.in.jinja2 +8 -0
  106. package/generator/build/lib/pygen/codegen/templates/packaging_templates/README.md.jinja2 +107 -0
  107. package/generator/build/lib/pygen/codegen/templates/packaging_templates/dev_requirements.txt.jinja2 +9 -0
  108. package/generator/build/lib/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +108 -0
  109. package/generator/build/lib/pygen/codegen/templates/paging_operation.py.jinja2 +21 -0
  110. package/generator/build/lib/pygen/codegen/templates/patch.py.jinja2 +19 -0
  111. package/generator/build/lib/pygen/codegen/templates/pkgutil_init.py.jinja2 +1 -0
  112. package/generator/build/lib/pygen/codegen/templates/request_builder.py.jinja2 +28 -0
  113. package/generator/build/lib/pygen/codegen/templates/request_builders.py.jinja2 +10 -0
  114. package/generator/build/lib/pygen/codegen/templates/rest_init.py.jinja2 +12 -0
  115. package/generator/build/lib/pygen/codegen/templates/sample.py.jinja2 +44 -0
  116. package/generator/build/lib/pygen/codegen/templates/serialization.py.jinja2 +2117 -0
  117. package/generator/build/lib/pygen/codegen/templates/test.py.jinja2 +50 -0
  118. package/generator/build/lib/pygen/codegen/templates/testpreparer.py.jinja2 +26 -0
  119. package/generator/build/lib/pygen/codegen/templates/types.py.jinja2 +7 -0
  120. package/generator/build/lib/pygen/codegen/templates/validation.py.jinja2 +38 -0
  121. package/generator/build/lib/pygen/codegen/templates/vendor.py.jinja2 +96 -0
  122. package/generator/build/lib/pygen/codegen/templates/version.py.jinja2 +4 -0
  123. package/generator/build/lib/pygen/m2r.py +65 -0
  124. package/generator/build/lib/pygen/preprocess/__init__.py +515 -0
  125. package/generator/build/lib/pygen/preprocess/helpers.py +27 -0
  126. package/generator/build/lib/pygen/preprocess/python_mappings.py +226 -0
  127. package/generator/build/lib/pygen/utils.py +163 -0
  128. package/generator/component-detection-pip-report.json +134 -0
  129. package/generator/dev_requirements.txt +0 -1
  130. package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
  131. package/generator/pygen/m2r.py +1 -1
  132. package/generator/pygen.egg-info/PKG-INFO +7 -4
  133. package/generator/pygen.egg-info/requires.txt +7 -4
  134. package/generator/requirements.txt +5 -10
  135. package/generator/setup.py +7 -4
  136. package/generator/test/azure/requirements.txt +2 -0
  137. package/generator/test/generic_mock_api_tests/unittests/test_m2r.py +10 -0
  138. package/generator/test/unbranded/requirements.txt +2 -0
  139. package/package.json +6 -5
@@ -0,0 +1,238 @@
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, TYPE_CHECKING, Optional, cast
7
+
8
+ from .base import BaseType
9
+ from .imports import FileImport, ImportType, TypingSection
10
+
11
+ if TYPE_CHECKING:
12
+ from .code_model import CodeModel
13
+
14
+
15
+ class EnumValue(BaseType):
16
+ """Model containing necessary information for a single value of an enum.
17
+
18
+ :param str name: The name of this enum value
19
+ :param str value: The value of this enum value
20
+ :param str description: Optional. The description for this enum value
21
+ """
22
+
23
+ def __init__(
24
+ self,
25
+ yaml_data: Dict[str, Any],
26
+ code_model: "CodeModel",
27
+ enum_type: "EnumType",
28
+ value_type: BaseType,
29
+ ) -> None:
30
+ super().__init__(yaml_data=yaml_data, code_model=code_model)
31
+ self.name: str = self.yaml_data["name"]
32
+ self.value: str = self.yaml_data["value"]
33
+ self.enum_type = enum_type
34
+ self.value_type = value_type
35
+
36
+ def description(self, *, is_operation_file: bool) -> str:
37
+ return self.yaml_data.get("description", "")
38
+
39
+ def type_annotation(self, **kwargs: Any) -> str:
40
+ """The python type used for type annotation"""
41
+ return f"Literal[{self.enum_type.name}.{self.name}]"
42
+
43
+ def get_declaration(self, value=None):
44
+ return self.enum_type.name + "." + self.name
45
+
46
+ def docstring_text(self, **kwargs: Any) -> str:
47
+ return self.enum_type.name + "." + self.name
48
+
49
+ def docstring_type(self, **kwargs: Any) -> str:
50
+ """The python type used for RST syntax input and type annotation."""
51
+
52
+ type_annotation = self.value_type.type_annotation(**kwargs)
53
+ enum_type_annotation = f"{self.code_model.namespace}.models.{self.name}"
54
+ return f"{type_annotation} or ~{enum_type_annotation}"
55
+
56
+ def get_json_template_representation(
57
+ self,
58
+ *,
59
+ client_default_value_declaration: Optional[str] = None,
60
+ ) -> Any:
61
+ # for better display effect, use the only value instead of var type
62
+ return self.value_type.get_json_template_representation(
63
+ client_default_value_declaration=client_default_value_declaration,
64
+ )
65
+
66
+ @property
67
+ def serialization_type(self) -> str:
68
+ return self.value_type.serialization_type
69
+
70
+ @property
71
+ def instance_check_template(self) -> str:
72
+ return self.value_type.instance_check_template
73
+
74
+ def imports(self, **kwargs: Any) -> FileImport:
75
+ file_import = FileImport(self.code_model)
76
+ file_import.merge(self.value_type.imports(**kwargs))
77
+ file_import.add_submodule_import("typing", "Literal", ImportType.STDLIB, TypingSection.REGULAR)
78
+ file_import.add_submodule_import("._enums", self.enum_type.name, ImportType.LOCAL, TypingSection.REGULAR)
79
+
80
+ return file_import
81
+
82
+ @classmethod
83
+ def from_yaml(cls, yaml_data: Dict[str, Any], code_model: "CodeModel") -> "EnumValue":
84
+ """Constructs an EnumValue from yaml data.
85
+
86
+ :param yaml_data: the yaml data from which we will construct this object
87
+ :type yaml_data: dict[str, Any]
88
+
89
+ :return: A created EnumValue
90
+ :rtype: ~autorest.models.EnumValue
91
+ """
92
+ from . import build_type
93
+
94
+ return cls(
95
+ yaml_data=yaml_data,
96
+ code_model=code_model,
97
+ enum_type=cast(EnumType, build_type(yaml_data["enumType"], code_model)),
98
+ value_type=build_type(yaml_data["valueType"], code_model),
99
+ )
100
+
101
+
102
+ class EnumType(BaseType):
103
+ """Schema for enums that will be serialized.
104
+
105
+ :param yaml_data: the yaml data for this schema
106
+ :type yaml_data: dict[str, Any]
107
+ :param str description: The description of this enum
108
+ :param str name: The name of the enum.
109
+ :type element_type: ~autorest.models.PrimitiveType
110
+ :param values: List of the values for this enum
111
+ :type values: list[~autorest.models.EnumValue]
112
+ """
113
+
114
+ def __init__(
115
+ self,
116
+ yaml_data: Dict[str, Any],
117
+ code_model: "CodeModel",
118
+ values: List["EnumValue"],
119
+ value_type: BaseType,
120
+ ) -> None:
121
+ super().__init__(yaml_data=yaml_data, code_model=code_model)
122
+ self.name: str = yaml_data["name"][0].upper() + yaml_data["name"][1:]
123
+ self.values = values
124
+ self.value_type = value_type
125
+ self.internal: bool = self.yaml_data.get("internal", False)
126
+ self.cross_language_definition_id: Optional[str] = self.yaml_data.get("crossLanguageDefinitionId")
127
+
128
+ def __lt__(self, other):
129
+ return self.name.lower() < other.name.lower()
130
+
131
+ @property
132
+ def serialization_type(self) -> str:
133
+ """Returns the serialization value for msrest.
134
+
135
+ :return: The serialization value for msrest
136
+ :rtype: str
137
+ """
138
+ return self.value_type.serialization_type
139
+
140
+ def description(self, *, is_operation_file: bool) -> str:
141
+ possible_values = [self.get_declaration(v.value) for v in self.values]
142
+ if not possible_values:
143
+ return ""
144
+ if len(possible_values) == 1:
145
+ return possible_values[0]
146
+ if len(possible_values) == 2:
147
+ possible_values_str = " and ".join(possible_values)
148
+ else:
149
+ possible_values_str = (
150
+ ", ".join(possible_values[: len(possible_values) - 1]) + f", and {possible_values[-1]}"
151
+ )
152
+
153
+ enum_description = f"Known values are: {possible_values_str}."
154
+ return enum_description
155
+
156
+ def type_annotation(self, **kwargs: Any) -> str:
157
+ """The python type used for type annotation
158
+
159
+ :return: The type annotation for this schema
160
+ :rtype: str
161
+ """
162
+ if self.code_model.options["models_mode"]:
163
+ module_name = "_models." if kwargs.get("need_module_name", True) else ""
164
+ file_name = f"{self.code_model.enums_filename}." if self.internal else ""
165
+ model_name = module_name + file_name + self.name
166
+ # we don't need quoted annotation in operation files, and need it in model folder files.
167
+ if not kwargs.get("is_operation_file", False):
168
+ model_name = f'"{model_name}"'
169
+
170
+ return f"Union[{self.value_type.type_annotation(**kwargs)}, {model_name}]"
171
+ return self.value_type.type_annotation(**kwargs)
172
+
173
+ def get_declaration(self, value: Any) -> str:
174
+ return self.value_type.get_declaration(value)
175
+
176
+ def docstring_text(self, **kwargs: Any) -> str:
177
+ if self.code_model.options["models_mode"]:
178
+ return self.name
179
+ return self.value_type.type_annotation(**kwargs)
180
+
181
+ def docstring_type(self, **kwargs: Any) -> str:
182
+ """The python type used for RST syntax input and type annotation."""
183
+ if self.code_model.options["models_mode"]:
184
+ type_annotation = self.value_type.type_annotation(**kwargs)
185
+ enum_type_annotation = f"{self.code_model.namespace}.models.{self.name}"
186
+ return f"{type_annotation} or ~{enum_type_annotation}"
187
+ return self.value_type.type_annotation(**kwargs)
188
+
189
+ def get_json_template_representation(
190
+ self,
191
+ *,
192
+ client_default_value_declaration: Optional[str] = None,
193
+ ) -> Any:
194
+ # for better display effect, use the only value instead of var type
195
+ return self.value_type.get_json_template_representation(
196
+ client_default_value_declaration=client_default_value_declaration,
197
+ )
198
+
199
+ @property
200
+ def instance_check_template(self) -> str:
201
+ return self.value_type.instance_check_template
202
+
203
+ def fill_instance_from_yaml(self, yaml_data: Dict[str, Any], code_model: "CodeModel") -> None:
204
+ for value in yaml_data["values"]:
205
+ self.values.append(EnumValue.from_yaml(value, code_model))
206
+
207
+ @classmethod
208
+ def from_yaml(cls, yaml_data: Dict[str, Any], code_model: "CodeModel") -> "EnumType":
209
+ raise ValueError(
210
+ "You shouldn't call from_yaml for EnumType to avoid recursion. "
211
+ "Please initial a blank EnumType, then call .fill_instance_from_yaml on the created type."
212
+ )
213
+
214
+ def imports(self, **kwargs: Any) -> FileImport:
215
+ operation = kwargs.pop("operation", False)
216
+ file_import = FileImport(self.code_model)
217
+ if self.code_model.options["models_mode"]:
218
+ file_import.add_submodule_import("typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL)
219
+ if not operation:
220
+ file_import.add_submodule_import(
221
+ "..",
222
+ "models",
223
+ ImportType.LOCAL,
224
+ TypingSection.TYPING,
225
+ alias="_models",
226
+ )
227
+ file_import.merge(self.value_type.imports(operation=operation, **kwargs))
228
+ relative_path = kwargs.pop("relative_path", None)
229
+ if self.code_model.options["models_mode"] and relative_path:
230
+ # add import for enums in operations file
231
+ file_import.add_submodule_import(
232
+ relative_path,
233
+ "models",
234
+ ImportType.LOCAL,
235
+ alias="_models",
236
+ typing_section=(TypingSection.TYPING if kwargs.get("model_typing") else TypingSection.REGULAR),
237
+ )
238
+ return file_import
@@ -0,0 +1,291 @@
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, auto
7
+ from typing import Dict, List, Optional, Tuple, Union, Set, TYPE_CHECKING
8
+
9
+ if TYPE_CHECKING:
10
+ from .code_model import CodeModel
11
+
12
+
13
+ class ImportType(str, Enum):
14
+ """
15
+ Ordering of these enum matters. We order import groupings in a file based off of this ordering.
16
+ """
17
+
18
+ STDLIB = "stdlib"
19
+ THIRDPARTY = "thirdparty"
20
+ SDKCORE = "sdkcore"
21
+ LOCAL = "local"
22
+ BY_VERSION = "by_version"
23
+
24
+
25
+ class TypingSection(str, Enum):
26
+ REGULAR = "regular" # this import is always a typing import
27
+ CONDITIONAL = "conditional" # is a typing import when we're dealing with files that py2 will use, else regular
28
+ TYPING = "typing" # never a typing import
29
+
30
+
31
+ class MsrestImportType(Enum):
32
+ Module = auto() # import _serialization.py or msrest.serialization as Module
33
+ Serializer = auto() # from _serialization.py or msrest.serialization import Serializer
34
+ SerializerDeserializer = auto() # from _serialization.py or msrest.serialization import Serializer and Deserializer
35
+
36
+
37
+ class ImportModel:
38
+ def __init__(
39
+ self,
40
+ typing_section: TypingSection,
41
+ import_type: ImportType,
42
+ module_name: str,
43
+ *,
44
+ submodule_name: Optional[str] = None,
45
+ alias: Optional[str] = None,
46
+ version_modules: Optional[Tuple[Tuple[Tuple[int, int], str, Optional[str]]]] = None,
47
+ ):
48
+ self.typing_section = typing_section
49
+ self.import_type = import_type
50
+ self.module_name = module_name
51
+ self.submodule_name = submodule_name
52
+ self.alias = alias
53
+ # version_modules: this field is for imports submodule from specified module by python version.
54
+ # It's a list of "python version, module_name, comments".
55
+ # The python version is in form of (major, minor), for instance (3, 9) stands for py3.9.
56
+ self.version_modules = version_modules
57
+
58
+ def __eq__(self, other):
59
+ try:
60
+ return (
61
+ self.typing_section == other.typing_section
62
+ and self.import_type == other.import_type
63
+ and self.module_name == other.module_name
64
+ and self.submodule_name == other.submodule_name
65
+ and self.alias == other.alias
66
+ )
67
+ except AttributeError:
68
+ return False
69
+
70
+ def __hash__(self) -> int:
71
+ retval: int = 0
72
+ for attr in dir(self):
73
+ if attr[0] != "_":
74
+ retval += hash(getattr(self, attr))
75
+ return retval
76
+
77
+
78
+ class TypeDefinition:
79
+ def __init__(
80
+ self,
81
+ sync_definition: str,
82
+ async_definition: str,
83
+ ):
84
+ self.sync_definition = sync_definition
85
+ self.async_definition = async_definition
86
+
87
+
88
+ class FileImport:
89
+ def __init__(self, code_model: "CodeModel") -> None:
90
+ self.imports: List[ImportModel] = []
91
+ self.code_model = code_model
92
+ # has sync and async type definitions
93
+ self.type_definitions: Dict[str, TypeDefinition] = {}
94
+ self.core_library = self.code_model.core_library
95
+
96
+ def _append_import(self, import_model: ImportModel) -> None:
97
+ if import_model.import_type == ImportType.SDKCORE:
98
+ mod_name = import_model.module_name
99
+ core_libraries = [
100
+ self.code_model.core_library,
101
+ "azure",
102
+ "msrest",
103
+ ]
104
+ if all(l not in mod_name for l in core_libraries):
105
+ # this is to make sure we don't tack on core libraries when we don't need to
106
+ import_model.module_name = f"{self.code_model.core_library}{'.' if mod_name else ''}{mod_name}"
107
+ if not any(
108
+ i
109
+ for i in self.imports
110
+ if all(getattr(i, attr) == getattr(import_model, attr) for attr in dir(i) if attr[0] != "_")
111
+ ):
112
+ self.imports.append(import_model)
113
+
114
+ def get_imports_from_section(self, typing_section: TypingSection) -> List[ImportModel]:
115
+ return [i for i in self.imports if i.typing_section == typing_section]
116
+
117
+ def add_submodule_import(
118
+ self,
119
+ module_name: str,
120
+ submodule_name: str,
121
+ import_type: ImportType,
122
+ typing_section: TypingSection = TypingSection.REGULAR,
123
+ alias: Optional[str] = None,
124
+ version_modules: Optional[Tuple[Tuple[Tuple[int, int], str, Optional[str]]]] = None,
125
+ ) -> None:
126
+ """Add an import to this import block."""
127
+ self._append_import(
128
+ ImportModel(
129
+ typing_section=typing_section,
130
+ import_type=import_type,
131
+ module_name=module_name,
132
+ submodule_name=submodule_name,
133
+ alias=alias,
134
+ version_modules=version_modules,
135
+ )
136
+ )
137
+
138
+ def add_import(
139
+ self,
140
+ module_name: str,
141
+ import_type: ImportType,
142
+ typing_section: TypingSection = TypingSection.REGULAR,
143
+ alias: Optional[str] = None,
144
+ ) -> None:
145
+ # Implementation detail: a regular import is just a "from" with no from
146
+ self._append_import(
147
+ ImportModel(
148
+ typing_section=typing_section,
149
+ import_type=import_type,
150
+ module_name=module_name,
151
+ alias=alias,
152
+ )
153
+ )
154
+
155
+ def define_mypy_type(
156
+ self,
157
+ type_name: str,
158
+ type_value: str,
159
+ async_type_value: Optional[str] = None,
160
+ ):
161
+ self.type_definitions[type_name] = TypeDefinition(type_value, async_type_value or type_value)
162
+
163
+ def merge(self, file_import: "FileImport") -> None:
164
+ """Merge the given file import format."""
165
+ for i in file_import.imports:
166
+ self._append_import(i)
167
+ self.type_definitions.update(file_import.type_definitions)
168
+
169
+ def add_mutable_mapping_import(self) -> None:
170
+ self.add_import("sys", ImportType.STDLIB)
171
+ self.add_submodule_import(
172
+ "typing",
173
+ "MutableMapping",
174
+ ImportType.BY_VERSION,
175
+ TypingSection.REGULAR,
176
+ None,
177
+ (((3, 9), "collections.abc", None),),
178
+ )
179
+
180
+ def define_mutable_mapping_type(self) -> None:
181
+ """Helper function for defining the mutable mapping type"""
182
+ self.add_mutable_mapping_import()
183
+ self.define_mypy_type(
184
+ "JSON",
185
+ "MutableMapping[str, Any] # pylint: disable=unsubscriptable-object",
186
+ )
187
+ self.add_submodule_import("typing", "Any", ImportType.STDLIB)
188
+
189
+ def to_dict(
190
+ self,
191
+ ) -> Dict[
192
+ TypingSection,
193
+ Dict[
194
+ ImportType,
195
+ Dict[
196
+ str,
197
+ Set[
198
+ Optional[
199
+ Union[
200
+ str,
201
+ Tuple[str, str],
202
+ Tuple[
203
+ str,
204
+ Optional[str],
205
+ Tuple[Tuple[Tuple[int, int], str, Optional[str]]],
206
+ ],
207
+ ]
208
+ ]
209
+ ],
210
+ ],
211
+ ],
212
+ ]:
213
+ retval: Dict[
214
+ TypingSection,
215
+ Dict[
216
+ ImportType,
217
+ Dict[
218
+ str,
219
+ Set[
220
+ Optional[
221
+ Union[
222
+ str,
223
+ Tuple[str, str],
224
+ Tuple[
225
+ str,
226
+ Optional[str],
227
+ Tuple[Tuple[Tuple[int, int], str, Optional[str]]],
228
+ ],
229
+ ]
230
+ ]
231
+ ],
232
+ ],
233
+ ],
234
+ ] = {}
235
+ for i in self.imports:
236
+ name_import: Optional[
237
+ Union[
238
+ str,
239
+ Tuple[str, str],
240
+ Tuple[
241
+ str,
242
+ Optional[str],
243
+ Tuple[Tuple[Tuple[int, int], str, Optional[str]]],
244
+ ],
245
+ ]
246
+ ] = None
247
+ if i.submodule_name:
248
+ if i.version_modules:
249
+ name_import = (i.submodule_name, i.alias, i.version_modules)
250
+ elif i.alias:
251
+ name_import = (i.submodule_name, i.alias)
252
+ else:
253
+ name_import = i.submodule_name
254
+ retval.setdefault(i.typing_section, {}).setdefault(i.import_type, {}).setdefault(i.module_name, set()).add(
255
+ name_import
256
+ )
257
+ return retval
258
+
259
+ def add_msrest_import(
260
+ self,
261
+ *,
262
+ relative_path: str,
263
+ msrest_import_type: MsrestImportType,
264
+ typing_section: TypingSection,
265
+ ):
266
+ if self.code_model.options["client_side_validation"]:
267
+ if msrest_import_type == MsrestImportType.Module:
268
+ self.add_import("msrest.serialization", ImportType.SDKCORE, typing_section)
269
+ else:
270
+ self.add_submodule_import("msrest", "Serializer", ImportType.THIRDPARTY, typing_section)
271
+ if msrest_import_type == MsrestImportType.SerializerDeserializer:
272
+ self.add_submodule_import("msrest", "Deserializer", ImportType.THIRDPARTY, typing_section)
273
+ else:
274
+ if self.code_model.options["multiapi"]:
275
+ relative_path += "."
276
+ if msrest_import_type == MsrestImportType.Module:
277
+ self.add_submodule_import(relative_path, "_serialization", ImportType.LOCAL, typing_section)
278
+ else:
279
+ self.add_submodule_import(
280
+ f"{relative_path}_serialization",
281
+ "Serializer",
282
+ ImportType.LOCAL,
283
+ typing_section,
284
+ )
285
+ if msrest_import_type == MsrestImportType.SerializerDeserializer:
286
+ self.add_submodule_import(
287
+ f"{relative_path}_serialization",
288
+ "Deserializer",
289
+ ImportType.LOCAL,
290
+ typing_section,
291
+ )
@@ -0,0 +1,143 @@
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, Optional, Union, TYPE_CHECKING, List
7
+ from .base import BaseType
8
+ from .imports import FileImport, ImportType, TypingSection
9
+
10
+ if TYPE_CHECKING:
11
+ from .code_model import CodeModel
12
+ from .model_type import ModelType
13
+
14
+
15
+ class ListType(BaseType):
16
+ def __init__(
17
+ self,
18
+ yaml_data: Dict[str, Any],
19
+ code_model: "CodeModel",
20
+ element_type: BaseType,
21
+ ) -> None:
22
+ super().__init__(yaml_data=yaml_data, code_model=code_model)
23
+ self.element_type = element_type
24
+ self.max_items: Optional[int] = yaml_data.get("maxItems")
25
+ self.min_items: Optional[int] = yaml_data.get("minItems")
26
+ self.unique_items: bool = yaml_data.get("uniqueItems", False)
27
+
28
+ @property
29
+ def encode(self) -> Optional[str]:
30
+ return self.element_type.encode if hasattr(self.element_type, "encode") else None # type: ignore
31
+
32
+ @property
33
+ def serialization_type(self) -> str:
34
+ return f"[{self.element_type.serialization_type}]"
35
+
36
+ def type_annotation(self, **kwargs: Any) -> str:
37
+ if (
38
+ self.code_model.options["version_tolerant"]
39
+ and self.element_type.is_xml
40
+ and not self.code_model.options["models_mode"]
41
+ ):
42
+ # this means we're version tolerant XML, we just return the XML element
43
+ return self.element_type.type_annotation(**kwargs)
44
+ return f"List[{self.element_type.type_annotation(**kwargs)}]"
45
+
46
+ def description(self, *, is_operation_file: bool) -> str:
47
+ return "" if is_operation_file else self.yaml_data.get("description", "")
48
+
49
+ @property
50
+ def xml_serialization_ctxt(self) -> Optional[str]:
51
+ attrs_list = []
52
+ base_xml_map = super().xml_serialization_ctxt
53
+ if base_xml_map:
54
+ attrs_list.append(base_xml_map)
55
+
56
+ # Attribute at the list level
57
+ if self.xml_metadata.get("wrapped", False):
58
+ attrs_list.append("'wrapped': True")
59
+
60
+ # Attributes of the items
61
+ item_xml_metadata = self.element_type.xml_metadata
62
+ if item_xml_metadata.get("name"):
63
+ attrs_list.append(f"'itemsName': '{item_xml_metadata['name']}'")
64
+ if item_xml_metadata.get("prefix", False):
65
+ attrs_list.append(f"'itemsPrefix': '{item_xml_metadata['prefix']}'")
66
+ if item_xml_metadata.get("namespace", False):
67
+ attrs_list.append(f"'itemsNs': '{item_xml_metadata['namespace']}'")
68
+
69
+ return ", ".join(attrs_list)
70
+
71
+ def docstring_type(self, **kwargs: Any) -> str:
72
+ if self.code_model.options["version_tolerant"] and self.element_type.xml_metadata:
73
+ # this means we're version tolerant XML, we just return the XML element
74
+ return self.element_type.docstring_type(**kwargs)
75
+ return f"list[{self.element_type.docstring_type(**kwargs)}]"
76
+
77
+ def docstring_text(self, **kwargs: Any) -> str:
78
+ if self.code_model.options["version_tolerant"] and self.element_type.xml_metadata:
79
+ # this means we're version tolerant XML, we just return the XML element
80
+ return self.element_type.docstring_text(**kwargs)
81
+ return f"list of {self.element_type.docstring_text(**kwargs)}"
82
+
83
+ @property
84
+ def validation(self) -> Optional[Dict[str, Union[bool, int, str]]]:
85
+ validation: Dict[str, Union[bool, int, str]] = {}
86
+ if self.max_items:
87
+ validation["max_items"] = self.max_items
88
+ validation["min_items"] = self.min_items or 0
89
+ if self.min_items:
90
+ validation["min_items"] = self.min_items
91
+ if self.unique_items:
92
+ validation["unique"] = True
93
+ return validation or None
94
+
95
+ def get_json_template_representation(
96
+ self,
97
+ *,
98
+ client_default_value_declaration: Optional[str] = None,
99
+ ) -> Any:
100
+ return [
101
+ self.element_type.get_json_template_representation(
102
+ client_default_value_declaration=client_default_value_declaration,
103
+ )
104
+ ]
105
+
106
+ def get_polymorphic_subtypes(self, polymorphic_subtypes: List["ModelType"]) -> None:
107
+ from .model_type import ModelType
108
+
109
+ if isinstance(self.element_type, ModelType):
110
+ is_polymorphic_subtype = (
111
+ self.element_type.discriminator_value and not self.element_type.discriminated_subtypes
112
+ )
113
+ if self.element_type.name not in (m.name for m in polymorphic_subtypes) and is_polymorphic_subtype:
114
+ polymorphic_subtypes.append(self.element_type)
115
+
116
+ @property
117
+ def instance_check_template(self) -> str:
118
+ return "isinstance({}, list)"
119
+
120
+ @classmethod
121
+ def from_yaml(cls, yaml_data: Dict[str, Any], code_model: "CodeModel") -> "ListType":
122
+ from . import build_type
123
+
124
+ return cls(
125
+ yaml_data=yaml_data,
126
+ code_model=code_model,
127
+ element_type=build_type(yaml_data=yaml_data["elementType"], code_model=code_model),
128
+ )
129
+
130
+ def imports(self, **kwargs: Any) -> FileImport:
131
+ file_import = FileImport(self.code_model)
132
+ if not (
133
+ self.code_model.options["version_tolerant"]
134
+ and self.element_type.is_xml
135
+ and not self.code_model.options["models_mode"]
136
+ ):
137
+ file_import.add_submodule_import("typing", "List", ImportType.STDLIB, TypingSection.CONDITIONAL)
138
+ file_import.merge(self.element_type.imports(**kwargs))
139
+ return file_import
140
+
141
+ @property
142
+ def type_description(self) -> str:
143
+ return f"[{self.element_type.type_description}]"