Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Backports:SLE-15-SP6:Update
python-python-cjson
py3.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File py3.patch of Package python-python-cjson
From f9060f9981dfc6bc7aed6ced93f10477b0a77d60 Mon Sep 17 00:00:00 2001 From: Felipe Machado <felipou@gmail.com> Date: Wed, 9 Aug 2017 15:48:27 -0300 Subject: [PATCH] Python 3 support - initial attempt --- cjson.c | 268 ++++++++++++++++++++++++++-------------------------- jsontest.py | 16 ++-- 2 files changed, 144 insertions(+), 140 deletions(-) diff --git a/cjson.c b/cjson.c index d3ecc81..a44e7e4 100644 --- a/cjson.c +++ b/cjson.c @@ -8,6 +8,16 @@ #include <ctype.h> #include <math.h> +#if PY_MAJOR_VERSION >= 3 +#define IS_PY3K +#endif + +#if PY_MAJOR_VERSION >= 3 +#define STRING_TYPE PyUnicodeObject +#else +#define STRING_TYPE PyStringObject +#endif + typedef struct JSONData { char *str; // the actual json string char *end; // pointer to the string end @@ -16,7 +26,6 @@ typedef struct JSONData { } JSONData; static PyObject* encode_object(PyObject *object); -static PyObject* encode_string(PyObject *object); static PyObject* encode_unicode(PyObject *object); static PyObject* encode_tuple(PyObject *object); static PyObject* encode_list(PyObject *object); @@ -68,6 +77,17 @@ typedef int Py_ssize_t; #define skipSpaces(d) while(isspace(*((d)->ptr))) (d)->ptr++ +static inline void +PyUnicode_ConcatAndDel(PyObject **left, PyObject *right) +{ + PyObject *newobj; + newobj = PyUnicode_Concat(*left, right); + Py_DECREF(*left); + Py_DECREF(right); + *left = newobj; +} + + /* ------------------------------ Decoding ----------------------------- */ static PyObject* @@ -161,12 +181,7 @@ decode_string(JSONData *jsondata) len = ptr - jsondata->ptr - 1; - if (has_unicode || jsondata->all_unicode) - object = PyUnicode_DecodeUnicodeEscape(jsondata->ptr+1, len, NULL); - else if (string_escape) - object = PyString_DecodeEscape(jsondata->ptr+1, len, NULL, 0, NULL); - else - object = PyString_FromStringAndSize(jsondata->ptr+1, len); + object = PyUnicode_DecodeUnicodeEscape(jsondata->ptr+1, len, NULL); if (object == NULL) { PyObject *type, *value, *tb, *reason; @@ -182,7 +197,7 @@ decode_string(JSONData *jsondata) PyErr_Format(JSON_DecodeError, "cannot decode string starting" " at position " SSIZE_T_F ": %s", (Py_ssize_t)(jsondata->ptr - jsondata->str), - reason ? PyString_AsString(reason) : "bad format"); + reason ? PyUnicode_AsUTF8(reason) : "bad format"); Py_XDECREF(reason); } else { PyErr_Format(JSON_DecodeError, @@ -292,14 +307,14 @@ decode_number(JSONData *jsondata) skipDigits(ptr); } - str = PyString_FromStringAndSize(jsondata->ptr, ptr - jsondata->ptr); + str = PyUnicode_FromStringAndSize(jsondata->ptr, ptr - jsondata->ptr); if (str == NULL) return NULL; if (is_float) - object = PyFloat_FromString(str, NULL); + object = PyFloat_FromString(str); else - object = PyInt_FromString(PyString_AS_STRING(str), NULL, 10); + object = PyLong_FromUnicodeObject(str, 10); Py_DECREF(str); @@ -579,75 +594,6 @@ decode_json(JSONData *jsondata) /* ------------------------------ Encoding ----------------------------- */ -/* - * This function is an almost verbatim copy of PyString_Repr() from - * Python's stringobject.c with the following differences: - * - * - it always quotes the output using double quotes. - * - it also quotes \b and \f - * - it replaces any non ASCII character hh with \u00hh instead of \xhh - */ -static PyObject* -encode_string(PyObject *string) -{ - register PyStringObject* op = (PyStringObject*) string; - size_t newsize = 2 + 6 * op->ob_size; - PyObject *v; - - if (op->ob_size > (PY_SSIZE_T_MAX-2)/6) { - PyErr_SetString(PyExc_OverflowError, - "string is too large to make repr"); - return NULL; - } - v = PyString_FromStringAndSize((char *)NULL, newsize); - if (v == NULL) { - return NULL; - } - else { - register Py_ssize_t i; - register char c; - register char *p; - int quote; - - quote = '"'; - - p = PyString_AS_STRING(v); - *p++ = quote; - for (i = 0; i < op->ob_size; i++) { - /* There's at least enough room for a hex escape - and a closing quote. */ - assert(newsize - (p - PyString_AS_STRING(v)) >= 7); - c = op->ob_sval[i]; - if (c == quote || c == '\\') - *p++ = '\\', *p++ = c; - else if (c == '\t') - *p++ = '\\', *p++ = 't'; - else if (c == '\n') - *p++ = '\\', *p++ = 'n'; - else if (c == '\r') - *p++ = '\\', *p++ = 'r'; - else if (c == '\f') - *p++ = '\\', *p++ = 'f'; - else if (c == '\b') - *p++ = '\\', *p++ = 'b'; - else if (c < ' ' || c >= 0x7f) { - /* For performance, we don't want to call - * PyOS_snprintf here (extra layers of - * function call). */ - sprintf(p, "\\u%04x", c & 0xff); - p += 6; - } - else - *p++ = c; - } - assert(newsize - (p - PyString_AS_STRING(v)) >= 1); - *p++ = quote; - *p = '\0'; - _PyString_Resize(&v, (int) (p - PyString_AS_STRING(v))); - return v; - } -} - /* * This function is an almost verbatim copy of unicodeescape_string() from * Python's unicodeobject.c with the following differences: @@ -662,7 +608,7 @@ encode_unicode(PyObject *unicode) PyObject *repr; Py_UNICODE *s; Py_ssize_t size; - char *p; + Py_UNICODE *p; static const char *hexdigit = "0123456789abcdef"; #ifdef Py_UNICODE_WIDE @@ -694,11 +640,11 @@ encode_unicode(PyObject *unicode) return NULL; } - repr = PyString_FromStringAndSize(NULL, 2 + expandsize*size + 1); + repr = PyUnicode_FromStringAndSize(NULL, 2 + expandsize*size + 1); if (repr == NULL) return NULL; - p = PyString_AS_STRING(repr); + p = PyUnicode_AS_UNICODE(repr); *p++ = '"'; @@ -706,7 +652,7 @@ encode_unicode(PyObject *unicode) Py_UNICODE ch = *s++; /* Escape quotes */ - if ((ch == (Py_UNICODE) PyString_AS_STRING(repr)[0] || ch == '\\')) { + if ((ch == (Py_UNICODE) PyUnicode_AS_UNICODE(repr)[0] || ch == '\\')) { *p++ = '\\'; *p++ = (char) ch; continue; @@ -801,10 +747,11 @@ encode_unicode(PyObject *unicode) *p++ = (char) ch; } - *p++ = PyString_AS_STRING(repr)[0]; + *p++ = PyUnicode_AS_UNICODE(repr)[0]; *p = '\0'; - _PyString_Resize(&repr, p - PyString_AS_STRING(repr)); + PyUnicode_Resize(&repr, p - PyUnicode_AS_UNICODE(repr)); + return repr; } @@ -825,9 +772,9 @@ encode_tuple(PyObject *tuple) PyObject *pieces, *result = NULL; PyTupleObject *v = (PyTupleObject*) tuple; - n = v->ob_size; + n = v->ob_base.ob_size; if (n == 0) - return PyString_FromString("[]"); + return PyUnicode_FromString("[]"); pieces = PyTuple_New(n); if (pieces == NULL) @@ -843,29 +790,29 @@ encode_tuple(PyObject *tuple) /* Add "[]" decorations to the first and last items. */ assert(n > 0); - s = PyString_FromString("["); + s = PyUnicode_FromString("["); if (s == NULL) goto Done; temp = PyTuple_GET_ITEM(pieces, 0); - PyString_ConcatAndDel(&s, temp); + PyUnicode_ConcatAndDel(&s, temp); PyTuple_SET_ITEM(pieces, 0, s); if (s == NULL) goto Done; - s = PyString_FromString("]"); + s = PyUnicode_FromString("]"); if (s == NULL) goto Done; temp = PyTuple_GET_ITEM(pieces, n-1); - PyString_ConcatAndDel(&temp, s); + PyUnicode_ConcatAndDel(&temp, s); PyTuple_SET_ITEM(pieces, n-1, temp); if (temp == NULL) goto Done; /* Paste them all together with ", " between. */ - s = PyString_FromString(", "); + s = PyUnicode_FromString(", "); if (s == NULL) goto Done; - result = _PyString_Join(s, pieces); + result = PyUnicode_Join(s, pieces); Py_DECREF(s); Done: @@ -899,8 +846,8 @@ encode_list(PyObject *list) return NULL; } - if (v->ob_size == 0) { - result = PyString_FromString("[]"); + if (v->ob_base.ob_size == 0) { + result = PyUnicode_FromString("[]"); goto Done; } @@ -910,7 +857,7 @@ encode_list(PyObject *list) /* Do repr() on each element. Note that this may mutate the list, * so must refetch the list size on each iteration. */ - for (i = 0; i < v->ob_size; ++i) { + for (i = 0; i < v->ob_base.ob_size; ++i) { int status; s = encode_object(v->ob_item[i]); if (s == NULL) @@ -923,29 +870,29 @@ encode_list(PyObject *list) /* Add "[]" decorations to the first and last items. */ assert(PyList_GET_SIZE(pieces) > 0); - s = PyString_FromString("["); + s = PyUnicode_FromString("["); if (s == NULL) goto Done; temp = PyList_GET_ITEM(pieces, 0); - PyString_ConcatAndDel(&s, temp); + PyUnicode_ConcatAndDel(&s, temp); PyList_SET_ITEM(pieces, 0, s); if (s == NULL) goto Done; - s = PyString_FromString("]"); + s = PyUnicode_FromString("]"); if (s == NULL) goto Done; temp = PyList_GET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1); - PyString_ConcatAndDel(&temp, s); + PyUnicode_ConcatAndDel(&temp, s); PyList_SET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1, temp); if (temp == NULL) goto Done; /* Paste them all together with ", " between. */ - s = PyString_FromString(", "); + s = PyUnicode_FromString(", "); if (s == NULL) goto Done; - result = _PyString_Join(s, pieces); + result = PyUnicode_Join(s, pieces); Py_DECREF(s); Done: @@ -984,7 +931,7 @@ encode_dict(PyObject *dict) } if (mp->ma_used == 0) { - result = PyString_FromString("{}"); + result = PyUnicode_FromString("{}"); goto Done; } @@ -992,7 +939,7 @@ encode_dict(PyObject *dict) if (pieces == NULL) goto Done; - colon = PyString_FromString(": "); + colon = PyUnicode_FromString(": "); if (colon == NULL) goto Done; @@ -1002,7 +949,7 @@ encode_dict(PyObject *dict) while (PyDict_Next((PyObject *)mp, &i, &key, &value)) { int status; - if (!PyString_Check(key) && !PyUnicode_Check(key)) { + if (!PyUnicode_Check(key)) { PyErr_SetString(JSON_EncodeError, "JSON encodable dictionaries " "must have string/unicode keys"); goto Done; @@ -1010,9 +957,10 @@ encode_dict(PyObject *dict) /* Prevent repr from deleting value during key format. */ Py_INCREF(value); - s = encode_object(key); - PyString_Concat(&s, colon); - PyString_ConcatAndDel(&s, encode_object(value)); + temp = encode_object(key); + s = PyUnicode_Concat(temp, colon); + Py_DECREF(temp); + PyUnicode_ConcatAndDel(&s, encode_object(value)); Py_DECREF(value); if (s == NULL) goto Done; @@ -1024,35 +972,36 @@ encode_dict(PyObject *dict) /* Add "{}" decorations to the first and last items. */ assert(PyList_GET_SIZE(pieces) > 0); - s = PyString_FromString("{"); + s = PyUnicode_FromString("{"); if (s == NULL) goto Done; temp = PyList_GET_ITEM(pieces, 0); - PyString_ConcatAndDel(&s, temp); + PyUnicode_ConcatAndDel(&s, temp); PyList_SET_ITEM(pieces, 0, s); if (s == NULL) goto Done; - s = PyString_FromString("}"); + s = PyUnicode_FromString("}"); if (s == NULL) goto Done; temp = PyList_GET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1); - PyString_ConcatAndDel(&temp, s); + PyUnicode_ConcatAndDel(&temp, s); PyList_SET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1, temp); if (temp == NULL) goto Done; /* Paste them all together with ", " between. */ - s = PyString_FromString(", "); + s = PyUnicode_FromString(", "); if (s == NULL) goto Done; - result = _PyString_Join(s, pieces); + result = PyUnicode_Join(s, pieces); Py_DECREF(s); Done: Py_XDECREF(pieces); Py_XDECREF(colon); Py_ReprLeave((PyObject *)mp); + return result; } @@ -1061,29 +1010,27 @@ static PyObject* encode_object(PyObject *object) { if (object == Py_True) { - return PyString_FromString("true"); + return PyUnicode_FromString("true"); } else if (object == Py_False) { - return PyString_FromString("false"); + return PyUnicode_FromString("false"); } else if (object == Py_None) { - return PyString_FromString("null"); - } else if (PyString_Check(object)) { - return encode_string(object); + return PyUnicode_FromString("null"); } else if (PyUnicode_Check(object)) { return encode_unicode(object); } else if (PyFloat_Check(object)) { double val = PyFloat_AS_DOUBLE(object); if (Py_IS_NAN(val)) { - return PyString_FromString("NaN"); + return PyUnicode_FromString("NaN"); } else if (Py_IS_INFINITY(val)) { if (val > 0) { - return PyString_FromString("Infinity"); + return PyUnicode_FromString("Infinity"); } else { - return PyString_FromString("-Infinity"); + return PyUnicode_FromString("-Infinity"); } } else { return PyObject_Repr(object); } - } else if (PyInt_Check(object) || PyLong_Check(object)) { + } else if (PyLong_Check(object)) { return PyObject_Str(object); } else if (PyList_Check(object)) { PyObject *result; @@ -1130,6 +1077,7 @@ JSON_decode(PyObject *self, PyObject *args, PyObject *kwargs) static char *kwlist[] = {"json", "all_unicode", NULL}; int all_unicode = False; // by default return unicode only when needed PyObject *object, *string, *str; + Py_ssize_t str_size; JSONData jsondata; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:decode", kwlist, @@ -1146,13 +1094,13 @@ JSON_decode(PyObject *self, PyObject *args, PyObject *kwargs) str = string; } - if (PyString_AsStringAndSize(str, &(jsondata.str), NULL) == -1) { + if (PyBytes_AsStringAndSize(str, &(jsondata.str), &str_size) == -1) { Py_DECREF(str); return NULL; // not a string object or it contains null bytes } jsondata.ptr = jsondata.str; - jsondata.end = jsondata.str + PyString_GET_SIZE(str); + jsondata.end = jsondata.str + str_size; jsondata.all_unicode = all_unicode; object = decode_json(&jsondata); @@ -1198,37 +1146,93 @@ PyDoc_STRVAR(module_doc, /* Initialization function for the module (*must* be called initcjson) */ +struct module_state { + PyObject *error; +}; + +#if PY_MAJOR_VERSION >= 3 +//############################################################################# +//# PYTHON 3 ################################################################## +//############################################################################# + +#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) + +static int cjson_traverse(PyObject *m, visitproc visit, void *arg) { + Py_VISIT(GETSTATE(m)->error); + return 0; +} + +static int cjson_clear(PyObject *m) { + Py_CLEAR(GETSTATE(m)->error); + return 0; +} + + +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "cjson", + module_doc, + sizeof(struct module_state), + cjson_methods, + NULL, + cjson_traverse, + cjson_clear, + NULL +}; + +#define INITERROR return NULL + +PyMODINIT_FUNC +PyInit_cjson(void) +//############################################################################# +#else +//############################################################################# +//# PYTHON 2 ################################################################## +//############################################################################# + +#define GETSTATE(m) (&_state) +static struct module_state _state; + +#define INITERROR return + PyMODINIT_FUNC initcjson(void) +//############################################################################# +#endif { PyObject *m; +#if PY_MAJOR_VERSION >= 3 + m = PyModule_Create(&moduledef); +#else m = Py_InitModule3("cjson", cjson_methods, module_doc); +#endif if (m == NULL) - return; + INITERROR; JSON_Error = PyErr_NewException("cjson.Error", NULL, NULL); if (JSON_Error == NULL) - return; + INITERROR; Py_INCREF(JSON_Error); PyModule_AddObject(m, "Error", JSON_Error); JSON_EncodeError = PyErr_NewException("cjson.EncodeError", JSON_Error, NULL); if (JSON_EncodeError == NULL) - return; + INITERROR; Py_INCREF(JSON_EncodeError); PyModule_AddObject(m, "EncodeError", JSON_EncodeError); JSON_DecodeError = PyErr_NewException("cjson.DecodeError", JSON_Error, NULL); if (JSON_DecodeError == NULL) - return; + INITERROR; Py_INCREF(JSON_DecodeError); PyModule_AddObject(m, "DecodeError", JSON_DecodeError); // Module version (the MODULE_VERSION macro is defined by setup.py) PyModule_AddStringConstant(m, "__version__", string(MODULE_VERSION)); +#if PY_MAJOR_VERSION >= 3 + return m; +#endif } - - diff --git a/jsontest.py b/jsontest.py index 0f79307..19c24fa 100644 --- a/jsontest.py +++ b/jsontest.py @@ -128,7 +128,7 @@ def testReadBadEscapedHexCharacter(self): self.assertRaises(_exception, self.doReadBadEscapedHexCharacter) def doReadBadEscapedHexCharacter(self): - cjson.decode('"\u10K5"') + cjson.decode(u'"\\u10K5"') def testReadBadObjectKey(self): self.assertRaises(_exception, self.doReadBadObjectKey) @@ -141,7 +141,7 @@ def testReadBadArray(self): def doReadBadArray(self): cjson.decode('[1,2,3,,]') - + def testReadBadObjectSyntax(self): self.assertRaises(_exception, self.doReadBadObjectSyntax) @@ -159,7 +159,7 @@ def testReadIntegerValue(self): def testReadNegativeIntegerValue(self): obj = cjson.decode('{ "key" : -44 }') self.assertEqual({ "key" : -44 }, obj) - + def testReadFloatValue(self): obj = cjson.decode('{ "age" : 44.5 }') self.assertEqual({ "age" : 44.5 }, obj) @@ -176,7 +176,7 @@ def doReadBadNumber(self): def testReadSmallObject(self): obj = cjson.decode('{ "name" : "Patrick", "age":44} ') - self.assertEqual({ "age" : 44, "name" : "Patrick" }, obj) + self.assertEqual({ "age" : 44, "name" : "Patrick" }, obj) def testReadEmptyArray(self): obj = cjson.decode('[]') @@ -194,7 +194,7 @@ def testWriteSmallArray(self): def testWriteSmallObject(self): s = cjson.encode({ "name" : "Patrick", "age": 44 }) - self.assertEqual('{"age":44,"name":"Patrick"}', _removeWhitespace(s)) + self.assertEqual('{"name":"Patrick","age":44}', _removeWhitespace(s)) def testWriteFloat(self): n = 3.44556677 @@ -276,7 +276,7 @@ def testWriteComplexArray(self): obj = [{"name":"Patrick","age":44,"Employed?":True,"Female?":False,"grandchildren":None}, "used","abused","confused", 1,2,[3,4,5]] - self.assertEqual('[{"Female?":false,"age":44,"name":"Patrick","grandchildren":null,"Employed?":true},"used","abused","confused",1,2,[3,4,5]]', + self.assertEqual('[{"name":"Patrick","age":44,"Employed?":true,"Female?":false,"grandchildren":null},"used","abused","confused",1,2,[3,4,5]]', _removeWhitespace(cjson.encode(obj))) @@ -290,7 +290,7 @@ def testReadWriteCopies(self): def testStringEncoding(self): s = cjson.encode([1, 2, 3]) - self.assertEqual(unicode("[1,2,3]", "utf-8"), _removeWhitespace(s)) + self.assertEqual("[1,2,3]", _removeWhitespace(s)) def testReadEmptyObjectAtEndOfArray(self): self.assertEqual(["a","b","c",{}], @@ -329,7 +329,7 @@ def testWriteLongUnicode(self): u'\u1234\u1234\u1234\u1234\u1234\u1234') self.assertEqual(r'"\U0001d11e\U0001d11e\U0001d11e\U0001d11e' r'\u1234\u1234\u1234\u1234\u1234\u1234"', s) - + def main(): unittest.main()
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor