diff --git a/doc/source/whatsnew/v1.0.2.rst b/doc/source/whatsnew/v1.0.2.rst index 07a837829c384..182ad7231983e 100644 --- a/doc/source/whatsnew/v1.0.2.rst +++ b/doc/source/whatsnew/v1.0.2.rst @@ -25,8 +25,9 @@ Fixed regressions Bug fixes ~~~~~~~~~ -- -- +**I/O** + +- Using ``pd.NA`` with :meth:`DataFrame.to_json` now correctly outputs a null value instead of an empty object (:issue:`31615`) .. --------------------------------------------------------------------------- diff --git a/pandas/_libs/src/ujson/python/objToJSON.c b/pandas/_libs/src/ujson/python/objToJSON.c index 0fc146d25459b..8cfc20ffd2c1c 100644 --- a/pandas/_libs/src/ujson/python/objToJSON.c +++ b/pandas/_libs/src/ujson/python/objToJSON.c @@ -53,6 +53,7 @@ static PyTypeObject *cls_dataframe; static PyTypeObject *cls_series; static PyTypeObject *cls_index; static PyTypeObject *cls_nat; +static PyTypeObject *cls_na; PyObject *cls_timedelta; npy_int64 get_nat(void) { return NPY_MIN_INT64; } @@ -149,6 +150,7 @@ int PdBlock_iterNext(JSOBJ, JSONTypeContext *); void *initObjToJSON(void) { PyObject *mod_pandas; PyObject *mod_nattype; + PyObject *mod_natype; PyObject *mod_decimal = PyImport_ImportModule("decimal"); type_decimal = (PyTypeObject *)PyObject_GetAttrString(mod_decimal, "Decimal"); @@ -174,6 +176,12 @@ void *initObjToJSON(void) { Py_DECREF(mod_nattype); } + mod_natype = PyImport_ImportModule("pandas._libs.missing"); + if (mod_natype) { + cls_na = (PyTypeObject *)PyObject_GetAttrString(mod_natype, "NAType"); + Py_DECREF(mod_natype); + } + /* Initialise numpy API */ import_array(); // GH 31463 @@ -1789,6 +1797,10 @@ void Object_beginTypeContext(JSOBJ _obj, JSONTypeContext *tc) { "%R (0d array) is not JSON serializable at the moment", obj); goto INVALID; + } else if (PyObject_TypeCheck(obj, cls_na)) { + PRINTMARK(); + tc->type = JT_NULL; + return; } ISITERABLE: diff --git a/pandas/tests/io/json/test_pandas.py b/pandas/tests/io/json/test_pandas.py index 602022a21c4a6..f2d35bfb3b5ae 100644 --- a/pandas/tests/io/json/test_pandas.py +++ b/pandas/tests/io/json/test_pandas.py @@ -1671,3 +1671,13 @@ def test_to_s3(self, s3_resource): assert target_file in ( obj.key for obj in s3_resource.Bucket("pandas-test").objects.all() ) + + def test_json_pandas_na(self): + # GH 31615 + result = pd.DataFrame([[pd.NA]]).to_json() + assert result == '{"0":{"0":null}}' + + def test_json_pandas_nulls(self, nulls_fixture): + # GH 31615 + result = pd.DataFrame([[nulls_fixture]]).to_json() + assert result == '{"0":{"0":null}}'