Skip to content
Merged
2 changes: 1 addition & 1 deletion ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
- Default to generating DPG SDKs with `--version-tolerant` now defaulting to `true`. For a list of flag default changes, please
see [here](https://github.com/Azure/autorest.python/issues/1186) #1304
- Only generate Python3 SDKs #1297
- Don't reformat initial query parameters into the next link #1297
- Don't reformat initial query parameters into the next link. However, we do append `api-version` parameters if they are not present in the next link #1297 #1309
- Don't generate operations with more than two body types. SDK authors need to implement this operation themselves #1300

**New Features**
Expand Down
16 changes: 15 additions & 1 deletion autorest/codegen/models/paging_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,21 @@ def imports(self, async_mode: bool, **kwargs: Any) -> FileImport:
file_import.merge(
self.get_request_builder_import(self.next_request_builder, async_mode)
)

elif "api-version" in [
p.rest_api_name for p in self.code_model.client.parameters
]:
file_import.add_submodule_import(
"urllib.parse", "urlparse", ImportType.STDLIB
)
file_import.add_submodule_import(
"urllib.parse", "urljoin", ImportType.STDLIB
)
file_import.add_submodule_import(
"urllib.parse", "parse_qs", ImportType.STDLIB
)
file_import.add_submodule_import(
"azure.core.utils", "case_insensitive_dict", ImportType.AZURECORE
)
return file_import


Expand Down
27 changes: 25 additions & 2 deletions autorest/codegen/serializers/builder_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1133,15 +1133,38 @@ def call_next_link_request_builder(self, builder: PagingOperationType) -> List[s
template_url = "next_link"

request_builder = builder.next_request_builder or builder.request_builder
if builder.next_request_builder or self.code_model.is_legacy:
if builder.next_request_builder:
return self._call_request_builder_helper(
builder,
request_builder,
template_url=template_url,
is_next_request=True,
)
retval = ['request = HttpRequest("GET", next_link)']
retval: List[str] = []
query_str = ""
next_link_str = "next_link"
try:
api_version_param = next(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm adding api version if it's a client parameter, even if it's not explicitly listed as a parameter for that operation. lmk thoughts about that. Thanks!

p
for p in self.code_model.client.parameters
if p.rest_api_name == "api-version"
)
retval.append("# make call to next link with the client's api-version")
retval.append("_parsed_next_link = urlparse(next_link)")
retval.append(
"_next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query))"
)
retval.append(
f'_next_request_params["api-version"] = {api_version_param.full_client_name}'
)
query_str = ", params=_next_request_params"
next_link_str = "urljoin(next_link, _parsed_next_link.path)"
except StopIteration:
pass

retval.append(f'request = HttpRequest("GET", {next_link_str}{query_str})')
retval.extend(self._postprocess_http_request(builder, "request.url"))

return retval

def _prepare_request_callback(self, builder: PagingOperationType) -> List[str]:
Expand Down
7 changes: 5 additions & 2 deletions autorest/preprocess/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,16 @@ def _update_lro_operation_helper(self, yaml_data: Dict[str, Any]) -> None:
def update_lro_paging_operation(self, yaml_data: Dict[str, Any]) -> None:
self.update_lro_operation(yaml_data)
self.update_paging_operation(yaml_data)
yaml_data["discriminator"] = "lropaging"
for response in yaml_data.get("responses", []):
response["discriminator"] = "lropaging"
for overload in yaml_data.get("overloads", []):
self.update_lro_paging_operation(overload)

def update_lro_operation(self, yaml_data: Dict[str, Any]) -> None:
self.update_operation(yaml_data)
self._update_lro_operation_helper(yaml_data)
for overload in yaml_data["overloads"]:
for overload in yaml_data.get("overloads", []):
self._update_lro_operation_helper(overload)

def update_paging_operation(self, yaml_data: Dict[str, Any]) -> None:
Expand All @@ -170,7 +173,7 @@ def update_paging_operation(self, yaml_data: Dict[str, Any]) -> None:
item_type = next(
p["type"]["elementType"]
for p in returned_response_object["type"]["properties"]
if p["restApiName"] == yaml_data["itemName"]
if p["restApiName"] == (yaml_data.get("itemName") or "value")
)
if yaml_data.get("nextOperation"):
yaml_data["nextOperation"]["groupName"] = pad_reserved_words(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------
from typing import Any, AsyncIterable, Callable, Dict, IO, Optional, TypeVar, Union, cast, overload
from urllib.parse import parse_qs, urljoin, urlparse

from azure.core.async_paging import AsyncItemPaged, AsyncList
from azure.core.exceptions import (
Expand Down Expand Up @@ -370,20 +371,11 @@ def prepare_request(next_link=None):
request.url = self._client.format_url(request.url) # type: ignore

else:
_maxresults = None
_timeout = None
if test_lro_and_paging_options is not None:
_maxresults = test_lro_and_paging_options.maxresults
_timeout = test_lro_and_paging_options.timeout

request = build_test_lro_and_paging_request(
client_request_id=client_request_id,
maxresults=_maxresults,
timeout=_timeout,
template_url=next_link,
headers=_headers,
params=_params,
)
# make call to next link with the client's api-version
_parsed_next_link = urlparse(next_link)
_next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query))
_next_request_params["api-version"] = self._config.api_version
request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params)
request = _convert_request(request)
request.url = self._client.format_url(request.url) # type: ignore
request.method = "GET"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------
from typing import Any, Callable, Dict, IO, Iterable, Optional, TypeVar, Union, cast, overload
from urllib.parse import parse_qs, urljoin, urlparse

from azure.core.exceptions import (
ClientAuthenticationError,
Expand Down Expand Up @@ -444,20 +445,11 @@ def prepare_request(next_link=None):
request.url = self._client.format_url(request.url) # type: ignore

else:
_maxresults = None
_timeout = None
if test_lro_and_paging_options is not None:
_maxresults = test_lro_and_paging_options.maxresults
_timeout = test_lro_and_paging_options.timeout

request = build_test_lro_and_paging_request(
client_request_id=client_request_id,
maxresults=_maxresults,
timeout=_timeout,
template_url=next_link,
headers=_headers,
params=_params,
)
# make call to next link with the client's api-version
_parsed_next_link = urlparse(next_link)
_next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query))
_next_request_params["api-version"] = self._config.api_version
request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params)
request = _convert_request(request)
request.url = self._client.format_url(request.url) # type: ignore
request.method = "GET"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------
from typing import Any, AsyncIterable, Callable, Dict, Optional, TypeVar
from urllib.parse import parse_qs, urljoin, urlparse

from azure.core.async_paging import AsyncItemPaged, AsyncList
from azure.core.exceptions import (
Expand Down Expand Up @@ -66,12 +67,11 @@ def prepare_request(next_link=None):
request.url = self._client.format_url(request.url) # type: ignore

else:

request = build_test_paging_request(
template_url=next_link,
headers=_headers,
params=_params,
)
# make call to next link with the client's api-version
_parsed_next_link = urlparse(next_link)
_next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query))
_next_request_params["api-version"] = self._config.api_version
request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params)
request = _convert_request(request)
request.url = self._client.format_url(request.url) # type: ignore
request.method = "GET"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------
from typing import Any, Callable, Dict, Iterable, Optional, TypeVar
from urllib.parse import parse_qs, urljoin, urlparse

from azure.core.exceptions import (
ClientAuthenticationError,
Expand Down Expand Up @@ -108,12 +109,11 @@ def prepare_request(next_link=None):
request.url = self._client.format_url(request.url) # type: ignore

else:

request = build_test_paging_request(
template_url=next_link,
headers=_headers,
params=_params,
)
# make call to next link with the client's api-version
_parsed_next_link = urlparse(next_link)
_next_request_params = case_insensitive_dict(parse_qs(_parsed_next_link.query))
_next_request_params["api-version"] = self._config.api_version
request = HttpRequest("GET", urljoin(next_link, _parsed_next_link.path), params=_next_request_params)
request = _convert_request(request)
request.url = self._client.format_url(request.url) # type: ignore
request.method = "GET"
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 @@
"@autorest/system-requirements": "~1.0.0"
},
"devDependencies": {
"@microsoft.azure/autorest.testserver": "^3.3.29"
"@microsoft.azure/autorest.testserver": "^3.3.30"
},
"files": [
"autorest/**/*.py",
Expand Down
14 changes: 14 additions & 0 deletions test/azure/legacy/AcceptanceTests/asynctests/test_paging.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,3 +247,17 @@ async def test_duplicate_params(self, client):
assert len(pages) == 1
assert pages[0].properties.id == 1
assert pages[0].properties.name == "Product"

@pytest.mark.asyncio
async def test_append_api_version(self, client):
pages = [p async for p in client.paging.append_api_version()]
assert len(pages) == 1
assert pages[0].properties.id == 1
assert pages[0].properties.name == "Product"

@pytest.mark.asyncio
async def test_replace_api_version(self, client):
pages = [p async for p in client.paging.replace_api_version()]
assert len(pages) == 1
assert pages[0].properties.id == 1
assert pages[0].properties.name == "Product"
12 changes: 12 additions & 0 deletions test/azure/legacy/AcceptanceTests/test_paging.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,18 @@ def test_duplicate_params(self, client):
assert pages[0].properties.id == 1
assert pages[0].properties.name == "Product"

def test_append_api_version(self, client):
pages = list(client.paging.append_api_version())
assert len(pages) == 1
assert pages[0].properties.id == 1
assert pages[0].properties.name == "Product"

def test_replace_api_version(self, client):
pages = list(client.paging.replace_api_version())
assert len(pages) == 1
assert pages[0].properties.id == 1
assert pages[0].properties.name == "Product"

def test_models(self):
from paging.models import OperationResult
from paging.models._models_py3 import OperationResult as OperationResultPy3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ class AutoRestPagingTestService: # pylint: disable=client-accepts-api-version-k
:type credential: ~azure.core.credentials.TokenCredential
:param base_url: Service URL. Default value is "http://localhost:3000".
:type base_url: str
:keyword api_version: Api Version. Default value is "1.0.0". Note that overriding this default
value may result in unsupported behavior.
:paramtype api_version: str
:keyword int polling_interval: Default waiting time between two polls for LRO operations if no
Retry-After header is present.
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,20 @@ class AutoRestPagingTestServiceConfiguration(Configuration): # pylint: disable=

:param credential: Credential needed for the client to connect to Azure. Required.
:type credential: ~azure.core.credentials.TokenCredential
:keyword api_version: Api Version. Default value is "1.0.0". Note that overriding this default
value may result in unsupported behavior.
:paramtype api_version: str
"""

def __init__(self, credential: "TokenCredential", **kwargs: Any) -> None:
super(AutoRestPagingTestServiceConfiguration, self).__init__(**kwargs)
api_version = kwargs.pop("api_version", "1.0.0") # type: str

if credential is None:
raise ValueError("Parameter 'credential' must not be None.")

self.credential = credential
self.api_version = api_version
self.credential_scopes = kwargs.pop("credential_scopes", ["https://management.azure.com/.default"])
kwargs.setdefault("sdk_moniker", "custompollerpager/{}".format(VERSION))
self._configure(**kwargs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ class AutoRestPagingTestService: # pylint: disable=client-accepts-api-version-k
:type credential: ~azure.core.credentials_async.AsyncTokenCredential
:param base_url: Service URL. Default value is "http://localhost:3000".
:type base_url: str
:keyword api_version: Api Version. Default value is "1.0.0". Note that overriding this default
value may result in unsupported behavior.
:paramtype api_version: str
:keyword int polling_interval: Default waiting time between two polls for LRO operations if no
Retry-After header is present.
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,20 @@ class AutoRestPagingTestServiceConfiguration(Configuration): # pylint: disable=

:param credential: Credential needed for the client to connect to Azure. Required.
:type credential: ~azure.core.credentials_async.AsyncTokenCredential
:keyword api_version: Api Version. Default value is "1.0.0". Note that overriding this default
value may result in unsupported behavior.
:paramtype api_version: str
"""

def __init__(self, credential: "AsyncTokenCredential", **kwargs: Any) -> None:
super(AutoRestPagingTestServiceConfiguration, self).__init__(**kwargs)
api_version = kwargs.pop("api_version", "1.0.0") # type: str

if credential is None:
raise ValueError("Parameter 'credential' must not be None.")

self.credential = credential
self.api_version = api_version
self.credential_scopes = kwargs.pop("credential_scopes", ["https://management.azure.com/.default"])
kwargs.setdefault("sdk_moniker", "custompollerpager/{}".format(VERSION))
self._configure(**kwargs)
Expand Down
Loading