# HG changeset patch # User RhodeCode Admin # Date 2023-03-31 11:17:33 # Node ID 2b0b3872641948ec2a24a5cb76cbe55b2814b6bd # Parent 8902033d8a7a43eac12643cea19b01bb887b9c5a ext-json: fixed tests and made the lib more consistent with orjson vs simplejson diff --git a/rhodecode/lib/ext_json.py b/rhodecode/lib/ext_json.py --- a/rhodecode/lib/ext_json.py +++ b/rhodecode/lib/ext_json.py @@ -3,8 +3,9 @@ import decimal import functools # we keep simplejson for having dump functionality still # orjson doesn't support it +import simplejson as sjson + import orjson -import simplejson import orjson as json @@ -26,7 +27,6 @@ def _obj_dump(obj): :param obj: """ - # See "Date Time String Format" in the ECMA-262 specification. # some code borrowed from django 1.4 if isinstance(obj, set): @@ -62,8 +62,11 @@ def _obj_dump(obj): raise TypeError(repr(obj) + " is not JSON serializable") +sjson.dumps = functools.partial(sjson.dumps, default=_obj_dump) +sjson.dump = functools.partial(sjson.dump, default=_obj_dump) + json.dumps = functools.partial(json.dumps, default=_obj_dump, option=orjson.OPT_NON_STR_KEYS) -json.dump = functools.partial(simplejson.dump, default=_obj_dump) +json.dump = functools.partial(sjson.dump, default=_obj_dump) def formatted_json(*args, **kwargs): diff --git a/rhodecode/tests/lib/test_ext_json.py b/rhodecode/tests/lib/test_ext_json.py --- a/rhodecode/tests/lib/test_ext_json.py +++ b/rhodecode/tests/lib/test_ext_json.py @@ -18,15 +18,14 @@ # RhodeCode Enterprise Edition, including its added features, Support services, # and proprietary license terms, please see https://rhodecode.com/licenses/ +import io import datetime import decimal -import io import textwrap import pytest -from rhodecode.lib.ext_json import json -from rhodecode.lib.ext_json import formatted_json +from rhodecode.lib import ext_json from rhodecode.translation import _, _pluralize @@ -38,87 +37,89 @@ class Timezone(datetime.tzinfo): return datetime.timedelta(hours=self.hours) +class SerializableObject(object): + def __json__(self): + return 'foo' + + def test_dumps_set(): - result = json.dumps(set((1, 2, 3))) + result = ext_json.json.dumps(set((1, 2, 3))) # We cannot infer what the order of result is going to be - result = json.loads(result) + result = ext_json.json.loads(result) assert isinstance(result, list) assert [1, 2, 3] == sorted(result) def test_dumps_decimal(): - assert '"1.5"' == json.dumps(decimal.Decimal('1.5')) + assert b'"1.5"' == ext_json.json.dumps(decimal.Decimal('1.5')) def test_dumps_complex(): - assert "[0.0, 1.0]" == json.dumps(1j) - assert "[1.0, 0.0]" == json.dumps(1 + 0j) - assert "[1.1, 1.2]" == json.dumps(1.1 + 1.2j) + assert b"[0.0,1.0]" == ext_json.json.dumps(1j) + assert b"[1.0,0.0]" == ext_json.json.dumps(1 + 0j) + assert b"[1.1,1.2]" == ext_json.json.dumps(1.1 + 1.2j) def test_dumps_object_with_json_method(): - class SerializableObject(object): - def __json__(self): - return 'foo' - - assert '"foo"' == json.dumps(SerializableObject()) + assert '"foo"' == ext_json.str_json(SerializableObject()) def test_dumps_object_with_json_attribute(): - class SerializableObject(object): - __json__ = 'foo' - assert '"foo"' == json.dumps(SerializableObject()) + assert '"foo"' == ext_json.str_json(SerializableObject()) def test_dumps_time(): - assert '"03:14:15.926"' == json.dumps(datetime.time(3, 14, 15, 926535)) + assert '"03:14:15.926535"' == ext_json.str_json(datetime.time(3, 14, 15, 926535)) def test_dumps_time_no_microseconds(): - assert '"03:14:15"' == json.dumps(datetime.time(3, 14, 15)) + assert '"03:14:15"' == ext_json.str_json(datetime.time(3, 14, 15)) def test_dumps_time_with_timezone(): with pytest.raises(TypeError) as excinfo: - json.dumps(datetime.time(3, 14, 15, 926535, Timezone(0))) + ext_json.json.dumps(datetime.time(3, 14, 15, 926535, Timezone(0))) error_msg = str(excinfo.value) - assert 'Time-zone aware times are not JSON serializable' in error_msg + + assert 'timezone library is not supported' in error_msg + # only for simplejson + #assert 'Time-zone aware times are not JSON serializable' in error_msg def test_dumps_date(): - assert '"1969-07-20"' == json.dumps(datetime.date(1969, 7, 20)) + assert b'"1969-07-20"' == ext_json.json.dumps(datetime.date(1969, 7, 20)) def test_dumps_datetime(): - json_data = json.dumps(datetime.datetime(1969, 7, 20, 3, 14, 15, 926535)) - assert '"1969-07-20T03:14:15.926"' == json_data + json_data = ext_json.json.dumps(datetime.datetime(1969, 7, 20, 3, 14, 15, 926535)) + assert b'"1969-07-20T03:14:15.926535"' == json_data def test_dumps_datetime_no_microseconds(): - json_data = json.dumps(datetime.datetime(1969, 7, 20, 3, 14, 15)) - assert '"1969-07-20T03:14:15"' == json_data + json_data = ext_json.json.dumps(datetime.datetime(1969, 7, 20, 3, 14, 15)) + assert b'"1969-07-20T03:14:15"' == json_data def test_dumps_datetime_with_utc_timezone(): - json_data = json.dumps( + json_data = ext_json.json.dumps( datetime.datetime(1969, 7, 20, 3, 14, 15, 926535, Timezone(0))) - assert '"1969-07-20T03:14:15.926Z"' == json_data + assert b'"1969-07-20T03:14:15.926535+00:00"' == json_data def test_dumps_datetime_with_plus1_timezone(): - json_data = json.dumps( + json_data = ext_json.json.dumps( datetime.datetime(1969, 7, 20, 3, 14, 15, 926535, Timezone(1))) - assert '"1969-07-20T03:14:15.926+01:00"' == json_data + assert b'"1969-07-20T03:14:15.926535+01:00"' == json_data def test_dumps_unserializable_class(): unserializable_obj = object() with pytest.raises(TypeError) as excinfo: - json.dumps(unserializable_obj) + ext_json.json.dumps(unserializable_obj) - assert repr(unserializable_obj) in str(excinfo.value) + assert 'object' in str(excinfo.value) assert 'is not JSON serializable' in str(excinfo.value) @@ -131,10 +132,10 @@ def test_dump_is_like_dumps(): 'time': datetime.time(3, 14, 15, 926535), 'date': datetime.date(1969, 7, 20), } - json_buffer = io.BytesIO() - json.dump(data, json_buffer) + json_buffer = io.StringIO() # StringIO because dump uses simplejson not orjson + ext_json.json.dump(data, json_buffer) - assert json.dumps(data) == json_buffer.getvalue() + assert ext_json.sjson.dumps(data) == json_buffer.getvalue() def test_formatted_json(): @@ -145,22 +146,22 @@ def test_formatted_json(): expected_data = textwrap.dedent(''' { - "a": { - "3": 3, - "4": 4 - }, - "b": { - "1": 1, - "2": 2 - } + "a": { + "3": 3, + "4": 4 + }, + "b": { + "1": 1, + "2": 2 + } }''').strip() - assert formatted_json(data) == expected_data + assert expected_data == ext_json.formatted_str_json(data) def test_lazy_translation_string(baseapp): data = {'label': _('hello')} data2 = {'label2': _pluralize('singular', 'plural', 1)} - assert json.dumps(data) == '{"label": "hello"}' - assert json.dumps(data2) == '{"label2": "singular"}' + assert b'{"label":"hello"}' == ext_json.json.dumps(data) + assert b'{"label2":"singular"}' == ext_json.json.dumps(data2)