@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.
Files changed (120) hide show
  1. package/ChangeLog.md +91 -2
  2. package/README.md +30 -4
  3. package/autorest/__init__.py +2 -3
  4. package/autorest/black/__init__.py +12 -5
  5. package/autorest/codegen/__init__.py +130 -179
  6. package/autorest/codegen/models/__init__.py +122 -78
  7. package/autorest/codegen/models/base_builder.py +70 -72
  8. package/autorest/codegen/models/base_model.py +7 -5
  9. package/autorest/codegen/models/{base_schema.py → base_type.py} +62 -49
  10. package/autorest/codegen/models/client.py +195 -36
  11. package/autorest/codegen/models/code_model.py +165 -299
  12. package/autorest/codegen/models/combined_type.py +107 -0
  13. package/autorest/codegen/models/constant_type.py +122 -0
  14. package/autorest/codegen/models/credential_types.py +224 -0
  15. package/autorest/codegen/models/dictionary_type.py +116 -0
  16. package/autorest/codegen/models/enum_type.py +195 -0
  17. package/autorest/codegen/models/imports.py +95 -41
  18. package/autorest/codegen/models/list_type.py +134 -0
  19. package/autorest/codegen/models/lro_operation.py +90 -133
  20. package/autorest/codegen/models/lro_paging_operation.py +28 -12
  21. package/autorest/codegen/models/model_type.py +239 -0
  22. package/autorest/codegen/models/operation.py +415 -241
  23. package/autorest/codegen/models/operation_group.py +82 -88
  24. package/autorest/codegen/models/paging_operation.py +101 -117
  25. package/autorest/codegen/models/parameter.py +307 -322
  26. package/autorest/codegen/models/parameter_list.py +366 -357
  27. package/autorest/codegen/models/primitive_types.py +544 -0
  28. package/autorest/codegen/models/property.py +122 -134
  29. package/autorest/codegen/models/request_builder.py +138 -86
  30. package/autorest/codegen/models/request_builder_parameter.py +122 -79
  31. package/autorest/codegen/models/response.py +325 -0
  32. package/autorest/codegen/models/utils.py +17 -1
  33. package/autorest/codegen/serializers/__init__.py +242 -118
  34. package/autorest/codegen/serializers/builder_serializer.py +863 -1027
  35. package/autorest/codegen/serializers/client_serializer.py +148 -82
  36. package/autorest/codegen/serializers/general_serializer.py +44 -47
  37. package/autorest/codegen/serializers/import_serializer.py +96 -31
  38. package/autorest/codegen/serializers/metadata_serializer.py +39 -79
  39. package/autorest/codegen/serializers/model_base_serializer.py +65 -29
  40. package/autorest/codegen/serializers/model_generic_serializer.py +9 -10
  41. package/autorest/codegen/serializers/model_init_serializer.py +4 -2
  42. package/autorest/codegen/serializers/model_python3_serializer.py +29 -22
  43. package/autorest/codegen/serializers/operation_groups_serializer.py +21 -18
  44. package/autorest/codegen/serializers/operations_init_serializer.py +23 -11
  45. package/autorest/codegen/serializers/parameter_serializer.py +174 -0
  46. package/autorest/codegen/serializers/patch_serializer.py +14 -2
  47. package/autorest/codegen/serializers/request_builders_serializer.py +57 -0
  48. package/autorest/codegen/serializers/utils.py +0 -103
  49. package/autorest/codegen/templates/MANIFEST.in.jinja2 +1 -0
  50. package/autorest/codegen/templates/{service_client.py.jinja2 → client.py.jinja2} +7 -7
  51. package/autorest/codegen/templates/config.py.jinja2 +13 -13
  52. package/autorest/codegen/templates/enum.py.jinja2 +4 -4
  53. package/autorest/codegen/templates/enum_container.py.jinja2 +1 -2
  54. package/autorest/codegen/templates/init.py.jinja2 +9 -6
  55. package/autorest/codegen/templates/keywords.jinja2 +14 -1
  56. package/autorest/codegen/templates/lro_operation.py.jinja2 +6 -5
  57. package/autorest/codegen/templates/lro_paging_operation.py.jinja2 +6 -5
  58. package/autorest/codegen/templates/metadata.json.jinja2 +36 -35
  59. package/autorest/codegen/templates/model.py.jinja2 +23 -29
  60. package/autorest/codegen/templates/model_container.py.jinja2 +2 -1
  61. package/autorest/codegen/templates/model_init.py.jinja2 +9 -8
  62. package/autorest/codegen/templates/operation.py.jinja2 +10 -15
  63. package/autorest/codegen/templates/operation_group.py.jinja2 +14 -13
  64. package/autorest/codegen/templates/operation_groups_container.py.jinja2 +1 -2
  65. package/autorest/codegen/templates/operation_tools.jinja2 +8 -2
  66. package/autorest/codegen/templates/operations_folder_init.py.jinja2 +4 -0
  67. package/autorest/codegen/templates/paging_operation.py.jinja2 +7 -8
  68. package/autorest/codegen/templates/patch.py.jinja2 +18 -29
  69. package/autorest/codegen/templates/request_builder.py.jinja2 +20 -13
  70. package/autorest/codegen/templates/setup.py.jinja2 +9 -3
  71. package/autorest/codegen/templates/vendor.py.jinja2 +12 -2
  72. package/autorest/jsonrpc/__init__.py +7 -12
  73. package/autorest/jsonrpc/localapi.py +4 -3
  74. package/autorest/jsonrpc/server.py +28 -9
  75. package/autorest/jsonrpc/stdstream.py +13 -6
  76. package/autorest/m2r/__init__.py +5 -8
  77. package/autorest/m4reformatter/__init__.py +1108 -0
  78. package/autorest/multiapi/__init__.py +24 -14
  79. package/autorest/multiapi/models/client.py +21 -11
  80. package/autorest/multiapi/models/code_model.py +23 -10
  81. package/autorest/multiapi/models/config.py +4 -1
  82. package/autorest/multiapi/models/constant_global_parameter.py +1 -0
  83. package/autorest/multiapi/models/global_parameter.py +2 -1
  84. package/autorest/multiapi/models/global_parameters.py +14 -8
  85. package/autorest/multiapi/models/imports.py +35 -18
  86. package/autorest/multiapi/models/mixin_operation.py +5 -5
  87. package/autorest/multiapi/models/operation_group.py +2 -1
  88. package/autorest/multiapi/models/operation_mixin_group.py +21 -10
  89. package/autorest/multiapi/serializers/__init__.py +20 -25
  90. package/autorest/multiapi/serializers/import_serializer.py +47 -15
  91. package/autorest/multiapi/serializers/multiapi_serializer.py +17 -17
  92. package/autorest/multiapi/templates/multiapi_config.py.jinja2 +3 -3
  93. package/autorest/multiapi/templates/multiapi_init.py.jinja2 +2 -2
  94. package/autorest/multiapi/templates/multiapi_operations_mixin.py.jinja2 +4 -4
  95. package/autorest/multiapi/templates/multiapi_service_client.py.jinja2 +9 -9
  96. package/autorest/multiapi/utils.py +3 -3
  97. package/autorest/postprocess/__init__.py +202 -0
  98. package/autorest/postprocess/get_all.py +19 -0
  99. package/autorest/postprocess/venvtools.py +73 -0
  100. package/autorest/preprocess/__init__.py +209 -0
  101. package/autorest/preprocess/helpers.py +54 -0
  102. package/autorest/{namer → preprocess}/python_mappings.py +25 -32
  103. package/package.json +3 -3
  104. package/run-python3.js +2 -3
  105. package/venvtools.py +1 -1
  106. package/autorest/codegen/models/constant_schema.py +0 -97
  107. package/autorest/codegen/models/credential_schema.py +0 -90
  108. package/autorest/codegen/models/credential_schema_policy.py +0 -77
  109. package/autorest/codegen/models/dictionary_schema.py +0 -103
  110. package/autorest/codegen/models/enum_schema.py +0 -246
  111. package/autorest/codegen/models/list_schema.py +0 -113
  112. package/autorest/codegen/models/object_schema.py +0 -249
  113. package/autorest/codegen/models/primitive_schemas.py +0 -476
  114. package/autorest/codegen/models/request_builder_parameter_list.py +0 -280
  115. package/autorest/codegen/models/rest.py +0 -42
  116. package/autorest/codegen/models/schema_request.py +0 -45
  117. package/autorest/codegen/models/schema_response.py +0 -123
  118. package/autorest/codegen/serializers/rest_serializer.py +0 -57
  119. package/autorest/namer/__init__.py +0 -25
  120. 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 and
40
- self.import_type == other.import_type and
41
- self.module_name == other.module_name and
42
- self.submodule_name == other.submodule_name and
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
- class FileImport:
58
+
59
+ class TypeDefinition:
56
60
  def __init__(
57
61
  self,
58
- imports: List[ImportModel] = None
59
- ) -> None:
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, Tuple[str, 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 for i in self.imports
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(self, typing_section: TypingSection) -> List[ImportModel]:
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
- self._append_import(ImportModel(
89
- typing_section=typing_section,
90
- import_type=import_type,
91
- module_name=module_name,
92
- submodule_name=submodule_name,
93
- alias=alias,
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(ImportModel(
104
- typing_section=typing_section,
105
- import_type=import_type,
106
- module_name=module_name,
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(self, type_name: str, type_value: str, async_type_value: Optional[str] = None):
110
- self.add_submodule_import("typing", "TypeVar", ImportType.STDLIB, TypingSection.CONDITIONAL)
111
- self.type_definitions[type_name] = (type_value, async_type_value or type_value)
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 to_dict(self) -> Dict[
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 = (i.submodule_name, i.alias) if i.alias else i.submodule_name
131
- retval.setdefault(
132
- i.typing_section, dict()
133
- ).setdefault(
134
- i.import_type, dict()
135
- ).setdefault(
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 logging
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 .parameter_list import ParameterList
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 .base_schema import BaseSchema
14
- from .schema_request import SchemaRequest
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
- _LOGGER = logging.getLogger(__name__)
17
+ LROResponseType = TypeVar(
18
+ "LROResponseType", bound=Union[LROResponse, LROPagingResponse]
19
+ )
17
20
 
18
21
 
19
- class LROOperation(Operation):
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
- description: str,
26
- api_versions: Set[str],
28
+ request_builder: RequestBuilder,
27
29
  parameters: ParameterList,
28
- multiple_content_type_parameters: ParameterList,
29
- schema_requests: List[SchemaRequest],
30
- summary: Optional[str] = None,
31
- responses: Optional[List[SchemaResponse]] = None,
32
- exceptions: Optional[List[SchemaResponse]] = None,
33
- want_description_docstring: bool = True,
34
- want_tracing: bool = True
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(LROOperation, self).__init__(
37
- code_model,
38
- yaml_data,
39
- name,
40
- description,
41
- api_versions,
42
- parameters,
43
- multiple_content_type_parameters,
44
- schema_requests,
45
- summary,
46
- responses,
47
- exceptions,
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 lro_response(self) -> Optional[SchemaResponse]:
56
- if not self.responses:
57
- return None
58
- responses_with_bodies = [r for r in self.responses if r.has_body]
59
- num_response_schemas = {r.schema for r in responses_with_bodies}
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 = responses_with_200_status_codes[0]
68
- schema_types = {r.schema for r in responses_with_bodies}
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 IndexError:
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.python_name} and none of them have a 200 status code."
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 = Operation(
86
- self.code_model,
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
- description="",
90
- api_versions=self.api_versions,
97
+ overloads=self.overloads,
91
98
  parameters=self.parameters,
92
- schema_requests=self.schema_requests,
93
- multiple_content_type_parameters=self.multiple_content_type_parameters,
94
- summary=self.summary,
95
- responses=self.responses,
96
- want_description_docstring=False,
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.get_poller_path(async_mode).split(".")[-1]
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 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.get_base_polling_method_path(async_mode).split(".")[-1]
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
- default_no_polling_method_import_path = ".".join(
163
- self.get_default_no_polling_method_path(async_mode).split(".")[:-1]
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
- 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)
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.decorator{'_async' if async_mode else ''}",
181
- f"distributed_trace{'_async' if async_mode else ''}",
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 LROOperation
8
- from .paging_operation import PagingOperation
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
- def imports(self, async_mode: bool) -> FileImport:
13
- lro_imports = LROOperation.imports(self, async_mode)
14
- paging_imports = PagingOperation.imports(self, async_mode)
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]