sanic/tests/test_json_encoding.py

108 lines
2.4 KiB
Python

import sys
from dataclasses import asdict, dataclass
from functools import partial
from json import dumps as sdumps
from string import ascii_lowercase
from typing import Dict
import pytest
try:
import ujson
from ujson import dumps as udumps
ujson_version = tuple(
map(int, ujson.__version__.strip(ascii_lowercase).split("."))
)
NO_UJSON = False
DEFAULT_DUMPS = udumps
except ModuleNotFoundError:
NO_UJSON = True
DEFAULT_DUMPS = partial(sdumps, separators=(",", ":"))
ujson_version = None
from sanic import Sanic
from sanic.response import BaseHTTPResponse, json
@dataclass
class Foo:
bar: str
def __json__(self):
return udumps(asdict(self))
@pytest.fixture
def foo():
return Foo(bar="bar")
@pytest.fixture
def payload(foo: Foo):
return {"foo": foo}
@pytest.fixture(autouse=True)
def default_back_to_ujson():
yield
BaseHTTPResponse._dumps = DEFAULT_DUMPS
def test_change_encoder():
Sanic("Test", dumps=sdumps)
assert BaseHTTPResponse._dumps == sdumps
def test_change_encoder_to_some_custom():
def my_custom_encoder():
return "foo"
Sanic("Test", dumps=my_custom_encoder)
assert BaseHTTPResponse._dumps == my_custom_encoder
@pytest.mark.skipif(NO_UJSON is True, reason="ujson not installed")
def test_json_response_ujson(payload: Dict[str, Foo]):
"""ujson will look at __json__"""
response = json(payload)
assert response.body == b'{"foo":{"bar":"bar"}}'
with pytest.raises(
TypeError, match="Object of type Foo is not JSON serializable"
):
json(payload, dumps=sdumps)
Sanic("Test", dumps=sdumps)
with pytest.raises(
TypeError, match="Object of type Foo is not JSON serializable"
):
json(payload)
@pytest.mark.skipif(
NO_UJSON is True or ujson_version >= (5, 4, 0),
reason=(
"ujson not installed or version is 5.4.0 or newer, "
"which can handle arbitrary size integers"
),
)
def test_json_response_json():
"""One of the easiest ways to tell the difference is that ujson cannot
serialize over 64 bits"""
too_big_for_ujson = 111111111111111111111
with pytest.raises(OverflowError, match="int too big to convert"):
json(too_big_for_ujson)
response = json(too_big_for_ujson, dumps=sdumps)
assert sys.getsizeof(response.body) == 54
Sanic("Test", dumps=sdumps)
response = json(too_big_for_ujson)
assert sys.getsizeof(response.body) == 54