Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
changeKind: internal
packages:
- "@autorest/python"
- "@azure-tools/typespec-python"
---

Add mock API test for Azure Core Page `withRelativeNextLink` scenario.
2 changes: 1 addition & 1 deletion packages/autorest.python/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
},
"homepage": "https://github.com/Azure/autorest.python/blob/main/README.md",
"dependencies": {
"@typespec/http-client-python": "https://artprodcus3.artifacts.visualstudio.com/A0fb41ef4-5012-48a9-bf39-4ee3de03ee35/29ec6040-b234-4e31-b139-33dc4287b756/_apis/artifact/cGlwZWxpbmVhcnRpZmFjdDovL2F6dXJlLXNkay9wcm9qZWN0SWQvMjllYzYwNDAtYjIzNC00ZTMxLWIxMzktMzNkYzQyODdiNzU2L2J1aWxkSWQvNTg3ODAwNi9hcnRpZmFjdE5hbWUvYnVpbGRfYXJ0aWZhY3RzX3B5dGhvbg2/content?format=file&subPath=%2Fpackages%2Ftypespec-http-client-python-0.27.1.tgz",
"@typespec/http-client-python": "https://artprodcus3.artifacts.visualstudio.com/A0fb41ef4-5012-48a9-bf39-4ee3de03ee35/29ec6040-b234-4e31-b139-33dc4287b756/_apis/artifact/cGlwZWxpbmVhcnRpZmFjdDovL2F6dXJlLXNkay9wcm9qZWN0SWQvMjllYzYwNDAtYjIzNC00ZTMxLWIxMzktMzNkYzQyODdiNzU2L2J1aWxkSWQvNTg3ODQwMi9hcnRpZmFjdE5hbWUvYnVpbGRfYXJ0aWZhY3RzX3B5dGhvbg2/content?format=file&subPath=%2Fpackages%2Ftypespec-http-client-python-0.27.1.tgz",
"@autorest/system-requirements": "~1.0.2",
"fs-extra": "~11.2.0",
"tsx": "~4.19.1"
Expand Down
8 changes: 4 additions & 4 deletions packages/typespec-python/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@
"@azure-tools/typespec-azure-resource-manager": ">=0.65.0 <1.0.0",
"@azure-tools/typespec-autorest": ">=0.65.0 <1.0.0",
"@azure-tools/typespec-azure-rulesets": ">=0.65.0 <1.0.0",
"@azure-tools/typespec-client-generator-core": ">=0.65.0 <1.0.0"
"@azure-tools/typespec-client-generator-core": ">=0.65.1 <1.0.0"
},
"dependencies": {
"js-yaml": "~4.1.0",
"semver": "~7.6.2",
"tsx": "~4.19.1",
"@typespec/http-client-python": "https://artprodcus3.artifacts.visualstudio.com/A0fb41ef4-5012-48a9-bf39-4ee3de03ee35/29ec6040-b234-4e31-b139-33dc4287b756/_apis/artifact/cGlwZWxpbmVhcnRpZmFjdDovL2F6dXJlLXNkay9wcm9qZWN0SWQvMjllYzYwNDAtYjIzNC00ZTMxLWIxMzktMzNkYzQyODdiNzU2L2J1aWxkSWQvNTg3ODAwNi9hcnRpZmFjdE5hbWUvYnVpbGRfYXJ0aWZhY3RzX3B5dGhvbg2/content?format=file&subPath=%2Fpackages%2Ftypespec-http-client-python-0.27.1.tgz",
"@typespec/http-client-python": "https://artprodcus3.artifacts.visualstudio.com/A0fb41ef4-5012-48a9-bf39-4ee3de03ee35/29ec6040-b234-4e31-b139-33dc4287b756/_apis/artifact/cGlwZWxpbmVhcnRpZmFjdDovL2F6dXJlLXNkay9wcm9qZWN0SWQvMjllYzYwNDAtYjIzNC00ZTMxLWIxMzktMzNkYzQyODdiNzU2L2J1aWxkSWQvNTg3ODQwMi9hcnRpZmFjdE5hbWUvYnVpbGRfYXJ0aWZhY3RzX3B5dGhvbg2/content?format=file&subPath=%2Fpackages%2Ftypespec-http-client-python-0.27.1.tgz",
"fs-extra": "~11.2.0"
},
"devDependencies": {
Expand All @@ -85,8 +85,8 @@
"@azure-tools/typespec-azure-core": "~0.65.0",
"@azure-tools/typespec-azure-rulesets": "~0.65.0",
"@azure-tools/typespec-autorest": "~0.65.0",
"@azure-tools/typespec-client-generator-core": "~0.65.0",
"@azure-tools/azure-http-specs": "0.1.0-alpha.37",
"@azure-tools/typespec-client-generator-core": "~0.65.1",
"@azure-tools/azure-http-specs": "0.1.0-alpha.38-dev.2",
"@typespec/http-specs": "0.1.0-alpha.32",
"@typespec/spector": "0.1.0-alpha.23",
"@typespec/spec-api": "0.1.0-alpha.12",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
"specs.azure.core.page.PageClient.list_with_custom_page_model": "_Specs_.Azure.Core.Page.listWithCustomPageModel",
"specs.azure.core.page.aio.PageClient.list_with_custom_page_model": "_Specs_.Azure.Core.Page.listWithCustomPageModel",
"specs.azure.core.page.PageClient.with_parameterized_next_link": "_Specs_.Azure.Core.Page.withParameterizedNextLink",
"specs.azure.core.page.aio.PageClient.with_parameterized_next_link": "_Specs_.Azure.Core.Page.withParameterizedNextLink"
"specs.azure.core.page.aio.PageClient.with_parameterized_next_link": "_Specs_.Azure.Core.Page.withParameterizedNextLink",
"specs.azure.core.page.PageClient.with_relative_next_link": "_Specs_.Azure.Core.Page.withRelativeNextLink",
"specs.azure.core.page.aio.PageClient.with_relative_next_link": "_Specs_.Azure.Core.Page.withRelativeNextLink"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,12 @@ def test_with_parameterized_next_link(self, page_endpoint):
result = [r for r in response]
# please add some check logic here by yourself
# ...

@PagePreparer()
@recorded_by_proxy
def test_with_relative_next_link(self, page_endpoint):
client = self.create_client(endpoint=page_endpoint)
response = client.with_relative_next_link()
result = [r for r in response]
# please add some check logic here by yourself
# ...
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,12 @@ async def test_with_parameterized_next_link(self, page_endpoint):
result = [r async for r in response]
# please add some check logic here by yourself
# ...

@PagePreparer()
@recorded_by_proxy_async
async def test_with_relative_next_link(self, page_endpoint):
client = self.create_async_client(endpoint=page_endpoint)
response = client.with_relative_next_link()
result = [r async for r in response]
# please add some check logic here by yourself
# ...
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
build_page_list_with_page_request,
build_page_list_with_parameters_request,
build_page_with_parameterized_next_link_request,
build_page_with_relative_next_link_request,
build_two_models_as_page_item_list_first_item_request,
build_two_models_as_page_item_list_second_item_request,
)
Expand Down Expand Up @@ -666,3 +667,84 @@ async def get_next(next_link=None):
return pipeline_response

return AsyncItemPaged(get_next, extract_data)

@distributed_trace
def with_relative_next_link(self, **kwargs: Any) -> AsyncItemPaged["_models.User"]:
"""List with relative nextLink URL that requires endpoint resolution.

:return: An iterator like instance of User
:rtype: ~azure.core.async_paging.AsyncItemPaged[~specs.azure.core.page.models.User]
:raises ~azure.core.exceptions.HttpResponseError:
"""
_headers = kwargs.pop("headers", {}) or {}
_params = kwargs.pop("params", {}) or {}

cls: ClsType[list[_models.User]] = kwargs.pop("cls", None)

error_map: MutableMapping = {
401: ClientAuthenticationError,
404: ResourceNotFoundError,
409: ResourceExistsError,
304: ResourceNotModifiedError,
}
error_map.update(kwargs.pop("error_map", {}) or {})

def prepare_request(next_link=None):
if not next_link:

_request = build_page_with_relative_next_link_request(
headers=_headers,
params=_params,
)
path_format_arguments = {
"endpoint": self._serialize.url(
"self._config.endpoint", self._config.endpoint, "str", skip_quote=True
),
}
_request.url = self._client.format_url(_request.url, **path_format_arguments)

else:
# make call to next link with the client's api-version
_parsed_next_link = urllib.parse.urlparse(next_link)
_next_request_params = case_insensitive_dict(
{
key: [urllib.parse.quote(v) for v in value]
for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items()
}
)
_next_request_params["api-version"] = self._config.api_version
_request = HttpRequest(
"GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params
)
path_format_arguments = {
"endpoint": self._serialize.url(
"self._config.endpoint", self._config.endpoint, "str", skip_quote=True
),
}
_request.url = self._client.format_url(_request.url, **path_format_arguments)

return _request

async def extract_data(pipeline_response):
deserialized = pipeline_response.http_response.json()
list_of_elem = _deserialize(list[_models.User], deserialized.get("value", []))
if cls:
list_of_elem = cls(list_of_elem) # type: ignore
return deserialized.get("nextLink") or None, AsyncList(list_of_elem)

async def get_next(next_link=None):
_request = prepare_request(next_link)

_stream = False
pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access
_request, stream=_stream, **kwargs
)
response = pipeline_response.http_response

if response.status_code not in [200]:
map_error(status_code=response.status_code, response=response, error_map=error_map)
raise HttpResponseError(response=response)

return pipeline_response

return AsyncItemPaged(get_next, extract_data)
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,20 @@ def build_page_with_parameterized_next_link_request( # pylint: disable=name-too
return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs)


def build_page_with_relative_next_link_request(**kwargs: Any) -> HttpRequest: # pylint: disable=name-too-long
_headers = case_insensitive_dict(kwargs.pop("headers", {}) or {})

accept = _headers.pop("Accept", "application/json")

# Construct URL
_url = "/azure/core/page/with-relative-next-link"

# Construct headers
_headers["Accept"] = _SERIALIZER.header("accept", accept, "str")

return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs)


class TwoModelsAsPageItemOperations:
"""
.. warning::
Expand Down Expand Up @@ -786,3 +800,84 @@ def get_next(next_link=None):
return pipeline_response

return ItemPaged(get_next, extract_data)

@distributed_trace
def with_relative_next_link(self, **kwargs: Any) -> ItemPaged["_models.User"]:
"""List with relative nextLink URL that requires endpoint resolution.

:return: An iterator like instance of User
:rtype: ~azure.core.paging.ItemPaged[~specs.azure.core.page.models.User]
:raises ~azure.core.exceptions.HttpResponseError:
"""
_headers = kwargs.pop("headers", {}) or {}
_params = kwargs.pop("params", {}) or {}

cls: ClsType[list[_models.User]] = kwargs.pop("cls", None)

error_map: MutableMapping = {
401: ClientAuthenticationError,
404: ResourceNotFoundError,
409: ResourceExistsError,
304: ResourceNotModifiedError,
}
error_map.update(kwargs.pop("error_map", {}) or {})

def prepare_request(next_link=None):
if not next_link:

_request = build_page_with_relative_next_link_request(
headers=_headers,
params=_params,
)
path_format_arguments = {
"endpoint": self._serialize.url(
"self._config.endpoint", self._config.endpoint, "str", skip_quote=True
),
}
_request.url = self._client.format_url(_request.url, **path_format_arguments)

else:
# make call to next link with the client's api-version
_parsed_next_link = urllib.parse.urlparse(next_link)
_next_request_params = case_insensitive_dict(
{
key: [urllib.parse.quote(v) for v in value]
for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items()
}
)
_next_request_params["api-version"] = self._config.api_version
_request = HttpRequest(
"GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params
)
path_format_arguments = {
"endpoint": self._serialize.url(
"self._config.endpoint", self._config.endpoint, "str", skip_quote=True
),
}
_request.url = self._client.format_url(_request.url, **path_format_arguments)

return _request

def extract_data(pipeline_response):
deserialized = pipeline_response.http_response.json()
list_of_elem = _deserialize(list[_models.User], deserialized.get("value", []))
if cls:
list_of_elem = cls(list_of_elem) # type: ignore
return deserialized.get("nextLink") or None, iter(list_of_elem)

def get_next(next_link=None):
_request = prepare_request(next_link)

_stream = False
pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access
_request, stream=_stream, **kwargs
)
response = pipeline_response.http_response

if response.status_code not in [200]:
map_error(status_code=response.status_code, response=response, error_map=error_map)
raise HttpResponseError(response=response)

return pipeline_response

return ItemPaged(get_next, extract_data)
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,15 @@ async def test_list_with_parameterized_next_link(client: aio.PageClient):
assert result[0].name == "User1"
assert result[1].id == 2
assert result[1].name == "User2"


@pytest.mark.asyncio
async def test_list_with_relative_next_link(client: aio.PageClient):
result = [item async for item in client.with_relative_next_link()]
assert len(result) == 2
assert result[0].id == 1
assert result[0].name == "User1"
assert result[0].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59"
assert result[1].id == 2
assert result[1].name == "User2"
assert result[1].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59"
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,14 @@ def test_list_with_parameterized_next_link(client: PageClient):
assert result[0].name == "User1"
assert result[1].id == 2
assert result[1].name == "User2"


def test_list_with_relative_next_link(client: PageClient):
result = list(client.with_relative_next_link())
assert len(result) == 2
assert result[0].id == 1
assert result[0].name == "User1"
assert result[0].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59"
assert result[1].id == 2
assert result[1].name == "User2"
assert result[1].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59"
Loading
Loading