@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
@@ -0,0 +1,195 @@
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
7
+
8
+ from .base_type import BaseType
9
+ from .imports import FileImport, ImportType, TypingSection
10
+ from .base_model import BaseModel
11
+
12
+ if TYPE_CHECKING:
13
+ from .code_model import CodeModel
14
+
15
+
16
+ class EnumValue(BaseModel):
17
+ """Model containing necessary information for a single value of an enum.
18
+
19
+ :param str name: The name of this enum value
20
+ :param str value: The value of this enum value
21
+ :param str description: Optional. The description for this enum value
22
+ """
23
+
24
+ def __init__(self, yaml_data: Dict[str, Any], code_model: "CodeModel") -> None:
25
+ super().__init__(yaml_data=yaml_data, code_model=code_model)
26
+ self.name: str = self.yaml_data["name"]
27
+ self.value: str = self.yaml_data["value"]
28
+ self.description: Optional[str] = self.yaml_data.get("description")
29
+
30
+ @classmethod
31
+ def from_yaml(
32
+ cls, yaml_data: Dict[str, Any], code_model: "CodeModel"
33
+ ) -> "EnumValue":
34
+ """Constructs an EnumValue from yaml data.
35
+
36
+ :param yaml_data: the yaml data from which we will construct this object
37
+ :type yaml_data: dict[str, Any]
38
+
39
+ :return: A created EnumValue
40
+ :rtype: ~autorest.models.EnumValue
41
+ """
42
+ return cls(
43
+ yaml_data=yaml_data,
44
+ code_model=code_model,
45
+ )
46
+
47
+
48
+ class EnumType(BaseType):
49
+ """Schema for enums that will be serialized.
50
+
51
+ :param yaml_data: the yaml data for this schema
52
+ :type yaml_data: dict[str, Any]
53
+ :param str description: The description of this enum
54
+ :param str name: The name of the enum.
55
+ :type element_type: ~autorest.models.PrimitiveType
56
+ :param values: List of the values for this enum
57
+ :type values: list[~autorest.models.EnumValue]
58
+ """
59
+
60
+ def __init__(
61
+ self,
62
+ yaml_data: Dict[str, Any],
63
+ code_model: "CodeModel",
64
+ values: List["EnumValue"],
65
+ value_type: BaseType,
66
+ ) -> None:
67
+ super().__init__(yaml_data=yaml_data, code_model=code_model)
68
+ self.name: str = yaml_data["name"]
69
+ self.values = values
70
+ self.value_type = value_type
71
+
72
+ def __lt__(self, other):
73
+ return self.name.lower() < other.name.lower()
74
+
75
+ @property
76
+ def serialization_type(self) -> str:
77
+ """Returns the serialization value for msrest.
78
+
79
+ :return: The serialization value for msrest
80
+ :rtype: str
81
+ """
82
+ return self.value_type.serialization_type
83
+
84
+ def description(
85
+ self, *, is_operation_file: bool # pylint: disable=unused-argument
86
+ ) -> str:
87
+ possible_values = [self.get_declaration(v.value) for v in self.values]
88
+ if not possible_values:
89
+ return ""
90
+ if len(possible_values) == 1:
91
+ return possible_values[0]
92
+ if len(possible_values) == 2:
93
+ possible_values_str = " and ".join(possible_values)
94
+ else:
95
+ possible_values_str = (
96
+ ", ".join(possible_values[: len(possible_values) - 1])
97
+ + f", and {possible_values[-1]}"
98
+ )
99
+
100
+ enum_description = f"Known values are: {possible_values_str}."
101
+ return enum_description
102
+
103
+ def type_annotation(self, **kwargs: Any) -> str:
104
+ """The python type used for type annotation
105
+
106
+ :return: The type annotation for this schema
107
+ :rtype: str
108
+ """
109
+ if self.code_model.options["models_mode"]:
110
+ return (
111
+ f"Union[{self.value_type.type_annotation(**kwargs)},"
112
+ f' "_models.{self.name}"]'
113
+ )
114
+ return self.value_type.type_annotation(**kwargs)
115
+
116
+ def get_declaration(self, value: Any) -> str:
117
+ return self.value_type.get_declaration(value)
118
+
119
+ def docstring_text(self, **kwargs: Any) -> str:
120
+ if self.code_model.options["models_mode"]:
121
+ return self.name
122
+ return self.value_type.type_annotation(**kwargs)
123
+
124
+ def docstring_type(self, **kwargs: Any) -> str:
125
+ """The python type used for RST syntax input and type annotation."""
126
+ if self.code_model.options["models_mode"]:
127
+ return f"{self.value_type.type_annotation(**kwargs)} or ~{self.code_model.namespace}.models.{self.name}"
128
+ return self.value_type.type_annotation(**kwargs)
129
+
130
+ def get_json_template_representation(
131
+ self,
132
+ *,
133
+ optional: bool = True,
134
+ client_default_value_declaration: Optional[str] = None,
135
+ description: Optional[str] = None,
136
+ ) -> Any:
137
+ # for better display effect, use the only value instead of var type
138
+ return self.value_type.get_json_template_representation(
139
+ optional=optional,
140
+ client_default_value_declaration=client_default_value_declaration,
141
+ description=description,
142
+ )
143
+
144
+ @property
145
+ def instance_check_template(self) -> str:
146
+ return self.value_type.instance_check_template
147
+
148
+ @classmethod
149
+ def from_yaml(
150
+ cls, yaml_data: Dict[str, Any], code_model: "CodeModel"
151
+ ) -> "EnumType":
152
+ """Constructs an EnumType from yaml data.
153
+
154
+ :param yaml_data: the yaml data from which we will construct this schema
155
+ :type yaml_data: dict[str, Any]
156
+
157
+ :return: A created EnumType
158
+ :rtype: ~autorest.models.EnumType
159
+ """
160
+ from . import build_type
161
+
162
+ return cls(
163
+ yaml_data=yaml_data,
164
+ code_model=code_model,
165
+ value_type=build_type(yaml_data["valueType"], code_model),
166
+ values=[
167
+ EnumValue.from_yaml(value, code_model) for value in yaml_data["values"]
168
+ ],
169
+ )
170
+
171
+ def imports(self, **kwargs: Any) -> FileImport:
172
+ is_operation_file = kwargs.pop("is_operation_file", False)
173
+ file_import = FileImport()
174
+ if self.code_model.options["models_mode"]:
175
+ file_import.add_submodule_import(
176
+ "typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL
177
+ )
178
+ if not is_operation_file:
179
+ file_import.add_submodule_import(
180
+ "..",
181
+ "models",
182
+ ImportType.LOCAL,
183
+ TypingSection.TYPING,
184
+ alias="_models",
185
+ )
186
+ file_import.merge(
187
+ self.value_type.imports(is_operation_file=is_operation_file, **kwargs)
188
+ )
189
+ relative_path = kwargs.pop("relative_path", None)
190
+ if self.code_model.options["models_mode"] and relative_path:
191
+ # add import for enums in operations file
192
+ file_import.add_submodule_import(
193
+ relative_path, "models", ImportType.LOCAL, alias="_models"
194
+ )
195
+ return file_import
@@ -3,8 +3,11 @@
3
3
  # Licensed under the MIT License. See License.txt in the project root for
4
4
  # license information.
5
5
  # --------------------------------------------------------------------------
6
- from enum import Enum
7
- from typing import Dict, List, Optional, Tuple, Union, Set, Mapping
6
+ from enum import Enum, auto
7
+ from typing import Dict, List, Optional, Tuple, Union, Set, Mapping, TYPE_CHECKING
8
+
9
+ if TYPE_CHECKING:
10
+ from .code_model import CodeModel
8
11
 
9
12
 
10
13
  class ImportType(str, Enum):
@@ -20,6 +23,16 @@ class TypingSection(str, Enum):
20
23
  TYPING = "typing" # never a typing import
21
24
 
22
25
 
26
+ class MsrestImportType(Enum):
27
+ Module = auto() # import _serialization.py or msrest.serialization as Module
28
+ Serializer = (
29
+ auto()
30
+ ) # from _serialization.py or msrest.serialization import Serializer
31
+ SerializerDeserializer = (
32
+ auto()
33
+ ) # from _serialization.py or msrest.serialization import Serializer and Deserializer
34
+
35
+
23
36
  class ImportModel:
24
37
  def __init__(
25
38
  self,
@@ -147,6 +160,29 @@ class FileImport:
147
160
  self._append_import(i)
148
161
  self.type_definitions.update(file_import.type_definitions)
149
162
 
163
+ def define_mutable_mapping_type(self) -> None:
164
+ """Helper function for defining the mutable mapping type"""
165
+ self.define_mypy_type(
166
+ "JSON",
167
+ "MutableMapping[str, Any] # pylint: disable=unsubscriptable-object",
168
+ None,
169
+ {
170
+ (3, 9): ImportModel(
171
+ TypingSection.CONDITIONAL,
172
+ ImportType.STDLIB,
173
+ "collections.abc",
174
+ submodule_name="MutableMapping",
175
+ ),
176
+ None: ImportModel(
177
+ TypingSection.CONDITIONAL,
178
+ ImportType.STDLIB,
179
+ "typing",
180
+ submodule_name="MutableMapping",
181
+ ),
182
+ },
183
+ )
184
+ self.add_submodule_import("typing", "Any", ImportType.STDLIB)
185
+
150
186
  def to_dict(
151
187
  self,
152
188
  ) -> Dict[
@@ -167,3 +203,45 @@ class FileImport:
167
203
  i.import_type, dict()
168
204
  ).setdefault(i.module_name, set()).add(name_import)
169
205
  return retval
206
+
207
+ def add_msrest_import(
208
+ self,
209
+ code_model: "CodeModel",
210
+ relative_path: str,
211
+ msrest_import_type: MsrestImportType,
212
+ typing_section: TypingSection,
213
+ ):
214
+ if code_model.options["client_side_validation"]:
215
+ if msrest_import_type == MsrestImportType.Module:
216
+ self.add_import(
217
+ "msrest.serialization", ImportType.AZURECORE, typing_section
218
+ )
219
+ else:
220
+ self.add_submodule_import(
221
+ "msrest", "Serializer", ImportType.THIRDPARTY, typing_section
222
+ )
223
+ if msrest_import_type == MsrestImportType.SerializerDeserializer:
224
+ self.add_submodule_import(
225
+ "msrest", "Deserializer", ImportType.THIRDPARTY, typing_section
226
+ )
227
+ else:
228
+ if code_model.options["multiapi"]:
229
+ relative_path += "."
230
+ if msrest_import_type == MsrestImportType.Module:
231
+ self.add_submodule_import(
232
+ relative_path, "_serialization", ImportType.LOCAL, typing_section
233
+ )
234
+ else:
235
+ self.add_submodule_import(
236
+ f"{relative_path}_serialization",
237
+ "Serializer",
238
+ ImportType.LOCAL,
239
+ typing_section,
240
+ )
241
+ if msrest_import_type == MsrestImportType.SerializerDeserializer:
242
+ self.add_submodule_import(
243
+ f"{relative_path}_serialization",
244
+ "Deserializer",
245
+ ImportType.LOCAL,
246
+ typing_section,
247
+ )
@@ -0,0 +1,149 @@
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_type 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 serialization_type(self) -> str:
30
+ return f"[{self.element_type.serialization_type}]"
31
+
32
+ def type_annotation(self, **kwargs: Any) -> str:
33
+ if self.code_model.options["version_tolerant"] and self.element_type.is_xml:
34
+ # this means we're version tolerant XML, we just return the XML element
35
+ return self.element_type.type_annotation(**kwargs)
36
+ return f"List[{self.element_type.type_annotation(**kwargs)}]"
37
+
38
+ def description(self, *, is_operation_file: bool) -> str:
39
+ return "" if is_operation_file else self.yaml_data.get("description", "")
40
+
41
+ @property
42
+ def xml_serialization_ctxt(self) -> Optional[str]:
43
+ attrs_list = []
44
+ base_xml_map = super().xml_serialization_ctxt
45
+ if base_xml_map:
46
+ attrs_list.append(base_xml_map)
47
+
48
+ # Attribute at the list level
49
+ if self.xml_metadata.get("wrapped", False):
50
+ attrs_list.append("'wrapped': True")
51
+
52
+ # Attributes of the items
53
+ item_xml_metadata = self.element_type.xml_metadata
54
+ if item_xml_metadata.get("name"):
55
+ attrs_list.append(f"'itemsName': '{item_xml_metadata['name']}'")
56
+ if item_xml_metadata.get("prefix", False):
57
+ attrs_list.append(f"'itemsPrefix': '{item_xml_metadata['prefix']}'")
58
+ if item_xml_metadata.get("namespace", False):
59
+ attrs_list.append(f"'itemsNs': '{item_xml_metadata['namespace']}'")
60
+
61
+ return ", ".join(attrs_list)
62
+
63
+ def docstring_type(self, **kwargs: Any) -> str:
64
+ if (
65
+ self.code_model.options["version_tolerant"]
66
+ and self.element_type.xml_metadata
67
+ ):
68
+ # this means we're version tolerant XML, we just return the XML element
69
+ return self.element_type.docstring_type(**kwargs)
70
+ return f"list[{self.element_type.docstring_type(**kwargs)}]"
71
+
72
+ def docstring_text(self, **kwargs: Any) -> str:
73
+ if (
74
+ self.code_model.options["version_tolerant"]
75
+ and self.element_type.xml_metadata
76
+ ):
77
+ # this means we're version tolerant XML, we just return the XML element
78
+ return self.element_type.docstring_text(**kwargs)
79
+ return f"list of {self.element_type.docstring_text(**kwargs)}"
80
+
81
+ @property
82
+ def validation(self) -> Optional[Dict[str, Union[bool, int, str]]]:
83
+ validation: Dict[str, Union[bool, int, str]] = {}
84
+ if self.max_items:
85
+ validation["max_items"] = self.max_items
86
+ validation["min_items"] = self.min_items or 0
87
+ if self.min_items:
88
+ validation["min_items"] = self.min_items
89
+ if self.unique_items:
90
+ validation["unique"] = True
91
+ return validation or None
92
+
93
+ def get_json_template_representation(
94
+ self,
95
+ *,
96
+ optional: bool = True,
97
+ client_default_value_declaration: Optional[str] = None,
98
+ description: Optional[str] = None,
99
+ ) -> Any:
100
+ return [
101
+ self.element_type.get_json_template_representation(
102
+ optional=optional,
103
+ client_default_value_declaration=client_default_value_declaration,
104
+ description=description,
105
+ )
106
+ ]
107
+
108
+ def get_polymorphic_subtypes(self, polymorphic_subtypes: List["ModelType"]) -> None:
109
+ from .model_type import ModelType
110
+
111
+ if isinstance(self.element_type, ModelType):
112
+ is_polymorphic_subtype = (
113
+ self.element_type.discriminator_value
114
+ and not self.element_type.discriminated_subtypes
115
+ )
116
+ if (
117
+ self.element_type.name not in (m.name for m in polymorphic_subtypes)
118
+ and is_polymorphic_subtype
119
+ ):
120
+ polymorphic_subtypes.append(self.element_type)
121
+
122
+ @property
123
+ def instance_check_template(self) -> str:
124
+ return "isinstance({}, list)"
125
+
126
+ @classmethod
127
+ def from_yaml(
128
+ cls, yaml_data: Dict[str, Any], code_model: "CodeModel"
129
+ ) -> "ListType":
130
+ from . import build_type
131
+
132
+ return cls(
133
+ yaml_data=yaml_data,
134
+ code_model=code_model,
135
+ element_type=build_type(
136
+ yaml_data=yaml_data["elementType"], code_model=code_model
137
+ ),
138
+ )
139
+
140
+ def imports(self, **kwargs: Any) -> FileImport:
141
+ file_import = FileImport()
142
+ if not (
143
+ self.code_model.options["version_tolerant"] and self.element_type.is_xml
144
+ ):
145
+ file_import.add_submodule_import(
146
+ "typing", "List", ImportType.STDLIB, TypingSection.CONDITIONAL
147
+ )
148
+ file_import.merge(self.element_type.imports(**kwargs))
149
+ return file_import