diff --git a/python/JSONtoObj.c b/python/JSONtoObj.c index cc752a47..f2a1a2c7 100644 --- a/python/JSONtoObj.c +++ b/python/JSONtoObj.c @@ -38,6 +38,7 @@ Numeric decoder derived from from TCL library #include #include +#include "ujson.h" //#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*/ - PyErr_Format (PyExc_ValueError, "%s", decoder.errorStr); + PyErr_Format (JSONDecodeError, "%s", decoder.errorStr); if (ret) { diff --git a/python/ujson.c b/python/ujson.c index f7c5e032..c2f37560 100644 --- a/python/ujson.c +++ b/python/ujson.c @@ -38,6 +38,7 @@ Numeric decoder derived from from TCL library #include #include "version.h" +#include "ujson.h" /* objToJSON */ PyObject* objToJSON(PyObject* self, PyObject *args, PyObject *kwargs); @@ -51,6 +52,8 @@ PyObject* objToJSONFile(PyObject* self, PyObject *args, PyObject *kwargs); /* JSONFileToObj */ PyObject* JSONFileToObj(PyObject* self, PyObject *args, PyObject *kwargs); +PyObject* JSONDecodeError; + #define ENCODER_HELP_TEXT "Use ensure_ascii=false to output UTF-8. " \ "Set encode_html_chars=True to encode < > & as unicode escape sequences. "\ @@ -188,5 +191,15 @@ PyMODINIT_FUNC PyInit_ujson(void) PyErr_Clear(); #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; } diff --git a/python/ujson.h b/python/ujson.h new file mode 100644 index 00000000..cb27c207 --- /dev/null +++ b/python/ujson.h @@ -0,0 +1 @@ +extern PyObject* JSONDecodeError; diff --git a/tests/test_ujson.py b/tests/test_ujson.py index 1557e7c0..eff07dfa 100644 --- a/tests/test_ujson.py +++ b/tests/test_ujson.py @@ -555,46 +555,46 @@ def test_decode_numeric_int_exp(test_input): @pytest.mark.parametrize( "test_input, expected", [ - ('{{1337:""}}', ValueError), # broken dict key type leak test - ('{{"key":"}', ValueError), # broken dict leak test - ('{{"key":"}', ValueError), # broken dict leak test - ("[[[true", ValueError), # broken list leak test + ('{{1337:""}}', ujson.JSONDecodeError), # broken dict key type leak test + ('{{"key":"}', ujson.JSONDecodeError), # broken dict leak test + ('{{"key":"}', ujson.JSONDecodeError), # broken dict leak test + ("[[[true", ujson.JSONDecodeError), # broken list leak test ], ) def test_decode_range_raises(test_input, expected): for x in range(1000): - with pytest.raises(ValueError): + with pytest.raises(expected): ujson.decode(test_input) @pytest.mark.parametrize( "test_input, expected", [ - ("fdsa sda v9sa fdsa", ValueError), # jibberish - ("[", ValueError), # broken array start - ("{", ValueError), # broken object start - ("]", ValueError), # broken array end - ("}", ValueError), # broken object end - ('{"one":1,}', ValueError), # object trailing comma fail - ('"TESTING', ValueError), # string unterminated - ('"TESTING\\"', ValueError), # string bad escape - ("tru", ValueError), # true broken - ("fa", ValueError), # false broken - ("n", ValueError), # null broken - ("{{{{31337}}}}", ValueError), # dict with no key - ('{{{{"key"}}}}', ValueError), # dict with no colon or value - ('{{{{"key":}}}}', ValueError), # dict with no value - ("[31337,]", ValueError), # array trailing comma fail - ("[,31337]", ValueError), # array leading comma fail - ("[,]", ValueError), # array only comma fail - ("[]]", ValueError), # array unmatched bracket fail - ("18446744073709551616", ValueError), # too big value - ("-90223372036854775809", ValueError), # too small value - ("18446744073709551616", ValueError), # very too big value - ("-90223372036854775809", ValueError), # very too small value - ("{}\n\t a", ValueError), # with trailing non whitespaces - ("[18446744073709551616]", ValueError), # array with big int - ('{"age", 44}', ValueError), # read bad object syntax + ("fdsa sda v9sa fdsa", ujson.JSONDecodeError), # jibberish + ("[", ujson.JSONDecodeError), # broken array start + ("{", ujson.JSONDecodeError), # broken object start + ("]", ujson.JSONDecodeError), # broken array end + ("}", ujson.JSONDecodeError), # broken object end + ('{"one":1,}', ujson.JSONDecodeError), # object trailing comma fail + ('"TESTING', ujson.JSONDecodeError), # string unterminated + ('"TESTING\\"', ujson.JSONDecodeError), # string bad escape + ("tru", ujson.JSONDecodeError), # true broken + ("fa", ujson.JSONDecodeError), # false broken + ("n", ujson.JSONDecodeError), # null broken + ("{{{{31337}}}}", ujson.JSONDecodeError), # dict with no key + ('{{{{"key"}}}}', ujson.JSONDecodeError), # dict with no colon or value + ('{{{{"key":}}}}', ujson.JSONDecodeError), # dict with no value + ("[31337,]", ujson.JSONDecodeError), # array trailing comma fail + ("[,31337]", ujson.JSONDecodeError), # array leading comma fail + ("[,]", ujson.JSONDecodeError), # array only comma fail + ("[]]", ujson.JSONDecodeError), # array unmatched bracket fail + ("18446744073709551616", ujson.JSONDecodeError), # too big value + ("-90223372036854775809", ujson.JSONDecodeError), # too small value + ("18446744073709551616", ujson.JSONDecodeError), # very too big value + ("-90223372036854775809", ujson.JSONDecodeError), # very too small value + ("{}\n\t a", ujson.JSONDecodeError), # with trailing non whitespaces + ("[18446744073709551616]", ujson.JSONDecodeError), # array with big int + ('{"age", 44}', ujson.JSONDecodeError), # read bad object syntax ], ) def test_decode_raises(test_input, expected): @@ -605,8 +605,8 @@ def test_decode_raises(test_input, expected): @pytest.mark.parametrize( "test_input, expected", [ - ("[", ValueError), # array depth too big - ("{", ValueError), # object depth too big + ("[", ujson.JSONDecodeError), # array depth too big + ("{", ujson.JSONDecodeError), # object depth too big ], ) 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)) +def test_decode_exception_is_value_error(): + assert issubclass(ujson.JSONDecodeError, ValueError) + + @pytest.mark.parametrize( "test_input, expected", [