From 0db58c9f9961c72eead924b5526caad07c2fb7e4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Feb 2026 22:26:37 +0000 Subject: [PATCH 1/4] Initial plan From bd1f95107ebc45ac854c36695d42e573aebfa513 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Feb 2026 22:34:29 +0000 Subject: [PATCH 2/4] feat(http-client-python): add XML deserialization test for EnumerationResults payload Co-authored-by: l0lawrence <100643745+l0lawrence@users.noreply.github.com> --- ...meration-results-test-2026-2-23-22-33-2.md | 7 +++++ .../test_model_base_xml_serialization.py | 26 +++++++++++++++++++ packages/http-client-python/package-lock.json | 1 + 3 files changed, 34 insertions(+) create mode 100644 .chronus/changes/http-client-python-xml-enumeration-results-test-2026-2-23-22-33-2.md diff --git a/.chronus/changes/http-client-python-xml-enumeration-results-test-2026-2-23-22-33-2.md b/.chronus/changes/http-client-python-xml-enumeration-results-test-2026-2-23-22-33-2.md new file mode 100644 index 00000000000..c4a7ac65651 --- /dev/null +++ b/.chronus/changes/http-client-python-xml-enumeration-results-test-2026-2-23-22-33-2.md @@ -0,0 +1,7 @@ +--- +changeKind: internal +packages: + - "@typespec/http-client-python" +--- + +Add unit test for deserializing Azure Blob Storage EnumerationResults XML payload with attributes, empty list element, and empty string element. diff --git a/packages/http-client-python/generator/test/unittests/test_model_base_xml_serialization.py b/packages/http-client-python/generator/test/unittests/test_model_base_xml_serialization.py index 27529cc5263..11c955f14f2 100644 --- a/packages/http-client-python/generator/test/unittests/test_model_base_xml_serialization.py +++ b/packages/http-client-python/generator/test/unittests/test_model_base_xml_serialization.py @@ -515,6 +515,32 @@ def __init__(self, *args, **kwargs): assert isinstance(result.filter, CorrelationFilter) assert result.filter.correlation_id == 12 + def test_enumeration_results(self): + """Test deserializing an Azure Blob Storage EnumerationResults XML payload.""" + xml_payload = '/' + + class EnumerationResults(Model): + service_endpoint: str = rest_field( + name="ServiceEndpoint", xml={"name": "ServiceEndpoint", "attribute": True} + ) + container_name: str = rest_field(name="ContainerName", xml={"name": "ContainerName", "attribute": True}) + delimiter: str = rest_field(name="Delimiter", xml={"name": "Delimiter"}) + blobs: list[str] = rest_field(name="Blobs", xml={"name": "Blobs"}) + next_marker: str = rest_field(name="NextMarker", xml={"name": "NextMarker"}) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + _xml = {"name": "EnumerationResults"} + + result = _deserialize_xml(EnumerationResults, xml_payload) + + assert result.service_endpoint == "https://service.blob.core.windows.net/" + assert result.container_name == "acontainer108f32e8" + assert result.delimiter == "/" + assert result.blobs == [] + assert result.next_marker == "" + class TestXmlSerialization: def test_basic(self): diff --git a/packages/http-client-python/package-lock.json b/packages/http-client-python/package-lock.json index ee93f122732..035891d5432 100644 --- a/packages/http-client-python/package-lock.json +++ b/packages/http-client-python/package-lock.json @@ -7265,6 +7265,7 @@ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", From 833e54e045409b1d2a1a719f3c0037c854fa6f18 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 17:05:46 +0000 Subject: [PATCH 3/4] test(http-client-python): add nested empty list XML deserialization test for EnumerationResults Co-authored-by: l0lawrence <100643745+l0lawrence@users.noreply.github.com> --- .../test_model_base_xml_serialization.py | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/packages/http-client-python/generator/test/unittests/test_model_base_xml_serialization.py b/packages/http-client-python/generator/test/unittests/test_model_base_xml_serialization.py index 11c955f14f2..873c9f7d897 100644 --- a/packages/http-client-python/generator/test/unittests/test_model_base_xml_serialization.py +++ b/packages/http-client-python/generator/test/unittests/test_model_base_xml_serialization.py @@ -541,6 +541,50 @@ def __init__(self, *args, **kwargs): assert result.blobs == [] assert result.next_marker == "" + def test_enumeration_results_nested_empty_list(self): + """Test deserializing XML where a container element holds a nested empty list (e.g. Blobs/BlobPrefixes).""" + xml_payload = '/' + + class BlobPrefix(Model): + name: str = rest_field(name="Name", xml={"name": "Name"}) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + _xml = {"name": "BlobPrefix"} + + class BlobsSegment(Model): + blob_prefixes: list[BlobPrefix] = rest_field( + name="BlobPrefixes", xml={"name": "BlobPrefixes", "itemsName": "BlobPrefix"} + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + _xml = {"name": "Blobs"} + + class EnumerationResults(Model): + service_endpoint: str = rest_field( + name="ServiceEndpoint", xml={"name": "ServiceEndpoint", "attribute": True} + ) + container_name: str = rest_field(name="ContainerName", xml={"name": "ContainerName", "attribute": True}) + delimiter: str = rest_field(name="Delimiter", xml={"name": "Delimiter"}) + blobs: BlobsSegment = rest_field(name="Blobs", xml={"name": "Blobs"}) + next_marker: str = rest_field(name="NextMarker", xml={"name": "NextMarker"}) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + _xml = {"name": "EnumerationResults"} + + result = _deserialize_xml(EnumerationResults, xml_payload) + + assert result.service_endpoint == "https://service.blob.core.windows.net/" + assert result.container_name == "acontainer" + assert result.delimiter == "/" + assert result.blobs.blob_prefixes == [] + assert result.next_marker == "" + class TestXmlSerialization: def test_basic(self): From 8caa8738ce7beb1823cfcbd7b0f2c8df243e6182 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 17:29:20 +0000 Subject: [PATCH 4/4] test(http-client-python): add Azure SDK pattern and unwrapped field XML deserialization tests Co-authored-by: l0lawrence <100643745+l0lawrence@users.noreply.github.com> --- .../test_model_base_xml_serialization.py | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/packages/http-client-python/generator/test/unittests/test_model_base_xml_serialization.py b/packages/http-client-python/generator/test/unittests/test_model_base_xml_serialization.py index 873c9f7d897..9004aa1640b 100644 --- a/packages/http-client-python/generator/test/unittests/test_model_base_xml_serialization.py +++ b/packages/http-client-python/generator/test/unittests/test_model_base_xml_serialization.py @@ -585,6 +585,116 @@ def __init__(self, *args, **kwargs): assert result.blobs.blob_prefixes == [] assert result.next_marker == "" + def test_enumeration_results_azure_sdk_pattern(self): + """Test the real Azure SDK model pattern where BlobsSegment has two unwrapped list fields.""" + # Both blob_prefixes and blob_items are unwrapped lists (items appear directly in ). + # With , no matching children are found so both are None. + xml_payload = '/' + + class BlobPrefix(Model): + name: str = rest_field(name="Name", xml={"name": "Name"}) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + _xml = {"name": "BlobPrefix"} + + class BlobItem(Model): + name: str = rest_field(name="Name", xml={"name": "Name"}) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + _xml = {"name": "Blob"} + + class BlobsSegment(Model): + blob_prefixes: list[BlobPrefix] = rest_field( + name="blob_prefixes", xml={"name": "BlobPrefix", "unwrapped": True} + ) + blob_items: list[BlobItem] = rest_field(name="blob_items", xml={"name": "Blob", "unwrapped": True}) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + _xml = {"name": "Blobs"} + + class EnumerationResults(Model): + service_endpoint: str = rest_field( + name="ServiceEndpoint", xml={"name": "ServiceEndpoint", "attribute": True} + ) + container_name: str = rest_field(name="ContainerName", xml={"name": "ContainerName", "attribute": True}) + delimiter: str = rest_field(name="Delimiter", xml={"name": "Delimiter"}) + blobs: BlobsSegment = rest_field(name="Blobs", xml={"name": "Blobs"}) + next_marker: str = rest_field(name="NextMarker", xml={"name": "NextMarker"}) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + _xml = {"name": "EnumerationResults"} + + result = _deserialize_xml(EnumerationResults, xml_payload) + + assert result.service_endpoint == "https://service.blob.core.windows.net/" + assert result.container_name == "acontainer" + assert result.delimiter == "/" + assert isinstance(result.blobs, BlobsSegment) + # With , no or children exist → unwrapped empty lists stay None + assert result.blobs.blob_prefixes is None + assert result.blobs.blob_items is None + assert result.next_marker == "" + + def test_enumeration_results_blobs_unwrapped(self): + """Test what happens when the blobs field itself is declared with unwrapped=True.""" + # When a non-list model field uses unwrapped=True, the matching XML elements are collected + # as a list and stored as-is (the field receives a list of ET.Element objects). + xml_payload = '/' + + class BlobPrefix(Model): + name: str = rest_field(name="Name", xml={"name": "Name"}) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + _xml = {"name": "BlobPrefix"} + + class BlobsSegment(Model): + blob_prefixes: list[BlobPrefix] = rest_field( + name="BlobPrefixes", xml={"name": "BlobPrefixes", "itemsName": "BlobPrefix"} + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + _xml = {"name": "Blobs"} + + class EnumerationResults(Model): + service_endpoint: str = rest_field( + name="ServiceEndpoint", xml={"name": "ServiceEndpoint", "attribute": True} + ) + container_name: str = rest_field(name="ContainerName", xml={"name": "ContainerName", "attribute": True}) + delimiter: str = rest_field(name="Delimiter", xml={"name": "Delimiter"}) + # unwrapped=True on a model-typed field: the deserialization collects matching XML + # elements as a list (rather than deserializing them into the model). + blobs: BlobsSegment = rest_field(name="Blobs", xml={"name": "Blobs", "unwrapped": True}) + next_marker: str = rest_field(name="NextMarker", xml={"name": "NextMarker"}) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + _xml = {"name": "EnumerationResults"} + + result = _deserialize_xml(EnumerationResults, xml_payload) + + assert result.service_endpoint == "https://service.blob.core.windows.net/" + assert result.container_name == "acontainer" + assert result.delimiter == "/" + # unwrapped=True on a model field collects matching elements; is found so it + # returns a list containing the raw ET.Element instead of a deserialized BlobsSegment. + assert isinstance(result.blobs, list) + assert len(result.blobs) == 1 + assert isinstance(result.blobs[0], ET.Element) + assert result.next_marker == "" + class TestXmlSerialization: def test_basic(self):