@autorest/python 5.15.0 → 5.18.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.
- package/ChangeLog.md +98 -4
- package/README.md +30 -4
- package/autorest/__init__.py +2 -3
- package/autorest/black/__init__.py +12 -5
- package/autorest/codegen/__init__.py +122 -211
- package/autorest/codegen/models/__init__.py +122 -78
- package/autorest/codegen/models/base_builder.py +70 -72
- package/autorest/codegen/models/base_model.py +7 -5
- package/autorest/codegen/models/{base_schema.py → base_type.py} +68 -45
- package/autorest/codegen/models/client.py +193 -40
- package/autorest/codegen/models/code_model.py +145 -245
- package/autorest/codegen/models/combined_type.py +107 -0
- package/autorest/codegen/models/constant_type.py +122 -0
- package/autorest/codegen/models/credential_types.py +224 -0
- package/autorest/codegen/models/dictionary_type.py +131 -0
- package/autorest/codegen/models/enum_type.py +195 -0
- package/autorest/codegen/models/imports.py +93 -41
- package/autorest/codegen/models/list_type.py +149 -0
- package/autorest/codegen/models/lro_operation.py +90 -133
- package/autorest/codegen/models/lro_paging_operation.py +28 -12
- package/autorest/codegen/models/model_type.py +262 -0
- package/autorest/codegen/models/operation.py +412 -259
- package/autorest/codegen/models/operation_group.py +80 -91
- package/autorest/codegen/models/paging_operation.py +101 -117
- package/autorest/codegen/models/parameter.py +302 -341
- package/autorest/codegen/models/parameter_list.py +373 -357
- package/autorest/codegen/models/primitive_types.py +544 -0
- package/autorest/codegen/models/property.py +136 -134
- package/autorest/codegen/models/request_builder.py +138 -86
- package/autorest/codegen/models/request_builder_parameter.py +122 -86
- package/autorest/codegen/models/response.py +325 -0
- package/autorest/codegen/models/utils.py +13 -17
- package/autorest/codegen/serializers/__init__.py +212 -112
- package/autorest/codegen/serializers/builder_serializer.py +931 -1040
- package/autorest/codegen/serializers/client_serializer.py +140 -84
- package/autorest/codegen/serializers/general_serializer.py +26 -50
- package/autorest/codegen/serializers/import_serializer.py +96 -31
- package/autorest/codegen/serializers/metadata_serializer.py +39 -79
- package/autorest/codegen/serializers/model_base_serializer.py +62 -34
- package/autorest/codegen/serializers/model_generic_serializer.py +9 -10
- package/autorest/codegen/serializers/model_init_serializer.py +4 -2
- package/autorest/codegen/serializers/model_python3_serializer.py +29 -22
- package/autorest/codegen/serializers/operation_groups_serializer.py +21 -19
- package/autorest/codegen/serializers/operations_init_serializer.py +23 -11
- package/autorest/codegen/serializers/parameter_serializer.py +174 -0
- package/autorest/codegen/serializers/patch_serializer.py +4 -1
- package/autorest/codegen/serializers/request_builders_serializer.py +57 -0
- package/autorest/codegen/serializers/utils.py +0 -126
- package/autorest/codegen/templates/MANIFEST.in.jinja2 +1 -0
- package/autorest/codegen/templates/{service_client.py.jinja2 → client.py.jinja2} +7 -7
- package/autorest/codegen/templates/config.py.jinja2 +13 -13
- package/autorest/codegen/templates/enum.py.jinja2 +4 -4
- package/autorest/codegen/templates/enum_container.py.jinja2 +1 -1
- package/autorest/codegen/templates/init.py.jinja2 +3 -3
- package/autorest/codegen/templates/lro_operation.py.jinja2 +6 -5
- package/autorest/codegen/templates/lro_paging_operation.py.jinja2 +6 -5
- package/autorest/codegen/templates/metadata.json.jinja2 +36 -35
- package/autorest/codegen/templates/model.py.jinja2 +23 -24
- package/autorest/codegen/templates/model_container.py.jinja2 +2 -1
- package/autorest/codegen/templates/model_init.py.jinja2 +3 -5
- package/autorest/codegen/templates/operation.py.jinja2 +10 -14
- package/autorest/codegen/templates/operation_group.py.jinja2 +9 -15
- package/autorest/codegen/templates/operation_groups_container.py.jinja2 +1 -1
- package/autorest/codegen/templates/operation_tools.jinja2 +8 -2
- package/autorest/codegen/templates/paging_operation.py.jinja2 +7 -8
- package/autorest/codegen/templates/request_builder.py.jinja2 +19 -10
- package/autorest/codegen/templates/setup.py.jinja2 +9 -3
- package/autorest/codegen/templates/vendor.py.jinja2 +1 -1
- package/autorest/jsonrpc/__init__.py +7 -12
- package/autorest/jsonrpc/localapi.py +4 -3
- package/autorest/jsonrpc/server.py +28 -9
- package/autorest/jsonrpc/stdstream.py +13 -6
- package/autorest/m2r/__init__.py +5 -8
- package/autorest/m4reformatter/__init__.py +1126 -0
- package/autorest/multiapi/__init__.py +24 -14
- package/autorest/multiapi/models/client.py +21 -11
- package/autorest/multiapi/models/code_model.py +23 -10
- package/autorest/multiapi/models/config.py +4 -1
- package/autorest/multiapi/models/constant_global_parameter.py +1 -0
- package/autorest/multiapi/models/global_parameter.py +2 -1
- package/autorest/multiapi/models/global_parameters.py +14 -8
- package/autorest/multiapi/models/imports.py +24 -17
- package/autorest/multiapi/models/mixin_operation.py +5 -5
- package/autorest/multiapi/models/operation_group.py +2 -1
- package/autorest/multiapi/models/operation_mixin_group.py +21 -10
- package/autorest/multiapi/serializers/__init__.py +20 -25
- package/autorest/multiapi/serializers/import_serializer.py +47 -17
- package/autorest/multiapi/serializers/multiapi_serializer.py +17 -17
- package/autorest/multiapi/templates/multiapi_config.py.jinja2 +3 -3
- package/autorest/multiapi/templates/multiapi_init.py.jinja2 +2 -2
- package/autorest/multiapi/templates/multiapi_operations_mixin.py.jinja2 +4 -4
- package/autorest/multiapi/templates/multiapi_service_client.py.jinja2 +9 -9
- package/autorest/multiapi/utils.py +3 -3
- package/autorest/postprocess/__init__.py +202 -0
- package/autorest/postprocess/get_all.py +19 -0
- package/autorest/postprocess/venvtools.py +73 -0
- package/autorest/preprocess/__init__.py +210 -0
- package/autorest/preprocess/helpers.py +54 -0
- package/autorest/{namer → preprocess}/python_mappings.py +25 -32
- package/package.json +3 -3
- package/run-python3.js +2 -3
- package/venvtools.py +1 -1
- package/autorest/codegen/models/constant_schema.py +0 -101
- package/autorest/codegen/models/credential_model.py +0 -47
- package/autorest/codegen/models/credential_schema.py +0 -91
- package/autorest/codegen/models/credential_schema_policy.py +0 -77
- package/autorest/codegen/models/dictionary_schema.py +0 -103
- package/autorest/codegen/models/enum_schema.py +0 -215
- package/autorest/codegen/models/list_schema.py +0 -123
- package/autorest/codegen/models/object_schema.py +0 -253
- package/autorest/codegen/models/primitive_schemas.py +0 -466
- package/autorest/codegen/models/request_builder_parameter_list.py +0 -280
- package/autorest/codegen/models/rest.py +0 -42
- package/autorest/codegen/models/schema_request.py +0 -45
- package/autorest/codegen/models/schema_response.py +0 -136
- package/autorest/codegen/serializers/rest_serializer.py +0 -57
- package/autorest/namer/__init__.py +0 -25
- package/autorest/namer/name_converter.py +0 -412
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
# license information.
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
6
|
from enum import Enum
|
|
7
|
-
from typing import Dict, List, Optional, Tuple, Union, Set
|
|
7
|
+
from typing import Dict, List, Optional, Tuple, Union, Set, Mapping
|
|
8
|
+
|
|
8
9
|
|
|
9
10
|
class ImportType(str, Enum):
|
|
10
11
|
STDLIB = "stdlib"
|
|
@@ -12,11 +13,13 @@ class ImportType(str, Enum):
|
|
|
12
13
|
AZURECORE = "azurecore"
|
|
13
14
|
LOCAL = "local"
|
|
14
15
|
|
|
16
|
+
|
|
15
17
|
class TypingSection(str, Enum):
|
|
16
18
|
REGULAR = "regular" # this import is always a typing import
|
|
17
19
|
CONDITIONAL = "conditional" # is a typing import when we're dealing with files that py2 will use, else regular
|
|
18
20
|
TYPING = "typing" # never a typing import
|
|
19
21
|
|
|
22
|
+
|
|
20
23
|
class ImportModel:
|
|
21
24
|
def __init__(
|
|
22
25
|
self,
|
|
@@ -36,11 +39,11 @@ class ImportModel:
|
|
|
36
39
|
def __eq__(self, other):
|
|
37
40
|
try:
|
|
38
41
|
return (
|
|
39
|
-
self.typing_section == other.typing_section
|
|
40
|
-
self.import_type == other.import_type
|
|
41
|
-
self.module_name == other.module_name
|
|
42
|
-
self.submodule_name == other.submodule_name
|
|
43
|
-
self.alias == other.alias
|
|
42
|
+
self.typing_section == other.typing_section
|
|
43
|
+
and self.import_type == other.import_type
|
|
44
|
+
and self.module_name == other.module_name
|
|
45
|
+
and self.submodule_name == other.submodule_name
|
|
46
|
+
and self.alias == other.alias
|
|
44
47
|
)
|
|
45
48
|
except AttributeError:
|
|
46
49
|
return False
|
|
@@ -52,18 +55,32 @@ class ImportModel:
|
|
|
52
55
|
retval += hash(getattr(self, attr))
|
|
53
56
|
return retval
|
|
54
57
|
|
|
55
|
-
|
|
58
|
+
|
|
59
|
+
class TypeDefinition:
|
|
56
60
|
def __init__(
|
|
57
61
|
self,
|
|
58
|
-
|
|
59
|
-
|
|
62
|
+
sync_definition: str,
|
|
63
|
+
async_definition: str,
|
|
64
|
+
version_imports: Mapping[Optional[Tuple[int, int]], ImportModel] = None,
|
|
65
|
+
):
|
|
66
|
+
# version_imports: a map of "python version -> ImportModel".
|
|
67
|
+
# The python version is in form of (major, minor), for instance (3, 9) stands for py3.9.
|
|
68
|
+
# If the python version is None, it's a default ImportModel.
|
|
69
|
+
self.sync_definition = sync_definition
|
|
70
|
+
self.async_definition = async_definition
|
|
71
|
+
self.version_imports = version_imports
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class FileImport:
|
|
75
|
+
def __init__(self, imports: List[ImportModel] = None) -> None:
|
|
60
76
|
self.imports = imports or []
|
|
61
77
|
# has sync and async type definitions
|
|
62
|
-
self.type_definitions: Dict[str,
|
|
78
|
+
self.type_definitions: Dict[str, TypeDefinition] = {}
|
|
63
79
|
|
|
64
80
|
def _append_import(self, import_model: ImportModel) -> None:
|
|
65
81
|
if not any(
|
|
66
|
-
i
|
|
82
|
+
i
|
|
83
|
+
for i in self.imports
|
|
67
84
|
if all(
|
|
68
85
|
getattr(i, attr) == getattr(import_model, attr)
|
|
69
86
|
for attr in dir(i)
|
|
@@ -72,7 +89,9 @@ class FileImport:
|
|
|
72
89
|
):
|
|
73
90
|
self.imports.append(import_model)
|
|
74
91
|
|
|
75
|
-
def get_imports_from_section(
|
|
92
|
+
def get_imports_from_section(
|
|
93
|
+
self, typing_section: TypingSection
|
|
94
|
+
) -> List[ImportModel]:
|
|
76
95
|
return [i for i in self.imports if i.typing_section == typing_section]
|
|
77
96
|
|
|
78
97
|
def add_submodule_import(
|
|
@@ -83,15 +102,16 @@ class FileImport:
|
|
|
83
102
|
typing_section: TypingSection = TypingSection.REGULAR,
|
|
84
103
|
alias: Optional[str] = None,
|
|
85
104
|
) -> None:
|
|
86
|
-
"""Add an import to this import block.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
105
|
+
"""Add an import to this import block."""
|
|
106
|
+
self._append_import(
|
|
107
|
+
ImportModel(
|
|
108
|
+
typing_section=typing_section,
|
|
109
|
+
import_type=import_type,
|
|
110
|
+
module_name=module_name,
|
|
111
|
+
submodule_name=submodule_name,
|
|
112
|
+
alias=alias,
|
|
113
|
+
)
|
|
114
|
+
)
|
|
95
115
|
|
|
96
116
|
def add_import(
|
|
97
117
|
self,
|
|
@@ -101,16 +121,25 @@ class FileImport:
|
|
|
101
121
|
alias: Optional[str] = None,
|
|
102
122
|
) -> None:
|
|
103
123
|
# Implementation detail: a regular import is just a "from" with no from
|
|
104
|
-
self._append_import(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
124
|
+
self._append_import(
|
|
125
|
+
ImportModel(
|
|
126
|
+
typing_section=typing_section,
|
|
127
|
+
import_type=import_type,
|
|
128
|
+
module_name=module_name,
|
|
129
|
+
alias=alias,
|
|
130
|
+
)
|
|
131
|
+
)
|
|
110
132
|
|
|
111
|
-
def define_mypy_type(
|
|
112
|
-
self
|
|
113
|
-
|
|
133
|
+
def define_mypy_type(
|
|
134
|
+
self,
|
|
135
|
+
type_name: str,
|
|
136
|
+
type_value: str,
|
|
137
|
+
async_type_value: Optional[str] = None,
|
|
138
|
+
version_imports: Mapping[Optional[Tuple[int, int]], ImportModel] = None,
|
|
139
|
+
):
|
|
140
|
+
self.type_definitions[type_name] = TypeDefinition(
|
|
141
|
+
type_value, async_type_value or type_value, version_imports
|
|
142
|
+
)
|
|
114
143
|
|
|
115
144
|
def merge(self, file_import: "FileImport") -> None:
|
|
116
145
|
"""Merge the given file import format."""
|
|
@@ -118,23 +147,46 @@ class FileImport:
|
|
|
118
147
|
self._append_import(i)
|
|
119
148
|
self.type_definitions.update(file_import.type_definitions)
|
|
120
149
|
|
|
121
|
-
def
|
|
150
|
+
def define_mutable_mapping_type(self) -> None:
|
|
151
|
+
"""Helper function for defining the mutable mapping type"""
|
|
152
|
+
self.define_mypy_type(
|
|
153
|
+
"JSON",
|
|
154
|
+
"MutableMapping[str, Any] # pylint: disable=unsubscriptable-object",
|
|
155
|
+
None,
|
|
156
|
+
{
|
|
157
|
+
(3, 9): ImportModel(
|
|
158
|
+
TypingSection.CONDITIONAL,
|
|
159
|
+
ImportType.STDLIB,
|
|
160
|
+
"collections.abc",
|
|
161
|
+
submodule_name="MutableMapping",
|
|
162
|
+
),
|
|
163
|
+
None: ImportModel(
|
|
164
|
+
TypingSection.CONDITIONAL,
|
|
165
|
+
ImportType.STDLIB,
|
|
166
|
+
"typing",
|
|
167
|
+
submodule_name="MutableMapping",
|
|
168
|
+
),
|
|
169
|
+
},
|
|
170
|
+
)
|
|
171
|
+
self.add_submodule_import("typing", "Any", ImportType.STDLIB)
|
|
172
|
+
|
|
173
|
+
def to_dict(
|
|
174
|
+
self,
|
|
175
|
+
) -> Dict[
|
|
122
176
|
TypingSection,
|
|
123
|
-
Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]]
|
|
177
|
+
Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]],
|
|
124
178
|
]:
|
|
125
179
|
retval: Dict[
|
|
126
180
|
TypingSection,
|
|
127
|
-
Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]]
|
|
181
|
+
Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]],
|
|
128
182
|
] = dict()
|
|
129
183
|
for i in self.imports:
|
|
130
184
|
name_import: Optional[Union[str, Tuple[str, str]]] = None
|
|
131
185
|
if i.submodule_name:
|
|
132
|
-
name_import = (
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
i.module_name, set()
|
|
139
|
-
).add(name_import)
|
|
186
|
+
name_import = (
|
|
187
|
+
(i.submodule_name, i.alias) if i.alias else i.submodule_name
|
|
188
|
+
)
|
|
189
|
+
retval.setdefault(i.typing_section, dict()).setdefault(
|
|
190
|
+
i.import_type, dict()
|
|
191
|
+
).setdefault(i.module_name, set()).add(name_import)
|
|
140
192
|
return retval
|
|
@@ -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
|
|
@@ -3,182 +3,139 @@
|
|
|
3
3
|
# Licensed under the MIT License. See License.txt in the project root for
|
|
4
4
|
# license information.
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
|
-
import
|
|
7
|
-
from typing import Dict, List, Any, Optional, Set, cast
|
|
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 .
|
|
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 .
|
|
14
|
-
from .
|
|
11
|
+
from .request_builder import RequestBuilder
|
|
12
|
+
from .parameter_list import ParameterList
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from .code_model import CodeModel
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
LROResponseType = TypeVar(
|
|
18
|
+
"LROResponseType", bound=Union[LROResponse, LROPagingResponse]
|
|
19
|
+
)
|
|
17
20
|
|
|
18
21
|
|
|
19
|
-
class
|
|
22
|
+
class LROOperationBase(OperationBase[LROResponseType]):
|
|
20
23
|
def __init__(
|
|
21
24
|
self,
|
|
22
|
-
code_model,
|
|
23
25
|
yaml_data: Dict[str, Any],
|
|
26
|
+
code_model: "CodeModel",
|
|
24
27
|
name: str,
|
|
25
|
-
|
|
26
|
-
api_versions: Set[str],
|
|
28
|
+
request_builder: RequestBuilder,
|
|
27
29
|
parameters: ParameterList,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
responses: List[LROResponseType],
|
|
31
|
+
exceptions: List[Response],
|
|
32
|
+
*,
|
|
33
|
+
overloads: Optional[List[Operation]] = None,
|
|
34
|
+
public: bool = True,
|
|
35
|
+
want_tracing: bool = True,
|
|
36
|
+
abstract: bool = False,
|
|
35
37
|
) -> None:
|
|
36
|
-
super(
|
|
37
|
-
code_model,
|
|
38
|
-
yaml_data,
|
|
39
|
-
name,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
want_description_docstring,
|
|
49
|
-
want_tracing,
|
|
38
|
+
super().__init__(
|
|
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,
|
|
48
|
+
want_tracing=want_tracing,
|
|
49
|
+
abstract=abstract,
|
|
50
50
|
)
|
|
51
|
-
self.lro_options = yaml_data.get("extensions", {}).get("x-ms-long-running-operation-options", {})
|
|
52
51
|
self.name = "begin_" + self.name
|
|
52
|
+
self.lro_options: Dict[str, Any] = self.yaml_data.get("lroOptions", {})
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def operation_type(self) -> str:
|
|
56
|
+
return "lro"
|
|
53
57
|
|
|
54
58
|
@property
|
|
55
|
-
def
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
+
}
|
|
60
68
|
response = None
|
|
61
69
|
if len(num_response_schemas) > 1:
|
|
62
70
|
# choose the response that has a status code of 200
|
|
63
|
-
responses_with_200_status_codes = [
|
|
64
|
-
r for r in responses_with_bodies if 200 in r.status_codes
|
|
65
|
-
]
|
|
66
71
|
try:
|
|
67
|
-
response =
|
|
68
|
-
|
|
69
|
-
response_schema = cast(BaseSchema, response.schema).serialization_type
|
|
70
|
-
_LOGGER.warning(
|
|
71
|
-
"Multiple schema types in responses: %s. Choosing: %s", schema_types, response_schema
|
|
72
|
+
response = next(
|
|
73
|
+
r for r in responses_with_bodies if 200 in r.status_codes
|
|
72
74
|
)
|
|
73
|
-
except
|
|
75
|
+
except StopIteration:
|
|
74
76
|
raise ValueError(
|
|
75
|
-
f"Your swagger is invalid because you have multiple response schemas for LRO"
|
|
76
|
-
f" method {self.
|
|
77
|
+
f"Your swagger is invalid because you have multiple response schemas for LRO"
|
|
78
|
+
+ f" method {self.name} and none of them have a 200 status code."
|
|
77
79
|
)
|
|
78
80
|
|
|
79
81
|
elif num_response_schemas:
|
|
80
82
|
response = responses_with_bodies[0]
|
|
81
83
|
return response
|
|
82
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
|
+
|
|
83
89
|
@property
|
|
84
90
|
def initial_operation(self) -> Operation:
|
|
85
|
-
operation
|
|
86
|
-
|
|
87
|
-
yaml_data=
|
|
91
|
+
"""Initial operation that creates the first call for LRO polling"""
|
|
92
|
+
return Operation(
|
|
93
|
+
yaml_data=self.yaml_data,
|
|
94
|
+
code_model=self.code_model,
|
|
95
|
+
request_builder=self.code_model.lookup_request_builder(id(self.yaml_data)),
|
|
88
96
|
name=self.name[5:] + "_initial",
|
|
89
|
-
|
|
90
|
-
api_versions=self.api_versions,
|
|
97
|
+
overloads=self.overloads,
|
|
91
98
|
parameters=self.parameters,
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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,
|
|
97
105
|
want_tracing=False,
|
|
98
106
|
)
|
|
99
|
-
operation.request_builder = self.request_builder
|
|
100
|
-
return operation
|
|
101
|
-
|
|
102
|
-
@property
|
|
103
|
-
def has_optional_return_type(self) -> bool:
|
|
104
|
-
"""An LROOperation will never have an optional return type, we will always return a poller"""
|
|
105
|
-
return False
|
|
106
|
-
|
|
107
|
-
def _get_lro_extension(self, extension_base, async_mode, *, azure_arm=None):
|
|
108
|
-
extension_name = extension_base + ("-async" if async_mode else "-sync")
|
|
109
|
-
extension = self.yaml_data["extensions"][extension_name]
|
|
110
|
-
arm_extension = None
|
|
111
|
-
if azure_arm is not None:
|
|
112
|
-
arm_extension = "azure-arm" if azure_arm else "data-plane"
|
|
113
|
-
return extension[arm_extension] if arm_extension else extension
|
|
114
|
-
|
|
115
|
-
def get_poller_path(self, async_mode: bool) -> str:
|
|
116
|
-
return self._get_lro_extension("poller", async_mode)
|
|
117
107
|
|
|
118
108
|
def get_poller(self, async_mode: bool) -> str:
|
|
119
|
-
return self.
|
|
120
|
-
|
|
121
|
-
def get_default_polling_method_path(self, async_mode: bool, azure_arm: bool) -> str:
|
|
122
|
-
return self._get_lro_extension("default-polling-method", async_mode, azure_arm=azure_arm)
|
|
123
|
-
|
|
124
|
-
def get_default_polling_method(self, async_mode: bool, azure_arm: bool) -> str:
|
|
125
|
-
return self.get_default_polling_method_path(async_mode, azure_arm).split(".")[-1]
|
|
109
|
+
return self.responses[0].get_poller(async_mode)
|
|
126
110
|
|
|
127
|
-
def
|
|
128
|
-
return self.
|
|
129
|
-
|
|
130
|
-
def get_default_no_polling_method(self, async_mode: bool) -> str:
|
|
131
|
-
return self.get_default_no_polling_method_path(async_mode).split(".")[-1]
|
|
132
|
-
|
|
133
|
-
def get_base_polling_method_path(self, async_mode: bool) -> str:
|
|
134
|
-
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)
|
|
135
113
|
|
|
136
114
|
def get_base_polling_method(self, async_mode: bool) -> str:
|
|
137
|
-
return self.
|
|
138
|
-
|
|
139
|
-
def imports_for_multiapi(self, async_mode: bool) -> FileImport:
|
|
140
|
-
file_import = super().imports_for_multiapi(async_mode)
|
|
141
|
-
poller_import_path = ".".join(self.get_poller_path(async_mode).split(".")[:-1])
|
|
142
|
-
poller = self.get_poller(async_mode)
|
|
143
|
-
file_import.add_submodule_import(poller_import_path, poller, ImportType.AZURECORE, TypingSection.CONDITIONAL)
|
|
144
|
-
return file_import
|
|
115
|
+
return self.responses[0].get_base_polling_method(async_mode)
|
|
145
116
|
|
|
146
|
-
def
|
|
147
|
-
|
|
148
|
-
file_import.add_submodule_import("typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
149
|
-
|
|
150
|
-
poller_import_path = ".".join(self.get_poller_path(async_mode).split(".")[:-1])
|
|
151
|
-
poller = self.get_poller(async_mode)
|
|
152
|
-
file_import.add_submodule_import(poller_import_path, poller, ImportType.AZURECORE)
|
|
117
|
+
def get_base_polling_method_path(self, async_mode: bool) -> str:
|
|
118
|
+
return self.responses[0].get_base_polling_method_path(async_mode)
|
|
153
119
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
)
|
|
157
|
-
default_polling_method = self.get_default_polling_method(async_mode, self.code_model.options['azure_arm'])
|
|
158
|
-
file_import.add_submodule_import(
|
|
159
|
-
default_polling_method_import_path, default_polling_method, ImportType.AZURECORE
|
|
160
|
-
)
|
|
120
|
+
def get_no_polling_method(self, async_mode: bool) -> str:
|
|
121
|
+
return self.responses[0].get_no_polling_method(async_mode)
|
|
161
122
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
file_import.add_submodule_import(
|
|
167
|
-
default_no_polling_method_import_path, default_no_polling_method, ImportType.AZURECORE
|
|
168
|
-
)
|
|
169
|
-
|
|
170
|
-
base_polling_method_import_path = ".".join(
|
|
171
|
-
self.get_base_polling_method_path(async_mode).split(".")[:-1]
|
|
172
|
-
)
|
|
173
|
-
base_polling_method = self.get_base_polling_method(async_mode)
|
|
174
|
-
file_import.add_submodule_import(base_polling_method_import_path, base_polling_method, ImportType.AZURECORE)
|
|
175
|
-
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)
|
|
176
127
|
if async_mode:
|
|
177
|
-
file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
178
|
-
if self.code_model.options["tracing"] and self.want_tracing:
|
|
179
128
|
file_import.add_submodule_import(
|
|
180
|
-
f"azure.core.tracing.
|
|
181
|
-
f"
|
|
129
|
+
f"azure.core.tracing.decorator_async",
|
|
130
|
+
f"distributed_trace_async",
|
|
182
131
|
ImportType.AZURECORE,
|
|
183
132
|
)
|
|
133
|
+
file_import.add_submodule_import(
|
|
134
|
+
"typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
135
|
+
)
|
|
136
|
+
file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
|
|
184
137
|
return file_import
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class LROOperation(LROOperationBase[LROResponse]):
|
|
141
|
+
...
|