@autorest/python 5.13.0 → 5.16.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 +67 -0
- package/autorest/__init__.py +1 -2
- package/autorest/black/__init__.py +12 -5
- package/autorest/codegen/__init__.py +239 -105
- package/autorest/codegen/models/__init__.py +29 -18
- package/autorest/codegen/models/base_builder.py +48 -11
- package/autorest/codegen/models/base_model.py +6 -4
- package/autorest/codegen/models/base_schema.py +21 -24
- package/autorest/codegen/models/client.py +70 -20
- package/autorest/codegen/models/code_model.py +144 -129
- package/autorest/codegen/models/constant_schema.py +32 -16
- package/autorest/codegen/models/credential_model.py +55 -0
- package/autorest/codegen/models/credential_schema.py +21 -16
- package/autorest/codegen/models/credential_schema_policy.py +11 -15
- package/autorest/codegen/models/dictionary_schema.py +27 -24
- package/autorest/codegen/models/enum_schema.py +41 -62
- package/autorest/codegen/models/imports.py +72 -41
- package/autorest/codegen/models/list_schema.py +40 -18
- package/autorest/codegen/models/lro_operation.py +61 -25
- package/autorest/codegen/models/lro_paging_operation.py +5 -6
- package/autorest/codegen/models/object_schema.py +113 -59
- package/autorest/codegen/models/operation.py +251 -111
- package/autorest/codegen/models/operation_group.py +67 -32
- package/autorest/codegen/models/paging_operation.py +48 -21
- package/autorest/codegen/models/parameter.py +182 -90
- package/autorest/codegen/models/parameter_list.py +184 -163
- package/autorest/codegen/models/primitive_schemas.py +89 -70
- package/autorest/codegen/models/property.py +49 -31
- package/autorest/codegen/models/request_builder.py +67 -32
- package/autorest/codegen/models/request_builder_parameter.py +54 -23
- package/autorest/codegen/models/request_builder_parameter_list.py +77 -108
- package/autorest/codegen/models/schema_request.py +16 -6
- package/autorest/codegen/models/schema_response.py +35 -17
- package/autorest/codegen/models/utils.py +24 -1
- package/autorest/codegen/serializers/__init__.py +273 -89
- package/autorest/codegen/serializers/builder_serializer.py +711 -333
- package/autorest/codegen/serializers/client_serializer.py +114 -43
- package/autorest/codegen/serializers/general_serializer.py +84 -25
- package/autorest/codegen/serializers/import_serializer.py +93 -31
- package/autorest/codegen/serializers/metadata_serializer.py +73 -24
- package/autorest/codegen/serializers/model_base_serializer.py +42 -14
- package/autorest/codegen/serializers/model_generic_serializer.py +1 -4
- package/autorest/codegen/serializers/model_init_serializer.py +5 -1
- package/autorest/codegen/serializers/model_python3_serializer.py +9 -8
- package/autorest/codegen/serializers/operation_groups_serializer.py +20 -8
- package/autorest/codegen/serializers/operations_init_serializer.py +23 -11
- package/autorest/codegen/serializers/patch_serializer.py +14 -2
- package/autorest/codegen/serializers/{rest_serializer.py → request_builders_serializer.py} +29 -12
- package/autorest/codegen/serializers/utils.py +60 -21
- package/autorest/codegen/templates/CHANGELOG.md.jinja2 +6 -0
- package/autorest/codegen/templates/LICENSE.jinja2 +21 -0
- package/autorest/codegen/templates/MANIFEST.in.jinja2 +7 -0
- package/autorest/codegen/templates/README.md.jinja2 +105 -0
- package/autorest/codegen/templates/config.py.jinja2 +4 -4
- package/autorest/codegen/templates/dev_requirements.txt.jinja2 +10 -0
- package/autorest/codegen/templates/enum.py.jinja2 +1 -1
- package/autorest/codegen/templates/enum_container.py.jinja2 +0 -1
- 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 +5 -7
- package/autorest/codegen/templates/lro_paging_operation.py.jinja2 +5 -7
- package/autorest/codegen/templates/metadata.json.jinja2 +10 -9
- package/autorest/codegen/templates/model.py.jinja2 +1 -6
- package/autorest/codegen/templates/model_init.py.jinja2 +7 -4
- package/autorest/codegen/templates/operation.py.jinja2 +8 -11
- package/autorest/codegen/templates/operation_group.py.jinja2 +15 -18
- package/autorest/codegen/templates/operation_groups_container.py.jinja2 +1 -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 +19 -14
- package/autorest/codegen/templates/setup.py.jinja2 +79 -20
- 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 +13 -6
- package/autorest/jsonrpc/stdstream.py +13 -6
- package/autorest/m2r/__init__.py +5 -8
- 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 +18 -23
- package/autorest/multiapi/serializers/import_serializer.py +47 -15
- package/autorest/multiapi/serializers/multiapi_serializer.py +17 -17
- package/autorest/multiapi/templates/multiapi_operations_mixin.py.jinja2 +1 -1
- package/autorest/multiapi/utils.py +3 -3
- package/autorest/namer/__init__.py +2 -4
- package/autorest/namer/name_converter.py +200 -103
- package/autorest/namer/python_mappings.py +10 -22
- package/package.json +3 -3
- package/run-python3.js +2 -3
- package/venvtools.py +1 -1
- package/autorest/codegen/models/rest.py +0 -42
|
@@ -13,6 +13,7 @@ from .operation_mixin_group import OperationMixinGroup
|
|
|
13
13
|
from .global_parameters import GlobalParameters
|
|
14
14
|
from ..utils import _get_default_api_version_from_list
|
|
15
15
|
|
|
16
|
+
|
|
16
17
|
class CodeModel: # pylint: disable=too-many-instance-attributes
|
|
17
18
|
def __init__(
|
|
18
19
|
self,
|
|
@@ -23,7 +24,7 @@ class CodeModel: # pylint: disable=too-many-instance-attributes
|
|
|
23
24
|
default_version_metadata: Dict[str, Any],
|
|
24
25
|
mod_to_api_version: Dict[str, str],
|
|
25
26
|
version_path_to_metadata: Dict[Path, Dict[str, Any]],
|
|
26
|
-
user_specified_default_api: Optional[str] = None
|
|
27
|
+
user_specified_default_api: Optional[str] = None,
|
|
27
28
|
):
|
|
28
29
|
self.module_name = module_name
|
|
29
30
|
self.package_name = package_name
|
|
@@ -33,9 +34,13 @@ class CodeModel: # pylint: disable=too-many-instance-attributes
|
|
|
33
34
|
self.azure_arm = default_version_metadata["client"]["azure_arm"]
|
|
34
35
|
self.default_version_metadata = default_version_metadata
|
|
35
36
|
self.version_path_to_metadata = version_path_to_metadata
|
|
36
|
-
self.service_client = Client(
|
|
37
|
+
self.service_client = Client(
|
|
38
|
+
self.azure_arm, default_version_metadata, version_path_to_metadata
|
|
39
|
+
)
|
|
37
40
|
self.config = Config(default_version_metadata)
|
|
38
|
-
self.operation_mixin_group = OperationMixinGroup(
|
|
41
|
+
self.operation_mixin_group = OperationMixinGroup(
|
|
42
|
+
version_path_to_metadata, default_api_version
|
|
43
|
+
)
|
|
39
44
|
self.global_parameters = GlobalParameters(
|
|
40
45
|
default_version_metadata["global_parameters"]
|
|
41
46
|
)
|
|
@@ -45,17 +50,24 @@ class CodeModel: # pylint: disable=too-many-instance-attributes
|
|
|
45
50
|
def operation_groups(self) -> List[OperationGroup]:
|
|
46
51
|
operation_groups: List[OperationGroup] = []
|
|
47
52
|
for version_path, metadata_json in self.version_path_to_metadata.items():
|
|
48
|
-
if not metadata_json.get(
|
|
53
|
+
if not metadata_json.get("operation_groups"):
|
|
49
54
|
continue
|
|
50
|
-
operation_groups_metadata = metadata_json[
|
|
51
|
-
for
|
|
55
|
+
operation_groups_metadata = metadata_json["operation_groups"]
|
|
56
|
+
for (
|
|
57
|
+
operation_group_name,
|
|
58
|
+
operation_group_class_name,
|
|
59
|
+
) in operation_groups_metadata.items():
|
|
52
60
|
try:
|
|
53
|
-
operation_group = [
|
|
61
|
+
operation_group = [
|
|
62
|
+
og for og in operation_groups if og.name == operation_group_name
|
|
63
|
+
][0]
|
|
54
64
|
except IndexError:
|
|
55
65
|
operation_group = OperationGroup(operation_group_name)
|
|
56
66
|
operation_groups.append(operation_group)
|
|
57
67
|
operation_group.append_available_api(version_path.name)
|
|
58
|
-
operation_group.append_api_class_name_pair(
|
|
68
|
+
operation_group.append_api_class_name_pair(
|
|
69
|
+
version_path.name, operation_group_class_name
|
|
70
|
+
)
|
|
59
71
|
operation_groups.sort(key=lambda x: x.name)
|
|
60
72
|
return operation_groups
|
|
61
73
|
|
|
@@ -110,7 +122,7 @@ class CodeModel: # pylint: disable=too-many-instance-attributes
|
|
|
110
122
|
self.mod_to_api_version,
|
|
111
123
|
api_versions_list,
|
|
112
124
|
self.preview_mode,
|
|
113
|
-
self.user_specified_default_api
|
|
125
|
+
self.user_specified_default_api,
|
|
114
126
|
)
|
|
115
127
|
if local_default_api_version == self.default_api_version:
|
|
116
128
|
continue
|
|
@@ -129,5 +141,6 @@ class CodeModel: # pylint: disable=too-many-instance-attributes
|
|
|
129
141
|
@property
|
|
130
142
|
def default_models(self):
|
|
131
143
|
return sorted(
|
|
132
|
-
{self.default_api_version}
|
|
144
|
+
{self.default_api_version}
|
|
145
|
+
| {versions for _, versions in self.last_rt_list.items()}
|
|
133
146
|
)
|
|
@@ -7,6 +7,7 @@ import json
|
|
|
7
7
|
from typing import Any, Dict
|
|
8
8
|
from .imports import FileImport
|
|
9
9
|
|
|
10
|
+
|
|
10
11
|
class Config:
|
|
11
12
|
def __init__(self, default_version_metadata: Dict[str, Any]):
|
|
12
13
|
self.credential = default_version_metadata["config"]["credential"]
|
|
@@ -15,7 +16,9 @@ class Config:
|
|
|
15
16
|
|
|
16
17
|
def imports(self, async_mode: bool) -> FileImport:
|
|
17
18
|
imports_to_load = "async_imports" if async_mode else "sync_imports"
|
|
18
|
-
return FileImport(
|
|
19
|
+
return FileImport(
|
|
20
|
+
json.loads(self.default_version_metadata["config"][imports_to_load])
|
|
21
|
+
)
|
|
19
22
|
|
|
20
23
|
def credential_call(self, async_mode: bool) -> str:
|
|
21
24
|
if async_mode:
|
|
@@ -5,12 +5,13 @@
|
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
6
|
from typing import Any, Dict
|
|
7
7
|
|
|
8
|
+
|
|
8
9
|
class GlobalParameter:
|
|
9
10
|
def __init__(
|
|
10
11
|
self,
|
|
11
12
|
name: str,
|
|
12
13
|
global_parameter_metadata_sync: Dict[str, Any],
|
|
13
|
-
global_parameter_metadata_async: Dict[str, Any]
|
|
14
|
+
global_parameter_metadata_async: Dict[str, Any],
|
|
14
15
|
):
|
|
15
16
|
self.name = name
|
|
16
17
|
self.global_parameter_metadata_sync = global_parameter_metadata_sync
|
|
@@ -7,17 +7,19 @@ from typing import Any, Dict, List
|
|
|
7
7
|
from .global_parameter import GlobalParameter
|
|
8
8
|
from .constant_global_parameter import ConstantGlobalParameter
|
|
9
9
|
|
|
10
|
+
|
|
10
11
|
def _convert_global_parameters(sync_metadata, async_metadata):
|
|
11
12
|
global_parameters = [
|
|
12
13
|
GlobalParameter(
|
|
13
14
|
name=parameter_name,
|
|
14
15
|
global_parameter_metadata_sync=gp_sync,
|
|
15
|
-
global_parameter_metadata_async=async_metadata[parameter_name]
|
|
16
|
+
global_parameter_metadata_async=async_metadata[parameter_name],
|
|
16
17
|
)
|
|
17
18
|
for parameter_name, gp_sync in sync_metadata.items()
|
|
18
19
|
]
|
|
19
20
|
return global_parameters
|
|
20
21
|
|
|
22
|
+
|
|
21
23
|
class GlobalParameters:
|
|
22
24
|
def __init__(
|
|
23
25
|
self,
|
|
@@ -31,12 +33,15 @@ class GlobalParameters:
|
|
|
31
33
|
"""Return global params specific to multiapi service client + config
|
|
32
34
|
api_version, endpoint (re-adding it in specific are), and profile
|
|
33
35
|
"""
|
|
34
|
-
service_client_params_sync = self.global_parameters_metadata[
|
|
35
|
-
|
|
36
|
+
service_client_params_sync = self.global_parameters_metadata[
|
|
37
|
+
"service_client_specific"
|
|
38
|
+
]["sync"]
|
|
39
|
+
service_client_params_async = self.global_parameters_metadata[
|
|
40
|
+
"service_client_specific"
|
|
41
|
+
]["async"]
|
|
36
42
|
|
|
37
43
|
return _convert_global_parameters(
|
|
38
|
-
service_client_params_sync,
|
|
39
|
-
service_client_params_async
|
|
44
|
+
service_client_params_sync, service_client_params_async
|
|
40
45
|
)
|
|
41
46
|
|
|
42
47
|
@property
|
|
@@ -45,13 +50,14 @@ class GlobalParameters:
|
|
|
45
50
|
global_parameters_metadata_async = self.global_parameters_metadata["async"]
|
|
46
51
|
|
|
47
52
|
return _convert_global_parameters(
|
|
48
|
-
global_parameters_metadata_sync,
|
|
49
|
-
global_parameters_metadata_async
|
|
53
|
+
global_parameters_metadata_sync, global_parameters_metadata_async
|
|
50
54
|
)
|
|
51
55
|
|
|
52
56
|
@property
|
|
53
57
|
def constant_parameters(self) -> List[ConstantGlobalParameter]:
|
|
54
58
|
return [
|
|
55
59
|
ConstantGlobalParameter(constant_name, constant_value)
|
|
56
|
-
for constant_name, constant_value in self.global_parameters_metadata[
|
|
60
|
+
for constant_name, constant_value in self.global_parameters_metadata[
|
|
61
|
+
"constant"
|
|
62
|
+
].items()
|
|
57
63
|
]
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# license information.
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
6
|
from enum import Enum
|
|
7
|
-
from typing import Dict, Optional, Set
|
|
7
|
+
from typing import Dict, Optional, Set, Union, Tuple
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class ImportType(str, Enum):
|
|
@@ -13,6 +13,7 @@ class ImportType(str, Enum):
|
|
|
13
13
|
AZURECORE = "azurecore"
|
|
14
14
|
LOCAL = "local"
|
|
15
15
|
|
|
16
|
+
|
|
16
17
|
class TypingSection(str, Enum):
|
|
17
18
|
REGULAR = "regular" # this import is always a typing import
|
|
18
19
|
CONDITIONAL = "conditional" # is a typing import when we're dealing with files that py2 will use, else regular
|
|
@@ -21,52 +22,66 @@ class TypingSection(str, Enum):
|
|
|
21
22
|
|
|
22
23
|
class FileImport:
|
|
23
24
|
def __init__(
|
|
24
|
-
self,
|
|
25
|
+
self,
|
|
26
|
+
imports: Dict[
|
|
27
|
+
TypingSection,
|
|
28
|
+
Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]],
|
|
29
|
+
] = None,
|
|
25
30
|
) -> None:
|
|
26
31
|
# Basic implementation
|
|
27
32
|
# First level dict: TypingSection
|
|
28
33
|
# Second level dict: ImportType
|
|
29
34
|
# Third level dict: the package name.
|
|
30
35
|
# Fourth level set: None if this import is a "import", the name to import if it's a "from"
|
|
31
|
-
self._imports: Dict[
|
|
36
|
+
self._imports: Dict[
|
|
37
|
+
TypingSection,
|
|
38
|
+
Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]],
|
|
39
|
+
] = (
|
|
40
|
+
imports or dict()
|
|
41
|
+
)
|
|
32
42
|
|
|
33
43
|
def _add_import(
|
|
34
44
|
self,
|
|
35
45
|
from_section: str,
|
|
36
46
|
import_type: ImportType,
|
|
37
|
-
name_import: Optional[str] = None,
|
|
38
|
-
typing_section: TypingSection = TypingSection.REGULAR
|
|
47
|
+
name_import: Optional[Union[str, Tuple[str, str]]] = None,
|
|
48
|
+
typing_section: TypingSection = TypingSection.REGULAR,
|
|
39
49
|
) -> None:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
50
|
+
name_input: Optional[Union[str, Tuple[str, str]]] = None
|
|
51
|
+
if isinstance(name_import, list):
|
|
52
|
+
name_input = tuple(name_import)
|
|
53
|
+
else:
|
|
54
|
+
name_input = name_import
|
|
55
|
+
self._imports.setdefault(typing_section, dict()).setdefault(
|
|
56
|
+
import_type, dict()
|
|
57
|
+
).setdefault(from_section, set()).add(name_input)
|
|
47
58
|
|
|
48
59
|
def add_submodule_import(
|
|
49
60
|
self,
|
|
50
61
|
from_section: str,
|
|
51
62
|
name_import: str,
|
|
52
63
|
import_type: ImportType,
|
|
53
|
-
typing_section: TypingSection = TypingSection.REGULAR
|
|
64
|
+
typing_section: TypingSection = TypingSection.REGULAR,
|
|
54
65
|
) -> None:
|
|
55
|
-
"""Add an import to this import block.
|
|
56
|
-
"""
|
|
66
|
+
"""Add an import to this import block."""
|
|
57
67
|
self._add_import(from_section, import_type, name_import, typing_section)
|
|
58
68
|
|
|
59
69
|
def add_import(
|
|
60
70
|
self,
|
|
61
71
|
name_import: str,
|
|
62
72
|
import_type: ImportType,
|
|
63
|
-
typing_section: TypingSection = TypingSection.REGULAR
|
|
73
|
+
typing_section: TypingSection = TypingSection.REGULAR,
|
|
64
74
|
) -> None:
|
|
65
75
|
# Implementation detail: a regular import is just a "from" with no from
|
|
66
76
|
self._add_import(name_import, import_type, None, typing_section)
|
|
67
77
|
|
|
68
78
|
@property
|
|
69
|
-
def imports(
|
|
79
|
+
def imports(
|
|
80
|
+
self,
|
|
81
|
+
) -> Dict[
|
|
82
|
+
TypingSection,
|
|
83
|
+
Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]],
|
|
84
|
+
]:
|
|
70
85
|
return self._imports
|
|
71
86
|
|
|
72
87
|
def merge(self, file_import: "FileImport") -> None:
|
|
@@ -75,4 +90,6 @@ class FileImport:
|
|
|
75
90
|
for import_type, package_list in import_type_dict.items():
|
|
76
91
|
for package_name, module_list in package_list.items():
|
|
77
92
|
for module_name in module_list:
|
|
78
|
-
self._add_import(
|
|
93
|
+
self._add_import(
|
|
94
|
+
package_name, import_type, module_name, typing_section
|
|
95
|
+
)
|
|
@@ -6,15 +6,19 @@
|
|
|
6
6
|
from typing import Any, Dict, List, TypeVar
|
|
7
7
|
from ..utils import _sync_or_async
|
|
8
8
|
|
|
9
|
-
T = TypeVar(
|
|
9
|
+
T = TypeVar("T")
|
|
10
10
|
OrderedSet = Dict[T, None]
|
|
11
11
|
|
|
12
|
+
|
|
12
13
|
class MixinOperation:
|
|
13
14
|
def __init__(self, name: str, mixin_operation_metadata: Dict[str, Any]):
|
|
14
15
|
self.name = name
|
|
15
16
|
self.mixin_operation_metadata = mixin_operation_metadata
|
|
16
17
|
self._available_apis: OrderedSet[str] = {}
|
|
17
18
|
|
|
19
|
+
def call(self, async_mode: bool) -> str:
|
|
20
|
+
return self.mixin_operation_metadata[_sync_or_async(async_mode)]["call"]
|
|
21
|
+
|
|
18
22
|
def signature(self, async_mode: bool) -> str:
|
|
19
23
|
return self.mixin_operation_metadata[_sync_or_async(async_mode)]["signature"]
|
|
20
24
|
|
|
@@ -26,10 +30,6 @@ class MixinOperation:
|
|
|
26
30
|
return False
|
|
27
31
|
return self.mixin_operation_metadata["async"]["coroutine"]
|
|
28
32
|
|
|
29
|
-
@property
|
|
30
|
-
def call(self) -> str:
|
|
31
|
-
return self.mixin_operation_metadata["call"]
|
|
32
|
-
|
|
33
33
|
@property
|
|
34
34
|
def available_apis(self) -> List[str]:
|
|
35
35
|
return list(self._available_apis.keys())
|
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
6
|
from typing import Dict, List, TypeVar
|
|
7
7
|
|
|
8
|
-
T = TypeVar(
|
|
8
|
+
T = TypeVar("T")
|
|
9
9
|
OrderedSet = Dict[T, None]
|
|
10
10
|
|
|
11
|
+
|
|
11
12
|
class OperationGroup:
|
|
12
13
|
def __init__(self, name: str):
|
|
13
14
|
self.name = name
|
|
@@ -9,11 +9,12 @@ from pathlib import Path
|
|
|
9
9
|
from .imports import FileImport
|
|
10
10
|
from .mixin_operation import MixinOperation
|
|
11
11
|
|
|
12
|
+
|
|
12
13
|
class OperationMixinGroup:
|
|
13
14
|
def __init__(
|
|
14
15
|
self,
|
|
15
16
|
version_path_to_metadata: Dict[Path, Dict[str, Any]],
|
|
16
|
-
default_api_version: str
|
|
17
|
+
default_api_version: str,
|
|
17
18
|
):
|
|
18
19
|
self.default_api_version = default_api_version
|
|
19
20
|
self.version_path_to_metadata = version_path_to_metadata
|
|
@@ -22,9 +23,9 @@ class OperationMixinGroup:
|
|
|
22
23
|
imports = FileImport()
|
|
23
24
|
imports_to_load = "async_imports" if async_mode else "sync_imports"
|
|
24
25
|
for metadata_json in self.version_path_to_metadata.values():
|
|
25
|
-
if not metadata_json.get(
|
|
26
|
+
if not metadata_json.get("operation_mixins"):
|
|
26
27
|
continue
|
|
27
|
-
mixin_imports = metadata_json[
|
|
28
|
+
mixin_imports = metadata_json["operation_mixins"][imports_to_load]
|
|
28
29
|
if mixin_imports != "None":
|
|
29
30
|
current_version_imports = FileImport(json.loads(mixin_imports))
|
|
30
31
|
imports.merge(current_version_imports)
|
|
@@ -34,20 +35,24 @@ class OperationMixinGroup:
|
|
|
34
35
|
self, mixin_operations: List[MixinOperation]
|
|
35
36
|
) -> List[MixinOperation]:
|
|
36
37
|
default_api_version_path = [
|
|
37
|
-
version_path
|
|
38
|
+
version_path
|
|
39
|
+
for version_path in self.version_path_to_metadata.keys()
|
|
38
40
|
if version_path.name == self.default_api_version
|
|
39
41
|
][0]
|
|
40
|
-
default_version_metadata = self.version_path_to_metadata[
|
|
42
|
+
default_version_metadata = self.version_path_to_metadata[
|
|
43
|
+
default_api_version_path
|
|
44
|
+
]
|
|
41
45
|
if not default_version_metadata.get("operation_mixins"):
|
|
42
46
|
return mixin_operations
|
|
43
|
-
for name, metadata in default_version_metadata["operation_mixins"][
|
|
47
|
+
for name, metadata in default_version_metadata["operation_mixins"][
|
|
48
|
+
"operations"
|
|
49
|
+
].items():
|
|
44
50
|
if name.startswith("_"):
|
|
45
51
|
continue
|
|
46
52
|
mixin_operation = [mo for mo in mixin_operations if mo.name == name][0]
|
|
47
53
|
mixin_operation.mixin_operation_metadata = metadata
|
|
48
54
|
return mixin_operations
|
|
49
55
|
|
|
50
|
-
|
|
51
56
|
@property
|
|
52
57
|
def mixin_operations(self) -> List[MixinOperation]:
|
|
53
58
|
mixin_operations: List[MixinOperation] = []
|
|
@@ -55,14 +60,20 @@ class OperationMixinGroup:
|
|
|
55
60
|
if not metadata_json.get("operation_mixins"):
|
|
56
61
|
continue
|
|
57
62
|
mixin_operations_metadata = metadata_json["operation_mixins"]["operations"]
|
|
58
|
-
for
|
|
63
|
+
for (
|
|
64
|
+
mixin_operation_name,
|
|
65
|
+
mixin_operation_metadata,
|
|
66
|
+
) in mixin_operations_metadata.items():
|
|
59
67
|
if mixin_operation_name.startswith("_"):
|
|
60
68
|
continue
|
|
61
69
|
try:
|
|
62
|
-
mixin_operation = [
|
|
70
|
+
mixin_operation = [
|
|
71
|
+
mo for mo in mixin_operations if mo.name == mixin_operation_name
|
|
72
|
+
][0]
|
|
63
73
|
except IndexError:
|
|
64
74
|
mixin_operation = MixinOperation(
|
|
65
|
-
name=mixin_operation_name,
|
|
75
|
+
name=mixin_operation_name,
|
|
76
|
+
mixin_operation_metadata=mixin_operation_metadata,
|
|
66
77
|
)
|
|
67
78
|
mixin_operations.append(mixin_operation)
|
|
68
79
|
mixin_operation.append_available_api(version_path.name)
|
|
@@ -21,9 +21,10 @@ _FILE_TO_TEMPLATE = {
|
|
|
21
21
|
"service_client": "multiapi_service_client.py.jinja2",
|
|
22
22
|
"config": "multiapi_config.py.jinja2",
|
|
23
23
|
"models": "multiapi_models.py.jinja2",
|
|
24
|
-
"operations_mixin": "multiapi_operations_mixin.py.jinja2"
|
|
24
|
+
"operations_mixin": "multiapi_operations_mixin.py.jinja2",
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
|
|
27
28
|
def _get_file_path(filename: str, async_mode: bool) -> Path:
|
|
28
29
|
filename += ".py"
|
|
29
30
|
if async_mode:
|
|
@@ -43,44 +44,45 @@ class MultiAPISerializer(object):
|
|
|
43
44
|
lstrip_blocks=True,
|
|
44
45
|
)
|
|
45
46
|
|
|
46
|
-
|
|
47
47
|
def _serialize_helper(self, code_model: CodeModel, async_mode: bool) -> None:
|
|
48
48
|
def _render_template(file: str, **kwargs: Any) -> str:
|
|
49
49
|
template = self.env.get_template(_FILE_TO_TEMPLATE[file])
|
|
50
|
-
return template.render(
|
|
50
|
+
return template.render(
|
|
51
|
+
code_model=code_model, async_mode=async_mode, **kwargs
|
|
52
|
+
)
|
|
51
53
|
|
|
52
54
|
# serialize init file
|
|
53
|
-
self._autorestapi.write_file(
|
|
55
|
+
self._autorestapi.write_file(
|
|
56
|
+
_get_file_path("__init__", async_mode), _render_template("init")
|
|
57
|
+
)
|
|
54
58
|
|
|
55
59
|
# serialize service client file
|
|
56
60
|
imports = FileImportSerializer(
|
|
57
|
-
code_model.service_client.imports(async_mode),
|
|
58
|
-
is_python3_file=async_mode
|
|
61
|
+
code_model.service_client.imports(async_mode), is_python3_file=async_mode
|
|
59
62
|
)
|
|
60
63
|
self._autorestapi.write_file(
|
|
61
64
|
_get_file_path(code_model.service_client.filename, async_mode),
|
|
62
|
-
_render_template("service_client", imports=imports)
|
|
65
|
+
_render_template("service_client", imports=imports),
|
|
63
66
|
)
|
|
64
67
|
|
|
65
68
|
# serialize config file
|
|
66
69
|
imports = FileImportSerializer(
|
|
67
|
-
code_model.config.imports(async_mode),
|
|
68
|
-
is_python3_file=async_mode
|
|
70
|
+
code_model.config.imports(async_mode), is_python3_file=async_mode
|
|
69
71
|
)
|
|
70
72
|
self._autorestapi.write_file(
|
|
71
73
|
_get_file_path("_configuration", async_mode),
|
|
72
|
-
_render_template("config", imports=imports)
|
|
74
|
+
_render_template("config", imports=imports),
|
|
73
75
|
)
|
|
74
76
|
|
|
75
77
|
# serialize mixins
|
|
76
78
|
if code_model.operation_mixin_group.mixin_operations:
|
|
77
79
|
imports = FileImportSerializer(
|
|
78
80
|
code_model.operation_mixin_group.imports(async_mode),
|
|
79
|
-
is_python3_file=async_mode
|
|
81
|
+
is_python3_file=async_mode,
|
|
80
82
|
)
|
|
81
83
|
self._autorestapi.write_file(
|
|
82
84
|
_get_file_path("_operations_mixin", async_mode),
|
|
83
|
-
_render_template("operations_mixin", imports=imports)
|
|
85
|
+
_render_template("operations_mixin", imports=imports),
|
|
84
86
|
)
|
|
85
87
|
|
|
86
88
|
# serialize models
|
|
@@ -89,21 +91,15 @@ class MultiAPISerializer(object):
|
|
|
89
91
|
def _serialize_version_file(self) -> None:
|
|
90
92
|
if self._autorestapi.read_file("_version.py"):
|
|
91
93
|
self._autorestapi.write_file(
|
|
92
|
-
"_version.py",
|
|
93
|
-
self._autorestapi.read_file("_version.py")
|
|
94
|
+
"_version.py", self._autorestapi.read_file("_version.py")
|
|
94
95
|
)
|
|
95
96
|
elif self._autorestapi.read_file("version.py"):
|
|
96
97
|
self._autorestapi.write_file(
|
|
97
|
-
"_version.py",
|
|
98
|
-
self._autorestapi.read_file("version.py")
|
|
98
|
+
"_version.py", self._autorestapi.read_file("version.py")
|
|
99
99
|
)
|
|
100
100
|
else:
|
|
101
101
|
template = self.env.get_template("multiapi_version.py.jinja2")
|
|
102
|
-
self._autorestapi.write_file(
|
|
103
|
-
Path("_version.py"),
|
|
104
|
-
template.render()
|
|
105
|
-
)
|
|
106
|
-
|
|
102
|
+
self._autorestapi.write_file(Path("_version.py"), template.render())
|
|
107
103
|
|
|
108
104
|
def serialize(self, code_model: CodeModel, no_async: Optional[bool]) -> None:
|
|
109
105
|
self._serialize_helper(code_model, async_mode=False)
|
|
@@ -115,8 +111,7 @@ class MultiAPISerializer(object):
|
|
|
115
111
|
# don't erase patch file
|
|
116
112
|
if self._autorestapi.read_file("_patch.py"):
|
|
117
113
|
self._autorestapi.write_file(
|
|
118
|
-
"_patch.py",
|
|
119
|
-
self._autorestapi.read_file("_patch.py")
|
|
114
|
+
"_patch.py", self._autorestapi.read_file("_patch.py")
|
|
120
115
|
)
|
|
121
116
|
|
|
122
117
|
self._autorestapi.write_file(Path("py.typed"), "# Marker file for PEP 561.")
|
|
@@ -7,19 +7,34 @@ from copy import deepcopy
|
|
|
7
7
|
from typing import Dict, Set, Optional, List
|
|
8
8
|
from ..models import ImportType, FileImport, TypingSection
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
def _serialize_package(
|
|
12
|
+
package_name: str, module_list: Set[Optional[str]], delimiter: str
|
|
13
|
+
) -> str:
|
|
11
14
|
buffer = []
|
|
12
15
|
if None in module_list:
|
|
13
16
|
buffer.append(f"import {package_name}")
|
|
14
17
|
if module_list != {None}:
|
|
15
18
|
buffer.append(
|
|
16
19
|
"from {} import {}".format(
|
|
17
|
-
package_name,
|
|
20
|
+
package_name,
|
|
21
|
+
", ".join(
|
|
22
|
+
sorted(
|
|
23
|
+
[
|
|
24
|
+
mod if isinstance(mod, str) else f"{mod[0]} as {mod[1]}"
|
|
25
|
+
for mod in module_list
|
|
26
|
+
if mod is not None
|
|
27
|
+
]
|
|
28
|
+
)
|
|
29
|
+
),
|
|
18
30
|
)
|
|
19
31
|
)
|
|
20
32
|
return delimiter.join(buffer)
|
|
21
33
|
|
|
22
|
-
|
|
34
|
+
|
|
35
|
+
def _serialize_type(
|
|
36
|
+
import_type_dict: Dict[str, Set[Optional[str]]], delimiter: str
|
|
37
|
+
) -> str:
|
|
23
38
|
"""Serialize a given import type."""
|
|
24
39
|
import_list = []
|
|
25
40
|
for package_name in sorted(list(import_type_dict.keys())):
|
|
@@ -27,7 +42,10 @@ def _serialize_type(import_type_dict: Dict[str, Set[Optional[str]]], delimiter:
|
|
|
27
42
|
import_list.append(_serialize_package(package_name, module_list, delimiter))
|
|
28
43
|
return delimiter.join(import_list)
|
|
29
44
|
|
|
30
|
-
|
|
45
|
+
|
|
46
|
+
def _get_import_clauses(
|
|
47
|
+
imports: Dict[ImportType, Dict[str, Set[Optional[str]]]], delimiter: str
|
|
48
|
+
) -> List[str]:
|
|
31
49
|
import_clause = []
|
|
32
50
|
for import_type in ImportType:
|
|
33
51
|
if import_type in imports:
|
|
@@ -42,33 +60,44 @@ class FileImportSerializer:
|
|
|
42
60
|
|
|
43
61
|
def _switch_typing_section_key(self, new_key: TypingSection):
|
|
44
62
|
switched_dictionary = {}
|
|
45
|
-
switched_dictionary[new_key] = self._file_import.imports[
|
|
63
|
+
switched_dictionary[new_key] = self._file_import.imports[
|
|
64
|
+
TypingSection.CONDITIONAL
|
|
65
|
+
]
|
|
46
66
|
return switched_dictionary
|
|
47
67
|
|
|
48
|
-
def _get_imports_dict(
|
|
68
|
+
def _get_imports_dict(
|
|
69
|
+
self, baseline_typing_section: TypingSection, add_conditional_typing: bool
|
|
70
|
+
):
|
|
49
71
|
# If this is a python 3 file, our regular imports include the CONDITIONAL category
|
|
50
72
|
# If this is not a python 3 file, our typing imports include the CONDITIONAL category
|
|
51
73
|
file_import_copy = deepcopy(self._file_import)
|
|
52
|
-
if add_conditional_typing and self._file_import.imports.get(
|
|
74
|
+
if add_conditional_typing and self._file_import.imports.get(
|
|
75
|
+
TypingSection.CONDITIONAL
|
|
76
|
+
):
|
|
53
77
|
# we switch the TypingSection key for the CONDITIONAL typing imports so we can merge
|
|
54
78
|
# the imports together
|
|
55
|
-
switched_imports_dictionary = self._switch_typing_section_key(
|
|
79
|
+
switched_imports_dictionary = self._switch_typing_section_key(
|
|
80
|
+
baseline_typing_section
|
|
81
|
+
)
|
|
56
82
|
switched_imports = FileImport(switched_imports_dictionary)
|
|
57
83
|
file_import_copy.merge(switched_imports)
|
|
58
84
|
return file_import_copy.imports.get(baseline_typing_section, {})
|
|
59
85
|
|
|
60
86
|
def _add_type_checking_import(self):
|
|
61
|
-
if (
|
|
62
|
-
self.
|
|
63
|
-
|
|
87
|
+
if self._file_import.imports.get(TypingSection.TYPING) or (
|
|
88
|
+
not self.is_python3_file
|
|
89
|
+
and self._file_import.imports.get(TypingSection.CONDITIONAL)
|
|
64
90
|
):
|
|
65
|
-
self._file_import.add_submodule_import(
|
|
91
|
+
self._file_import.add_submodule_import(
|
|
92
|
+
"typing", "TYPE_CHECKING", ImportType.STDLIB
|
|
93
|
+
)
|
|
66
94
|
|
|
67
95
|
def __str__(self) -> str:
|
|
68
96
|
self._add_type_checking_import()
|
|
69
97
|
regular_imports = ""
|
|
70
98
|
regular_imports_dict = self._get_imports_dict(
|
|
71
|
-
baseline_typing_section=TypingSection.REGULAR,
|
|
99
|
+
baseline_typing_section=TypingSection.REGULAR,
|
|
100
|
+
add_conditional_typing=self.is_python3_file,
|
|
72
101
|
)
|
|
73
102
|
|
|
74
103
|
if regular_imports_dict:
|
|
@@ -78,10 +107,13 @@ class FileImportSerializer:
|
|
|
78
107
|
|
|
79
108
|
typing_imports = ""
|
|
80
109
|
typing_imports_dict = self._get_imports_dict(
|
|
81
|
-
baseline_typing_section=TypingSection.TYPING,
|
|
110
|
+
baseline_typing_section=TypingSection.TYPING,
|
|
111
|
+
add_conditional_typing=not self.is_python3_file,
|
|
82
112
|
)
|
|
83
113
|
if typing_imports_dict:
|
|
84
114
|
typing_imports += "\n\nif TYPE_CHECKING:\n # pylint: disable=unused-import,ungrouped-imports\n "
|
|
85
|
-
typing_imports += "\n\n ".join(
|
|
115
|
+
typing_imports += "\n\n ".join(
|
|
116
|
+
_get_import_clauses(typing_imports_dict, "\n ")
|
|
117
|
+
)
|
|
86
118
|
|
|
87
119
|
return regular_imports + typing_imports
|