1
0
mirror of https://github.com/ultrajson/ultrajson.git synced 2024-11-23 04:12:13 +01:00

Raise JSONDecodeError in place of ValueError on failed decode (#498)

So as to match the behaviour of Python's json library.
Fixes #497
This commit is contained in:
JustAnotherArchivist 2022-02-05 20:39:05 +00:00 committed by GitHub
parent d5b701f209
commit 316d384f41
Signed by: GitHub
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 33 deletions

@ -38,6 +38,7 @@ http://www.opensource.apple.com/source/tcl/tcl-14/tcl/license.terms
#include <Python.h> #include <Python.h>
#include <ultrajson.h> #include <ultrajson.h>
#include "ujson.h"
//#define PRINTMARK() fprintf(stderr, "%s: MARK(%d)\n", __FILE__, __LINE__) //#define PRINTMARK() fprintf(stderr, "%s: MARK(%d)\n", __FILE__, __LINE__)
@ -187,7 +188,7 @@ PyObject* JSONToObj(PyObject* self, PyObject *args, PyObject *kwargs)
/* /*
FIXME: It's possible to give a much nicer error message here with actual failing element in input etc*/ FIXME: It's possible to give a much nicer error message here with actual failing element in input etc*/
PyErr_Format (PyExc_ValueError, "%s", decoder.errorStr); PyErr_Format (JSONDecodeError, "%s", decoder.errorStr);
if (ret) if (ret)
{ {

@ -38,6 +38,7 @@ http://www.opensource.apple.com/source/tcl/tcl-14/tcl/license.terms
#include <Python.h> #include <Python.h>
#include "version.h" #include "version.h"
#include "ujson.h"
/* objToJSON */ /* objToJSON */
PyObject* objToJSON(PyObject* self, PyObject *args, PyObject *kwargs); PyObject* objToJSON(PyObject* self, PyObject *args, PyObject *kwargs);
@ -51,6 +52,8 @@ PyObject* objToJSONFile(PyObject* self, PyObject *args, PyObject *kwargs);
/* JSONFileToObj */ /* JSONFileToObj */
PyObject* JSONFileToObj(PyObject* self, PyObject *args, PyObject *kwargs); PyObject* JSONFileToObj(PyObject* self, PyObject *args, PyObject *kwargs);
PyObject* JSONDecodeError;
#define ENCODER_HELP_TEXT "Use ensure_ascii=false to output UTF-8. " \ #define ENCODER_HELP_TEXT "Use ensure_ascii=false to output UTF-8. " \
"Set encode_html_chars=True to encode < > & as unicode escape sequences. "\ "Set encode_html_chars=True to encode < > & as unicode escape sequences. "\
@ -188,5 +191,15 @@ PyMODINIT_FUNC PyInit_ujson(void)
PyErr_Clear(); PyErr_Clear();
#endif #endif
JSONDecodeError = PyErr_NewException("ujson.JSONDecodeError", PyExc_ValueError, NULL);
Py_XINCREF(JSONDecodeError);
if (PyModule_AddObject(module, "JSONDecodeError", JSONDecodeError) < 0)
{
Py_XDECREF(JSONDecodeError);
Py_CLEAR(JSONDecodeError);
Py_DECREF(module);
return NULL;
}
return module; return module;
} }

1
python/ujson.h Normal file

@ -0,0 +1 @@
extern PyObject* JSONDecodeError;

@ -555,46 +555,46 @@ def test_decode_numeric_int_exp(test_input):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"test_input, expected", "test_input, expected",
[ [
('{{1337:""}}', ValueError), # broken dict key type leak test ('{{1337:""}}', ujson.JSONDecodeError), # broken dict key type leak test
('{{"key":"}', ValueError), # broken dict leak test ('{{"key":"}', ujson.JSONDecodeError), # broken dict leak test
('{{"key":"}', ValueError), # broken dict leak test ('{{"key":"}', ujson.JSONDecodeError), # broken dict leak test
("[[[true", ValueError), # broken list leak test ("[[[true", ujson.JSONDecodeError), # broken list leak test
], ],
) )
def test_decode_range_raises(test_input, expected): def test_decode_range_raises(test_input, expected):
for x in range(1000): for x in range(1000):
with pytest.raises(ValueError): with pytest.raises(expected):
ujson.decode(test_input) ujson.decode(test_input)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"test_input, expected", "test_input, expected",
[ [
("fdsa sda v9sa fdsa", ValueError), # jibberish ("fdsa sda v9sa fdsa", ujson.JSONDecodeError), # jibberish
("[", ValueError), # broken array start ("[", ujson.JSONDecodeError), # broken array start
("{", ValueError), # broken object start ("{", ujson.JSONDecodeError), # broken object start
("]", ValueError), # broken array end ("]", ujson.JSONDecodeError), # broken array end
("}", ValueError), # broken object end ("}", ujson.JSONDecodeError), # broken object end
('{"one":1,}', ValueError), # object trailing comma fail ('{"one":1,}', ujson.JSONDecodeError), # object trailing comma fail
('"TESTING', ValueError), # string unterminated ('"TESTING', ujson.JSONDecodeError), # string unterminated
('"TESTING\\"', ValueError), # string bad escape ('"TESTING\\"', ujson.JSONDecodeError), # string bad escape
("tru", ValueError), # true broken ("tru", ujson.JSONDecodeError), # true broken
("fa", ValueError), # false broken ("fa", ujson.JSONDecodeError), # false broken
("n", ValueError), # null broken ("n", ujson.JSONDecodeError), # null broken
("{{{{31337}}}}", ValueError), # dict with no key ("{{{{31337}}}}", ujson.JSONDecodeError), # dict with no key
('{{{{"key"}}}}', ValueError), # dict with no colon or value ('{{{{"key"}}}}', ujson.JSONDecodeError), # dict with no colon or value
('{{{{"key":}}}}', ValueError), # dict with no value ('{{{{"key":}}}}', ujson.JSONDecodeError), # dict with no value
("[31337,]", ValueError), # array trailing comma fail ("[31337,]", ujson.JSONDecodeError), # array trailing comma fail
("[,31337]", ValueError), # array leading comma fail ("[,31337]", ujson.JSONDecodeError), # array leading comma fail
("[,]", ValueError), # array only comma fail ("[,]", ujson.JSONDecodeError), # array only comma fail
("[]]", ValueError), # array unmatched bracket fail ("[]]", ujson.JSONDecodeError), # array unmatched bracket fail
("18446744073709551616", ValueError), # too big value ("18446744073709551616", ujson.JSONDecodeError), # too big value
("-90223372036854775809", ValueError), # too small value ("-90223372036854775809", ujson.JSONDecodeError), # too small value
("18446744073709551616", ValueError), # very too big value ("18446744073709551616", ujson.JSONDecodeError), # very too big value
("-90223372036854775809", ValueError), # very too small value ("-90223372036854775809", ujson.JSONDecodeError), # very too small value
("{}\n\t a", ValueError), # with trailing non whitespaces ("{}\n\t a", ujson.JSONDecodeError), # with trailing non whitespaces
("[18446744073709551616]", ValueError), # array with big int ("[18446744073709551616]", ujson.JSONDecodeError), # array with big int
('{"age", 44}', ValueError), # read bad object syntax ('{"age", 44}', ujson.JSONDecodeError), # read bad object syntax
], ],
) )
def test_decode_raises(test_input, expected): def test_decode_raises(test_input, expected):
@ -605,8 +605,8 @@ def test_decode_raises(test_input, expected):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"test_input, expected", "test_input, expected",
[ [
("[", ValueError), # array depth too big ("[", ujson.JSONDecodeError), # array depth too big
("{", ValueError), # object depth too big ("{", ujson.JSONDecodeError), # object depth too big
], ],
) )
def test_decode_raises_for_long_input(test_input, expected): def test_decode_raises_for_long_input(test_input, expected):
@ -614,6 +614,10 @@ def test_decode_raises_for_long_input(test_input, expected):
ujson.decode(test_input * (1024 * 1024)) ujson.decode(test_input * (1024 * 1024))
def test_decode_exception_is_value_error():
assert issubclass(ujson.JSONDecodeError, ValueError)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"test_input, expected", "test_input, expected",
[ [