Skip to content

Commit

Permalink
custom base url with different host templates across multiapi versions (
Browse files Browse the repository at this point in the history
  • Loading branch information
iscai-msft authored Jul 22, 2020
1 parent e1a9789 commit e5c551f
Show file tree
Hide file tree
Showing 50 changed files with 1,929 additions and 19 deletions.
39 changes: 27 additions & 12 deletions autorest/multiapi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,20 @@ def there_is_a_rt_that_contains_api_version(rt_dict, api_version):
last_rt_list[operation] = local_last_api_version
return last_rt_list

def _extract_version(metadata_json: Dict[str, Any], version_path: Path) -> str:
version = metadata_json['chosen_version']
total_api_version_list = metadata_json['total_api_version_list']
if not version:
if total_api_version_list:
sys.exit(
f"Unable to match {total_api_version_list} to label {version_path.stem}"
)
else:
sys.exit(
f"Unable to extract api version of {version_path.stem}"
)
return version

class MultiAPI:
def __init__(
self,
Expand Down Expand Up @@ -201,6 +215,17 @@ def _build_operation_mixin_meta(self, paths_to_versions: List[Path]) -> Dict[str

return mixin_operations

def _build_custom_base_url_to_api_version(
self, paths_to_versions: List[Path]
) -> Dict[str, List[str]]:
custom_base_url_to_api_version: Dict[str, List[str]] = {}
for version_path in paths_to_versions:
metadata_json = json.loads(self._autorestapi.read_file(version_path / "_metadata.json"))
custom_base_url = metadata_json["client"]["custom_base_url"]
version = _extract_version(metadata_json, version_path)
custom_base_url_to_api_version.setdefault(custom_base_url, []).append(version)
return custom_base_url_to_api_version

def _build_operation_meta(
self, paths_to_versions: List[Path]
) -> Tuple[Dict[str, List[Tuple[str, str]]], Dict[str, str]]:
Expand All @@ -218,17 +243,7 @@ def _build_operation_meta(
for version_path in paths_to_versions:
metadata_json = json.loads(self._autorestapi.read_file(version_path / "_metadata.json"))
operation_groups = metadata_json['operation_groups']
version = metadata_json['chosen_version']
total_api_version_list = metadata_json['total_api_version_list']
if not version:
if total_api_version_list:
sys.exit(
f"Unable to match {total_api_version_list} to label {version_path.stem}"
)
else:
sys.exit(
f"Unable to extract api version of {version_path.stem}"
)
version = _extract_version(metadata_json, version_path)
mod_to_api_version[version_path.name] = version
for operation_group, operation_group_class_name in operation_groups.items():
versioned_operations_dict[operation_group].append((version_path.name, operation_group_class_name))
Expand Down Expand Up @@ -366,7 +381,7 @@ def process(self) -> bool:
"sync_imports": str(FileImportSerializer(sync_imports, is_python_3_file=False)),
"async_imports": str(FileImportSerializer(async_imports, is_python_3_file=True)),
"base_url": metadata_json["client"]["base_url"],
"custom_base_url": metadata_json["client"]["custom_base_url"],
"custom_base_url_to_api_version": self._build_custom_base_url_to_api_version(paths_to_versions),
"azure_arm": metadata_json["client"]["azure_arm"]
}

Expand Down
12 changes: 10 additions & 2 deletions autorest/multiapi/templates/multiapi_service_client.py.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ def __init__(
{% endif %}
{% endfor %}
api_version=None,
{% if base_url %}
base_url=None,
{% endif %}
profile=KnownProfiles.default,
**kwargs # type: Any
){{" -> None" if async_mode else "" }}:{% endmacro %}
Expand Down Expand Up @@ -71,7 +73,7 @@ class {{ client_name }}({% if mixin_operations %}{{ client_name }}OperationsMixi
{% endfor %}
:param str api_version: API version to use if no profile is provided, or if
missing in profile.
{% if not custom_base_url %}
{% if base_url %}
:param str base_url: Service URL
{% endif %}
:param profile: A profile definition, from KnownProfiles to dict.
Expand All @@ -94,7 +96,13 @@ class {{ client_name }}({% if mixin_operations %}{{ client_name }}OperationsMixi

{{ method_signature()|indent }}
{% if not base_url %}
base_url = {{ custom_base_url }}
{% for custom_base_url, api_versions in custom_base_url_to_api_version|dictsort %}
{% set if_statement = "if" if loop.first else "elif" %}
{{ if_statement ~ " api_version == '" ~ api_versions|join("' or api_version == '") ~ "'" }}:
base_url = {{ custom_base_url }}
{% endfor %}
else:
raise NotImplementedError("APIVersion {} is not available".format(api_version))
{% else %}
if not base_url:
base_url = {{ base_url }}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
},
"devDependencies": {
"@autorest/autorest": "^3.0.0",
"@microsoft.azure/autorest.testserver": "^2.10.48"
"@microsoft.azure/autorest.testserver": "^2.10.53"
},
"files": [
"autorest/**/*.py",
Expand Down
8 changes: 5 additions & 3 deletions tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,10 +353,12 @@ def regenerate_multiapi(c, debug=False, swagger_name="test"):
"test/multiapi/specification/multiapiwithsubmodule/README.md",
# create multiapi client with no aio folder (package-name=multiapinoasync)
"test/multiapi/specification/multiapinoasync/README.md",
# create multiapi client with AzureKeyCredentialPolicy
# create multiapi client with AzureKeyCredentialPolicy (package-name=multiapicredentialdefaultpolicy)
"test/multiapi/specification/multiapicredentialdefaultpolicy/README.md",
# create multiapi client data plane
"test/multiapi/specification/multiapidataplane/README.md"
# create multiapi client data plane (package-name=multiapidataplane)
"test/multiapi/specification/multiapidataplane/README.md",
# multiapi client with custom base url (package-name=multiapicustombaseurl)
"test/multiapi/specification/multiapicustombaseurl/README.md",
]

cmds = [_multiapi_command_line(spec) for spec in available_specifications if swagger_name.lower() in spec]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# --------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#
# --------------------------------------------------------------------------
import pytest
from async_generator import yield_, async_generator
from multiapicustombaseurl.aio import MultiapiCustomBaseUrlServiceClient

@pytest.fixture
@async_generator
async def client(credential, authentication_policy, api_version):

async with MultiapiCustomBaseUrlServiceClient(
endpoint="http://localhost:3000",
api_version=api_version,
credential=credential,
authentication_policy=authentication_policy
) as client:
await yield_(client)

class TestMultiapiCustomBaseUrl(object):

@pytest.mark.parametrize('api_version', ["1.0.0"])
@pytest.mark.asyncio
async def test_custom_base_url_version_one(self, client):
await client.test(id=1)

@pytest.mark.parametrize('api_version', ["2.0.0"])
@pytest.mark.asyncio
async def test_custom_base_url_version_two(self, client):
await client.test(id=2)
48 changes: 48 additions & 0 deletions test/multiapi/AcceptanceTests/test_multiapi_custom_base_url.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# --------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#
# --------------------------------------------------------------------------
import pytest
from multiapicustombaseurl import MultiapiCustomBaseUrlServiceClient

@pytest.fixture
def client(credential, authentication_policy, api_version):

with MultiapiCustomBaseUrlServiceClient(
endpoint="http://localhost:3000",
api_version=api_version,
credential=credential,
authentication_policy=authentication_policy
) as client:
yield client

class TestMultiapiCustomBaseUrl(object):

@pytest.mark.parametrize('api_version', ["1.0.0"])
def test_custom_base_url_version_one(self, client):
client.test(id=1)

@pytest.mark.parametrize('api_version', ["2.0.0"])
def test_custom_base_url_version_two(self, client):
client.test(id=2)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# Code generated by Microsoft (R) AutoRest Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------

from ._multiapi_custom_base_url_service_client import MultiapiCustomBaseUrlServiceClient
__all__ = ['MultiapiCustomBaseUrlServiceClient']

try:
from ._patch import patch_sdk # type: ignore
patch_sdk()
except ImportError:
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
#
# Code generated by Microsoft (R) AutoRest Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is
# regenerated.
# --------------------------------------------------------------------------
from typing import Any

from azure.core.configuration import Configuration
from azure.core.pipeline import policies

from ._version import VERSION


class MultiapiCustomBaseUrlServiceClientConfiguration(Configuration):
"""Configuration for MultiapiCustomBaseUrlServiceClient.
Note that all parameters used to create this instance are saved as instance
attributes.
:param credential: Credential needed for the client to connect to Azure.
:type credential: ~azure.core.credentials.TokenCredential
:param endpoint: Pass in https://localhost:3000.
:type endpoint: str
"""

def __init__(
self,
credential, # type: "TokenCredential"
endpoint, # type: str
**kwargs # type: Any
):
# type: (...) -> None
if credential is None:
raise ValueError("Parameter 'credential' must not be None.")
if endpoint is None:
raise ValueError("Parameter 'endpoint' must not be None.")
super(MultiapiCustomBaseUrlServiceClientConfiguration, self).__init__(**kwargs)

self.credential = credential
self.endpoint = endpoint
self.credential_scopes = []
self.credential_scopes.extend(kwargs.pop('credential_scopes', []))
kwargs.setdefault('sdk_moniker', 'multiapicustombaseurl/{}'.format(VERSION))
self._configure(**kwargs)

def _configure(
self,
**kwargs # type: Any
):
# type: (...) -> None
self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs)
self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs)
self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs)
self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs)
self.http_logging_policy = kwargs.get('http_logging_policy') or policies.HttpLoggingPolicy(**kwargs)
self.retry_policy = kwargs.get('retry_policy') or policies.RetryPolicy(**kwargs)
self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs)
self.redirect_policy = kwargs.get('redirect_policy') or policies.RedirectPolicy(**kwargs)
self.authentication_policy = kwargs.get('authentication_policy')
if not self.credential_scopes and not self.authentication_policy:
raise ValueError("You must provide either credential_scopes or authentication_policy as kwargs")
if self.credential and not self.authentication_policy:
self.authentication_policy = policies.BearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs)
Loading

0 comments on commit e5c551f

Please sign in to comment.