Skip to content

Commit dedce56

Browse files
authored
Sync from typespec main (2026-02-13) (efbf17f) (#3345)
* Update dependencies * Sync shared files from typespec repo (2026-02-13 13:52:58) * Add changelog * Update dependencies (2026-02-13 13:53:58) * Regenerate for typespec-python (2026-02-13 13:59:16) --------- Co-authored-by: AutoPrFromHttpClientPython <AutoPrFromHttpClientPython>
1 parent 239aed6 commit dedce56

11 files changed

Lines changed: 265 additions & 37 deletions

File tree

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
changeKind: internal
3+
packages:
4+
- "@autorest/python"
5+
- "@azure-tools/typespec-python"
6+
---
7+
8+
Add mock API test for Azure Core Page `withRelativeNextLink` scenario.

packages/autorest.python/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
},
3030
"homepage": "https://github.com/Azure/autorest.python/blob/main/README.md",
3131
"dependencies": {
32-
"@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",
32+
"@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",
3333
"@autorest/system-requirements": "~1.0.2",
3434
"fs-extra": "~11.2.0",
3535
"tsx": "~4.19.1"

packages/typespec-python/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,13 @@
6161
"@azure-tools/typespec-azure-resource-manager": ">=0.65.0 <1.0.0",
6262
"@azure-tools/typespec-autorest": ">=0.65.0 <1.0.0",
6363
"@azure-tools/typespec-azure-rulesets": ">=0.65.0 <1.0.0",
64-
"@azure-tools/typespec-client-generator-core": ">=0.65.0 <1.0.0"
64+
"@azure-tools/typespec-client-generator-core": ">=0.65.1 <1.0.0"
6565
},
6666
"dependencies": {
6767
"js-yaml": "~4.1.0",
6868
"semver": "~7.6.2",
6969
"tsx": "~4.19.1",
70-
"@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",
70+
"@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",
7171
"fs-extra": "~11.2.0"
7272
},
7373
"devDependencies": {
@@ -85,8 +85,8 @@
8585
"@azure-tools/typespec-azure-core": "~0.65.0",
8686
"@azure-tools/typespec-azure-rulesets": "~0.65.0",
8787
"@azure-tools/typespec-autorest": "~0.65.0",
88-
"@azure-tools/typespec-client-generator-core": "~0.65.0",
89-
"@azure-tools/azure-http-specs": "0.1.0-alpha.37",
88+
"@azure-tools/typespec-client-generator-core": "~0.65.1",
89+
"@azure-tools/azure-http-specs": "0.1.0-alpha.38-dev.2",
9090
"@typespec/http-specs": "0.1.0-alpha.32",
9191
"@typespec/spector": "0.1.0-alpha.23",
9292
"@typespec/spec-api": "0.1.0-alpha.12",

packages/typespec-python/test/azure/generated/azure-core-page/apiview-properties.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
"specs.azure.core.page.PageClient.list_with_custom_page_model": "_Specs_.Azure.Core.Page.listWithCustomPageModel",
1919
"specs.azure.core.page.aio.PageClient.list_with_custom_page_model": "_Specs_.Azure.Core.Page.listWithCustomPageModel",
2020
"specs.azure.core.page.PageClient.with_parameterized_next_link": "_Specs_.Azure.Core.Page.withParameterizedNextLink",
21-
"specs.azure.core.page.aio.PageClient.with_parameterized_next_link": "_Specs_.Azure.Core.Page.withParameterizedNextLink"
21+
"specs.azure.core.page.aio.PageClient.with_parameterized_next_link": "_Specs_.Azure.Core.Page.withParameterizedNextLink",
22+
"specs.azure.core.page.PageClient.with_relative_next_link": "_Specs_.Azure.Core.Page.withRelativeNextLink",
23+
"specs.azure.core.page.aio.PageClient.with_relative_next_link": "_Specs_.Azure.Core.Page.withRelativeNextLink"
2224
}
2325
}

packages/typespec-python/test/azure/generated/azure-core-page/generated_tests/test_page.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,12 @@ def test_with_parameterized_next_link(self, page_endpoint):
5151
result = [r for r in response]
5252
# please add some check logic here by yourself
5353
# ...
54+
55+
@PagePreparer()
56+
@recorded_by_proxy
57+
def test_with_relative_next_link(self, page_endpoint):
58+
client = self.create_client(endpoint=page_endpoint)
59+
response = client.with_relative_next_link()
60+
result = [r for r in response]
61+
# please add some check logic here by yourself
62+
# ...

packages/typespec-python/test/azure/generated/azure-core-page/generated_tests/test_page_async.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,12 @@ async def test_with_parameterized_next_link(self, page_endpoint):
5252
result = [r async for r in response]
5353
# please add some check logic here by yourself
5454
# ...
55+
56+
@PagePreparer()
57+
@recorded_by_proxy_async
58+
async def test_with_relative_next_link(self, page_endpoint):
59+
client = self.create_async_client(endpoint=page_endpoint)
60+
response = client.with_relative_next_link()
61+
result = [r async for r in response]
62+
# please add some check logic here by yourself
63+
# ...

packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/aio/operations/_operations.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
build_page_list_with_page_request,
3737
build_page_list_with_parameters_request,
3838
build_page_with_parameterized_next_link_request,
39+
build_page_with_relative_next_link_request,
3940
build_two_models_as_page_item_list_first_item_request,
4041
build_two_models_as_page_item_list_second_item_request,
4142
)
@@ -666,3 +667,84 @@ async def get_next(next_link=None):
666667
return pipeline_response
667668

668669
return AsyncItemPaged(get_next, extract_data)
670+
671+
@distributed_trace
672+
def with_relative_next_link(self, **kwargs: Any) -> AsyncItemPaged["_models.User"]:
673+
"""List with relative nextLink URL that requires endpoint resolution.
674+
675+
:return: An iterator like instance of User
676+
:rtype: ~azure.core.async_paging.AsyncItemPaged[~specs.azure.core.page.models.User]
677+
:raises ~azure.core.exceptions.HttpResponseError:
678+
"""
679+
_headers = kwargs.pop("headers", {}) or {}
680+
_params = kwargs.pop("params", {}) or {}
681+
682+
cls: ClsType[list[_models.User]] = kwargs.pop("cls", None)
683+
684+
error_map: MutableMapping = {
685+
401: ClientAuthenticationError,
686+
404: ResourceNotFoundError,
687+
409: ResourceExistsError,
688+
304: ResourceNotModifiedError,
689+
}
690+
error_map.update(kwargs.pop("error_map", {}) or {})
691+
692+
def prepare_request(next_link=None):
693+
if not next_link:
694+
695+
_request = build_page_with_relative_next_link_request(
696+
headers=_headers,
697+
params=_params,
698+
)
699+
path_format_arguments = {
700+
"endpoint": self._serialize.url(
701+
"self._config.endpoint", self._config.endpoint, "str", skip_quote=True
702+
),
703+
}
704+
_request.url = self._client.format_url(_request.url, **path_format_arguments)
705+
706+
else:
707+
# make call to next link with the client's api-version
708+
_parsed_next_link = urllib.parse.urlparse(next_link)
709+
_next_request_params = case_insensitive_dict(
710+
{
711+
key: [urllib.parse.quote(v) for v in value]
712+
for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items()
713+
}
714+
)
715+
_next_request_params["api-version"] = self._config.api_version
716+
_request = HttpRequest(
717+
"GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params
718+
)
719+
path_format_arguments = {
720+
"endpoint": self._serialize.url(
721+
"self._config.endpoint", self._config.endpoint, "str", skip_quote=True
722+
),
723+
}
724+
_request.url = self._client.format_url(_request.url, **path_format_arguments)
725+
726+
return _request
727+
728+
async def extract_data(pipeline_response):
729+
deserialized = pipeline_response.http_response.json()
730+
list_of_elem = _deserialize(list[_models.User], deserialized.get("value", []))
731+
if cls:
732+
list_of_elem = cls(list_of_elem) # type: ignore
733+
return deserialized.get("nextLink") or None, AsyncList(list_of_elem)
734+
735+
async def get_next(next_link=None):
736+
_request = prepare_request(next_link)
737+
738+
_stream = False
739+
pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access
740+
_request, stream=_stream, **kwargs
741+
)
742+
response = pipeline_response.http_response
743+
744+
if response.status_code not in [200]:
745+
map_error(status_code=response.status_code, response=response, error_map=error_map)
746+
raise HttpResponseError(response=response)
747+
748+
return pipeline_response
749+
750+
return AsyncItemPaged(get_next, extract_data)

packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/operations/_operations.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,20 @@ def build_page_with_parameterized_next_link_request( # pylint: disable=name-too
168168
return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs)
169169

170170

171+
def build_page_with_relative_next_link_request(**kwargs: Any) -> HttpRequest: # pylint: disable=name-too-long
172+
_headers = case_insensitive_dict(kwargs.pop("headers", {}) or {})
173+
174+
accept = _headers.pop("Accept", "application/json")
175+
176+
# Construct URL
177+
_url = "/azure/core/page/with-relative-next-link"
178+
179+
# Construct headers
180+
_headers["Accept"] = _SERIALIZER.header("accept", accept, "str")
181+
182+
return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs)
183+
184+
171185
class TwoModelsAsPageItemOperations:
172186
"""
173187
.. warning::
@@ -786,3 +800,84 @@ def get_next(next_link=None):
786800
return pipeline_response
787801

788802
return ItemPaged(get_next, extract_data)
803+
804+
@distributed_trace
805+
def with_relative_next_link(self, **kwargs: Any) -> ItemPaged["_models.User"]:
806+
"""List with relative nextLink URL that requires endpoint resolution.
807+
808+
:return: An iterator like instance of User
809+
:rtype: ~azure.core.paging.ItemPaged[~specs.azure.core.page.models.User]
810+
:raises ~azure.core.exceptions.HttpResponseError:
811+
"""
812+
_headers = kwargs.pop("headers", {}) or {}
813+
_params = kwargs.pop("params", {}) or {}
814+
815+
cls: ClsType[list[_models.User]] = kwargs.pop("cls", None)
816+
817+
error_map: MutableMapping = {
818+
401: ClientAuthenticationError,
819+
404: ResourceNotFoundError,
820+
409: ResourceExistsError,
821+
304: ResourceNotModifiedError,
822+
}
823+
error_map.update(kwargs.pop("error_map", {}) or {})
824+
825+
def prepare_request(next_link=None):
826+
if not next_link:
827+
828+
_request = build_page_with_relative_next_link_request(
829+
headers=_headers,
830+
params=_params,
831+
)
832+
path_format_arguments = {
833+
"endpoint": self._serialize.url(
834+
"self._config.endpoint", self._config.endpoint, "str", skip_quote=True
835+
),
836+
}
837+
_request.url = self._client.format_url(_request.url, **path_format_arguments)
838+
839+
else:
840+
# make call to next link with the client's api-version
841+
_parsed_next_link = urllib.parse.urlparse(next_link)
842+
_next_request_params = case_insensitive_dict(
843+
{
844+
key: [urllib.parse.quote(v) for v in value]
845+
for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items()
846+
}
847+
)
848+
_next_request_params["api-version"] = self._config.api_version
849+
_request = HttpRequest(
850+
"GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params
851+
)
852+
path_format_arguments = {
853+
"endpoint": self._serialize.url(
854+
"self._config.endpoint", self._config.endpoint, "str", skip_quote=True
855+
),
856+
}
857+
_request.url = self._client.format_url(_request.url, **path_format_arguments)
858+
859+
return _request
860+
861+
def extract_data(pipeline_response):
862+
deserialized = pipeline_response.http_response.json()
863+
list_of_elem = _deserialize(list[_models.User], deserialized.get("value", []))
864+
if cls:
865+
list_of_elem = cls(list_of_elem) # type: ignore
866+
return deserialized.get("nextLink") or None, iter(list_of_elem)
867+
868+
def get_next(next_link=None):
869+
_request = prepare_request(next_link)
870+
871+
_stream = False
872+
pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access
873+
_request, stream=_stream, **kwargs
874+
)
875+
response = pipeline_response.http_response
876+
877+
if response.status_code not in [200]:
878+
map_error(status_code=response.status_code, response=response, error_map=error_map)
879+
raise HttpResponseError(response=response)
880+
881+
return pipeline_response
882+
883+
return ItemPaged(get_next, extract_data)

packages/typespec-python/test/azure/mock_api_tests/asynctests/test_azure_core_page_async.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,15 @@ async def test_list_with_parameterized_next_link(client: aio.PageClient):
6666
assert result[0].name == "User1"
6767
assert result[1].id == 2
6868
assert result[1].name == "User2"
69+
70+
71+
@pytest.mark.asyncio
72+
async def test_list_with_relative_next_link(client: aio.PageClient):
73+
result = [item async for item in client.with_relative_next_link()]
74+
assert len(result) == 2
75+
assert result[0].id == 1
76+
assert result[0].name == "User1"
77+
assert result[0].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59"
78+
assert result[1].id == 2
79+
assert result[1].name == "User2"
80+
assert result[1].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59"

packages/typespec-python/test/azure/mock_api_tests/test_azure_core_page.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,14 @@ def test_list_with_parameterized_next_link(client: PageClient):
5858
assert result[0].name == "User1"
5959
assert result[1].id == 2
6060
assert result[1].name == "User2"
61+
62+
63+
def test_list_with_relative_next_link(client: PageClient):
64+
result = list(client.with_relative_next_link())
65+
assert len(result) == 2
66+
assert result[0].id == 1
67+
assert result[0].name == "User1"
68+
assert result[0].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59"
69+
assert result[1].id == 2
70+
assert result[1].name == "User2"
71+
assert result[1].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59"

0 commit comments

Comments
 (0)