diff --git a/.chronus/changes/copilot-add-test-case-http-client-2026-0-19-7-35-17.md b/.chronus/changes/copilot-add-test-case-http-client-2026-0-19-7-35-17.md new file mode 100644 index 00000000000..a38cc874111 --- /dev/null +++ b/.chronus/changes/copilot-add-test-case-http-client-2026-0-19-7-35-17.md @@ -0,0 +1,7 @@ +--- +changeKind: feature +packages: + - "@typespec/http-client-python" +--- + +Support enum type for array encode \ No newline at end of file diff --git a/packages/http-client-python/generator/pygen/codegen/templates/model_base.py.jinja2 b/packages/http-client-python/generator/pygen/codegen/templates/model_base.py.jinja2 index 28b877006da..650204d2e35 100644 --- a/packages/http-client-python/generator/pygen/codegen/templates/model_base.py.jinja2 +++ b/packages/http-client-python/generator/pygen/codegen/templates/model_base.py.jinja2 @@ -848,6 +848,14 @@ def _deserialize_multiple_sequence( return type(obj)(_deserialize(deserializer, entry, module) for entry, deserializer in zip(obj, entry_deserializers)) +def _is_array_encoded_deserializer(deserializer: functools.partial) -> bool: + return ( + isinstance(deserializer, functools.partial) + and isinstance(deserializer.args[0], functools.partial) + and deserializer.args[0].func == _deserialize_array_encoded # pylint: disable=comparison-with-callable + ) + + def _deserialize_sequence( deserializer: typing.Optional[typing.Callable], module: typing.Optional[str], @@ -857,17 +865,19 @@ def _deserialize_sequence( return obj if isinstance(obj, ET.Element): obj = list(obj) - try: - if ( - isinstance(obj, str) - and isinstance(deserializer, functools.partial) - and isinstance(deserializer.args[0], functools.partial) - and deserializer.args[0].func == _deserialize_array_encoded # pylint: disable=comparison-with-callable - ): - # encoded string may be deserialized to sequence + + # encoded string may be deserialized to sequence + if isinstance(obj, str) and isinstance(deserializer, functools.partial): + # for list[str] + if _is_array_encoded_deserializer(deserializer): return deserializer(obj) - except: # pylint: disable=bare-except - pass + + # for list[Union[...]] + if isinstance(deserializer.args[0], list): + for sub_deserializer in deserializer.args[0]: + if _is_array_encoded_deserializer(sub_deserializer): + return sub_deserializer(obj) + return type(obj)(_deserialize(deserializer, entry, module) for entry in obj) diff --git a/packages/http-client-python/generator/test/generic_mock_api_tests/asynctests/test_encode_array_async.py b/packages/http-client-python/generator/test/generic_mock_api_tests/asynctests/test_encode_array_async.py index 27cae3caa09..925780cd4aa 100644 --- a/packages/http-client-python/generator/test/generic_mock_api_tests/asynctests/test_encode_array_async.py +++ b/packages/http-client-python/generator/test/generic_mock_api_tests/asynctests/test_encode_array_async.py @@ -41,3 +41,99 @@ async def test_newline_delimited(client: ArrayClient): body = models.NewlineDelimitedArrayProperty(value=["blue", "red", "green"]) result = await client.property.newline_delimited(body) assert result.value == ["blue", "red", "green"] + + +@pytest.mark.asyncio +async def test_enum_comma_delimited(client: ArrayClient): + body = models.CommaDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) + result = await client.property.enum_comma_delimited(body) + assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] + + +@pytest.mark.asyncio +async def test_enum_space_delimited(client: ArrayClient): + body = models.SpaceDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) + result = await client.property.enum_space_delimited(body) + assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] + + +@pytest.mark.asyncio +async def test_enum_pipe_delimited(client: ArrayClient): + body = models.PipeDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) + result = await client.property.enum_pipe_delimited(body) + assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] + + +@pytest.mark.asyncio +async def test_enum_newline_delimited(client: ArrayClient): + body = models.NewlineDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) + result = await client.property.enum_newline_delimited(body) + assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] + + +@pytest.mark.asyncio +async def test_extensible_enum_comma_delimited(client: ArrayClient): + body = models.CommaDelimitedExtensibleEnumArrayProperty( + value=[ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + ) + result = await client.property.extensible_enum_comma_delimited(body) + assert result.value == [ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + + +@pytest.mark.asyncio +async def test_extensible_enum_space_delimited(client: ArrayClient): + body = models.SpaceDelimitedExtensibleEnumArrayProperty( + value=[ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + ) + result = await client.property.extensible_enum_space_delimited(body) + assert result.value == [ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + + +@pytest.mark.asyncio +async def test_extensible_enum_pipe_delimited(client: ArrayClient): + body = models.PipeDelimitedExtensibleEnumArrayProperty( + value=[ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + ) + result = await client.property.extensible_enum_pipe_delimited(body) + assert result.value == [ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + + +@pytest.mark.asyncio +async def test_extensible_enum_newline_delimited(client: ArrayClient): + body = models.NewlineDelimitedExtensibleEnumArrayProperty( + value=[ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + ) + result = await client.property.extensible_enum_newline_delimited(body) + assert result.value == [ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] diff --git a/packages/http-client-python/generator/test/generic_mock_api_tests/test_encode_array.py b/packages/http-client-python/generator/test/generic_mock_api_tests/test_encode_array.py index 3e1b48c908e..a09a05a793b 100644 --- a/packages/http-client-python/generator/test/generic_mock_api_tests/test_encode_array.py +++ b/packages/http-client-python/generator/test/generic_mock_api_tests/test_encode_array.py @@ -36,3 +36,91 @@ def test_newline_delimited(client: ArrayClient): body = models.NewlineDelimitedArrayProperty(value=["blue", "red", "green"]) result = client.property.newline_delimited(body) assert result.value == ["blue", "red", "green"] + + +def test_enum_comma_delimited(client: ArrayClient): + body = models.CommaDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) + result = client.property.enum_comma_delimited(body) + assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] + + +def test_enum_space_delimited(client: ArrayClient): + body = models.SpaceDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) + result = client.property.enum_space_delimited(body) + assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] + + +def test_enum_pipe_delimited(client: ArrayClient): + body = models.PipeDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) + result = client.property.enum_pipe_delimited(body) + assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] + + +def test_enum_newline_delimited(client: ArrayClient): + body = models.NewlineDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) + result = client.property.enum_newline_delimited(body) + assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] + + +def test_extensible_enum_comma_delimited(client: ArrayClient): + body = models.CommaDelimitedExtensibleEnumArrayProperty( + value=[ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + ) + result = client.property.extensible_enum_comma_delimited(body) + assert result.value == [ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + + +def test_extensible_enum_space_delimited(client: ArrayClient): + body = models.SpaceDelimitedExtensibleEnumArrayProperty( + value=[ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + ) + result = client.property.extensible_enum_space_delimited(body) + assert result.value == [ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + + +def test_extensible_enum_pipe_delimited(client: ArrayClient): + body = models.PipeDelimitedExtensibleEnumArrayProperty( + value=[ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + ) + result = client.property.extensible_enum_pipe_delimited(body) + assert result.value == [ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + + +def test_extensible_enum_newline_delimited(client: ArrayClient): + body = models.NewlineDelimitedExtensibleEnumArrayProperty( + value=[ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + ) + result = client.property.extensible_enum_newline_delimited(body) + assert result.value == [ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] diff --git a/packages/http-client-python/package-lock.json b/packages/http-client-python/package-lock.json index 1fc2eff24cb..6b39d9b20f6 100644 --- a/packages/http-client-python/package-lock.json +++ b/packages/http-client-python/package-lock.json @@ -29,7 +29,7 @@ "@typespec/compiler": "^1.8.0", "@typespec/events": "~0.78.0", "@typespec/http": "^1.8.0", - "@typespec/http-specs": "0.1.0-alpha.31", + "@typespec/http-specs": "0.1.0-alpha.32-dev.1", "@typespec/openapi": "^1.8.0", "@typespec/rest": "~0.78.0", "@typespec/spec-api": "0.1.0-alpha.12", @@ -2318,14 +2318,14 @@ } }, "node_modules/@typespec/http-specs": { - "version": "0.1.0-alpha.31", - "resolved": "https://registry.npmjs.org/@typespec/http-specs/-/http-specs-0.1.0-alpha.31.tgz", - "integrity": "sha512-ji+Zt4wB8NnVw3cFiE+LmkXCTfBWEq1xwBQrxJ83q28NQeKBMOVxynjiCz344gxOCcEfhAX4mwKcYeJUKAFVYQ==", + "version": "0.1.0-alpha.32-dev.1", + "resolved": "https://registry.npmjs.org/@typespec/http-specs/-/http-specs-0.1.0-alpha.32-dev.1.tgz", + "integrity": "sha512-b+uzFhToERrmV154eqnCoQiw4Jekn+DRamfZVAl7ndVeayDq9zLNZyPnCmeU1+bdKxUGO8WoGkpA9BeGP3teeA==", "dev": true, "license": "MIT", "dependencies": { - "@typespec/spec-api": "^0.1.0-alpha.12", - "@typespec/spector": "^0.1.0-alpha.22", + "@typespec/spec-api": "^0.1.0-alpha.12 || >=0.1.0-alpha.13-dev <0.1.0-alpha.13", + "@typespec/spector": "^0.1.0-alpha.22 || >=0.1.0-alpha.23-dev <0.1.0-alpha.23", "deep-equal": "^2.2.0" }, "engines": { @@ -2334,9 +2334,9 @@ "peerDependencies": { "@typespec/compiler": "^1.8.0", "@typespec/http": "^1.8.0", - "@typespec/rest": "^0.78.0", - "@typespec/versioning": "^0.78.0", - "@typespec/xml": "^0.78.0" + "@typespec/rest": "^0.78.0 || >=0.79.0-dev <0.79.0", + "@typespec/versioning": "^0.78.0 || >=0.79.0-dev <0.79.0", + "@typespec/xml": "^0.78.0 || >=0.79.0-dev <0.79.0" } }, "node_modules/@typespec/openapi": { diff --git a/packages/http-client-python/package.json b/packages/http-client-python/package.json index 3a14ca246a4..a122c496717 100644 --- a/packages/http-client-python/package.json +++ b/packages/http-client-python/package.json @@ -94,7 +94,7 @@ "@typespec/sse": "~0.78.0", "@typespec/streams": "~0.78.0", "@typespec/xml": "~0.78.0", - "@typespec/http-specs": "0.1.0-alpha.31", + "@typespec/http-specs": "0.1.0-alpha.32-dev.1", "@types/js-yaml": "~4.0.5", "@types/node": "~24.1.0", "@types/semver": "7.5.8",