Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 11 additions & 12 deletions src/cloudevents/core/formats/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions tests/test_core/test_format/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from datetime import datetime, timezone
from json import loads
from typing import Any

import pytest

Expand Down Expand Up @@ -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()
Expand Down
Loading