diff --git a/.chronus/changes/add-python-post-paging-lro-with-body-test-2026-7-22-2-4-0.md b/.chronus/changes/add-python-post-paging-lro-with-body-test-2026-7-22-2-4-0.md new file mode 100644 index 00000000000..f0b0c763632 --- /dev/null +++ b/.chronus/changes/add-python-post-paging-lro-with-body-test-2026-7-22-2-4-0.md @@ -0,0 +1,7 @@ +--- +changeKind: internal +packages: + - "@typespec/http-client-python" +--- + +Add mock API tests for the new ARM operation-templates scenarios (`postPagingLroWithBody`, `getLro`, `postActionPaging`, `markAsPageable`, `Legacy.routedGet`, and `Legacy.createOrReplaceOptionalBody`). diff --git a/packages/http-client-python/package-lock.json b/packages/http-client-python/package-lock.json index 24fce49d063..3ef1a9618f1 100644 --- a/packages/http-client-python/package-lock.json +++ b/packages/http-client-python/package-lock.json @@ -1,12 +1,12 @@ { "name": "@typespec/http-client-python", - "version": "0.34.2", + "version": "0.35.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@typespec/http-client-python", - "version": "0.34.2", + "version": "0.35.0", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -17,7 +17,7 @@ "tsx": "^4.21.0" }, "devDependencies": { - "@azure-tools/azure-http-specs": "0.1.0-alpha.43", + "@azure-tools/azure-http-specs": "0.1.0-alpha.44-dev.4", "@azure-tools/typespec-autorest": "~0.70.0", "@azure-tools/typespec-azure-core": "~0.70.0", "@azure-tools/typespec-azure-resource-manager": "~0.70.0", @@ -66,25 +66,124 @@ } }, "node_modules/@azure-tools/azure-http-specs": { - "version": "0.1.0-alpha.43", - "resolved": "https://registry.npmjs.org/@azure-tools/azure-http-specs/-/azure-http-specs-0.1.0-alpha.43.tgz", - "integrity": "sha512-5FTIh21iGlMtVkQHZrbFPg7fIDYtIxjG1oYNbcxdirfQUm/XtWvCv8UAwr3OzEBrE1+YEC6c164x4+bINm5UHA==", + "version": "0.1.0-alpha.44-dev.4", + "resolved": "https://registry.npmjs.org/@azure-tools/azure-http-specs/-/azure-http-specs-0.1.0-alpha.44-dev.4.tgz", + "integrity": "sha512-5NWKMkg4anwmJ0BL/0IBAZJviiG/nQR36nfM57GDTcduSBrOrUDlCM0dGTyCwjlVsEk9Y7SKe1Lg5e2CKnMybQ==", "dev": true, "license": "MIT", "dependencies": { - "@typespec/spec-api": "^0.1.0-alpha.15", - "@typespec/spector": "^0.1.0-alpha.26" + "@typespec/spec-api": "^0.1.0-alpha.15 || >=0.1.0-alpha.16-dev <0.1.0-alpha.16", + "@typespec/spector": "^0.1.0-alpha.27 || >=0.1.0-alpha.28-dev <0.1.0-alpha.28" }, "engines": { "node": ">=22.0.0" }, "peerDependencies": { - "@azure-tools/typespec-azure-core": "^0.70.0", + "@azure-tools/typespec-azure-core": "^0.70.0 || >=0.71.0-dev <0.71.0", + "@typespec/compiler": "^1.14.0", + "@typespec/http": "^1.14.0", + "@typespec/rest": "^0.84.0 || >=0.85.0-dev <0.85.0", + "@typespec/versioning": "^0.84.0 || >=0.85.0-dev <0.85.0", + "@typespec/xml": "^0.84.0 || >=0.85.0-dev <0.85.0" + } + }, + "node_modules/@azure-tools/azure-http-specs/node_modules/@typespec/spector": { + "version": "0.1.0-alpha.27", + "resolved": "https://registry.npmjs.org/@typespec/spector/-/spector-0.1.0-alpha.27.tgz", + "integrity": "sha512-Um9DcYa/emNAN1RjuBCgGawSXfaACp+b16D4YDnCr+jsSnclAcRwbKl3hwPkRjFiWSUy2Qvdots16MCLAD9w7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/identity": "^4.13.1", "@typespec/compiler": "^1.14.0", "@typespec/http": "^1.14.0", "@typespec/rest": "^0.84.0", + "@typespec/spec-api": "^0.1.0-alpha.15", + "@typespec/spec-coverage-sdk": "^0.1.0-alpha.16", "@typespec/versioning": "^0.84.0", - "@typespec/xml": "^0.84.0" + "ajv": "^8.18.0", + "express": "^5.2.1", + "micromatch": "^4.0.8", + "morgan": "^1.10.1", + "multer": "^2.2.0", + "picocolors": "^1.1.1", + "source-map-support": "^0.5.21", + "yaml": "^2.8.3", + "yargs": "^18.0.0" + }, + "bin": { + "tsp-spector": "cmd/cli.mjs" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure-tools/azure-http-specs/node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@azure-tools/azure-http-specs/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@azure-tools/azure-http-specs/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@azure-tools/azure-http-specs/node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/@azure-tools/azure-http-specs/node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" } }, "node_modules/@azure-tools/typespec-autorest": { diff --git a/packages/http-client-python/package.json b/packages/http-client-python/package.json index 25f1b0409a5..fce2fe4387e 100644 --- a/packages/http-client-python/package.json +++ b/packages/http-client-python/package.json @@ -108,7 +108,7 @@ "@azure-tools/typespec-azure-resource-manager": "~0.70.0", "@azure-tools/typespec-azure-rulesets": "~0.70.0", "@azure-tools/typespec-client-generator-core": "~0.70.0", - "@azure-tools/azure-http-specs": "0.1.0-alpha.43", + "@azure-tools/azure-http-specs": "0.1.0-alpha.44-dev.4", "@typespec/compiler": "^1.14.0", "@typespec/http": "^1.14.0", "@typespec/openapi": "^1.14.0", diff --git a/packages/http-client-python/tests/mock_api/azure/asynctests/test_azure_arm_operationtemplates_async.py b/packages/http-client-python/tests/mock_api/azure/asynctests/test_azure_arm_operationtemplates_async.py index d28064a1bcc..4881c77f1c9 100644 --- a/packages/http-client-python/tests/mock_api/azure/asynctests/test_azure_arm_operationtemplates_async.py +++ b/packages/http-client-python/tests/mock_api/azure/asynctests/test_azure_arm_operationtemplates_async.py @@ -204,3 +204,96 @@ async def test_lro_paging_begin_post_paging_lro(client): assert items[1].name == "product2" assert items[1].properties.product_id == "product2" assert items[1].properties.provisioning_state == "Succeeded" + + +@pytest.mark.asyncio +async def test_lro_paging_begin_post_paging_lro_with_body(client): + poller = await client.lro_paging.begin_post_paging_lro_with_body( + resource_group_name=RESOURCE_GROUP_NAME, + product_name="default", + body=models.VnetProfile(vnet_id="vnet1"), + ) + result = await poller.result() + items = [item async for item in result] + assert len(items) == 2 + assert items[0].name == "product1" + assert items[0].properties.product_id == "product1" + assert items[0].properties.provisioning_state == "Succeeded" + assert items[1].name == "product2" + assert items[1].properties.product_id == "product2" + assert items[1].properties.provisioning_state == "Succeeded" + + +@pytest.mark.asyncio +async def test_lro_begin_get_lro(client): + poller = await client.lro.begin_get_lro( + scope=f"subscriptions/{SUBSCRIPTION_ID}/resourceGroups/{RESOURCE_GROUP_NAME}", + operation_id="report1", + ) + result = await poller.result() + assert result.name == "report1" + assert result.properties.download_url == "https://storage.blob.core.windows.net/reports/report1.csv" + assert result.properties.provisioning_state == "Succeeded" + + +@pytest.mark.asyncio +async def test_paging_post_action_paging(client): + result = client.paging.post_action_paging( + resource_group_name=RESOURCE_GROUP_NAME, + monitor_name="monitor1", + body=models.LogStatusRequest(filter="status eq 'active'"), + ) + items = [item async for item in result] + assert items[0].id.endswith("/Microsoft.Compute/virtualMachines/vm1") + assert items[0].sending_metrics == True + + +@pytest.mark.asyncio +async def test_paging_mark_as_pageable(client): + result = client.paging.mark_as_pageable( + resource_group_name=RESOURCE_GROUP_NAME, + monitor_name="monitor1", + ) + items = [item async for item in result] + assert len(items) == 2 + assert items[0].name == "collection1" + assert items[0].properties.display_name == "Test Collection" + assert items[1].name == "collection2" + assert items[1].properties.display_name == "Another Collection" + + +@pytest.mark.asyncio +async def test_legacy_routed_get(client): + result = await client.legacy.routed_get( + resource_group_name=RESOURCE_GROUP_NAME, + name="default", + diagnostic_name="memory", + ) + assert result.name == "memory" + assert result.status == "healthy" + + +@pytest.mark.asyncio +async def test_legacy_create_or_replace_optional_body_with_body(client): + result = await client.legacy.create_or_replace_optional_body( + resource_group_name=RESOURCE_GROUP_NAME, + configuration_name="default", + resource=models.Configuration( + location="eastus", + properties=models.ConfigurationProperties(config_value="custom-value"), + ), + ) + assert result.name == "default" + assert result.properties.config_value == "custom-value" + assert result.properties.provisioning_state == "Succeeded" + + +@pytest.mark.asyncio +async def test_legacy_create_or_replace_optional_body_without_body(client): + result = await client.legacy.create_or_replace_optional_body( + resource_group_name=RESOURCE_GROUP_NAME, + configuration_name="default", + ) + assert result.name == "default" + assert result.properties.config_value == "default-value" + assert result.properties.provisioning_state == "Succeeded" diff --git a/packages/http-client-python/tests/mock_api/azure/test_azure_arm_operationtemplates.py b/packages/http-client-python/tests/mock_api/azure/test_azure_arm_operationtemplates.py index c86c95ef4a9..b7c92737fef 100644 --- a/packages/http-client-python/tests/mock_api/azure/test_azure_arm_operationtemplates.py +++ b/packages/http-client-python/tests/mock_api/azure/test_azure_arm_operationtemplates.py @@ -178,3 +178,87 @@ def test_lro_paging_begin_post_paging_lro(client): assert items[1].name == "product2" assert items[1].properties.product_id == "product2" assert items[1].properties.provisioning_state == "Succeeded" + + +def test_lro_paging_begin_post_paging_lro_with_body(client): + result = client.lro_paging.begin_post_paging_lro_with_body( + resource_group_name=RESOURCE_GROUP_NAME, + product_name="default", + body=models.VnetProfile(vnet_id="vnet1"), + ).result() + items = list(result) + assert len(items) == 2 + assert items[0].name == "product1" + assert items[0].properties.product_id == "product1" + assert items[0].properties.provisioning_state == "Succeeded" + assert items[1].name == "product2" + assert items[1].properties.product_id == "product2" + assert items[1].properties.provisioning_state == "Succeeded" + + +def test_lro_begin_get_lro(client): + result = client.lro.begin_get_lro( + scope=f"subscriptions/{SUBSCRIPTION_ID}/resourceGroups/{RESOURCE_GROUP_NAME}", + operation_id="report1", + ).result() + assert result.name == "report1" + assert result.properties.download_url == "https://storage.blob.core.windows.net/reports/report1.csv" + assert result.properties.provisioning_state == "Succeeded" + + +def test_paging_post_action_paging(client): + result = client.paging.post_action_paging( + resource_group_name=RESOURCE_GROUP_NAME, + monitor_name="monitor1", + body=models.LogStatusRequest(filter="status eq 'active'"), + ) + items = list(result) + assert items[0].id.endswith("/Microsoft.Compute/virtualMachines/vm1") + assert items[0].sending_metrics == True + + +def test_paging_mark_as_pageable(client): + result = client.paging.mark_as_pageable( + resource_group_name=RESOURCE_GROUP_NAME, + monitor_name="monitor1", + ) + items = list(result) + assert len(items) == 2 + assert items[0].name == "collection1" + assert items[0].properties.display_name == "Test Collection" + assert items[1].name == "collection2" + assert items[1].properties.display_name == "Another Collection" + + +def test_legacy_routed_get(client): + result = client.legacy.routed_get( + resource_group_name=RESOURCE_GROUP_NAME, + name="default", + diagnostic_name="memory", + ) + assert result.name == "memory" + assert result.status == "healthy" + + +def test_legacy_create_or_replace_optional_body_with_body(client): + result = client.legacy.create_or_replace_optional_body( + resource_group_name=RESOURCE_GROUP_NAME, + configuration_name="default", + resource=models.Configuration( + location="eastus", + properties=models.ConfigurationProperties(config_value="custom-value"), + ), + ) + assert result.name == "default" + assert result.properties.config_value == "custom-value" + assert result.properties.provisioning_state == "Succeeded" + + +def test_legacy_create_or_replace_optional_body_without_body(client): + result = client.legacy.create_or_replace_optional_body( + resource_group_name=RESOURCE_GROUP_NAME, + configuration_name="default", + ) + assert result.name == "default" + assert result.properties.config_value == "default-value" + assert result.properties.provisioning_state == "Succeeded"