Skip to content

Commit

Permalink
Removed generic serialization of objects/iterables
Browse files Browse the repository at this point in the history
The behavior of ujson has always been to try to serialize all objects in
any way possible. This has been quite a deviation from other json
libraries, including Pythons standard json module, and the source of a
lot of confusion and bugs. Removing this quirk moves ultrajson closer to
the expected behavior.

Instead of trying to coerce serialization ultrajson will now throw a
TypeError: "repr(obj) is not JSON serializable" exception.
  • Loading branch information
Jahaja committed Feb 6, 2017
1 parent ac4637f commit 53f85b1
Showing 1 changed file with 11 additions and 214 deletions.
225 changes: 11 additions & 214 deletions python/objToJSON.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ static void *PyUnicodeToUTF8(JSOBJ _obj, JSONTypeContext *tc, void *outValue, si
PyObject *obj = (PyObject *) _obj;
PyObject *newObj;
#if (PY_VERSION_HEX >= 0x03030000)
if(PyUnicode_IS_COMPACT_ASCII(obj))
if (PyUnicode_IS_COMPACT_ASCII(obj))
{
Py_ssize_t len;
char *data = PyUnicode_AsUTF8AndSize(obj, &len);
Expand All @@ -171,10 +171,12 @@ static void *PyUnicodeToUTF8(JSOBJ _obj, JSONTypeContext *tc, void *outValue, si
static void *PyRawJSONToUTF8(JSOBJ _obj, JSONTypeContext *tc, void *outValue, size_t *_outLen)
{
PyObject *obj = GET_TC(tc)->rawJSONValue;
if (PyUnicode_Check(obj)) {
if (PyUnicode_Check(obj))
{
return PyUnicodeToUTF8(obj, tc, outValue, _outLen);
}
else {
else
{
return PyStringToUTF8(obj, tc, outValue, _outLen);
}
}
Expand All @@ -186,7 +188,8 @@ static void *PyDateTimeToINT64(JSOBJ _obj, JSONTypeContext *tc, void *outValue,
int y, m, d, h, mn, s, days;

utcoffset = PyObject_CallMethod(obj, "utcoffset", NULL);
if(utcoffset != Py_None){
if (utcoffset != Py_None)
{
obj = PyNumber_Subtract(obj, utcoffset);
}

Expand Down Expand Up @@ -271,164 +274,6 @@ static char *Tuple_iterGetName(JSOBJ obj, JSONTypeContext *tc, size_t *outLen)
return NULL;
}

static int Iter_iterNext(JSOBJ obj, JSONTypeContext *tc)
{
PyObject *item;

if (GET_TC(tc)->itemValue)
{
Py_DECREF(GET_TC(tc)->itemValue);
GET_TC(tc)->itemValue = NULL;
}

if (GET_TC(tc)->iterator == NULL)
{
return 0;
}

item = PyIter_Next(GET_TC(tc)->iterator);

if (item == NULL)
{
return 0;
}

GET_TC(tc)->itemValue = item;
return 1;
}

static void Iter_iterEnd(JSOBJ obj, JSONTypeContext *tc)
{
if (GET_TC(tc)->itemValue)
{
Py_DECREF(GET_TC(tc)->itemValue);
GET_TC(tc)->itemValue = NULL;
}

if (GET_TC(tc)->iterator)
{
Py_DECREF(GET_TC(tc)->iterator);
GET_TC(tc)->iterator = NULL;
}
}

static JSOBJ Iter_iterGetValue(JSOBJ obj, JSONTypeContext *tc)
{
return GET_TC(tc)->itemValue;
}

static char *Iter_iterGetName(JSOBJ obj, JSONTypeContext *tc, size_t *outLen)
{
return NULL;
}

static void Dir_iterEnd(JSOBJ obj, JSONTypeContext *tc)
{
if (GET_TC(tc)->itemValue)
{
Py_DECREF(GET_TC(tc)->itemValue);
GET_TC(tc)->itemValue = NULL;
}

if (GET_TC(tc)->itemName)
{
Py_DECREF(GET_TC(tc)->itemName);
GET_TC(tc)->itemName = NULL;
}

Py_DECREF( (PyObject *) GET_TC(tc)->attrList);
PRINTMARK();
}

static int Dir_iterNext(JSOBJ _obj, JSONTypeContext *tc)
{
PyObject *obj = (PyObject *) _obj;
PyObject *itemValue = GET_TC(tc)->itemValue;
PyObject *itemName = GET_TC(tc)->itemName;
PyObject* attr;
PyObject* attrName;
char* attrStr;

if (itemValue)
{
Py_DECREF(GET_TC(tc)->itemValue);
GET_TC(tc)->itemValue = itemValue = NULL;
}

if (itemName)
{
Py_DECREF(GET_TC(tc)->itemName);
GET_TC(tc)->itemName = itemName = NULL;
}

for (; GET_TC(tc)->index < GET_TC(tc)->size; GET_TC(tc)->index ++)
{
attrName = PyList_GET_ITEM(GET_TC(tc)->attrList, GET_TC(tc)->index);
#if PY_MAJOR_VERSION >= 3
attr = PyUnicode_AsUTF8String(attrName);
#else
attr = attrName;
Py_INCREF(attr);
#endif
attrStr = PyString_AS_STRING(attr);

if (attrStr[0] == '_')
{
PRINTMARK();
Py_DECREF(attr);
continue;
}

itemValue = PyObject_GetAttr(obj, attrName);
if (itemValue == NULL)
{
PyErr_Clear();
Py_DECREF(attr);
PRINTMARK();
continue;
}

if (PyCallable_Check(itemValue))
{
Py_DECREF(itemValue);
Py_DECREF(attr);
PRINTMARK();
continue;
}

PRINTMARK();
itemName = attr;
break;
}

if (itemName == NULL)
{
GET_TC(tc)->index = GET_TC(tc)->size;
GET_TC(tc)->itemValue = NULL;
return 0;
}

GET_TC(tc)->itemName = itemName;
GET_TC(tc)->itemValue = itemValue;
GET_TC(tc)->index ++;

PRINTMARK();
return 1;
}

static JSOBJ Dir_iterGetValue(JSOBJ obj, JSONTypeContext *tc)
{
PRINTMARK();
return GET_TC(tc)->itemValue;
}

static char *Dir_iterGetName(JSOBJ obj, JSONTypeContext *tc, size_t *outLen)
{
PRINTMARK();
*outLen = PyString_GET_SIZE(GET_TC(tc)->itemName);
return PyString_AS_STRING(GET_TC(tc)->itemName);
}

static int List_iterNext(JSOBJ obj, JSONTypeContext *tc)
{
if (GET_TC(tc)->index >= GET_TC(tc)->size)
Expand Down Expand Up @@ -644,7 +489,6 @@ static char *SortedDict_iterGetName(JSOBJ obj, JSONTypeContext *tc, size_t *outL
return PyString_AS_STRING(GET_TC(tc)->itemName);
}


static void SetupDictIter(PyObject *dictObj, TypeContext *pc, JSONObjectEncoder *enc)
{
if (enc->sortKeys) {
Expand All @@ -665,7 +509,7 @@ static void SetupDictIter(PyObject *dictObj, TypeContext *pc, JSONObjectEncoder

static void Object_beginTypeContext (JSOBJ _obj, JSONTypeContext *tc, JSONObjectEncoder *enc)
{
PyObject *obj, *exc, *iter;
PyObject *obj, *objRepr, *exc;
TypeContext *pc;
PRINTMARK();
if (!_obj) {
Expand Down Expand Up @@ -828,20 +672,6 @@ static void Object_beginTypeContext (JSOBJ _obj, JSONTypeContext *tc, JSONObject

return;
}
/*
else
if (PyAnySet_Check(obj))
{
PRINTMARK();
tc->type = JT_ARRAY;
pc->iterBegin = NULL;
pc->iterEnd = Iter_iterEnd;
pc->iterNext = Iter_iterNext;
pc->iterGetValue = Iter_iterGetValue;
pc->iterGetName = Iter_iterGetName;
return;
}
*/

if (UNLIKELY(PyObject_HasAttrString(obj, "toDict")))
{
Expand Down Expand Up @@ -905,42 +735,9 @@ static void Object_beginTypeContext (JSOBJ _obj, JSONTypeContext *tc, JSONObject
PRINTMARK();
PyErr_Clear();

iter = PyObject_GetIter(obj);

if (iter != NULL)
{
PRINTMARK();
tc->type = JT_ARRAY;
pc->iterator = iter;
pc->iterEnd = Iter_iterEnd;
pc->iterNext = Iter_iterNext;
pc->iterGetValue = Iter_iterGetValue;
pc->iterGetName = Iter_iterGetName;
return;
}

PRINTMARK();
PyErr_Clear();

PRINTMARK();
tc->type = JT_OBJECT;
GET_TC(tc)->attrList = PyObject_Dir(obj);

if (GET_TC(tc)->attrList == NULL)
{
PyErr_Clear();
goto INVALID;
}

GET_TC(tc)->index = 0;
GET_TC(tc)->size = PyList_GET_SIZE(GET_TC(tc)->attrList);
PRINTMARK();

pc->iterEnd = Dir_iterEnd;
pc->iterNext = Dir_iterNext;
pc->iterGetValue = Dir_iterGetValue;
pc->iterGetName = Dir_iterGetName;
return;
objRepr = PyObject_Repr(obj);
PyErr_Format (PyExc_TypeError, "%s is not JSON serializable", PyString_AS_STRING(objRepr));
Py_DECREF(objRepr);

INVALID:
PRINTMARK();
Expand Down

0 comments on commit 53f85b1

Please sign in to comment.