diff --git a/CHANGELOG.md b/CHANGELOG.md index aa654e2a..2f55cc87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Fixed binary content mode producing invalid JSON for list, boolean and other + non-dict JSON data (e.g. `['a']` instead of `["a"]`). + ## [2.2.0] ### Changed diff --git a/src/cloudevents/core/formats/json.py b/src/cloudevents/core/formats/json.py index f20e0538..44e55ceb 100644 --- a/src/cloudevents/core/formats/json.py +++ b/src/cloudevents/core/formats/json.py @@ -172,18 +172,17 @@ def write_data( if isinstance(data, str): return data.encode("utf-8") - # If data is a dict and content type is JSON, serialize as JSON - if isinstance(data, dict): - content_type = datacontenttype or self.DEFAULT_CONTENT_TYPE - if re.match(JSONFormat.JSON_CONTENT_TYPE_PATTERN, content_type): - return dumps(data, cls=_JSONEncoderWithDatetime).encode("utf-8") - - # for other contenttypes we still try to generate a json-decodable string - # if not possible, a string representing - try: - return dumps(data, cls=_JSONEncoderWithDatetime).encode("utf-8") - except TypeError: - pass + # Any other value (dict, list, number, bool) is serialized as JSON + content_type = datacontenttype or self.DEFAULT_CONTENT_TYPE + if re.match(JSONFormat.JSON_CONTENT_TYPE_PATTERN, content_type): + return dumps(data, cls=_JSONEncoderWithDatetime).encode("utf-8") + + # for other contenttypes we still try to generate a json-decodable string + # if not possible, a string representing + try: + return dumps(data, cls=_JSONEncoderWithDatetime).encode("utf-8") + except TypeError: + pass # according to the spec, we return an encoded string per default # careful: the result is not json-decodable as the dict keys are single-quoted diff --git a/tests/test_core/test_format/test_json.py b/tests/test_core/test_format/test_json.py index 9971779b..a0eef3e0 100644 --- a/tests/test_core/test_format/test_json.py +++ b/tests/test_core/test_format/test_json.py @@ -14,6 +14,7 @@ from datetime import datetime, timezone from json import loads +from typing import Any import pytest @@ -339,6 +340,18 @@ def test_write_data_dict(content_type: str) -> None: assert loads(result) == data +@pytest.mark.parametrize( + "content_type", [None, "application/json", "application/octet-stream"] +) +@pytest.mark.parametrize("data", [["a", {"b": None}], True, 1.5]) +def test_write_data_non_dict_json_value(content_type: str, data: Any) -> None: + formatter = JSONFormat() + result = formatter.write_data(data, datacontenttype=content_type) + + assert isinstance(result, bytes) + assert loads(result) == data + + @pytest.mark.parametrize("content_type", [None, "application/json"]) def test_read_data_json_body(content_type: str) -> None: formatter = JSONFormat()