diff --git a/pandas/_libs/json.pyi b/pandas/_libs/json.pyi index 8e7ba60ccce24..bc4fe68573b94 100644 --- a/pandas/_libs/json.pyi +++ b/pandas/_libs/json.pyi @@ -3,7 +3,7 @@ from typing import ( Callable, ) -def dumps( +def ujson_dumps( obj: Any, ensure_ascii: bool = ..., double_precision: int = ..., @@ -14,7 +14,7 @@ def dumps( default_handler: None | Callable[[Any], str | float | bool | list | dict | None] = ..., ) -> str: ... -def loads( +def ujson_loads( s: str, precise_float: bool = ..., numpy: bool = ..., diff --git a/pandas/_libs/src/vendored/ujson/python/ujson.c b/pandas/_libs/src/vendored/ujson/python/ujson.c index 15ea4b056b02d..6a6a1bdcbe0e0 100644 --- a/pandas/_libs/src/vendored/ujson/python/ujson.c +++ b/pandas/_libs/src/vendored/ujson/python/ujson.c @@ -54,14 +54,9 @@ PyObject *JSONToObj(PyObject *self, PyObject *args, PyObject *kwargs); "encode_html_chars=True to encode < > & as unicode escape sequences." static PyMethodDef ujsonMethods[] = { - {"encode", (PyCFunction)objToJSON, METH_VARARGS | METH_KEYWORDS, + {"ujson_dumps", (PyCFunction)objToJSON, METH_VARARGS | METH_KEYWORDS, "Converts arbitrary object recursively into JSON. " ENCODER_HELP_TEXT}, - {"decode", (PyCFunction)JSONToObj, METH_VARARGS | METH_KEYWORDS, - "Converts JSON as string to dict object structure. Use precise_float=True " - "to use high precision float decoder."}, - {"dumps", (PyCFunction)objToJSON, METH_VARARGS | METH_KEYWORDS, - "Converts arbitrary object recursively into JSON. " ENCODER_HELP_TEXT}, - {"loads", (PyCFunction)JSONToObj, METH_VARARGS | METH_KEYWORDS, + {"ujson_loads", (PyCFunction)JSONToObj, METH_VARARGS | METH_KEYWORDS, "Converts JSON as string to dict object structure. Use precise_float=True " "to use high precision float decoder."}, {NULL, NULL, 0, NULL} /* Sentinel */ diff --git a/pandas/io/excel/_odswriter.py b/pandas/io/excel/_odswriter.py index 2d5c61a4139f6..a4b4d965089dc 100644 --- a/pandas/io/excel/_odswriter.py +++ b/pandas/io/excel/_odswriter.py @@ -247,7 +247,7 @@ def _process_style(self, style: dict[str, Any]) -> str: if style is None: return None - style_key = json.dumps(style) + style_key = json.ujson_dumps(style) if style_key in self._style_dict: return self._style_dict[style_key] name = f"pd{len(self._style_dict)+1}" diff --git a/pandas/io/excel/_xlsxwriter.py b/pandas/io/excel/_xlsxwriter.py index fb0d452c69ca0..d7c29a812c2b7 100644 --- a/pandas/io/excel/_xlsxwriter.py +++ b/pandas/io/excel/_xlsxwriter.py @@ -261,7 +261,7 @@ def _write_cells( for cell in cells: val, fmt = self._value_with_fmt(cell.val) - stylekey = json.dumps(cell.style) + stylekey = json.ujson_dumps(cell.style) if fmt: stylekey += fmt diff --git a/pandas/io/json/__init__.py b/pandas/io/json/__init__.py index 52c65dd6f0c4e..ff19cf6e9d4cc 100644 --- a/pandas/io/json/__init__.py +++ b/pandas/io/json/__init__.py @@ -1,8 +1,8 @@ from pandas.io.json._json import ( - dumps, - loads, read_json, to_json, + ujson_dumps as dumps, + ujson_loads as loads, ) from pandas.io.json._table_schema import build_table_schema diff --git a/pandas/io/json/_json.py b/pandas/io/json/_json.py index ec0469a393873..fb45622dac3af 100644 --- a/pandas/io/json/_json.py +++ b/pandas/io/json/_json.py @@ -22,8 +22,8 @@ from pandas._libs import lib from pandas._libs.json import ( - dumps, - loads, + ujson_dumps, + ujson_loads, ) from pandas._libs.tslibs import iNaT from pandas.compat._optional import import_optional_dependency @@ -255,7 +255,7 @@ def _format_axes(self): def write(self) -> str: iso_dates = self.date_format == "iso" - return dumps( + return ujson_dumps( self.obj_to_write, orient=self.orient, double_precision=self.double_precision, @@ -1327,7 +1327,7 @@ class SeriesParser(Parser): _split_keys = ("name", "index", "data") def _parse(self) -> None: - data = loads(self.json, precise_float=self.precise_float) + data = ujson_loads(self.json, precise_float=self.precise_float) if self.orient == "split": decoded = {str(k): v for k, v in data.items()} @@ -1356,12 +1356,12 @@ def _parse(self) -> None: if orient == "columns": self.obj = DataFrame( - loads(json, precise_float=self.precise_float), dtype=None + ujson_loads(json, precise_float=self.precise_float), dtype=None ) elif orient == "split": decoded = { str(k): v - for k, v in loads(json, precise_float=self.precise_float).items() + for k, v in ujson_loads(json, precise_float=self.precise_float).items() } self.check_keys_split(decoded) orig_names = [ @@ -1375,7 +1375,7 @@ def _parse(self) -> None: self.obj = DataFrame(dtype=None, **decoded) elif orient == "index": self.obj = DataFrame.from_dict( - loads(json, precise_float=self.precise_float), + ujson_loads(json, precise_float=self.precise_float), dtype=None, orient="index", ) @@ -1383,7 +1383,7 @@ def _parse(self) -> None: self.obj = parse_table_schema(json, precise_float=self.precise_float) else: self.obj = DataFrame( - loads(json, precise_float=self.precise_float), dtype=None + ujson_loads(json, precise_float=self.precise_float), dtype=None ) def _process_converter(self, f, filt=None) -> None: diff --git a/pandas/io/json/_table_schema.py b/pandas/io/json/_table_schema.py index 97680923554d5..3f2291ba7a0c3 100644 --- a/pandas/io/json/_table_schema.py +++ b/pandas/io/json/_table_schema.py @@ -13,7 +13,7 @@ import warnings from pandas._libs import lib -from pandas._libs.json import loads +from pandas._libs.json import ujson_loads from pandas._libs.tslibs import timezones from pandas.util._exceptions import find_stack_level @@ -352,7 +352,7 @@ def parse_table_schema(json, precise_float: bool) -> DataFrame: build_table_schema : Inverse function. pandas.read_json """ - table = loads(json, precise_float=precise_float) + table = ujson_loads(json, precise_float=precise_float) col_order = [field["name"] for field in table["schema"]["fields"]] df = DataFrame(table["data"], columns=col_order)[col_order] diff --git a/pandas/tests/io/json/test_ujson.py b/pandas/tests/io/json/test_ujson.py index 0df6b1eef72c0..7a43fc6118550 100644 --- a/pandas/tests/io/json/test_ujson.py +++ b/pandas/tests/io/json/test_ujson.py @@ -56,57 +56,57 @@ class TestUltraJSONTests: @pytest.mark.skipif(not IS64, reason="not compliant on 32-bit, xref #15865") def test_encode_decimal(self): sut = decimal.Decimal("1337.1337") - encoded = ujson.encode(sut, double_precision=15) - decoded = ujson.decode(encoded) + encoded = ujson.ujson_dumps(sut, double_precision=15) + decoded = ujson.ujson_loads(encoded) assert decoded == 1337.1337 sut = decimal.Decimal("0.95") - encoded = ujson.encode(sut, double_precision=1) + encoded = ujson.ujson_dumps(sut, double_precision=1) assert encoded == "1.0" - decoded = ujson.decode(encoded) + decoded = ujson.ujson_loads(encoded) assert decoded == 1.0 sut = decimal.Decimal("0.94") - encoded = ujson.encode(sut, double_precision=1) + encoded = ujson.ujson_dumps(sut, double_precision=1) assert encoded == "0.9" - decoded = ujson.decode(encoded) + decoded = ujson.ujson_loads(encoded) assert decoded == 0.9 sut = decimal.Decimal("1.95") - encoded = ujson.encode(sut, double_precision=1) + encoded = ujson.ujson_dumps(sut, double_precision=1) assert encoded == "2.0" - decoded = ujson.decode(encoded) + decoded = ujson.ujson_loads(encoded) assert decoded == 2.0 sut = decimal.Decimal("-1.95") - encoded = ujson.encode(sut, double_precision=1) + encoded = ujson.ujson_dumps(sut, double_precision=1) assert encoded == "-2.0" - decoded = ujson.decode(encoded) + decoded = ujson.ujson_loads(encoded) assert decoded == -2.0 sut = decimal.Decimal("0.995") - encoded = ujson.encode(sut, double_precision=2) + encoded = ujson.ujson_dumps(sut, double_precision=2) assert encoded == "1.0" - decoded = ujson.decode(encoded) + decoded = ujson.ujson_loads(encoded) assert decoded == 1.0 sut = decimal.Decimal("0.9995") - encoded = ujson.encode(sut, double_precision=3) + encoded = ujson.ujson_dumps(sut, double_precision=3) assert encoded == "1.0" - decoded = ujson.decode(encoded) + decoded = ujson.ujson_loads(encoded) assert decoded == 1.0 sut = decimal.Decimal("0.99999999999999944") - encoded = ujson.encode(sut, double_precision=15) + encoded = ujson.ujson_dumps(sut, double_precision=15) assert encoded == "1.0" - decoded = ujson.decode(encoded) + decoded = ujson.ujson_loads(encoded) assert decoded == 1.0 @pytest.mark.parametrize("ensure_ascii", [True, False]) @@ -118,13 +118,13 @@ def test_encode_string_conversion(self, ensure_ascii): ) def helper(expected_output, **encode_kwargs): - output = ujson.encode( + output = ujson.ujson_dumps( string_input, ensure_ascii=ensure_ascii, **encode_kwargs ) assert output == expected_output assert string_input == json.loads(output) - assert string_input == ujson.decode(output) + assert string_input == ujson.ujson_loads(output) # Default behavior assumes encode_html_chars=False. helper(not_html_encoded) @@ -140,9 +140,9 @@ def helper(expected_output, **encode_kwargs): ) def test_double_long_numbers(self, long_number): sut = {"a": long_number} - encoded = ujson.encode(sut, double_precision=15) + encoded = ujson.ujson_dumps(sut, double_precision=15) - decoded = ujson.decode(encoded) + decoded = ujson.ujson_loads(encoded) assert sut == decoded def test_encode_non_c_locale(self): @@ -152,72 +152,72 @@ def test_encode_non_c_locale(self): for new_locale in ("it_IT.UTF-8", "Italian_Italy"): if tm.can_set_locale(new_locale, lc_category): with tm.set_locale(new_locale, lc_category): - assert ujson.loads(ujson.dumps(4.78e60)) == 4.78e60 - assert ujson.loads("4.78", precise_float=True) == 4.78 + assert ujson.ujson_loads(ujson.ujson_dumps(4.78e60)) == 4.78e60 + assert ujson.ujson_loads("4.78", precise_float=True) == 4.78 break def test_decimal_decode_test_precise(self): sut = {"a": 4.56} - encoded = ujson.encode(sut) - decoded = ujson.decode(encoded, precise_float=True) + encoded = ujson.ujson_dumps(sut) + decoded = ujson.ujson_loads(encoded, precise_float=True) assert sut == decoded def test_encode_double_tiny_exponential(self): num = 1e-40 - assert num == ujson.decode(ujson.encode(num)) + assert num == ujson.ujson_loads(ujson.ujson_dumps(num)) num = 1e-100 - assert num == ujson.decode(ujson.encode(num)) + assert num == ujson.ujson_loads(ujson.ujson_dumps(num)) num = -1e-45 - assert num == ujson.decode(ujson.encode(num)) + assert num == ujson.ujson_loads(ujson.ujson_dumps(num)) num = -1e-145 - assert np.allclose(num, ujson.decode(ujson.encode(num))) + assert np.allclose(num, ujson.ujson_loads(ujson.ujson_dumps(num))) @pytest.mark.parametrize("unicode_key", ["key1", "بن"]) def test_encode_dict_with_unicode_keys(self, unicode_key): unicode_dict = {unicode_key: "value1"} - assert unicode_dict == ujson.decode(ujson.encode(unicode_dict)) + assert unicode_dict == ujson.ujson_loads(ujson.ujson_dumps(unicode_dict)) @pytest.mark.parametrize( "double_input", [math.pi, -math.pi] # Should work with negatives too. ) def test_encode_double_conversion(self, double_input): - output = ujson.encode(double_input) + output = ujson.ujson_dumps(double_input) assert round(double_input, 5) == round(json.loads(output), 5) - assert round(double_input, 5) == round(ujson.decode(output), 5) + assert round(double_input, 5) == round(ujson.ujson_loads(output), 5) def test_encode_with_decimal(self): decimal_input = 1.0 - output = ujson.encode(decimal_input) + output = ujson.ujson_dumps(decimal_input) assert output == "1.0" def test_encode_array_of_nested_arrays(self): nested_input = [[[[]]]] * 20 - output = ujson.encode(nested_input) + output = ujson.ujson_dumps(nested_input) assert nested_input == json.loads(output) - assert nested_input == ujson.decode(output) + assert nested_input == ujson.ujson_loads(output) def test_encode_array_of_doubles(self): doubles_input = [31337.31337, 31337.31337, 31337.31337, 31337.31337] * 10 - output = ujson.encode(doubles_input) + output = ujson.ujson_dumps(doubles_input) assert doubles_input == json.loads(output) - assert doubles_input == ujson.decode(output) + assert doubles_input == ujson.ujson_loads(output) def test_double_precision(self): double_input = 30.012345678901234 - output = ujson.encode(double_input, double_precision=15) + output = ujson.ujson_dumps(double_input, double_precision=15) assert double_input == json.loads(output) - assert double_input == ujson.decode(output) + assert double_input == ujson.ujson_loads(output) for double_precision in (3, 9): - output = ujson.encode(double_input, double_precision=double_precision) + output = ujson.ujson_dumps(double_input, double_precision=double_precision) rounded_input = round(double_input, double_precision) assert rounded_input == json.loads(output) - assert rounded_input == ujson.decode(output) + assert rounded_input == ujson.ujson_loads(output) @pytest.mark.parametrize( "invalid_val", @@ -237,14 +237,14 @@ def test_invalid_double_precision(self, invalid_val): r"object cannot be interpreted as an integer" ) with pytest.raises(expected_exception, match=msg): - ujson.encode(double_input, double_precision=invalid_val) + ujson.ujson_dumps(double_input, double_precision=invalid_val) def test_encode_string_conversion2(self): string_input = "A string \\ / \b \f \n \r \t" - output = ujson.encode(string_input) + output = ujson.ujson_dumps(string_input) assert string_input == json.loads(output) - assert string_input == ujson.decode(output) + assert string_input == ujson.ujson_loads(output) assert output == '"A string \\\\ \\/ \\b \\f \\n \\r \\t"' @pytest.mark.parametrize( @@ -252,41 +252,41 @@ def test_encode_string_conversion2(self): ["Räksmörgås اسامة بن محمد بن عوض بن لادن", "\xe6\x97\xa5\xd1\x88"], ) def test_encode_unicode_conversion(self, unicode_input): - enc = ujson.encode(unicode_input) - dec = ujson.decode(enc) + enc = ujson.ujson_dumps(unicode_input) + dec = ujson.ujson_loads(enc) assert enc == json.dumps(unicode_input) assert dec == json.loads(enc) def test_encode_control_escaping(self): escaped_input = "\x19" - enc = ujson.encode(escaped_input) - dec = ujson.decode(enc) + enc = ujson.ujson_dumps(escaped_input) + dec = ujson.ujson_loads(enc) assert escaped_input == dec assert enc == json.dumps(escaped_input) def test_encode_unicode_surrogate_pair(self): surrogate_input = "\xf0\x90\x8d\x86" - enc = ujson.encode(surrogate_input) - dec = ujson.decode(enc) + enc = ujson.ujson_dumps(surrogate_input) + dec = ujson.ujson_loads(enc) assert enc == json.dumps(surrogate_input) assert dec == json.loads(enc) def test_encode_unicode_4bytes_utf8(self): four_bytes_input = "\xf0\x91\x80\xb0TRAILINGNORMAL" - enc = ujson.encode(four_bytes_input) - dec = ujson.decode(enc) + enc = ujson.ujson_dumps(four_bytes_input) + dec = ujson.ujson_loads(enc) assert enc == json.dumps(four_bytes_input) assert dec == json.loads(enc) def test_encode_unicode_4bytes_utf8highest(self): four_bytes_input = "\xf3\xbf\xbf\xbfTRAILINGNORMAL" - enc = ujson.encode(four_bytes_input) + enc = ujson.ujson_dumps(four_bytes_input) - dec = ujson.decode(enc) + dec = ujson.ujson_loads(enc) assert enc == json.dumps(four_bytes_input) assert dec == json.loads(enc) @@ -298,15 +298,15 @@ def test_encode_unicode_error(self): r"in position 1: surrogates not allowed" ) with pytest.raises(UnicodeEncodeError, match=msg): - ujson.dumps([string]) + ujson.ujson_dumps([string]) def test_encode_array_in_array(self): arr_in_arr_input = [[[[]]]] - output = ujson.encode(arr_in_arr_input) + output = ujson.ujson_dumps(arr_in_arr_input) assert arr_in_arr_input == json.loads(output) assert output == json.dumps(arr_in_arr_input) - assert arr_in_arr_input == ujson.decode(output) + assert arr_in_arr_input == ujson.ujson_loads(output) @pytest.mark.parametrize( "num_input", @@ -317,70 +317,70 @@ def test_encode_array_in_array(self): ], ) def test_encode_num_conversion(self, num_input): - output = ujson.encode(num_input) + output = ujson.ujson_dumps(num_input) assert num_input == json.loads(output) assert output == json.dumps(num_input) - assert num_input == ujson.decode(output) + assert num_input == ujson.ujson_loads(output) def test_encode_list_conversion(self): list_input = [1, 2, 3, 4] - output = ujson.encode(list_input) + output = ujson.ujson_dumps(list_input) assert list_input == json.loads(output) - assert list_input == ujson.decode(output) + assert list_input == ujson.ujson_loads(output) def test_encode_dict_conversion(self): dict_input = {"k1": 1, "k2": 2, "k3": 3, "k4": 4} - output = ujson.encode(dict_input) + output = ujson.ujson_dumps(dict_input) assert dict_input == json.loads(output) - assert dict_input == ujson.decode(output) + assert dict_input == ujson.ujson_loads(output) @pytest.mark.parametrize("builtin_value", [None, True, False]) def test_encode_builtin_values_conversion(self, builtin_value): - output = ujson.encode(builtin_value) + output = ujson.ujson_dumps(builtin_value) assert builtin_value == json.loads(output) assert output == json.dumps(builtin_value) - assert builtin_value == ujson.decode(output) + assert builtin_value == ujson.ujson_loads(output) def test_encode_datetime_conversion(self): datetime_input = datetime.datetime.fromtimestamp(time.time()) - output = ujson.encode(datetime_input, date_unit="s") + output = ujson.ujson_dumps(datetime_input, date_unit="s") expected = calendar.timegm(datetime_input.utctimetuple()) assert int(expected) == json.loads(output) - assert int(expected) == ujson.decode(output) + assert int(expected) == ujson.ujson_loads(output) def test_encode_date_conversion(self): date_input = datetime.date.fromtimestamp(time.time()) - output = ujson.encode(date_input, date_unit="s") + output = ujson.ujson_dumps(date_input, date_unit="s") tup = (date_input.year, date_input.month, date_input.day, 0, 0, 0) expected = calendar.timegm(tup) assert int(expected) == json.loads(output) - assert int(expected) == ujson.decode(output) + assert int(expected) == ujson.ujson_loads(output) @pytest.mark.parametrize( "test", [datetime.time(), datetime.time(1, 2, 3), datetime.time(10, 12, 15, 343243)], ) def test_encode_time_conversion_basic(self, test): - output = ujson.encode(test) + output = ujson.ujson_dumps(test) expected = f'"{test.isoformat()}"' assert expected == output def test_encode_time_conversion_pytz(self): # see gh-11473: to_json segfaults with timezone-aware datetimes test = datetime.time(10, 12, 15, 343243, pytz.utc) - output = ujson.encode(test) + output = ujson.ujson_dumps(test) expected = f'"{test.isoformat()}"' assert expected == output def test_encode_time_conversion_dateutil(self): # see gh-11473: to_json segfaults with timezone-aware datetimes test = datetime.time(10, 12, 15, 343243, dateutil.tz.tzutc()) - output = ujson.encode(test) + output = ujson.ujson_dumps(test) expected = f'"{test.isoformat()}"' assert expected == output @@ -388,33 +388,33 @@ def test_encode_time_conversion_dateutil(self): "decoded_input", [NaT, np.datetime64("NaT"), np.nan, np.inf, -np.inf] ) def test_encode_as_null(self, decoded_input): - assert ujson.encode(decoded_input) == "null", "Expected null" + assert ujson.ujson_dumps(decoded_input) == "null", "Expected null" def test_datetime_units(self): val = datetime.datetime(2013, 8, 17, 21, 17, 12, 215504) stamp = Timestamp(val).as_unit("ns") - roundtrip = ujson.decode(ujson.encode(val, date_unit="s")) + roundtrip = ujson.ujson_loads(ujson.ujson_dumps(val, date_unit="s")) assert roundtrip == stamp._value // 10**9 - roundtrip = ujson.decode(ujson.encode(val, date_unit="ms")) + roundtrip = ujson.ujson_loads(ujson.ujson_dumps(val, date_unit="ms")) assert roundtrip == stamp._value // 10**6 - roundtrip = ujson.decode(ujson.encode(val, date_unit="us")) + roundtrip = ujson.ujson_loads(ujson.ujson_dumps(val, date_unit="us")) assert roundtrip == stamp._value // 10**3 - roundtrip = ujson.decode(ujson.encode(val, date_unit="ns")) + roundtrip = ujson.ujson_loads(ujson.ujson_dumps(val, date_unit="ns")) assert roundtrip == stamp._value msg = "Invalid value 'foo' for option 'date_unit'" with pytest.raises(ValueError, match=msg): - ujson.encode(val, date_unit="foo") + ujson.ujson_dumps(val, date_unit="foo") def test_encode_to_utf8(self): unencoded = "\xe6\x97\xa5\xd1\x88" - enc = ujson.encode(unencoded, ensure_ascii=False) - dec = ujson.decode(enc) + enc = ujson.ujson_dumps(unencoded, ensure_ascii=False) + dec = ujson.ujson_loads(enc) assert enc == json.dumps(unencoded, ensure_ascii=False) assert dec == json.loads(enc) @@ -422,8 +422,8 @@ def test_encode_to_utf8(self): def test_decode_from_unicode(self): unicode_input = '{"obj": 31337}' - dec1 = ujson.decode(unicode_input) - dec2 = ujson.decode(str(unicode_input)) + dec1 = ujson.ujson_loads(unicode_input) + dec2 = ujson.ujson_loads(str(unicode_input)) assert dec1 == dec2 @@ -441,13 +441,13 @@ class O1: decoded_input.member.member = decoded_input with pytest.raises(OverflowError, match="Maximum recursion level reached"): - ujson.encode(decoded_input) + ujson.ujson_dumps(decoded_input) def test_decode_jibberish(self): jibberish = "fdsa sda v9sa fdsa" msg = "Unexpected character found when decoding 'false'" with pytest.raises(ValueError, match=msg): - ujson.decode(jibberish) + ujson.ujson_loads(jibberish) @pytest.mark.parametrize( "broken_json", @@ -461,12 +461,12 @@ def test_decode_jibberish(self): def test_decode_broken_json(self, broken_json): msg = "Expected object or value" with pytest.raises(ValueError, match=msg): - ujson.decode(broken_json) + ujson.ujson_loads(broken_json) @pytest.mark.parametrize("too_big_char", ["[", "{"]) def test_decode_depth_too_big(self, too_big_char): with pytest.raises(ValueError, match="Reached object decoding depth limit"): - ujson.decode(too_big_char * (1024 * 1024)) + ujson.ujson_loads(too_big_char * (1024 * 1024)) @pytest.mark.parametrize( "bad_string", @@ -484,7 +484,7 @@ def test_decode_bad_string(self, bad_string): "Unmatched ''\"' when when decoding 'string'" ) with pytest.raises(ValueError, match=msg): - ujson.decode(bad_string) + ujson.ujson_loads(bad_string) @pytest.mark.parametrize( "broken_json, err_msg", @@ -500,7 +500,7 @@ def test_decode_bad_string(self, bad_string): def test_decode_broken_json_leak(self, broken_json, err_msg): for _ in range(1000): with pytest.raises(ValueError, match=re.escape(err_msg)): - ujson.decode(broken_json) + ujson.ujson_loads(broken_json) @pytest.mark.parametrize( "invalid_dict", @@ -517,33 +517,33 @@ def test_decode_invalid_dict(self, invalid_dict): "Expected object or value" ) with pytest.raises(ValueError, match=msg): - ujson.decode(invalid_dict) + ujson.ujson_loads(invalid_dict) @pytest.mark.parametrize( "numeric_int_as_str", ["31337", "-31337"] # Should work with negatives. ) def test_decode_numeric_int(self, numeric_int_as_str): - assert int(numeric_int_as_str) == ujson.decode(numeric_int_as_str) + assert int(numeric_int_as_str) == ujson.ujson_loads(numeric_int_as_str) def test_encode_null_character(self): wrapped_input = "31337 \x00 1337" - output = ujson.encode(wrapped_input) + output = ujson.ujson_dumps(wrapped_input) assert wrapped_input == json.loads(output) assert output == json.dumps(wrapped_input) - assert wrapped_input == ujson.decode(output) + assert wrapped_input == ujson.ujson_loads(output) alone_input = "\x00" - output = ujson.encode(alone_input) + output = ujson.ujson_dumps(alone_input) assert alone_input == json.loads(output) assert output == json.dumps(alone_input) - assert alone_input == ujson.decode(output) - assert '" \\u0000\\r\\n "' == ujson.dumps(" \u0000\r\n ") + assert alone_input == ujson.ujson_loads(output) + assert '" \\u0000\\r\\n "' == ujson.ujson_dumps(" \u0000\r\n ") def test_decode_null_character(self): wrapped_input = '"31337 \\u0000 31337"' - assert ujson.decode(wrapped_input) == json.loads(wrapped_input) + assert ujson.ujson_loads(wrapped_input) == json.loads(wrapped_input) def test_encode_list_long_conversion(self): long_input = [ @@ -554,54 +554,54 @@ def test_encode_list_long_conversion(self): 9223372036854775807, 9223372036854775807, ] - output = ujson.encode(long_input) + output = ujson.ujson_dumps(long_input) assert long_input == json.loads(output) - assert long_input == ujson.decode(output) + assert long_input == ujson.ujson_loads(output) @pytest.mark.parametrize("long_input", [9223372036854775807, 18446744073709551615]) def test_encode_long_conversion(self, long_input): - output = ujson.encode(long_input) + output = ujson.ujson_dumps(long_input) assert long_input == json.loads(output) assert output == json.dumps(long_input) - assert long_input == ujson.decode(output) + assert long_input == ujson.ujson_loads(output) @pytest.mark.parametrize("bigNum", [2**64, -(2**63) - 1]) def test_dumps_ints_larger_than_maxsize(self, bigNum): - encoding = ujson.encode(bigNum) + encoding = ujson.ujson_dumps(bigNum) assert str(bigNum) == encoding with pytest.raises( ValueError, match="Value is too big|Value is too small", ): - assert ujson.loads(encoding) == bigNum + assert ujson.ujson_loads(encoding) == bigNum @pytest.mark.parametrize( "int_exp", ["1337E40", "1.337E40", "1337E+9", "1.337e+40", "1.337E-4"] ) def test_decode_numeric_int_exp(self, int_exp): - assert ujson.decode(int_exp) == json.loads(int_exp) + assert ujson.ujson_loads(int_exp) == json.loads(int_exp) def test_loads_non_str_bytes_raises(self): msg = "Expected 'str' or 'bytes'" with pytest.raises(TypeError, match=msg): - ujson.loads(None) + ujson.ujson_loads(None) @pytest.mark.parametrize("val", [3590016419, 2**31, 2**32, (2**32) - 1]) def test_decode_number_with_32bit_sign_bit(self, val): # Test that numbers that fit within 32 bits but would have the # sign bit set (2**31 <= x < 2**32) are decoded properly. doc = f'{{"id": {val}}}' - assert ujson.decode(doc)["id"] == val + assert ujson.ujson_loads(doc)["id"] == val def test_encode_big_escape(self): # Make sure no Exception is raised. for _ in range(10): base = "\u00e5".encode() escape_input = base * 1024 * 1024 * 2 - ujson.encode(escape_input) + ujson.ujson_dumps(escape_input) def test_decode_big_escape(self): # Make sure no Exception is raised. @@ -610,7 +610,7 @@ def test_decode_big_escape(self): quote = b'"' escape_input = quote + (base * 1024 * 1024 * 2) + quote - ujson.decode(escape_input) + ujson.ujson_loads(escape_input) def test_to_dict(self): d = {"key": 31337} @@ -620,9 +620,9 @@ def toDict(self): return d o = DictTest() - output = ujson.encode(o) + output = ujson.ujson_dumps(o) - dec = ujson.decode(output) + dec = ujson.ujson_loads(output) assert dec == d def test_default_handler(self): @@ -639,13 +639,13 @@ def __str__(self) -> str: msg = "Maximum recursion level reached" with pytest.raises(OverflowError, match=msg): - ujson.encode(_TestObject("foo")) - assert '"foo"' == ujson.encode(_TestObject("foo"), default_handler=str) + ujson.ujson_dumps(_TestObject("foo")) + assert '"foo"' == ujson.ujson_dumps(_TestObject("foo"), default_handler=str) def my_handler(_): return "foobar" - assert '"foobar"' == ujson.encode( + assert '"foobar"' == ujson.ujson_dumps( _TestObject("foo"), default_handler=my_handler ) @@ -653,14 +653,14 @@ def my_handler_raises(_): raise TypeError("I raise for anything") with pytest.raises(TypeError, match="I raise for anything"): - ujson.encode(_TestObject("foo"), default_handler=my_handler_raises) + ujson.ujson_dumps(_TestObject("foo"), default_handler=my_handler_raises) def my_int_handler(_): return 42 assert ( - ujson.decode( - ujson.encode(_TestObject("foo"), default_handler=my_int_handler) + ujson.ujson_loads( + ujson.ujson_dumps(_TestObject("foo"), default_handler=my_int_handler) ) == 42 ) @@ -668,15 +668,15 @@ def my_int_handler(_): def my_obj_handler(_): return datetime.datetime(2013, 2, 3) - assert ujson.decode( - ujson.encode(datetime.datetime(2013, 2, 3)) - ) == ujson.decode( - ujson.encode(_TestObject("foo"), default_handler=my_obj_handler) + assert ujson.ujson_loads( + ujson.ujson_dumps(datetime.datetime(2013, 2, 3)) + ) == ujson.ujson_loads( + ujson.ujson_dumps(_TestObject("foo"), default_handler=my_obj_handler) ) obj_list = [_TestObject("foo"), _TestObject("bar")] - assert json.loads(json.dumps(obj_list, default=str)) == ujson.decode( - ujson.encode(obj_list, default_handler=str) + assert json.loads(json.dumps(obj_list, default=str)) == ujson.ujson_loads( + ujson.ujson_dumps(obj_list, default_handler=str) ) def test_encode_object(self): @@ -692,7 +692,11 @@ def e(self): # JSON keys should be all non-callable non-underscore attributes, see GH-42768 test_object = _TestObject(a=1, b=2, _c=3, d=4) - assert ujson.decode(ujson.encode(test_object)) == {"a": 1, "b": 2, "d": 4} + assert ujson.ujson_loads(ujson.ujson_dumps(test_object)) == { + "a": 1, + "b": 2, + "d": 4, + } def test_ujson__name__(self): # GH 52898 @@ -703,27 +707,27 @@ class TestNumpyJSONTests: @pytest.mark.parametrize("bool_input", [True, False]) def test_bool(self, bool_input): b = bool(bool_input) - assert ujson.decode(ujson.encode(b)) == b + assert ujson.ujson_loads(ujson.ujson_dumps(b)) == b def test_bool_array(self): bool_array = np.array( [True, False, True, True, False, True, False, False], dtype=bool ) - output = np.array(ujson.decode(ujson.encode(bool_array)), dtype=bool) + output = np.array(ujson.ujson_loads(ujson.ujson_dumps(bool_array)), dtype=bool) tm.assert_numpy_array_equal(bool_array, output) def test_int(self, any_int_numpy_dtype): klass = np.dtype(any_int_numpy_dtype).type num = klass(1) - assert klass(ujson.decode(ujson.encode(num))) == num + assert klass(ujson.ujson_loads(ujson.ujson_dumps(num))) == num def test_int_array(self, any_int_numpy_dtype): arr = np.arange(100, dtype=int) arr_input = arr.astype(any_int_numpy_dtype) arr_output = np.array( - ujson.decode(ujson.encode(arr_input)), dtype=any_int_numpy_dtype + ujson.ujson_loads(ujson.ujson_dumps(arr_input)), dtype=any_int_numpy_dtype ) tm.assert_numpy_array_equal(arr_input, arr_output) @@ -740,20 +744,20 @@ def test_int_max(self, any_int_numpy_dtype): else: num = np.iinfo(any_int_numpy_dtype).max - assert klass(ujson.decode(ujson.encode(num))) == num + assert klass(ujson.ujson_loads(ujson.ujson_dumps(num))) == num def test_float(self, float_numpy_dtype): klass = np.dtype(float_numpy_dtype).type num = klass(256.2013) - assert klass(ujson.decode(ujson.encode(num))) == num + assert klass(ujson.ujson_loads(ujson.ujson_dumps(num))) == num def test_float_array(self, float_numpy_dtype): arr = np.arange(12.5, 185.72, 1.7322, dtype=float) float_input = arr.astype(float_numpy_dtype) float_output = np.array( - ujson.decode(ujson.encode(float_input, double_precision=15)), + ujson.ujson_loads(ujson.ujson_dumps(float_input, double_precision=15)), dtype=float_numpy_dtype, ) tm.assert_almost_equal(float_input, float_output) @@ -763,21 +767,25 @@ def test_float_max(self, float_numpy_dtype): num = klass(np.finfo(float_numpy_dtype).max / 10) tm.assert_almost_equal( - klass(ujson.decode(ujson.encode(num, double_precision=15))), num + klass(ujson.ujson_loads(ujson.ujson_dumps(num, double_precision=15))), num ) def test_array_basic(self): arr = np.arange(96) arr = arr.reshape((2, 2, 2, 2, 3, 2)) - tm.assert_numpy_array_equal(np.array(ujson.decode(ujson.encode(arr))), arr) + tm.assert_numpy_array_equal( + np.array(ujson.ujson_loads(ujson.ujson_dumps(arr))), arr + ) @pytest.mark.parametrize("shape", [(10, 10), (5, 5, 4), (100, 1)]) def test_array_reshaped(self, shape): arr = np.arange(100) arr = arr.reshape(shape) - tm.assert_numpy_array_equal(np.array(ujson.decode(ujson.encode(arr))), arr) + tm.assert_numpy_array_equal( + np.array(ujson.ujson_loads(ujson.ujson_dumps(arr))), arr + ) def test_array_list(self): arr_list = [ @@ -792,7 +800,7 @@ def test_array_list(self): {"key": "val"}, ] arr = np.array(arr_list, dtype=object) - result = np.array(ujson.decode(ujson.encode(arr)), dtype=object) + result = np.array(ujson.ujson_loads(ujson.ujson_dumps(arr)), dtype=object) tm.assert_numpy_array_equal(result, arr) def test_array_float(self): @@ -801,14 +809,14 @@ def test_array_float(self): arr = np.arange(100.202, 200.202, 1, dtype=dtype) arr = arr.reshape((5, 5, 4)) - arr_out = np.array(ujson.decode(ujson.encode(arr)), dtype=dtype) + arr_out = np.array(ujson.ujson_loads(ujson.ujson_dumps(arr)), dtype=dtype) tm.assert_almost_equal(arr, arr_out) def test_0d_array(self): # gh-18878 msg = re.escape("array(1) (0d array) is not JSON serializable at the moment") with pytest.raises(TypeError, match=msg): - ujson.encode(np.array(1)) + ujson.ujson_dumps(np.array(1)) class TestPandasJSONTests: @@ -824,7 +832,7 @@ def test_dataframe(self, orient): encode_kwargs = {} if orient is None else {"orient": orient} assert (df.dtypes == dtype).all() - output = ujson.decode(ujson.encode(df, **encode_kwargs)) + output = ujson.ujson_loads(ujson.ujson_dumps(df, **encode_kwargs)) assert (df.dtypes == dtype).all() # Ensure proper DataFrame initialization. @@ -855,10 +863,10 @@ def test_dataframe_nested(self, orient): kwargs = {} if orient is None else {"orient": orient} exp = { - "df1": ujson.decode(ujson.encode(df, **kwargs)), - "df2": ujson.decode(ujson.encode(df, **kwargs)), + "df1": ujson.ujson_loads(ujson.ujson_dumps(df, **kwargs)), + "df2": ujson.ujson_loads(ujson.ujson_dumps(df, **kwargs)), } - assert ujson.decode(ujson.encode(nested, **kwargs)) == exp + assert ujson.ujson_loads(ujson.ujson_dumps(nested, **kwargs)) == exp def test_series(self, orient): dtype = np.int64 @@ -872,7 +880,7 @@ def test_series(self, orient): encode_kwargs = {} if orient is None else {"orient": orient} - output = ujson.decode(ujson.encode(s, **encode_kwargs)) + output = ujson.ujson_loads(ujson.ujson_dumps(s, **encode_kwargs)) assert s.dtype == dtype if orient == "split": @@ -900,19 +908,19 @@ def test_series_nested(self, orient): kwargs = {} if orient is None else {"orient": orient} exp = { - "s1": ujson.decode(ujson.encode(s, **kwargs)), - "s2": ujson.decode(ujson.encode(s, **kwargs)), + "s1": ujson.ujson_loads(ujson.ujson_dumps(s, **kwargs)), + "s2": ujson.ujson_loads(ujson.ujson_dumps(s, **kwargs)), } - assert ujson.decode(ujson.encode(nested, **kwargs)) == exp + assert ujson.ujson_loads(ujson.ujson_dumps(nested, **kwargs)) == exp def test_index(self): i = Index([23, 45, 18, 98, 43, 11], name="index") # Column indexed. - output = Index(ujson.decode(ujson.encode(i)), name="index") + output = Index(ujson.ujson_loads(ujson.ujson_dumps(i)), name="index") tm.assert_index_equal(i, output) - dec = _clean_dict(ujson.decode(ujson.encode(i, orient="split"))) + dec = _clean_dict(ujson.ujson_loads(ujson.ujson_dumps(i, orient="split"))) output = Index(**dec) tm.assert_index_equal(i, output) @@ -921,13 +929,19 @@ def test_index(self): tm.assert_index_equal(i, output) assert i.name == output.name - output = Index(ujson.decode(ujson.encode(i, orient="values")), name="index") + output = Index( + ujson.ujson_loads(ujson.ujson_dumps(i, orient="values")), name="index" + ) tm.assert_index_equal(i, output) - output = Index(ujson.decode(ujson.encode(i, orient="records")), name="index") + output = Index( + ujson.ujson_loads(ujson.ujson_dumps(i, orient="records")), name="index" + ) tm.assert_index_equal(i, output) - output = Index(ujson.decode(ujson.encode(i, orient="index")), name="index") + output = Index( + ujson.ujson_loads(ujson.ujson_dumps(i, orient="index")), name="index" + ) tm.assert_index_equal(i, output) def test_datetime_index(self): @@ -935,13 +949,13 @@ def test_datetime_index(self): # freq doesn't round-trip rng = DatetimeIndex(list(date_range("1/1/2000", periods=20)), freq=None) - encoded = ujson.encode(rng, date_unit=date_unit) + encoded = ujson.ujson_dumps(rng, date_unit=date_unit) - decoded = DatetimeIndex(np.array(ujson.decode(encoded))) + decoded = DatetimeIndex(np.array(ujson.ujson_loads(encoded))) tm.assert_index_equal(rng, decoded) ts = Series(np.random.randn(len(rng)), index=rng) - decoded = Series(ujson.decode(ujson.encode(ts, date_unit=date_unit))) + decoded = Series(ujson.ujson_loads(ujson.ujson_dumps(ts, date_unit=date_unit))) idx_values = decoded.index.values.astype(np.int64) decoded.index = DatetimeIndex(idx_values) @@ -962,15 +976,15 @@ def test_decode_invalid_array(self, invalid_arr): "Unexpected character found when decoding array value" ) with pytest.raises(ValueError, match=msg): - ujson.decode(invalid_arr) + ujson.ujson_loads(invalid_arr) @pytest.mark.parametrize("arr", [[], [31337]]) def test_decode_array(self, arr): - assert arr == ujson.decode(str(arr)) + assert arr == ujson.ujson_loads(str(arr)) @pytest.mark.parametrize("extreme_num", [9223372036854775807, -9223372036854775808]) def test_decode_extreme_numbers(self, extreme_num): - assert extreme_num == ujson.decode(str(extreme_num)) + assert extreme_num == ujson.ujson_loads(str(extreme_num)) @pytest.mark.parametrize("too_extreme_num", [f"{2**64}", f"{-2**63-1}"]) def test_decode_too_extreme_numbers(self, too_extreme_num): @@ -978,14 +992,14 @@ def test_decode_too_extreme_numbers(self, too_extreme_num): ValueError, match="Value is too big|Value is too small", ): - ujson.decode(too_extreme_num) + ujson.ujson_loads(too_extreme_num) def test_decode_with_trailing_whitespaces(self): - assert {} == ujson.decode("{}\n\t ") + assert {} == ujson.ujson_loads("{}\n\t ") def test_decode_with_trailing_non_whitespaces(self): with pytest.raises(ValueError, match="Trailing data"): - ujson.decode("{}\n\t a") + ujson.ujson_loads("{}\n\t a") @pytest.mark.parametrize("value", [f"{2**64}", f"{-2**63-1}"]) def test_decode_array_with_big_int(self, value): @@ -993,7 +1007,7 @@ def test_decode_array_with_big_int(self, value): ValueError, match="Value is too big|Value is too small", ): - ujson.loads(value) + ujson.ujson_loads(value) @pytest.mark.parametrize( "float_number", @@ -1012,7 +1026,9 @@ def test_decode_array_with_big_int(self, value): @pytest.mark.parametrize("sign", [-1, 1]) def test_decode_floating_point(self, sign, float_number): float_number *= sign - tm.assert_almost_equal(float_number, ujson.loads(str(float_number)), rtol=1e-15) + tm.assert_almost_equal( + float_number, ujson.ujson_loads(str(float_number)), rtol=1e-15 + ) def test_encode_big_set(self): s = set() @@ -1021,15 +1037,15 @@ def test_encode_big_set(self): s.add(x) # Make sure no Exception is raised. - ujson.encode(s) + ujson.ujson_dumps(s) def test_encode_empty_set(self): - assert "[]" == ujson.encode(set()) + assert "[]" == ujson.ujson_dumps(set()) def test_encode_set(self): s = {1, 2, 3, 4, 5, 6, 7, 8, 9} - enc = ujson.encode(s) - dec = ujson.decode(enc) + enc = ujson.ujson_dumps(s) + dec = ujson.ujson_loads(enc) for v in dec: assert v in s @@ -1050,7 +1066,7 @@ def test_encode_set(self): ) def test_encode_timedelta_iso(self, td): # GH 28256 - result = ujson.encode(td, iso_dates=True) + result = ujson.ujson_dumps(td, iso_dates=True) expected = f'"{td.isoformat()}"' assert result == expected