From 74ef3e3474d736a1efd2f905c663f7546a014f16 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Wed, 5 Aug 2026 10:58:00 -0400 Subject: [PATCH 1/3] fix: add missing 'suggested_currency' field from snapd JSON response payload Signed-off-by: Christian Goeschel Ndjomouo --- snap_http/types.py | 1 + 1 file changed, 1 insertion(+) diff --git a/snap_http/types.py b/snap_http/types.py index 665c57a..eb3cbee 100644 --- a/snap_http/types.py +++ b/snap_http/types.py @@ -38,6 +38,7 @@ class SnapdResponse: change: Union[str, None] = None warning_timestamp: Union[str, None] = None warning_count: Union[int, None] = None + suggested_currency: Union[str, None] = None @classmethod def from_http_response( From ba33ccae23ab6281d28eba8c6618f0612e82be57 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Wed, 5 Aug 2026 10:58:09 -0400 Subject: [PATCH 2/3] fix: guard against unknown fields in the snapd JSON response payload If snapd returns a JSON response that contains fields not registered for the SnapdResponse dataclass, the Snapdresponse __init__() will error out and not instantiate a usable object. To avoid this problem we can filter out all JSON response fields that are currently not set for our dataclass and silently ignore them. Signed-off-by: Christian Goeschel Ndjomouo --- snap_http/types.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/snap_http/types.py b/snap_http/types.py index eb3cbee..1d646d9 100644 --- a/snap_http/types.py +++ b/snap_http/types.py @@ -2,7 +2,7 @@ import json from abc import ABC, abstractproperty -from dataclasses import dataclass +from dataclasses import dataclass, fields from functools import cached_property from io import BytesIO from pathlib import Path @@ -44,8 +44,15 @@ class SnapdResponse: def from_http_response( cls: Type["SnapdResponse"], response: Dict[str, Any] ) -> SnapdResponse: - return cls(**{k.replace("-", "_"): v for k, v in response.items()}) - + # In case snapd returns to us unknown fields in its response + cls_fields = {f.name for f in fields(cls)} + filtered_fields = {} + + for k, v in response.items(): + key = k.replace("-", "_") + if key in cls_fields: + filtered_fields[key] = v + return cls(**filtered_fields) class AbstractRequestBody(ABC): """An abstract base class for the request body of a HTTP request.""" From 5218a74352f44084543e4c5846004b6db7ffde20 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Tue, 18 Aug 2026 11:33:16 -0400 Subject: [PATCH 3/3] ci: add data serialization filter unit test --- tests/unit/test_types.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/unit/test_types.py b/tests/unit/test_types.py index 6a859e2..b29dda4 100644 --- a/tests/unit/test_types.py +++ b/tests/unit/test_types.py @@ -108,3 +108,22 @@ def test_assertion_data_serialization(): body = types.AssertionData("assertion-header: value\n\nsignature") assert body.content_type == "application/x.ubuntu.assertion" assert body.serialized == b"assertion-header: value\n\nsignature" + + +def test_data_serialization_filter(): + """Test filtering of unknown response data fields.""" + mock_response = { + "type": "async", + "status_code": 200, + "status": "Accepted", + "result": None, + "unknown": "bogus", + } + + resp = types.SnapdResponse.from_http_response(mock_response) + + assert not hasattr(resp, "unknown") + assert resp.type == "async" + assert resp.status_code == 200 + assert resp.status == "Accepted" + assert resp.result is None \ No newline at end of file