Skip to content

Commit 3890870

Browse files
iscai-msftiscai-msfttadelesh
authored
[python] add support for parameterized next link (#7152)
fixes #6681 --------- Co-authored-by: iscai-msft <[email protected]> Co-authored-by: tadelesh <[email protected]>
1 parent 9a874eb commit 3890870

File tree

12 files changed

+539
-311
lines changed

12 files changed

+539
-311
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
changeKind: fix
3+
packages:
4+
- "@typespec/http-client-python"
5+
---
6+
7+
Add support for legacy parameterized next links

cspell.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ words:
203203
- recorda
204204
- regen
205205
- rehype
206+
- reinjected
206207
- repr
207208
- respecify
208209
- rjust

packages/http-client-python/.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"cwd": "${workspaceFolder}",
1111
"args": [
1212
"compile",
13-
"${workspaceFolder}/DocumentIntelligence",
13+
"${workspaceFolder}/node_modules/@azure-tools/azure-http-specs/specs/azure/core/page",
1414
"--emit=${workspaceFolder}",
1515
"--option=@typespec/http-client-python.debug=true"
1616
],

packages/http-client-python/emitter/src/http.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,13 +208,26 @@ function addPagingInformation(
208208
base.responses.forEach((resp: Record<string, any>) => {
209209
resp.type = itemType;
210210
});
211+
const nextLinkReInjectedParameters: Record<string, any>[] = [];
212+
for (const segList of method.pagingMetadata.nextLinkReInjectedParametersSegments ?? []) {
213+
for (const param of segList) {
214+
if (param.kind === "method") {
215+
for (const parameter of method.operation.parameters) {
216+
if (parameter.kind === "query" && parameter.correspondingMethodParams.includes(param)) {
217+
nextLinkReInjectedParameters.push(emitHttpQueryParameter(context, parameter, method));
218+
}
219+
}
220+
}
221+
}
222+
}
211223
return {
212224
...base,
213225
name: camelToSnakeCase(method.name),
214226
discriminator: "paging",
215227
exposeStreamKeyword: false,
216228
itemName,
217229
nextLinkName,
230+
nextLinkReInjectedParameters,
218231
itemType,
219232
description: method.doc ?? "",
220233
summary: method.summary,

packages/http-client-python/eng/scripts/ci/mypy.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
[mypy]
33
python_version = 3.9
44
# Exclude mypy check for sub client tests
5-
exclude = (azure/clientgenerator/core/clientinitialization/operations/_operations\.py|azure/clientgenerator/core/clientinitialization/aio/operations/_operations\.py)
5+
exclude = (.*azure/clientgenerator/core/clientinitialization/operations/_operations\.py|.*azure/clientgenerator/core/clientinitialization/aio/operations/_operations\.py)
66

77
# module level configurations
88
[mypy-jsonrpc.*]

packages/http-client-python/eng/scripts/ci/regenerate.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ async function executeCommand(tspCommand: TspCommand): Promise<void> {
263263
}
264264
const execFileAsync = promisify(execFile);
265265
try {
266+
console.log(chalk.green(`start tsp ${tspCommand.command.join(" ")}`));
266267
await execFileAsync("tsp", tspCommand.command, { shell: true });
267268
console.log(chalk.green(`tsp ${tspCommand.command.join(" ")} succeeded`));
268269
} catch (err) {
@@ -404,16 +405,20 @@ function _getCmdList(spec: string, flags: RegenerateFlags): TspCommand[] {
404405
}
405406

406407
async function runTaskPool(tasks: Array<() => Promise<void>>, poolLimit: number): Promise<void> {
407-
let currentIndex = 0;
408-
409-
async function worker() {
410-
while (currentIndex < tasks.length) {
411-
const index = currentIndex++;
412-
await tasks[index]();
408+
async function worker(start: number, end: number) {
409+
while (start < end) {
410+
await tasks[start]();
411+
start++;
413412
}
414413
}
415414

416-
const workers = new Array(Math.min(poolLimit, tasks.length)).fill(null).map(() => worker());
415+
const workers = [];
416+
let start = 0;
417+
while (start < tasks.length) {
418+
const end = Math.min(start + poolLimit, tasks.length);
419+
workers.push((async () => await worker(start, end))());
420+
start = end;
421+
}
417422
await Promise.all(workers);
418423
}
419424

packages/http-client-python/generator/pygen/codegen/models/paging_operation.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from .parameter_list import ParameterList
1717
from .model_type import ModelType
1818
from .list_type import ListType
19+
from .parameter import Parameter
1920

2021
if TYPE_CHECKING:
2122
from .code_model import CodeModel
@@ -59,6 +60,9 @@ def __init__(
5960
self.pager_sync: str = yaml_data.get("pagerSync") or f"{self.code_model.core_library}.paging.ItemPaged"
6061
self.pager_async: str = yaml_data.get("pagerAsync") or f"{self.code_model.core_library}.paging.AsyncItemPaged"
6162
self.continuation_token: Dict[str, Any] = yaml_data.get("continuationToken", {})
63+
self.next_link_reinjected_parameters: List[Parameter] = [
64+
Parameter.from_yaml(p, code_model) for p in yaml_data.get("nextLinkReInjectedParameters", [])
65+
]
6266

6367
@property
6468
def has_continuation_token(self) -> bool:

packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,6 +1276,17 @@ def call_next_link_request_builder(self, builder: PagingOperationType) -> List[s
12761276
else api_version_param.full_client_name
12771277
)
12781278
retval.append(f'_next_request_params["api-version"] = {api_version}')
1279+
if builder.next_link_reinjected_parameters:
1280+
for param in builder.next_link_reinjected_parameters:
1281+
if param.location == ParameterLocation.QUERY:
1282+
retval.extend(
1283+
self.parameter_serializer.serialize_query_header(
1284+
param,
1285+
"next_request_params",
1286+
self.serializer_name,
1287+
self.code_model.is_legacy,
1288+
)
1289+
)
12791290
query_str = ", params=_next_request_params"
12801291
next_link_str = "urllib.parse.urljoin(next_link, _parsed_next_link.path)"
12811292
except StopIteration:

packages/http-client-python/generator/test/azure/mock_api_tests/asynctests/test_azure_core_page_async.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,13 @@ async def test_two_models_as_page_item(client: aio.PageClient):
5656
result = [item async for item in client.two_models_as_page_item.list_second_item()]
5757
assert len(result) == 1
5858
assert result[0].name == "Madge"
59+
60+
61+
@pytest.mark.asyncio
62+
async def test_list_with_parameterized_next_link(client: aio.PageClient):
63+
result = [item async for item in client.with_parameterized_next_link(select="name", include_pending=True)]
64+
assert len(result) == 2
65+
assert result[0].id == 1
66+
assert result[0].name == "User1"
67+
assert result[1].id == 2
68+
assert result[1].name == "User2"

packages/http-client-python/generator/test/azure/mock_api_tests/test_azure_core_page.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,12 @@ def test_two_models_as_page_item(client: PageClient):
4949
result = list(client.two_models_as_page_item.list_second_item())
5050
assert len(result) == 1
5151
assert result[0].name == "Madge"
52+
53+
54+
def test_list_with_parameterized_next_link(client: PageClient):
55+
result = list(client.with_parameterized_next_link(select="name", include_pending=True))
56+
assert len(result) == 2
57+
assert result[0].id == 1
58+
assert result[0].name == "User1"
59+
assert result[1].id == 2
60+
assert result[1].name == "User2"

0 commit comments

Comments
 (0)