@autorest/python 5.14.0 → 5.17.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 +91 -2
- package/README.md +30 -4
- package/autorest/__init__.py +2 -3
- package/autorest/black/__init__.py +12 -5
- package/autorest/codegen/__init__.py +130 -179
- 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} +62 -49
- package/autorest/codegen/models/client.py +195 -36
- package/autorest/codegen/models/code_model.py +165 -299
- 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 +116 -0
- package/autorest/codegen/models/enum_type.py +195 -0
- package/autorest/codegen/models/imports.py +95 -41
- package/autorest/codegen/models/list_type.py +134 -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 +239 -0
- package/autorest/codegen/models/operation.py +415 -241
- package/autorest/codegen/models/operation_group.py +82 -88
- package/autorest/codegen/models/paging_operation.py +101 -117
- package/autorest/codegen/models/parameter.py +307 -322
- package/autorest/codegen/models/parameter_list.py +366 -357
- package/autorest/codegen/models/primitive_types.py +544 -0
- package/autorest/codegen/models/property.py +122 -134
- package/autorest/codegen/models/request_builder.py +138 -86
- package/autorest/codegen/models/request_builder_parameter.py +122 -79
- package/autorest/codegen/models/response.py +325 -0
- package/autorest/codegen/models/utils.py +17 -1
- package/autorest/codegen/serializers/__init__.py +242 -118
- package/autorest/codegen/serializers/builder_serializer.py +863 -1027
- package/autorest/codegen/serializers/client_serializer.py +148 -82
- package/autorest/codegen/serializers/general_serializer.py +44 -47
- 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 +65 -29
- 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 -18
- 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 +14 -2
- package/autorest/codegen/serializers/request_builders_serializer.py +57 -0
- package/autorest/codegen/serializers/utils.py +0 -103
- 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 -2
- package/autorest/codegen/templates/init.py.jinja2 +9 -6
- package/autorest/codegen/templates/keywords.jinja2 +14 -1
- 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 -29
- package/autorest/codegen/templates/model_container.py.jinja2 +2 -1
- package/autorest/codegen/templates/model_init.py.jinja2 +9 -8
- package/autorest/codegen/templates/operation.py.jinja2 +10 -15
- package/autorest/codegen/templates/operation_group.py.jinja2 +14 -13
- package/autorest/codegen/templates/operation_groups_container.py.jinja2 +1 -2
- package/autorest/codegen/templates/operation_tools.jinja2 +8 -2
- package/autorest/codegen/templates/operations_folder_init.py.jinja2 +4 -0
- package/autorest/codegen/templates/paging_operation.py.jinja2 +7 -8
- package/autorest/codegen/templates/patch.py.jinja2 +18 -29
- package/autorest/codegen/templates/request_builder.py.jinja2 +20 -13
- package/autorest/codegen/templates/setup.py.jinja2 +9 -3
- package/autorest/codegen/templates/vendor.py.jinja2 +12 -2
- 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 +1108 -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 +35 -18
- 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 -15
- 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 +209 -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 -97
- package/autorest/codegen/models/credential_schema.py +0 -90
- 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 -246
- package/autorest/codegen/models/list_schema.py +0 -113
- package/autorest/codegen/models/object_schema.py +0 -249
- package/autorest/codegen/models/primitive_schemas.py +0 -476
- 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 -123
- 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,32 +102,44 @@ 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,
|
|
98
118
|
module_name: str,
|
|
99
119
|
import_type: ImportType,
|
|
100
|
-
typing_section: TypingSection = TypingSection.REGULAR
|
|
120
|
+
typing_section: TypingSection = TypingSection.REGULAR,
|
|
121
|
+
alias: Optional[str] = None,
|
|
101
122
|
) -> None:
|
|
102
123
|
# Implementation detail: a regular import is just a "from" with no from
|
|
103
|
-
self._append_import(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
+
)
|
|
108
132
|
|
|
109
|
-
def define_mypy_type(
|
|
110
|
-
self
|
|
111
|
-
|
|
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
|
+
)
|
|
112
143
|
|
|
113
144
|
def merge(self, file_import: "FileImport") -> None:
|
|
114
145
|
"""Merge the given file import format."""
|
|
@@ -116,23 +147,46 @@ class FileImport:
|
|
|
116
147
|
self._append_import(i)
|
|
117
148
|
self.type_definitions.update(file_import.type_definitions)
|
|
118
149
|
|
|
119
|
-
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[
|
|
120
176
|
TypingSection,
|
|
121
|
-
Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]]
|
|
177
|
+
Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]],
|
|
122
178
|
]:
|
|
123
179
|
retval: Dict[
|
|
124
180
|
TypingSection,
|
|
125
|
-
Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]]
|
|
181
|
+
Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]],
|
|
126
182
|
] = dict()
|
|
127
183
|
for i in self.imports:
|
|
128
184
|
name_import: Optional[Union[str, Tuple[str, str]]] = None
|
|
129
185
|
if i.submodule_name:
|
|
130
|
-
name_import = (
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
i.module_name, set()
|
|
137
|
-
).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)
|
|
138
192
|
return retval
|
|
@@ -0,0 +1,134 @@
|
|
|
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
|
|
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
|
+
|
|
13
|
+
|
|
14
|
+
class ListType(BaseType):
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
yaml_data: Dict[str, Any],
|
|
18
|
+
code_model: "CodeModel",
|
|
19
|
+
element_type: BaseType,
|
|
20
|
+
) -> None:
|
|
21
|
+
super().__init__(yaml_data=yaml_data, code_model=code_model)
|
|
22
|
+
self.element_type = element_type
|
|
23
|
+
self.max_items: Optional[int] = yaml_data.get("maxItems")
|
|
24
|
+
self.min_items: Optional[int] = yaml_data.get("minItems")
|
|
25
|
+
self.unique_items: bool = yaml_data.get("uniqueItems", False)
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def serialization_type(self) -> str:
|
|
29
|
+
return f"[{self.element_type.serialization_type}]"
|
|
30
|
+
|
|
31
|
+
def type_annotation(self, **kwargs: Any) -> str:
|
|
32
|
+
if self.code_model.options["version_tolerant"] and self.element_type.is_xml:
|
|
33
|
+
# this means we're version tolerant XML, we just return the XML element
|
|
34
|
+
return self.element_type.type_annotation(**kwargs)
|
|
35
|
+
return f"List[{self.element_type.type_annotation(**kwargs)}]"
|
|
36
|
+
|
|
37
|
+
def description(self, *, is_operation_file: bool) -> str:
|
|
38
|
+
return "" if is_operation_file else self.yaml_data.get("description", "")
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def xml_serialization_ctxt(self) -> Optional[str]:
|
|
42
|
+
attrs_list = []
|
|
43
|
+
base_xml_map = super().xml_serialization_ctxt
|
|
44
|
+
if base_xml_map:
|
|
45
|
+
attrs_list.append(base_xml_map)
|
|
46
|
+
|
|
47
|
+
# Attribute at the list level
|
|
48
|
+
if self.xml_metadata.get("wrapped", False):
|
|
49
|
+
attrs_list.append("'wrapped': True")
|
|
50
|
+
|
|
51
|
+
# Attributes of the items
|
|
52
|
+
item_xml_metadata = self.element_type.xml_metadata
|
|
53
|
+
if item_xml_metadata.get("name"):
|
|
54
|
+
attrs_list.append(f"'itemsName': '{item_xml_metadata['name']}'")
|
|
55
|
+
if item_xml_metadata.get("prefix", False):
|
|
56
|
+
attrs_list.append(f"'itemsPrefix': '{item_xml_metadata['prefix']}'")
|
|
57
|
+
if item_xml_metadata.get("namespace", False):
|
|
58
|
+
attrs_list.append(f"'itemsNs': '{item_xml_metadata['namespace']}'")
|
|
59
|
+
|
|
60
|
+
return ", ".join(attrs_list)
|
|
61
|
+
|
|
62
|
+
def docstring_type(self, **kwargs: Any) -> str:
|
|
63
|
+
if (
|
|
64
|
+
self.code_model.options["version_tolerant"]
|
|
65
|
+
and self.element_type.xml_metadata
|
|
66
|
+
):
|
|
67
|
+
# this means we're version tolerant XML, we just return the XML element
|
|
68
|
+
return self.element_type.docstring_type(**kwargs)
|
|
69
|
+
return f"list[{self.element_type.docstring_type(**kwargs)}]"
|
|
70
|
+
|
|
71
|
+
def docstring_text(self, **kwargs: Any) -> str:
|
|
72
|
+
if (
|
|
73
|
+
self.code_model.options["version_tolerant"]
|
|
74
|
+
and self.element_type.xml_metadata
|
|
75
|
+
):
|
|
76
|
+
# this means we're version tolerant XML, we just return the XML element
|
|
77
|
+
return self.element_type.docstring_text(**kwargs)
|
|
78
|
+
return f"list of {self.element_type.docstring_text(**kwargs)}"
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def validation(self) -> Optional[Dict[str, Union[bool, int, str]]]:
|
|
82
|
+
validation: Dict[str, Union[bool, int, str]] = {}
|
|
83
|
+
if self.max_items:
|
|
84
|
+
validation["max_items"] = self.max_items
|
|
85
|
+
validation["min_items"] = self.min_items or 0
|
|
86
|
+
if self.min_items:
|
|
87
|
+
validation["min_items"] = self.min_items
|
|
88
|
+
if self.unique_items:
|
|
89
|
+
validation["unique"] = True
|
|
90
|
+
return validation or None
|
|
91
|
+
|
|
92
|
+
def get_json_template_representation(
|
|
93
|
+
self,
|
|
94
|
+
*,
|
|
95
|
+
optional: bool = True,
|
|
96
|
+
client_default_value_declaration: Optional[str] = None,
|
|
97
|
+
description: Optional[str] = None,
|
|
98
|
+
) -> Any:
|
|
99
|
+
return [
|
|
100
|
+
self.element_type.get_json_template_representation(
|
|
101
|
+
optional=optional,
|
|
102
|
+
client_default_value_declaration=client_default_value_declaration,
|
|
103
|
+
description=description,
|
|
104
|
+
)
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def instance_check_template(self) -> str:
|
|
109
|
+
return "isinstance({}, list)"
|
|
110
|
+
|
|
111
|
+
@classmethod
|
|
112
|
+
def from_yaml(
|
|
113
|
+
cls, yaml_data: Dict[str, Any], code_model: "CodeModel"
|
|
114
|
+
) -> "ListType":
|
|
115
|
+
from . import build_type
|
|
116
|
+
|
|
117
|
+
return cls(
|
|
118
|
+
yaml_data=yaml_data,
|
|
119
|
+
code_model=code_model,
|
|
120
|
+
element_type=build_type(
|
|
121
|
+
yaml_data=yaml_data["elementType"], code_model=code_model
|
|
122
|
+
),
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
def imports(self, **kwargs: Any) -> FileImport:
|
|
126
|
+
file_import = FileImport()
|
|
127
|
+
if not (
|
|
128
|
+
self.code_model.options["version_tolerant"] and self.element_type.is_xml
|
|
129
|
+
):
|
|
130
|
+
file_import.add_submodule_import(
|
|
131
|
+
"typing", "List", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
132
|
+
)
|
|
133
|
+
file_import.merge(self.element_type.imports(**kwargs))
|
|
134
|
+
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]
|
|
126
|
-
|
|
127
|
-
def get_default_no_polling_method_path(self, async_mode: bool) -> str:
|
|
128
|
-
return self._get_lro_extension("default-no-polling-method", async_mode)
|
|
109
|
+
return self.responses[0].get_poller(async_mode)
|
|
129
110
|
|
|
130
|
-
def
|
|
131
|
-
return self.
|
|
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
|
|
145
|
-
|
|
146
|
-
def imports(self, async_mode: bool) -> FileImport:
|
|
147
|
-
file_import = super().imports(async_mode)
|
|
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)
|
|
153
|
-
|
|
154
|
-
default_polling_method_import_path = ".".join(
|
|
155
|
-
self.get_default_polling_method_path(async_mode, self.code_model.options['azure_arm']).split(".")[:-1]
|
|
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
|
-
)
|
|
115
|
+
return self.responses[0].get_base_polling_method(async_mode)
|
|
161
116
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
)
|
|
165
|
-
default_no_polling_method = self.get_default_no_polling_method(async_mode)
|
|
166
|
-
file_import.add_submodule_import(
|
|
167
|
-
default_no_polling_method_import_path, default_no_polling_method, ImportType.AZURECORE
|
|
168
|
-
)
|
|
117
|
+
def get_base_polling_method_path(self, async_mode: bool) -> str:
|
|
118
|
+
return self.responses[0].get_base_polling_method_path(async_mode)
|
|
169
119
|
|
|
170
|
-
|
|
171
|
-
|
|
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)
|
|
120
|
+
def get_no_polling_method(self, async_mode: bool) -> str:
|
|
121
|
+
return self.responses[0].get_no_polling_method(async_mode)
|
|
175
122
|
|
|
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
|
+
...
|
|
@@ -3,22 +3,38 @@
|
|
|
3
3
|
# Licensed under the MIT License. See License.txt in the project root for
|
|
4
4
|
# license information.
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
|
+
from typing import Any
|
|
6
7
|
from .imports import FileImport
|
|
7
|
-
from .lro_operation import
|
|
8
|
-
from .paging_operation import
|
|
8
|
+
from .lro_operation import LROOperationBase
|
|
9
|
+
from .paging_operation import PagingOperationBase
|
|
10
|
+
from .response import LROPagingResponse, Response
|
|
9
11
|
|
|
10
|
-
class LROPagingOperation(PagingOperation, LROOperation):
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
class LROPagingOperation(
|
|
14
|
+
LROOperationBase[LROPagingResponse], PagingOperationBase[LROPagingResponse]
|
|
15
|
+
):
|
|
16
|
+
@property
|
|
17
|
+
def success_status_codes(self):
|
|
18
|
+
"""The list of all successfull status code."""
|
|
19
|
+
return [200]
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def operation_type(self) -> str:
|
|
23
|
+
return "lropaging"
|
|
24
|
+
|
|
25
|
+
def cls_type_annotation(self, *, async_mode: bool) -> str:
|
|
26
|
+
return f"ClsType[{Response.type_annotation(self.responses[0], async_mode=async_mode)}]" # pylint: disable=no-member
|
|
27
|
+
|
|
28
|
+
def imports(
|
|
29
|
+
self, async_mode: bool, is_python3_file: bool, **kwargs: Any
|
|
30
|
+
) -> FileImport:
|
|
31
|
+
lro_imports = LROOperationBase.imports(
|
|
32
|
+
self, async_mode, is_python3_file, **kwargs
|
|
33
|
+
)
|
|
34
|
+
paging_imports = PagingOperationBase.imports(
|
|
35
|
+
self, async_mode, is_python3_file, **kwargs
|
|
36
|
+
)
|
|
15
37
|
|
|
16
38
|
file_import = lro_imports
|
|
17
39
|
file_import.merge(paging_imports)
|
|
18
40
|
return file_import
|
|
19
|
-
|
|
20
|
-
@property
|
|
21
|
-
def success_status_code(self):
|
|
22
|
-
"""The list of all successfull status code.
|
|
23
|
-
"""
|
|
24
|
-
return [200]
|