Index: src/persistent/cPickleCache.c =================================================================== --- src/persistent/cPickleCache.c (revision 103608) +++ src/persistent/cPickleCache.c (working copy) @@ -361,7 +361,7 @@ if (_p_invalidate == NULL) { - _p_invalidate = PyString_InternFromString("_p_invalidate"); + _p_invalidate = PyUnicode_InternFromString("_p_invalidate"); if (_p_invalidate == NULL) { /* It doesn't make any sense to ignore this error, but @@ -411,7 +411,7 @@ } else { - if (PyString_Check(inv)) + if (PyBytes_Check(inv)) { if (_invalidate(self, inv) < 0) return NULL; @@ -659,7 +659,7 @@ for (here = self->ring_home.r_next; here != &self->ring_home; here = here->r_next) c++; - return PyInt_FromLong(c); + return PyLong_FromLong(c); } static PyObject * @@ -933,10 +933,10 @@ oid = PyObject_GetAttr(v, py__p_oid); if (oid == NULL) return -1; - if (! PyString_Check(oid)) + if (! PyBytes_Check(oid)) { PyErr_Format(PyExc_TypeError, - "Cached object oid must be a string, not a %s", + "Cached object oid must be bytes, not a %s", oid->ob_type->tp_name); return -1; } @@ -944,14 +944,14 @@ /* we know they are both strings. * now check if they are the same string. */ - result = PyObject_Compare(key, oid); - if (PyErr_Occurred()) + result = PyObject_RichCompareBool(key, oid, Py_EQ); + if (result < 0) { Py_DECREF(oid); return -1; } Py_DECREF(oid); - if (result) + if (!result) { PyErr_SetString(PyExc_ValueError, "Cache key does not match oid"); return -1; @@ -1087,10 +1087,10 @@ static int cc_ass_sub(ccobject *self, PyObject *key, PyObject *v) { - if (!PyString_Check(key)) + if (!PyBytes_Check(key)) { PyErr_Format(PyExc_TypeError, - "cPickleCache key must be a string, not a %s", + "cPickleCache key must be bytes, not a %s", key->ob_type->tp_name); return -1; } @@ -1124,11 +1124,11 @@ {"cache_size", T_INT, offsetof(ccobject, cache_size)}, {"cache_size_bytes", T_LONG, offsetof(ccobject, cache_size_bytes)}, {"total_estimated_size", T_LONG, offsetof(ccobject, total_estimated_size), - RO}, + READONLY}, {"cache_drain_resistance", T_INT, offsetof(ccobject, cache_drain_resistance)}, - {"cache_non_ghost_count", T_INT, offsetof(ccobject, non_ghost_count), RO}, - {"cache_klass_count", T_INT, offsetof(ccobject, klass_count), RO}, + {"cache_non_ghost_count", T_INT, offsetof(ccobject, non_ghost_count), READONLY}, + {"cache_klass_count", T_INT, offsetof(ccobject, klass_count), READONLY}, {NULL} }; @@ -1142,8 +1142,7 @@ #define DEFERRED_ADDRESS(ADDR) 0 static PyTypeObject Cctype = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, /* ob_size */ + PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type),0) "persistent.PickleCache", /* tp_name */ sizeof(ccobject), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -1182,43 +1181,65 @@ (initproc)cc_init, /* tp_init */ }; -void -initcPickleCache(void) +static struct PyModuleDef _module = { + PyModuleDef_HEAD_INIT, + "cPickleCache", + cPickleCache_doc_string, + -1, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +static PyObject* +init(void) { PyObject *m; - Cctype.ob_type = &PyType_Type; + Py_TYPE(&Cctype) = &PyType_Type; Cctype.tp_new = &PyType_GenericNew; if (PyType_Ready(&Cctype) < 0) { - return; + return NULL; } - m = Py_InitModule3("cPickleCache", NULL, cPickleCache_doc_string); + m = PyModule_Create(&_module); + if (!m) + return NULL; capi = (cPersistenceCAPIstruct *)PyCObject_Import( "persistent.cPersistence", "CAPI"); if (!capi) - return; + return NULL; capi->percachedel = (percachedelfunc)cc_oid_unreferenced; - py__p_changed = PyString_InternFromString("_p_changed"); + py__p_changed = PyUnicode_InternFromString("_p_changed"); if (!py__p_changed) - return; - py__p_deactivate = PyString_InternFromString("_p_deactivate"); + return NULL; + py__p_deactivate = PyUnicode_InternFromString("_p_deactivate"); if (!py__p_deactivate) - return; - py__p_jar = PyString_InternFromString("_p_jar"); + return NULL; + py__p_jar = PyUnicode_InternFromString("_p_jar"); if (!py__p_jar) - return; - py__p_oid = PyString_InternFromString("_p_oid"); + return NULL; + py__p_oid = PyUnicode_InternFromString("_p_oid"); if (!py__p_oid) - return; + return NULL; if (PyModule_AddStringConstant(m, "cache_variant", "stiff/c") < 0) - return; + return NULL; /* This leaks a reference to Cctype, but it doesn't matter. */ if (PyModule_AddObject(m, "PickleCache", (PyObject *)&Cctype) < 0) - return; + return NULL; + + return m; } + +PyObject* +PyInit_cPickleCache(void) +{ + return init(); +} Index: src/persistent/mapping.py =================================================================== --- src/persistent/mapping.py (revision 103608) +++ src/persistent/mapping.py (working copy) @@ -17,7 +17,13 @@ $Id$""" import persistent -import UserDict +import sys +if sys.version_info <= (3,): + import UserDict +else: + # XXX there should be a fixer for IterableUserDict + import collections + collections.IterableUserDict = collections.UserDict class default(object): Index: src/persistent/TimeStamp.c =================================================================== --- src/persistent/TimeStamp.c (revision 103608) +++ src/persistent/TimeStamp.c (working copy) @@ -106,15 +106,56 @@ PyObject_Del(ts); } +#if 0 static int -TimeStamp_compare(TimeStamp *v, TimeStamp *w) +TimeStamp_compare(PyObject *_v, PyObject *_w) { + TimeStamp *v = (TimeStamp*)_v; + TimeStamp *w = (TimeStamp*)_w; int cmp = memcmp(v->data, w->data, 8); if (cmp < 0) return -1; if (cmp > 0) return 1; return 0; } +#else +#define TimeStamp_compare 0 +#endif +static PyObject* +TimeStamp_richcompare(PyObject *_v, PyObject *_w, int code) +{ + TimeStamp *v = (TimeStamp*)_v; + TimeStamp *w = (TimeStamp*)_w; + PyObject *r; + int cmp = memcmp(v->data, w->data, 8); + switch(code) { + case Py_EQ: + cmp = cmp == 0; + break; + case Py_NE: + cmp = cmp != 0; + break; + case Py_LE: + cmp = cmp <= 0; + break; + case Py_GE: + cmp = cmp >= 0; + break; + case Py_LT: + cmp = cmp < 0; + break; + case Py_GT: + cmp = cmp > 0; + break; + default: + PyErr_BadArgument(); + return NULL; + } + r = cmp ? Py_True : Py_False; + Py_INCREF(r); + return r; +} + static long TimeStamp_hash(TimeStamp *self) { @@ -165,7 +206,7 @@ { TimeStampParts p; TimeStamp_unpack(self, &p); - return PyInt_FromLong(p.y); + return PyLong_FromLong(p.y); } static PyObject * @@ -173,7 +214,7 @@ { TimeStampParts p; TimeStamp_unpack(self, &p); - return PyInt_FromLong(p.m); + return PyLong_FromLong(p.m); } static PyObject * @@ -181,7 +222,7 @@ { TimeStampParts p; TimeStamp_unpack(self, &p); - return PyInt_FromLong(p.d); + return PyLong_FromLong(p.d); } static PyObject * @@ -189,7 +230,7 @@ { TimeStampParts p; TimeStamp_unpack(self, &p); - return PyInt_FromLong(p.mi / 60); + return PyLong_FromLong(p.mi / 60); } static PyObject * @@ -197,7 +238,7 @@ { TimeStampParts p; TimeStamp_unpack(self, &p); - return PyInt_FromLong(p.mi % 60); + return PyLong_FromLong(p.mi % 60); } static PyObject * @@ -218,7 +259,7 @@ static PyObject * TimeStamp_raw(TimeStamp *self) { - return PyString_FromStringAndSize((const char*)self->data, 8); + return PyBytes_FromStringAndSize((const char*)self->data, 8); } static PyObject * @@ -233,7 +274,7 @@ p.y, p.m, p.d, p.mi / 60, p.mi % 60, TimeStamp_sec(self)); - return PyString_FromStringAndSize(buf, len); + return PyUnicode_FromStringAndSize(buf, len); } @@ -245,7 +286,7 @@ unsigned char new[8]; int i; - if (obj->ob_type != self->ob_type) { + if (Py_TYPE(obj) != Py_TYPE(self)) { PyErr_SetString(PyExc_TypeError, "expected TimeStamp object"); return NULL; } @@ -299,8 +340,7 @@ }; static PyTypeObject TimeStamp_type = { - PyObject_HEAD_INIT(NULL) - 0, + PyVarObject_HEAD_INIT(NULL,0) "persistent.TimeStamp", sizeof(TimeStamp), 0, @@ -308,7 +348,7 @@ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - (cmpfunc)TimeStamp_compare, /* tp_compare */ + TimeStamp_compare, /* tp_compare */ (reprfunc)TimeStamp_raw, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ @@ -323,7 +363,7 @@ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + TimeStamp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ @@ -419,19 +459,37 @@ }; -void -initTimeStamp(void) +static struct PyModuleDef _module = { + PyModuleDef_HEAD_INIT, + "TimeStamp", + TimeStampModule_doc, + -1, + TimeStampModule_functions, + NULL, + NULL, + NULL, + NULL +}; + +static PyObject* +init(void) { PyObject *m; if (TimeStamp_init_gmoff() < 0) - return; + return NULL; - m = Py_InitModule4("TimeStamp", TimeStampModule_functions, - TimeStampModule_doc, NULL, PYTHON_API_VERSION); + m = PyModule_Create(&_module); if (m == NULL) - return; + return NULL; - TimeStamp_type.ob_type = &PyType_Type; + Py_TYPE(&TimeStamp_type) = &PyType_Type; TimeStamp_type.tp_getattro = PyObject_GenericGetAttr; + return m; } + +PyObject* +PyInit_TimeStamp(void) +{ + return init(); +} Index: src/persistent/__init__.py =================================================================== --- src/persistent/__init__.py (revision 103608) +++ src/persistent/__init__.py (working copy) @@ -16,10 +16,10 @@ $Id$ """ -from cPersistence import Persistent, GHOST, UPTODATE, CHANGED, STICKY -from cPickleCache import PickleCache +from persistent.cPersistence import Persistent, GHOST, UPTODATE, CHANGED, STICKY +from persistent.cPickleCache import PickleCache -from cPersistence import simple_new +from persistent.cPersistence import simple_new import copy_reg copy_reg.constructor(simple_new) Index: src/persistent/list.py =================================================================== --- src/persistent/list.py (revision 103608) +++ src/persistent/list.py (working copy) @@ -22,8 +22,8 @@ class PersistentList(UserList, persistent.Persistent): __super_setitem = UserList.__setitem__ __super_delitem = UserList.__delitem__ - __super_setslice = UserList.__setslice__ - __super_delslice = UserList.__delslice__ + __super_setslice = getattr(UserList,'__setslice__',None) # gone in 3.0 + __super_delslice = getattr(UserList,'__delslice__',None) __super_iadd = UserList.__iadd__ __super_imul = UserList.__imul__ __super_append = UserList.append Index: src/persistent/cPersistence.c =================================================================== --- src/persistent/cPersistence.c (revision 103608) +++ src/persistent/cPersistence.c (working copy) @@ -38,7 +38,7 @@ init_strings(void) { #define INIT_STRING(S) \ - if (!(py_ ## S = PyString_InternFromString(#S))) \ + if (!(py_ ## S = PyUnicode_InternFromString(#S))) \ return -1; INIT_STRING(keys); INIT_STRING(setstate); @@ -69,7 +69,7 @@ "unghost the object simultaneously.\n" "That's not legal, but ZODB can't stop it.\n" "See Collector #1350.\n", - caller, self, self->ob_type->tp_name, detail); + caller, self, Py_TYPE(self)->tp_name, detail); Py_FatalError(buf); } #endif @@ -118,7 +118,7 @@ #else PyErr_Format(PyExc_SystemError, "object at %p with type " "%.200s not in the cache despite that we just " - "unghostified it", self, self->ob_type->tp_name); + "unghostified it", self, Py_TYPE(self)->tp_name); return -1; #endif } @@ -198,7 +198,7 @@ static PyObject *s_register; if (s_register == NULL) - s_register = PyString_InternFromString("register"); + s_register = PyUnicode_InternFromString("register"); meth = PyObject_GetAttr((PyObject *)self->jar, s_register); if (meth == NULL) return -1; @@ -307,7 +307,7 @@ pickle_copy_dict(PyObject *state) { PyObject *copy, *key, *value; - char *ckey; + Py_UNICODE *ckey; Py_ssize_t pos = 0; copy = PyDict_New(); @@ -319,9 +319,9 @@ while (PyDict_Next(state, &pos, &key, &value)) { - if (key && PyString_Check(key)) + if (key && PyUnicode_Check(key)) { - ckey = PyString_AS_STRING(key); + ckey = PyUnicode_AS_UNICODE(key); if (*ckey == '_' && (ckey[1] == 'v' || ckey[1] == 'p') && ckey[2] == '_') @@ -363,7 +363,7 @@ PyObject **dictp; int n=0; - slotnames = pickle_slotnames(self->ob_type); + slotnames = pickle_slotnames(Py_TYPE(self)); if (!slotnames) return NULL; @@ -387,12 +387,12 @@ for (i = 0; i < PyList_GET_SIZE(slotnames); i++) { PyObject *name, *value; - char *cname; + Py_UNICODE *cname; name = PyList_GET_ITEM(slotnames, i); - if (PyString_Check(name)) + if (PyUnicode_Check(name)) { - cname = PyString_AS_STRING(name); + cname = PyUnicode_AS_UNICODE(name); if (*cname == '_' && (cname[1] == 'v' || cname[1] == 'p') && cname[2] == '_') @@ -538,8 +538,8 @@ if (args == NULL) goto end; - Py_INCREF(self->ob_type); - PyTuple_SET_ITEM(args, 0, (PyObject*)(self->ob_type)); + Py_INCREF(Py_TYPE(self)); + PyTuple_SET_ITEM(args, 0, (PyObject*)(Py_TYPE(self))); for (i = 0; i < l; i++) { Py_INCREF(PyTuple_GET_ITEM(bargs, i)); @@ -618,7 +618,7 @@ Py_XDECREF(self->cache); Py_XDECREF(self->jar); Py_XDECREF(self->oid); - self->ob_type->tp_free(self); + Py_TYPE(self)->tp_free(self); } static int @@ -648,7 +648,7 @@ static PyObject * convert_name(PyObject *name) { -#ifdef Py_USING_UNICODE +#if 0 /* The Unicode to string conversion is done here because the existing tp_setattro slots expect a string object as name and we wouldn't want to break those. */ @@ -658,7 +658,7 @@ } else #endif - if (!PyString_Check(name)) + if (!PyUnicode_Check(name)) { PyErr_SetString(PyExc_TypeError, "attribute name must be a string"); return NULL; @@ -679,8 +679,14 @@ __setstate__ */ +static Py_UNICODE class__[] = {'c','l','a','s','_','_',0}; +static Py_UNICODE el__[] = {'e','l','_','_',0}; +static Py_UNICODE ict__[] = {'i','c','t','_','_',0}; +static Py_UNICODE of__[] = {'o','f','_','_',0}; +static Py_UNICODE setstate__[] = {'s','e','t','s','t','a','t','e','_','_',0}; + static int -unghost_getattr(const char *s) +unghost_getattr(const Py_UNICODE *s) { if (*s++ != '_') return 1; @@ -698,18 +704,18 @@ switch (*s) { case 'c': - return strcmp(s, "class__"); + return Py_UNICODE_strcmp(s, class__); case 'd': s++; - if (!strcmp(s, "el__")) + if (!Py_UNICODE_strcmp(s, el__)) return 0; /* __del__ */ - if (!strcmp(s, "ict__")) + if (!Py_UNICODE_strcmp(s, ict__)) return 0; /* __dict__ */ return 1; case 'o': - return strcmp(s, "of__"); + return Py_UNICODE_strcmp(s, of__); case 's': - return strcmp(s, "setstate__"); + return Py_UNICODE_strcmp(s, setstate__); default: return 1; } @@ -721,12 +727,12 @@ Per_getattro(cPersistentObject *self, PyObject *name) { PyObject *result = NULL; /* guilty until proved innocent */ - char *s; + Py_UNICODE *s; name = convert_name(name); if (!name) goto Done; - s = PyString_AS_STRING(name); + s = PyUnicode_AS_UNICODE(name); if (unghost_getattr(s)) { @@ -746,12 +752,12 @@ Per__p_getattr(cPersistentObject *self, PyObject *name) { PyObject *result = NULL; /* guilty until proved innocent */ - char *s; + Py_UNICODE *s; name = convert_name(name); if (!name) goto Done; - s = PyString_AS_STRING(name); + s = PyUnicode_AS_UNICODE(name); if (*s != '_' || unghost_getattr(s)) { @@ -778,19 +784,19 @@ Per_setattro(cPersistentObject *self, PyObject *name, PyObject *v) { int result = -1; /* guilty until proved innocent */ - char *s; + Py_UNICODE *s; name = convert_name(name); if (!name) goto Done; - s = PyString_AS_STRING(name); + s = PyUnicode_AS_UNICODE(name); - if (strncmp(s, "_p_", 3) != 0) + if (s[0] != '_' || s[1] != 'p' || s[2] != '_') /* not _p_ */ { if (unghostify(self) < 0) goto Done; accessed(self); - if (strncmp(s, "_v_", 3) != 0 + if ((s[0] != '_' || s[1] != 'p' || s[2] != '_') /* not _v_ */ && self->state != cPersistent_CHANGED_STATE) { if (changed(self) < 0) @@ -809,14 +815,14 @@ Per_p_set_or_delattro(cPersistentObject *self, PyObject *name, PyObject *v) { int result = -1; /* guilty until proved innocent */ - char *s; + Py_UNICODE *s; name = convert_name(name); if (!name) goto Done; - s = PyString_AS_STRING(name); + s = PyUnicode_AS_UNICODE(name); - if (strncmp(s, "_p_", 3)) + if (s[0] != '_' || s[1] != 'p' || s[2] != '_') { if (unghostify(self) < 0) goto Done; @@ -972,9 +978,10 @@ "can't delete _p_oid of cached object"); return -1; } - if (PyObject_Cmp(self->oid, v, &result) < 0) + result = PyObject_RichCompareBool(self->oid, v, Py_EQ); + if (result < 0) return -1; - if (result) + if (!result) { PyErr_SetString(PyExc_ValueError, "can not change _p_oid of cached object"); @@ -1008,9 +1015,10 @@ "can't delete _p_jar of cached object"); return -1; } - if (PyObject_Cmp(self->jar, v, &result) < 0) + result = PyObject_RichCompareBool(self->jar, v, Py_EQ); + if (result < 0) return -1; - if (result) + if (!result) { PyErr_SetString(PyExc_ValueError, "can not change _p_jar of cached object"); @@ -1026,7 +1034,7 @@ static PyObject * Per_get_serial(cPersistentObject *self) { - return PyString_FromStringAndSize(self->serial, 8); + return PyBytes_FromStringAndSize(self->serial, 8); } static int @@ -1034,8 +1042,8 @@ { if (v) { - if (PyString_Check(v) && PyString_GET_SIZE(v) == 8) - memcpy(self->serial, PyString_AS_STRING(v), 8); + if (PyBytes_Check(v) && PyBytes_GET_SIZE(v) == 8) + memcpy(self->serial, PyBytes_AS_STRING(v), 8); else { PyErr_SetString(PyExc_ValueError, @@ -1075,13 +1083,13 @@ static PyObject * Per_get_state(cPersistentObject *self) { - return PyInt_FromLong(self->state); + return PyLong_FromLong(self->state); } static PyObject * Per_get_estimated_size(cPersistentObject *self) { - return PyInt_FromLong(_estimated_size_in_bytes(self->estimated_size)); + return PyLong_FromLong(_estimated_size_in_bytes(self->estimated_size)); } static int @@ -1089,9 +1097,9 @@ { if (v) { - if (PyInt_Check(v)) + if (PyLong_Check(v)) { - long lv = PyInt_AS_LONG(v); + long lv = PyLong_AS_LONG(v); if (lv < 0) { PyErr_SetString(PyExc_ValueError, @@ -1183,8 +1191,7 @@ #define DEFERRED_ADDRESS(ADDR) 0 static PyTypeObject Pertype = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyPersist_MetaType)) - 0, /* ob_size */ + PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyPersist_MetaType),0) "persistent.Persistent", /* tp_name */ sizeof(cPersistentObject), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -1261,73 +1268,92 @@ shared library. */ }; -void -initcPersistence(void) +static struct PyModuleDef _module = { + PyModuleDef_HEAD_INIT, + "cPersistence", + cPersistence_doc_string, + -1, + cPersistence_methods, + NULL, + NULL, + NULL, + NULL +}; + +static PyObject* +init(void) { PyObject *m, *s; PyObject *copy_reg; if (init_strings() < 0) - return; + return NULL; - m = Py_InitModule3("cPersistence", cPersistence_methods, - cPersistence_doc_string); - - Pertype.ob_type = &PyType_Type; + m = PyModule_Create(&_module); + if (!m) + return NULL; + Py_TYPE(&Pertype) = &PyType_Type; Pertype.tp_new = PyType_GenericNew; if (PyType_Ready(&Pertype) < 0) - return; + return NULL; if (PyModule_AddObject(m, "Persistent", (PyObject *)&Pertype) < 0) - return; + return NULL; cPersistenceCAPI = &truecPersistenceCAPI; s = PyCObject_FromVoidPtr(cPersistenceCAPI, NULL); if (!s) - return; + return NULL; if (PyModule_AddObject(m, "CAPI", s) < 0) - return; + return NULL; if (PyModule_AddIntConstant(m, "GHOST", cPersistent_GHOST_STATE) < 0) - return; + return NULL; if (PyModule_AddIntConstant(m, "UPTODATE", cPersistent_UPTODATE_STATE) < 0) - return; + return NULL; if (PyModule_AddIntConstant(m, "CHANGED", cPersistent_CHANGED_STATE) < 0) - return; + return NULL; if (PyModule_AddIntConstant(m, "STICKY", cPersistent_STICKY_STATE) < 0) - return; + return NULL; py_simple_new = PyObject_GetAttrString(m, "simple_new"); if (!py_simple_new) - return; + return NULL; - copy_reg = PyImport_ImportModule("copy_reg"); + copy_reg = PyImport_ImportModule("copyreg"); if (!copy_reg) - return; + return NULL; copy_reg_slotnames = PyObject_GetAttrString(copy_reg, "_slotnames"); if (!copy_reg_slotnames) { Py_DECREF(copy_reg); - return; + return NULL; } __newobj__ = PyObject_GetAttrString(copy_reg, "__newobj__"); if (!__newobj__) { Py_DECREF(copy_reg); - return; + return NULL; } if (!TimeStamp) { - m = PyImport_ImportModule("persistent.TimeStamp"); - if (!m) - return; - TimeStamp = PyObject_GetAttrString(m, "TimeStamp"); - Py_DECREF(m); - /* fall through to immediate return on error */ + PyObject *m2 = PyImport_ImportModule("persistent.TimeStamp"); + if (!m2) + return NULL; + TimeStamp = PyObject_GetAttrString(m2, "TimeStamp"); + Py_DECREF(m2); + /* fall through to immediate return NULL on error */ } + return m; } + +PyObject* +PyInit_cPersistence(void) +{ + return init(); +} Index: src/BTrees/_OOBTree.c =================================================================== --- src/BTrees/_OOBTree.c (revision 103608) +++ src/BTrees/_OOBTree.c (working copy) @@ -23,7 +23,7 @@ #define PERSISTENT #define MOD_NAME_PREFIX "OO" -#define INITMODULE init_OOBTree +#define MOD_NAME _OOBTree #define DEFAULT_MAX_BUCKET_SIZE 30 #define DEFAULT_MAX_BTREE_SIZE 250 Index: src/BTrees/BTreeItemsTemplate.c =================================================================== --- src/BTrees/BTreeItemsTemplate.c (revision 103608) +++ src/BTrees/BTreeItemsTemplate.c (working copy) @@ -402,12 +402,15 @@ } static PyNumberMethods BTreeItems_as_number_for_nonzero = { - 0,0,0,0,0,0,0,0,0,0, + 0,0,0, +#if PY_MAJOR_VERSION < 3 + 0, /* nb_divide */ +#endif + 0,0,0,0,0,0, (inquiry)BTreeItems_nonzero}; static PyTypeObject BTreeItemsType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT(NULL,0) MOD_NAME_PREFIX "BTreeItems", /*tp_name*/ sizeof(BTreeItems), /*tp_basicsize*/ 0, /*tp_itemsize*/ @@ -416,7 +419,7 @@ (printfunc)0, /*tp_print*/ (getattrfunc)0, /*obsolete tp_getattr*/ (setattrfunc)0, /*obsolete tp_setattr*/ - (cmpfunc)0, /*tp_compare*/ + 0, /*tp_compare*/ (reprfunc)0, /*tp_repr*/ &BTreeItems_as_number_for_nonzero, /*tp_as_number*/ &BTreeItems_as_sequence, /*tp_as_sequence*/ @@ -659,8 +662,7 @@ } static PyTypeObject BTreeIter_Type = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ + PyVarObject_HEAD_INIT(NULL,0) MOD_NAME_PREFIX "-iterator", /* tp_name */ sizeof(BTreeIter), /* tp_basicsize */ 0, /* tp_itemsize */ Index: src/BTrees/IOBTree.py =================================================================== --- src/BTrees/IOBTree.py (revision 103608) +++ src/BTrees/IOBTree.py (working copy) @@ -16,6 +16,6 @@ import BTrees.Interfaces # hack to overcome dynamic-linking headache. -from _IOBTree import * +from BTrees._IOBTree import * zope.interface.moduleProvides(BTrees.Interfaces.IIntegerObjectBTreeModule) Index: src/BTrees/OIBTree.py =================================================================== --- src/BTrees/OIBTree.py (revision 103608) +++ src/BTrees/OIBTree.py (working copy) @@ -16,6 +16,6 @@ import BTrees.Interfaces # hack to overcome dynamic-linking headache. -from _OIBTree import * +from BTrees._OIBTree import * zope.interface.moduleProvides(BTrees.Interfaces.IObjectIntegerBTreeModule) Index: src/BTrees/intvaluemacros.h =================================================================== --- src/BTrees/intvaluemacros.h (revision 103608) +++ src/BTrees/intvaluemacros.h (working copy) @@ -1,6 +1,10 @@ #define VALUEMACROS_H "$Id$\n" +/* Python 3.x: PyInt_Check will be defined to return 0. + PyInt_FromLong will return longs. +*/ + #ifdef ZODB_64BIT_INTS #define NEED_LONG_LONG_SUPPORT #define VALUE_TYPE PY_LONG_LONG @@ -21,8 +25,12 @@ #define COPY_VALUE_TO_OBJECT(O, K) O=PyInt_FromLong(K) #define COPY_VALUE_FROM_ARG(TARGET, ARG, STATUS) \ if (PyInt_Check(ARG)) TARGET=PyInt_AsLong(ARG); else { \ + if (PyLong_Check(ARG)) { long res=PyLong_AsLong(ARG); \ + if (res == -1 && PyErr_Occurred()) { (STATUS)=0; (TARGET)=0; } \ + else TARGET=res; } \ + else { \ PyErr_SetString(PyExc_TypeError, "expected integer value"); \ - (STATUS)=0; (TARGET)=0; } + (STATUS)=0; (TARGET)=0; }} #endif #undef VALUE_TYPE_IS_PYOBJECT Index: src/BTrees/OLBTree.py =================================================================== --- src/BTrees/OLBTree.py (revision 103608) +++ src/BTrees/OLBTree.py (working copy) @@ -16,6 +16,6 @@ import BTrees.Interfaces # hack to overcome dynamic-linking headache. -from _OLBTree import * +from BTrees._OLBTree import * zope.interface.moduleProvides(BTrees.Interfaces.IObjectIntegerBTreeModule) Index: src/BTrees/OOBTree.py =================================================================== --- src/BTrees/OOBTree.py (revision 103608) +++ src/BTrees/OOBTree.py (working copy) @@ -16,6 +16,6 @@ import BTrees.Interfaces # hack to overcome dynamic-linking headache. -from _OOBTree import * +from BTrees._OOBTree import * zope.interface.moduleProvides(BTrees.Interfaces.IObjectObjectBTreeModule) Index: src/BTrees/BucketTemplate.c =================================================================== --- src/BTrees/BucketTemplate.c (revision 103608) +++ src/BTrees/BucketTemplate.c (working copy) @@ -1355,7 +1355,8 @@ int result = -1; if (asobj != NULL) { - result = PyInt_AsLong(asobj) ? 1 : 0; + /* asobj will be Python 0 or 1 */ + result = PyObject_IsTrue(asobj); Py_DECREF(asobj); } return result; @@ -1505,7 +1506,7 @@ if (!PyArg_ParseTuple(args, "OOO", &s[0], &s[1], &s[2])) return NULL; - return _bucket__p_resolveConflict((PyObject *)self->ob_type, s); + return _bucket__p_resolveConflict((PyObject *)Py_TYPE(self), s); } #endif @@ -1710,6 +1711,7 @@ static PyObject * bucket_repr(Bucket *self) { +#if PY_MAJOR_VERSION < 3 PyObject *i, *r; char repr[10000]; int rv; @@ -1723,7 +1725,7 @@ return NULL; } rv = PyOS_snprintf(repr, sizeof(repr), - "%s(%s)", self->ob_type->tp_name, + "%s(%s)", Py_TYPE(self)->tp_name, PyString_AS_STRING(r)); if (rv > 0 && rv < sizeof(repr)) { Py_DECREF(r); @@ -1735,22 +1737,44 @@ PyObject *s; /* 3 for the parens and the null byte */ - size = strlen(self->ob_type->tp_name) + PyString_GET_SIZE(r) + 3; + size = strlen(Py_TYPE(self)->tp_name) + PyString_GET_SIZE(r) + 3; s = PyString_FromStringAndSize(NULL, size); if (!s) { Py_DECREF(r); return r; } PyOS_snprintf(PyString_AS_STRING(s), size, - "%s(%s)", self->ob_type->tp_name, PyString_AS_STRING(r)); + "%s(%s)", Py_TYPE(self)->tp_name, PyString_AS_STRING(r)); Py_DECREF(r); return s; } +#else + PyObject *r1 = NULL, *r2 = NULL, *i = NULL; + + i = bucket_items(self, NULL, NULL); + if (!i) + return NULL; + + r1 = PyObject_Repr(i); + Py_DECREF(i); + if (!r1) + return NULL; + + r2 = PyObject_GetAttrString((PyObject*)Py_TYPE(self), "__name__"); + if (!r2) { + Py_DECREF(r1); + return NULL; + } + + i = PyUnicode_FromFormat("%U(%U)", r1, r2); + Py_DECREF(r1); + Py_DECREF(r2); + return i; +#endif } static PyTypeObject BucketType = { - PyObject_HEAD_INIT(NULL) /* PyPersist_Type */ - 0, /* ob_size */ + PyVarObject_HEAD_INIT(NULL,0) MODULE_NAME MOD_NAME_PREFIX "Bucket",/* tp_name */ sizeof(Bucket), /* tp_basicsize */ 0, /* tp_itemsize */ Index: src/BTrees/floatvaluemacros.h =================================================================== --- src/BTrees/floatvaluemacros.h (revision 103608) +++ src/BTrees/floatvaluemacros.h (working copy) @@ -14,6 +14,7 @@ #define COPY_VALUE_FROM_ARG(TARGET, ARG, STATUS) \ if (PyFloat_Check(ARG)) TARGET = (float)PyFloat_AsDouble(ARG); \ else if (PyInt_Check(ARG)) TARGET = (float)PyInt_AsLong(ARG); \ + else if (PyLong_Check(ARG)) TARGET = (float)PyLong_AsDouble(ARG); \ else { \ PyErr_SetString(PyExc_TypeError, "expected float or int value"); \ (STATUS)=0; (TARGET)=0; } Index: src/BTrees/intkeymacros.h =================================================================== --- src/BTrees/intkeymacros.h (revision 103608) +++ src/BTrees/intkeymacros.h (working copy) @@ -19,12 +19,16 @@ #else /* C int as key */ #define KEY_TYPE int -#define KEY_CHECK PyInt_Check +#define KEY_CHECK int_check #define COPY_KEY_TO_OBJECT(O, K) O=PyInt_FromLong(K) #define COPY_KEY_FROM_ARG(TARGET, ARG, STATUS) \ if (PyInt_Check(ARG)) TARGET=PyInt_AS_LONG(ARG); else { \ + if (PyLong_Check(ARG)) { long res=PyLong_AsLong(ARG); \ + if (res == -1 && PyErr_Occurred()) { (STATUS)=0; (TARGET)=0; } \ + else TARGET=res; } \ + else { \ PyErr_SetString(PyExc_TypeError, "expected integer key"); \ - (STATUS)=0; (TARGET)=0; } + (STATUS)=0; (TARGET)=0; }} #endif #undef KEY_TYPE_IS_PYOBJECT Index: src/BTrees/_IFBTree.c =================================================================== --- src/BTrees/_IFBTree.c (revision 103608) +++ src/BTrees/_IFBTree.c (working copy) @@ -25,7 +25,7 @@ #define PERSISTENT #define MOD_NAME_PREFIX "IF" -#define INITMODULE init_IFBTree +#define MODNAME _IFBTree #define DEFAULT_MAX_BUCKET_SIZE 120 #define DEFAULT_MAX_BTREE_SIZE 500 Index: src/BTrees/_LFBTree.c =================================================================== --- src/BTrees/_LFBTree.c (revision 103608) +++ src/BTrees/_LFBTree.c (working copy) @@ -25,7 +25,7 @@ #define PERSISTENT #define MOD_NAME_PREFIX "LF" -#define INITMODULE init_LFBTree +#define MOD_NAME _LFBTree #define DEFAULT_MAX_BUCKET_SIZE 120 #define DEFAULT_MAX_BTREE_SIZE 500 Index: src/BTrees/SetOpTemplate.c =================================================================== --- src/BTrees/SetOpTemplate.c (revision 103608) +++ src/BTrees/SetOpTemplate.c (working copy) @@ -461,7 +461,7 @@ o1 = set_operation(o1, o2, 1, 1, w1, w2, 0, 1, 0); if (o1) ASSIGN(o1, Py_BuildValue(VALUE_PARSE "O", - ((o1->ob_type == (PyTypeObject*)(&SetType)) ? w2+w1 : 1), + ((Py_TYPE(o1) == (PyTypeObject*)(&SetType)) ? w2+w1 : 1), o1)); return o1; @@ -506,8 +506,8 @@ goto Error; /* If set is a bucket, do a straight resize + memcpy. */ - if (set->ob_type == (PyTypeObject*)&SetType || - set->ob_type == (PyTypeObject*)&BucketType) + if (Py_TYPE(set) == (PyTypeObject*)&SetType || + Py_TYPE(set) == (PyTypeObject*)&BucketType) { Bucket *b = BUCKET(set); int status = 0; Index: src/BTrees/_LLBTree.c =================================================================== --- src/BTrees/_LLBTree.c (revision 103608) +++ src/BTrees/_LLBTree.c (working copy) @@ -25,7 +25,7 @@ #define PERSISTENT #define MOD_NAME_PREFIX "LL" -#define INITMODULE init_LLBTree +#define MOD_NAME _LLBTree #define DEFAULT_MAX_BUCKET_SIZE 120 #define DEFAULT_MAX_BTREE_SIZE 500 Index: src/BTrees/LFBTree.py =================================================================== --- src/BTrees/LFBTree.py (revision 103608) +++ src/BTrees/LFBTree.py (working copy) @@ -16,6 +16,6 @@ import BTrees.Interfaces # hack to overcome dynamic-linking headache. -from _LFBTree import * +from BTrees._LFBTree import * zope.interface.moduleProvides(BTrees.Interfaces.IIntegerFloatBTreeModule) Index: src/BTrees/_OLBTree.c =================================================================== --- src/BTrees/_OLBTree.c (revision 103608) +++ src/BTrees/_OLBTree.c (working copy) @@ -23,7 +23,7 @@ #define PERSISTENT #define MOD_NAME_PREFIX "OL" -#define INITMODULE init_OLBTree +#define MOD_NAME _OLBTree #define DEFAULT_MAX_BUCKET_SIZE 60 #define DEFAULT_MAX_BTREE_SIZE 250 Index: src/BTrees/BTreeTemplate.c =================================================================== --- src/BTrees/BTreeTemplate.c (revision 103608) +++ src/BTrees/BTreeTemplate.c (working copy) @@ -59,10 +59,10 @@ * on self's pointers being intact. */ #ifdef PERSISTENT - CHECK(self->firstbucket->ob_refcnt >= 1, + CHECK(Py_REFCNT(self->firstbucket) >= 1, "Non-empty BTree firstbucket has refcount < 1"); #else - CHECK(self->firstbucket->ob_refcnt >= 2, + CHECK(Py_REFCNT(self->firstbucket) >= 2, "Non-empty BTree firstbucket has refcount < 2"); #endif @@ -108,9 +108,9 @@ CHECK(child->len >= 1, "Bucket length < 1"); /* no empty buckets! */ CHECK(child->len <= child->size, "Bucket len > size"); #ifdef PERSISTENT - CHECK(child->ob_refcnt >= 1, "Bucket has refcount < 1"); + CHECK(Py_REFCNT(child) >= 1, "Bucket has refcount < 1"); #else - CHECK(child->ob_refcnt >= 2, "Bucket has refcount < 2"); + CHECK(Py_REFCNT(child) >= 2, "Bucket has refcount < 2"); #endif if (i == self->len - 1) bucketafter = nextbucket; @@ -190,7 +190,7 @@ if (self->len == 0) { /* empty BTree */ if (has_key) - result = PyInt_FromLong(0); + result = PyLong_FromLong(0); else PyErr_SetObject(PyExc_KeyError, keyarg); } @@ -236,7 +236,7 @@ Sized *result; /* _bucket_type_str defined in BTreeModuleTemplate.c */ - factory = PyObject_GetAttr((PyObject *)self->ob_type, _bucket_type_str); + factory = PyObject_GetAttr((PyObject *)Py_TYPE(self), _bucket_type_str); if (factory == NULL) return NULL; /* TODO: Should we check that the factory actually returns something @@ -318,7 +318,7 @@ BTreeItem *d; /* Create a child BTree, and a new data vector for self. */ - child = BTREE(PyObject_CallObject(OBJECT(self->ob_type), NULL)); + child = BTREE(PyObject_CallObject(OBJECT(Py_TYPE(self)), NULL)); if (!child) return -1; d = BTree_Malloc(sizeof(BTreeItem) * 2); @@ -389,7 +389,7 @@ d = self->data + index; v = d->child; /* Create a new object of the same type as the target value */ - e = (Sized *)PyObject_CallObject((PyObject *)v->ob_type, NULL); + e = (Sized *)PyObject_CallObject((PyObject *)Py_TYPE(v), NULL); if (e == NULL) return -1; @@ -546,10 +546,10 @@ * count": we can only rely on self's pointers being intact. */ #ifdef PERSISTENT - ASSERT(self->firstbucket->ob_refcnt > 0, + ASSERT(Py_REFCNT(self->firstbucket) > 0, "Invalid firstbucket pointer", -1); #else - ASSERT(self->firstbucket->ob_refcnt > 1, + ASSERT(Py_REFCNT(self->firstbucket) > 1, "Invalid firstbucket pointer", -1); #endif Py_DECREF(self->firstbucket); @@ -966,7 +966,7 @@ goto err; if (self->len == 1 - && self->data->child->ob_type != self->ob_type + && Py_TYPE(self->data->child) != Py_TYPE(self) #ifdef PERSISTENT && BUCKET(self->data->child)->oid == NULL #endif @@ -1826,7 +1826,7 @@ int result = -1; if (asobj != NULL) { - result = PyInt_AsLong(asobj) ? 1 : 0; + result = PyLong_AsLong(asobj) ? 1 : 0; Py_DECREF(asobj); } return result; @@ -1841,7 +1841,7 @@ UNLESS (PyArg_ParseTuple(args, "OO", &key, &v)) return NULL; if ((grew=_BTree_set(self, key, v, 1, 0)) < 0) return NULL; - return PyInt_FromLong(grew); + return PyLong_FromLong(grew); } /**************************************************************************/ @@ -1906,7 +1906,7 @@ */ static struct PyMemberDef BTree_members[] = { - {"_firstbucket", T_OBJECT, offsetof(BTree, firstbucket), RO}, + {"_firstbucket", T_OBJECT, offsetof(BTree, firstbucket), READONLY}, {NULL} }; @@ -2038,8 +2038,8 @@ goto Done; \ } - if (self->ob_type == &BTreeType) - assert(self->ob_type->tp_dictoffset == 0); + if (Py_TYPE(self) == &BTreeType) + assert(Py_TYPE(self)->tp_dictoffset == 0); /* Call our base type's traverse function. Because BTrees are * subclasses of Peristent, there must be one. @@ -2155,12 +2155,15 @@ } static PyNumberMethods BTree_as_number_for_nonzero = { - 0,0,0,0,0,0,0,0,0,0, + 0,0,0, +#if 0 + 0, +#endif + 0,0,0,0,0,0, (inquiry)BTree_nonzero}; static PyTypeObject BTreeType = { - PyObject_HEAD_INIT(NULL) /* PyPersist_Type */ - 0, /* ob_size */ + PyVarObject_HEAD_INIT(NULL,0) /* PyPersist_Type */ MODULE_NAME MOD_NAME_PREFIX "BTree",/* tp_name */ sizeof(BTree), /* tp_basicsize */ 0, /* tp_itemsize */ Index: src/BTrees/LLBTree.py =================================================================== --- src/BTrees/LLBTree.py (revision 103608) +++ src/BTrees/LLBTree.py (working copy) @@ -16,6 +16,6 @@ import BTrees.Interfaces # hack to overcome dynamic-linking headache. -from _LLBTree import * +from BTrees._LLBTree import * zope.interface.moduleProvides(BTrees.Interfaces.IIntegerIntegerBTreeModule) Index: src/BTrees/fsBTree.py =================================================================== --- src/BTrees/fsBTree.py (revision 103608) +++ src/BTrees/fsBTree.py (working copy) @@ -16,4 +16,4 @@ # expected to be "public" excpect to FileStorage. # hack to overcome dynamic-linking headache. -from _fsBTree import * +from BTrees._fsBTree import * Index: src/BTrees/LOBTree.py =================================================================== --- src/BTrees/LOBTree.py (revision 103608) +++ src/BTrees/LOBTree.py (working copy) @@ -16,6 +16,6 @@ import BTrees.Interfaces # hack to overcome dynamic-linking headache. -from _LOBTree import * +from BTrees._LOBTree import * zope.interface.moduleProvides(BTrees.Interfaces.IIntegerObjectBTreeModule) Index: src/BTrees/BTreeModuleTemplate.c =================================================================== --- src/BTrees/BTreeModuleTemplate.c (revision 103608) +++ src/BTrees/BTreeModuleTemplate.c (working copy) @@ -16,6 +16,47 @@ /* include structmember.h for offsetof */ #include "structmember.h" +#ifndef PyVarObject_HEAD_INIT +#define PyVarObject_HEAD_INIT(TYPE, SIZE) PyObject_HEAD_INIT(TYPE) SIZE, +#endif + +#ifndef Py_TYPE +#define Py_TYPE(O) ((O)->ob_type) +#endif + +/* for int{key|value}macros.h */ +#if PY_MAJOR_VERSION < 3 +#define int_check(x) (PyInt_Check(x) || PyLong_Check(x)) +#else +#define int_check(x) PyLong_Check(x) +#define PyInt_Check(x) 0 +#define PyInt_AsLong(x) PyLong_AsLong(x) +#define PyInt_AS_LONG(x) PyLong_AS_LONG(x) +#define PyInt_FromLong(x) PyLong_FromLong(x) +#endif + +#if PY_MAJOR_VERSION < 3 +#define Text_InternFromString(s) PyString_InternFromString(s) +#else +#define Text_InternFromString(s) PyUnicode_InternFromString(s) +#endif + +#ifdef NEED_3WAY +#if PY_MAJOR_VERSION < 3 +#define compare_3way(o1, o2) PyObject_Compare(o1, o2) +#else +static int compare_3way(PyObject *o1, PyObject *o2) +{ + int res = PyObject_RichCompareBool(o1, o2, Py_EQ); + if(res == -1)return -2; + if(res)return 0; + res = PyObject_RichCompareBool(o1, o2, Py_LT); + if(res == -1)return -2; + return res ? -1 : +1; +} +#endif /* 3.x */ +#endif /* NEED_3WAY */ + #ifdef PERSISTENT #include "persistent/cPersistence.h" #else @@ -65,7 +106,7 @@ #define MAX_BTREE_SIZE(B) DEFAULT_MAX_BTREE_SIZE #define MAX_BUCKET_SIZE(B) DEFAULT_MAX_BUCKET_SIZE -#define SameType_Check(O1, O2) ((O1)->ob_type==(O2)->ob_type) +#define SameType_Check(O1, O2) (Py_TYPE(O1)==Py_TYPE(O2)) #define ASSERT(C, S, R) if (! (C)) { \ PyErr_SetString(PyExc_AssertionError, (S)); return (R); } @@ -98,13 +139,17 @@ static PyObject * longlong_as_object(PY_LONG_LONG val) { +#if 0 static PY_LONG_LONG maxint = 0; if (maxint == 0) maxint = PyInt_GetMax(); if ((val > maxint) || (val < (-maxint-1))) +#endif return PyLong_FromLongLong(val); +#if 0 return PyInt_FromLong((long)val); +#endif } #endif @@ -291,7 +336,7 @@ { PyObject *v; - v = PyInt_FromLong(i); + v = PyLong_FromLong(i); if (!v) { v = Py_None; Py_INCREF(v); @@ -451,7 +496,7 @@ int init_persist_type(PyTypeObject *type) { - type->ob_type = &PyType_Type; + Py_TYPE(type) = &PyType_Type; type->tp_base = cPersistenceCAPI->pertype; if (PyType_Ready(type) < 0) @@ -460,23 +505,37 @@ return 1; } -void -INITMODULE (void) +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef _module = { + PyModuleDef_HEAD_INIT, + "_" MOD_NAME_PREFIX "BTree", + BTree_module_documentation, + -1, + module_methods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +static PyObject* +init (void) { PyObject *m, *d, *c; - sort_str = PyString_InternFromString("sort"); + sort_str = Text_InternFromString("sort"); if (!sort_str) - return; - reverse_str = PyString_InternFromString("reverse"); + return NULL; + reverse_str = Text_InternFromString("reverse"); if (!reverse_str) - return; - __setstate___str = PyString_InternFromString("__setstate__"); + return NULL; + __setstate___str = Text_InternFromString("__setstate__"); if (!__setstate___str) - return; - _bucket_type_str = PyString_InternFromString("_bucket_type"); + return NULL; + _bucket_type_str = Text_InternFromString("_bucket_type"); if (!_bucket_type_str) - return; + return NULL; /* Grab the ConflictError class */ m = PyImport_ImportModule("ZODB.POSException"); @@ -495,57 +554,61 @@ /* Initialize the PyPersist_C_API and the type objects. */ cPersistenceCAPI = PyCObject_Import("persistent.cPersistence", "CAPI"); if (cPersistenceCAPI == NULL) - return; + return NULL; - BTreeItemsType.ob_type = &PyType_Type; - BTreeIter_Type.ob_type = &PyType_Type; + Py_TYPE(&BTreeItemsType) = &PyType_Type; + Py_TYPE(&BTreeIter_Type) = &PyType_Type; BTreeIter_Type.tp_getattro = PyObject_GenericGetAttr; BucketType.tp_new = PyType_GenericNew; SetType.tp_new = PyType_GenericNew; BTreeType.tp_new = PyType_GenericNew; TreeSetType.tp_new = PyType_GenericNew; if (!init_persist_type(&BucketType)) - return; + return NULL; if (!init_persist_type(&BTreeType)) - return; + return NULL; if (!init_persist_type(&SetType)) - return; + return NULL; if (!init_persist_type(&TreeSetType)) - return; + return NULL; if (PyDict_SetItem(BTreeType.tp_dict, _bucket_type_str, (PyObject *)&BucketType) < 0) { fprintf(stderr, "btree failed\n"); - return; + return NULL; } if (PyDict_SetItem(TreeSetType.tp_dict, _bucket_type_str, (PyObject *)&SetType) < 0) { fprintf(stderr, "bucket failed\n"); - return; + return NULL; } /* Create the module and add the functions */ +#if PY_MAJOR_VERSION < 3 m = Py_InitModule4("_" MOD_NAME_PREFIX "BTree", - module_methods, BTree_module_documentation, - (PyObject *)NULL, PYTHON_API_VERSION); + module_methods, BTree_module_documentation, + (PyObject *)NULL, PYTHON_API_VERSION); +#else + m = PyModule_Create(&_module); +#endif /* Add some symbolic constants to the module */ d = PyModule_GetDict(m); if (PyDict_SetItemString(d, MOD_NAME_PREFIX "Bucket", (PyObject *)&BucketType) < 0) - return; + return NULL; if (PyDict_SetItemString(d, MOD_NAME_PREFIX "BTree", (PyObject *)&BTreeType) < 0) - return; + return NULL; if (PyDict_SetItemString(d, MOD_NAME_PREFIX "Set", (PyObject *)&SetType) < 0) - return; + return NULL; if (PyDict_SetItemString(d, MOD_NAME_PREFIX "TreeSet", (PyObject *)&TreeSetType) < 0) - return; + return NULL; if (PyDict_SetItemString(d, MOD_NAME_PREFIX "TreeIterator", (PyObject *)&BTreeIter_Type) < 0) - return; + return NULL; /* We also want to be able to access these constants without the prefix * so that code can more easily exchange modules (particularly the integer * and long modules, but also others). The TreeIterator is only internal, @@ -553,21 +616,37 @@ */ if (PyDict_SetItemString(d, "Bucket", (PyObject *)&BucketType) < 0) - return; + return NULL; if (PyDict_SetItemString(d, "BTree", (PyObject *)&BTreeType) < 0) - return; + return NULL; if (PyDict_SetItemString(d, "Set", (PyObject *)&SetType) < 0) - return; + return NULL; if (PyDict_SetItemString(d, "TreeSet", (PyObject *)&TreeSetType) < 0) - return; + return NULL; #if defined(ZODB_64BIT_INTS) && defined(NEED_LONG_LONG_SUPPORT) if (PyDict_SetItemString(d, "using64bits", Py_True) < 0) - return; + return NULL; #else if (PyDict_SetItemString(d, "using64bits", Py_False) < 0) - return; + return NULL; #endif + return m; } + +#define CONCAT(N1, N2) N1##N2 +#if PY_MAJOR_VERSION < 3 +void +CONCAT(init, MODNAME)(void) +{ + init(); +} +#else +PyObject* +CONCAT(PyInit_, MODNAME)(void) +{ + return init(); +} +#endif Index: src/BTrees/TreeSetTemplate.c =================================================================== --- src/BTrees/TreeSetTemplate.c (revision 103608) +++ src/BTrees/TreeSetTemplate.c (working copy) @@ -25,7 +25,7 @@ i = _BTree_set(self, key, Py_None, 1, 1); if (i < 0) return NULL; - return PyInt_FromLong(i); + return PyLong_FromLong(i); } /* _Set_update and _TreeSet_update are identical except for the @@ -85,7 +85,7 @@ return NULL; } - return PyInt_FromLong(n); + return PyLong_FromLong(n); } @@ -204,8 +204,7 @@ } static PyTypeObject TreeSetType = { - PyObject_HEAD_INIT(NULL) /* PyPersist_Type */ - 0, /* ob_size */ + PyVarObject_HEAD_INIT(NULL,0) MODULE_NAME MOD_NAME_PREFIX "TreeSet",/* tp_name */ sizeof(BTree), /* tp_basicsize */ 0, /* tp_itemsize */ Index: src/BTrees/objectvaluemacros.h =================================================================== --- src/BTrees/objectvaluemacros.h (revision 103608) +++ src/BTrees/objectvaluemacros.h (working copy) @@ -3,7 +3,8 @@ #define VALUE_TYPE PyObject * #define VALUE_TYPE_IS_PYOBJECT -#define TEST_VALUE(VALUE, TARGET) PyObject_Compare((VALUE),(TARGET)) +#define NEED_3WAY +#define TEST_VALUE(VALUE, TARGET) compare_3way((VALUE),(TARGET)) #define DECLARE_VALUE(NAME) VALUE_TYPE NAME #define INCREF_VALUE(k) Py_INCREF(k) #define DECREF_VALUE(k) Py_DECREF(k) Index: src/BTrees/_IIBTree.c =================================================================== --- src/BTrees/_IIBTree.c (revision 103608) +++ src/BTrees/_IIBTree.c (working copy) @@ -25,7 +25,7 @@ #define PERSISTENT #define MOD_NAME_PREFIX "II" -#define INITMODULE init_IIBTree +#define MOD_NAME _IIBTree #define DEFAULT_MAX_BUCKET_SIZE 120 #define DEFAULT_MAX_BTREE_SIZE 500 Index: src/BTrees/IFBTree.py =================================================================== --- src/BTrees/IFBTree.py (revision 103608) +++ src/BTrees/IFBTree.py (working copy) @@ -16,6 +16,6 @@ import BTrees.Interfaces # hack to overcome dynamic-linking headache. -from _IFBTree import * +from BTrees._IFBTree import * zope.interface.moduleProvides(BTrees.Interfaces.IIntegerFloatBTreeModule) Index: src/BTrees/SetTemplate.c =================================================================== --- src/BTrees/SetTemplate.c (revision 103608) +++ src/BTrees/SetTemplate.c (working copy) @@ -22,7 +22,7 @@ UNLESS (PyArg_ParseTuple(args, "O", &key)) return NULL; if ( (i=_bucket_set(self, key, Py_None, 1, 1, 0)) < 0) return NULL; - return PyInt_FromLong(i); + return PyLong_FromLong(i); } /* _Set_update and _TreeSet_update are identical except for the @@ -82,7 +82,7 @@ return NULL; } - return PyInt_FromLong(n); + return PyLong_FromLong(n); } static PyObject * @@ -240,12 +240,12 @@ PyObject *r, *t; if (!format) - format = PyString_FromString(MOD_NAME_PREFIX "Set(%s)"); + format = PyUnicode_FromString(MOD_NAME_PREFIX "Set(%s)"); UNLESS (t = PyTuple_New(1)) return NULL; UNLESS (r = bucket_keys(self, NULL, NULL)) goto err; PyTuple_SET_ITEM(t, 0, r); r = t; - ASSIGN(r, PyString_Format(format, r)); + ASSIGN(r, PyUnicode_Format(format, r)); return r; err: Py_DECREF(t); @@ -296,8 +296,7 @@ }; static PyTypeObject SetType = { - PyObject_HEAD_INIT(NULL) /* PyPersist_Type */ - 0, /* ob_size */ + PyVarObject_HEAD_INIT(NULL,0) MODULE_NAME MOD_NAME_PREFIX "Set", /* tp_name */ sizeof(Bucket), /* tp_basicsize */ 0, /* tp_itemsize */ Index: src/BTrees/_OIBTree.c =================================================================== --- src/BTrees/_OIBTree.c (revision 103608) +++ src/BTrees/_OIBTree.c (working copy) @@ -23,7 +23,7 @@ #define PERSISTENT #define MOD_NAME_PREFIX "OI" -#define INITMODULE init_OIBTree +#define MOD_NAME _OIBTree #define DEFAULT_MAX_BUCKET_SIZE 60 #define DEFAULT_MAX_BTREE_SIZE 250 Index: src/BTrees/_IOBTree.c =================================================================== --- src/BTrees/_IOBTree.c (revision 103608) +++ src/BTrees/_IOBTree.c (working copy) @@ -25,7 +25,7 @@ #define MOD_NAME_PREFIX "IO" #define DEFAULT_MAX_BUCKET_SIZE 60 #define DEFAULT_MAX_BTREE_SIZE 500 -#define INITMODULE init_IOBTree +#define MOD_NAME _IOBTree #include "intkeymacros.h" #include "objectvaluemacros.h" Index: src/BTrees/_fsBTree.c =================================================================== --- src/BTrees/_fsBTree.c (revision 103608) +++ src/BTrees/_fsBTree.c (working copy) @@ -31,7 +31,7 @@ #define PERSISTENT #define MOD_NAME_PREFIX "fs" -#define INITMODULE init_fsBTree +#define MOD_NAME _fsBTree #define DEFAULT_MAX_BUCKET_SIZE 500 #define DEFAULT_MAX_BTREE_SIZE 500 @@ -40,14 +40,14 @@ #define KEYMACROS_H "$Id$\n" #define KEY_TYPE char2 #undef KEY_TYPE_IS_PYOBJECT -#define KEY_CHECK(K) (PyString_Check(K) && PyString_GET_SIZE(K)==2) +#define KEY_CHECK(K) (PyBytes_Check(K) && PyBytes_GET_SIZE(K)==2) #define TEST_KEY_SET_OR(V, K, T) if ( ( (V) = ((*(K) < *(T) || (*(K) == *(T) && (K)[1] < (T)[1])) ? -1 : ((*(K) == *(T) && (K)[1] == (T)[1]) ? 0 : 1)) ), 0 ) #define DECREF_KEY(KEY) #define INCREF_KEY(k) #define COPY_KEY(KEY, E) (*(KEY)=*(E), (KEY)[1]=(E)[1]) -#define COPY_KEY_TO_OBJECT(O, K) O=PyString_FromStringAndSize((const char*)K,2) +#define COPY_KEY_TO_OBJECT(O, K) O=PyBytes_FromStringAndSize((const char*)K,2) #define COPY_KEY_FROM_ARG(TARGET, ARG, STATUS) \ - if (KEY_CHECK(ARG)) memcpy(TARGET, PyString_AS_STRING(ARG), 2); else { \ + if (KEY_CHECK(ARG)) memcpy(TARGET, PyBytes_AS_STRING(ARG), 2); else { \ PyErr_SetString(PyExc_TypeError, "expected two-character string key"); \ (STATUS)=0; } @@ -59,10 +59,10 @@ #define DECREF_VALUE(k) #define INCREF_VALUE(k) #define COPY_VALUE(V, E) (memcpy(V, E, 6)) -#define COPY_VALUE_TO_OBJECT(O, K) O=PyString_FromStringAndSize((const char*)K,6) +#define COPY_VALUE_TO_OBJECT(O, K) O=PyBytes_FromStringAndSize((const char*)K,6) #define COPY_VALUE_FROM_ARG(TARGET, ARG, STATUS) \ - if ((PyString_Check(ARG) && PyString_GET_SIZE(ARG)==6)) \ - memcpy(TARGET, PyString_AS_STRING(ARG), 6); else { \ + if ((PyBytes_Check(ARG) && PyBytes_GET_SIZE(ARG)==6)) \ + memcpy(TARGET, PyBytes_AS_STRING(ARG), 6); else { \ PyErr_SetString(PyExc_TypeError, "expected six-character string key"); \ (STATUS)=0; } Index: src/BTrees/IIBTree.py =================================================================== --- src/BTrees/IIBTree.py (revision 103608) +++ src/BTrees/IIBTree.py (working copy) @@ -16,6 +16,6 @@ import BTrees.Interfaces # hack to overcome dynamic-linking headache. -from _IIBTree import * +from BTrees._IIBTree import * zope.interface.moduleProvides(BTrees.Interfaces.IIntegerIntegerBTreeModule) Index: src/BTrees/objectkeymacros.h =================================================================== --- src/BTrees/objectkeymacros.h (revision 103608) +++ src/BTrees/objectkeymacros.h (working copy) @@ -1,7 +1,8 @@ #define KEYMACROS_H "$Id$\n" #define KEY_TYPE PyObject * #define KEY_TYPE_IS_PYOBJECT -#define TEST_KEY_SET_OR(V, KEY, TARGET) if ( ( (V) = PyObject_Compare((KEY),(TARGET)) ), PyErr_Occurred() ) +#define NEED_3WAY +#define TEST_KEY_SET_OR(V, KEY, TARGET) if ( ( (V) = compare_3way((KEY),(TARGET)) ), PyErr_Occurred() ) #define INCREF_KEY(k) Py_INCREF(k) #define DECREF_KEY(KEY) Py_DECREF(KEY) #define COPY_KEY(KEY, E) KEY=(E) Index: src/BTrees/_LOBTree.c =================================================================== --- src/BTrees/_LOBTree.c (revision 103608) +++ src/BTrees/_LOBTree.c (working copy) @@ -25,7 +25,7 @@ #define MOD_NAME_PREFIX "LO" #define DEFAULT_MAX_BUCKET_SIZE 60 #define DEFAULT_MAX_BTREE_SIZE 500 -#define INITMODULE init_LOBTree +#define MOD_NAME init_LOBTree #define ZODB_64BIT_INTS Index: src/ZEO/scripts/zeoqueue.py =================================================================== --- src/ZEO/scripts/zeoqueue.py (revision 103608) +++ src/ZEO/scripts/zeoqueue.py (working copy) @@ -38,8 +38,9 @@ try: True, False except NameError: - True = 1 - False = 0 + # 3.x prohibits assignment to True, and 2to3 doesn't fix it + globals()["True"] = 1 + globals()["False"] = 0 Index: src/ZODB/fsrecover.py =================================================================== --- src/ZODB/fsrecover.py (revision 103608) +++ src/ZODB/fsrecover.py (working copy) @@ -81,7 +81,7 @@ import ZODB import ZODB.FileStorage -from ZODB.utils import u64 +from ZODB.utils import u64, as_text from ZODB.FileStorage import TransactionRecord from persistent.TimeStamp import TimeStamp @@ -108,6 +108,7 @@ raise EOFError tid, stl, status, ul, dl, el = unpack(">8s8scHHH",h) + status = as_text(status) tl = u64(stl) if pos + (tl + 8) > file_size: Index: src/ZODB/BaseStorage.py =================================================================== --- src/ZODB/BaseStorage.py (revision 103608) +++ src/ZODB/BaseStorage.py (working copy) @@ -27,7 +27,7 @@ import ZODB.interfaces from ZODB import POSException -from ZODB.utils import z64, oid_repr +from ZODB.utils import z64, oid_repr, byte_ord, byte_chr from ZODB.UndoLogCompatible import UndoLogCompatible log = logging.getLogger("ZODB.BaseStorage") @@ -94,7 +94,7 @@ t = time.time() t = self._ts = TimeStamp(*(time.gmtime(t)[:5] + (t%60,))) - self._tid = repr(t) + self._tid = t.raw() # ._oid is the highest oid in use (0 is always in use -- it's # a reserved oid for the root object). Our new_oid() method @@ -169,9 +169,9 @@ self._lock_acquire() try: last = self._oid - d = ord(last[-1]) + d = byte_ord(last[-1]) if d < 255: # fast path for the usual case - last = last[:-1] + chr(d+1) + last = last[:-1] + byte_chr(d+1) else: # there's a carry out of the last byte last_as_long, = _structunpack(">Q", last) last = _structpack(">Q", last_as_long + 1) @@ -242,7 +242,7 @@ now = time.time() t = TimeStamp(*(time.gmtime(now)[:5] + (now % 60,))) self._ts = t = t.laterThan(self._ts) - self._tid = repr(t) + self._tid = t.raw() else: self._ts = TimeStamp(tid) self._tid = tid Index: src/ZODB/Connection.py =================================================================== --- src/ZODB/Connection.py (revision 103608) +++ src/ZODB/Connection.py (working copy) @@ -49,7 +49,7 @@ from ZODB.POSException import Unsupported, ReadOnlyHistoryError from ZODB.POSException import POSKeyError from ZODB.serialize import ObjectWriter, ObjectReader, myhasattr -from ZODB.utils import p64, u64, z64, oid_repr, positive_id +from ZODB.utils import p64, u64, z64, oid_repr, positive_id, bytes from ZODB import utils global_reset_counter = 0 @@ -688,7 +688,7 @@ if not store_return: return - if isinstance(store_return, str): + if isinstance(store_return, bytes): assert oid is not None self._handle_one_serial(oid, store_return, change) else: @@ -696,7 +696,7 @@ self._handle_one_serial(oid, serial, change) def _handle_one_serial(self, oid, serial, change): - if not isinstance(serial, str): + if not isinstance(serial, bytes): raise serial obj = self._cache.get(oid, None) if obj is None: Index: src/ZODB/scripts/migrate.py =================================================================== --- src/ZODB/scripts/migrate.py (revision 103608) +++ src/ZODB/scripts/migrate.py (working copy) @@ -92,8 +92,9 @@ try: True, False except NameError: - True = 1 - False = 0 + # 3.x prohibits assignment to True, and 2to3 doesn't fix it + globals()["True"] = 1 + globals()["False"] = 0 Index: src/ZODB/fsIndex.py =================================================================== --- src/ZODB/fsIndex.py (revision 103608) +++ src/ZODB/fsIndex.py (working copy) @@ -43,6 +43,7 @@ from BTrees._fsBTree import fsBucket from BTrees.OOBTree import OOBTree +from ZODB.utils import b # convert between numbers and six-byte strings @@ -50,7 +51,7 @@ return struct.pack(">Q", n)[2:] def str2num(s): - return struct.unpack(">Q", "\000\000" + s)[0] + return struct.unpack(">Q", b("\000\000") + s)[0] def prefix_plus_one(s): num = str2num(s) Index: src/ZODB/DB.py =================================================================== --- src/ZODB/DB.py (revision 103608) +++ src/ZODB/DB.py (working copy) @@ -15,7 +15,6 @@ """ import cPickle -import cStringIO import sys import threading import logging @@ -23,6 +22,14 @@ import calendar import time import warnings +if sys.version_info <= (3,): + from cStringIO import StringIO + _protocol = 1 +else: + # 2to3 assumes that StringIO maps to StringIO, + # when we really want BytesIO + from io import BytesIO as StringIO + _protocol = 3 from ZODB.broken import find_global from ZODB.utils import z64 @@ -452,8 +459,8 @@ root = PersistentMapping() # Manually create a pickle for the root to put in the storage. # The pickle must be in the special ZODB format. - file = cStringIO.StringIO() - p = cPickle.Pickler(file, 1) + file = StringIO() + p = cPickle.Pickler(file, _protocol) p.dump((root.__class__, None)) p.dump(root.__getstate__()) t = transaction.Transaction() Index: src/ZODB/serialize.py =================================================================== --- src/ZODB/serialize.py (revision 103608) +++ src/ZODB/serialize.py (working copy) @@ -136,8 +136,16 @@ import cPickle import cStringIO import logging +import sys +if sys.version_info <= (3,): + from cStringIO import StringIO + _protocol = 1 +else: + from io import BytesIO as StringIO + _protocol = 3 + from persistent import Persistent from persistent.wref import WeakRefMarker, WeakRef from ZODB import broken @@ -171,9 +179,13 @@ _jar = None def __init__(self, obj=None): - self._file = cStringIO.StringIO() - self._p = cPickle.Pickler(self._file, 1) - self._p.inst_persistent_id = self.persistent_id + self._file = StringIO() + self._p = cPickle.Pickler(self._file, _protocol) + if sys.version_info <= (3,): + self._p.inst_persistent_id = self.persistent_id + else: + # XXX this rename could be done with a fixer + self._p.persistent_id = self.persistent_id self._stack = [] if obj is not None: self._stack.append(obj) @@ -446,6 +458,15 @@ else: raise StopIteration +if sys.version_info <= (3,): + _Unpickler = cPickle.Unpickler +else: + # Py3k doesn't allow assignments to find_global, + # instead, find_class can be overridden + class _Unpickler(cPickle.Unpickler): + def find_class(self, modulename, name): + return self.find_global(modulename, name) + class ObjectReader: def __init__(self, conn=None, cache=None, factory=None): @@ -457,8 +478,8 @@ return self._factory(self._conn, module, name) def _get_unpickler(self, pickle): - file = cStringIO.StringIO(pickle) - unpickler = cPickle.Unpickler(file) + file = StringIO(pickle) + unpickler = _Unpickler(file) unpickler.persistent_load = self._persistent_load factory = self._factory conn = self._conn @@ -624,10 +645,16 @@ """ refs = [] - u = cPickle.Unpickler(cStringIO.StringIO(p)) - u.persistent_load = refs - u.noload() - u.noload() + u = cPickle.Unpickler(StringIO(p)) + if sys.version_info <= (3,): + u.persistent_load = refs + u.noload() + u.noload() + else: + # no noload in 3.x + u.persistent_load= refs.append + u.load() + u.load() # Now we have a list of referencs. Need to convert to list of # oids: @@ -661,7 +688,7 @@ """ refs = [] - u = cPickle.Unpickler(cStringIO.StringIO(a_pickle)) + u = cPickle.Unpickler(StringIO(a_pickle)) u.persistent_load = refs u.noload() u.noload() Index: src/ZODB/utils.py =================================================================== --- src/ZODB/utils.py (revision 103608) +++ src/ZODB/utils.py (working copy) @@ -26,7 +26,8 @@ from persistent.TimeStamp import TimeStamp -__all__ = ['z64', +__all__ = ['b', + 'z64', 'p64', 'u64', 'U64', @@ -67,7 +68,40 @@ warnings.warn("This will be removed in ZODB 3.8:\n%s" % msg, DeprecationWarning, stacklevel=3) -z64 = '\0'*8 +if sys.version_info < (3,): + def b(string): + "Decorator string literals that should be used as bytes" + return string + bytes = str + def as_bytes(obj): + "Convert obj into bytes" + return str(obj) + def as_text(bytes): + "Convert bytes into string" + return bytes + # Convert an element of a bytes object into an int + byte_ord = ord + byte_chr = chr +else: + import builtins + def b(string): + # some string literals have codes above 128, + # so we can't use ascii here. + return string.encode('iso-8859-1') + bytes = builtins.bytes + def as_bytes(obj): + if isinstance(obj, bytes): + # invoking str on a bytes object gives its repr() + return obj + return str(obj).encode("ascii") + def as_text(bytes): + return bytes.decode("ascii") + def byte_ord(byte): + return byte # elements of bytes are already ints + def byte_chr(int): + return bytes((int,)) + +z64 = b('\0'*8) assert sys.hexversion >= 0x02030000 @@ -230,19 +264,19 @@ class Locked(object): def __init__(self, func, inst=None, class_=None, preconditions=()): - self.im_func = func - self.im_self = inst - self.im_class = class_ + self.IM_func = func + self.IM_self = inst + self.IM_class = class_ self.preconditions = preconditions def __get__(self, inst, class_): - return self.__class__(self.im_func, inst, class_, self.preconditions) + return self.__class__(self.IM_func, inst, class_, self.preconditions) def __call__(self, *args, **kw): - inst = self.im_self + inst = self.IM_self if inst is None: inst = args[0] - func = self.im_func.__get__(self.im_self, self.im_class) + func = self.IM_func.__get__(self.IM_self, self.IM_class) inst._lock_acquire() try: @@ -269,4 +303,4 @@ def __call__(self, func): return Locked(func, preconditions=self.preconditions) - + Index: src/ZODB/ExportImport.py =================================================================== --- src/ZODB/ExportImport.py (revision 103608) +++ src/ZODB/ExportImport.py (working copy) @@ -14,8 +14,14 @@ """Support for database export and import.""" import os +import sys -from cStringIO import StringIO +if sys.version_info <= (3,): + from cStringIO import StringIO + _protocol = 1 +else: + from io import BytesIO as StringIO + _protocol = 3 from cPickle import Pickler, Unpickler from tempfile import TemporaryFile import logging @@ -24,7 +30,7 @@ from ZODB.interfaces import IBlobStorage from ZODB.POSException import ExportError, POSKeyError from ZODB.serialize import referencesf -from ZODB.utils import p64, u64, cp, mktemp +from ZODB.utils import p64, u64, cp, mktemp, b logger = logging.getLogger('ZODB.ExportImport') @@ -35,10 +41,10 @@ f = TemporaryFile() elif isinstance(f, str): f = open(f,'w+b') - f.write('ZEXP') + f.write(b('ZEXP')) oids = [oid] done_oids = {} - done=done_oids.has_key + done=done_oids.__contains__ load=self._storage.load supports_blobs = IBlobStorage.providedBy(self._storage) while oids: @@ -76,7 +82,7 @@ f = open(f, 'rb') magic = f.read(4) - if magic != 'ZEXP': + if magic != b('ZEXP'): if customImporters and customImporters.has_key(magic): f.seek(0) return customImporters[magic](self, f, clue) @@ -169,8 +175,11 @@ unpickler.persistent_load = persistent_load newp = StringIO() - pickler = Pickler(newp, 1) - pickler.inst_persistent_id = persistent_id + pickler = Pickler(newp, _protocol) + if sys.version_info <= (3,): + pickler.inst_persistent_id = persistent_id + else: + pickler.persistent_id = persistent_id pickler.dump(unpickler.load()) pickler.dump(unpickler.load()) @@ -183,8 +192,8 @@ self._storage.store(oid, None, data, '', transaction) -export_end_marker = '\377'*16 -blob_begin_marker = '\000BLOBSTART' +export_end_marker = b('\377'*16) +blob_begin_marker = b('\000BLOBSTART') class Ghost(object): __slots__ = ("oid",) Index: src/ZODB/FileStorage/format.py =================================================================== --- src/ZODB/FileStorage/format.py (revision 103608) +++ src/ZODB/FileStorage/format.py (working copy) @@ -83,11 +83,12 @@ # When we undo a record, we don't copy (or delete) # data. Instead, we write records with back pointers. +import sys import struct import logging from ZODB.POSException import POSKeyError -from ZODB.utils import u64, oid_repr +from ZODB.utils import u64, oid_repr, b, as_bytes class CorruptedError(Exception): @@ -255,7 +256,10 @@ return DATA_HDR_LEN + (self.plen or 8) def TxnHeaderFromString(s): - return TxnHeader(*struct.unpack(TRANS_HDR, s)) + res = TxnHeader(*struct.unpack(TRANS_HDR, s)) + if sys.version_info >= (3,): + res.status = res.status.decode('ascii') + return res class TxnHeader(object): """Header for a transaction record.""" @@ -273,9 +277,9 @@ assert elen >= 0 def asString(self): - s = struct.pack(TRANS_HDR, self.tid, self.tlen, self.status, + s = struct.pack(TRANS_HDR, self.tid, self.tlen, as_bytes(self.status), self.ulen, self.dlen, self.elen) - return "".join(map(str, [s, self.user, self.descr, self.ext])) + return b("").join(map(as_bytes, [s, self.user, self.descr, self.ext])) def headerlen(self): return TRANS_HDR_LEN + self.ulen + self.dlen + self.elen Index: src/ZODB/FileStorage/FileStorage.py =================================================================== --- src/ZODB/FileStorage/FileStorage.py (revision 103608) +++ src/ZODB/FileStorage/FileStorage.py (working copy) @@ -19,7 +19,11 @@ from cPickle import Pickler, Unpickler, loads from persistent.TimeStamp import TimeStamp from struct import pack, unpack -from types import StringType +try: + from types import StringType +except ImportError: + # XXX missing fixer + StringType = str from zc.lockfile import LockFile from ZODB.FileStorage.format import CorruptedError, CorruptedDataError from ZODB.FileStorage.format import FileStorageFormatter, DataHeader @@ -30,9 +34,8 @@ from ZODB import BaseStorage, ConflictResolution, POSException from ZODB.loglevels import BLATHER from ZODB.POSException import UndoError, POSKeyError, MultipleUndoErrors -from ZODB.utils import p64, u64, z64 +from ZODB.utils import p64, u64, z64, b, as_bytes, as_text -import base64 import BTrees.OOBTree import errno import logging @@ -44,10 +47,15 @@ import zope.interface import ZODB.utils +if sys.version_info <= (3,): + from base64 import decodestring,encodestring +else: + from base64 import decodebytes as decodestring, encodebytes as encodestring + # Not all platforms have fsync fsync = getattr(os, "fsync", None) -packed_version = "FS21" +packed_version = b("FS21") logger = logging.getLogger('ZODB.FileStorage') @@ -119,7 +127,7 @@ raise ValueError("time-travel only supported in read-only mode") if stop is None: - stop='\377'*8 + stop=b('\377'*8) # Lock the database and set up the temp file. if not read_only: @@ -586,6 +594,7 @@ self._file.seek(tpos) h = self._file.read(TRANS_HDR_LEN) tid, tl, status, ul, dl, el = unpack(TRANS_HDR, h) + status = as_text(status) self._file.read(ul + dl + el) tend = tpos + tl + 8 pos = self._file.tell() @@ -742,7 +751,7 @@ if self._nextpos: # Clear the checkpoint flag self._file.seek(self._pos+16) - self._file.write(self._tstatus) + self._file.write(as_bytes(self._tstatus)) try: # At this point, we may have committed the data to disk. # If we fail from here, we're in bad shape. @@ -938,7 +947,7 @@ def _txn_undo(self, transaction_id): # Find the right transaction to undo and call _txn_undo_write(). - tid = base64.decodestring(transaction_id + '\n') + tid = decodestring(transaction_id + b('\n')) assert len(tid) == 8 tpos = self._txn_find(tid, 1) tindex = self._txn_undo_write(tpos) @@ -957,7 +966,7 @@ return pos if stop_at_pack: # check the status field of the transaction header - if h[16] == 'p': + if h[16] == b('p'): break raise UndoError("Invalid transaction id") @@ -1333,6 +1342,7 @@ h=read(TRANS_HDR_LEN) if len(h) < TRANS_HDR_LEN: break tid, stl, status, ul, dl, el = unpack(TRANS_HDR,h) + status = as_text(status) if status=='c': break # Oops. we found a checkpoint flag. tl=u64(stl) tpos=pos @@ -1435,7 +1445,7 @@ -def read_index(file, name, index, tindex, stop='\377'*8, +def read_index(file, name, index, tindex, stop=b('\377'*8), ltid=z64, start=4L, maxoid=z64, recover=0, read_only=0): """Scan the file storage and update the index. @@ -1504,6 +1514,7 @@ break tid, tl, status, ul, dl, el = unpack(TRANS_HDR, h) + status = as_text(status) if tid <= ltid: logger.warning("%s time-stamp reduction at %s", name, pos) @@ -1978,6 +1989,7 @@ self.file.seek(self.pos) h = self.file.read(TRANS_HDR_LEN) tid, tl, status, ul, dl, el = unpack(TRANS_HDR, h) + status = as_text(status) if status == 'p': self.stop = 1 return None @@ -1994,7 +2006,7 @@ e = loads(self.file.read(el)) except: pass - d = {'id': base64.encodestring(tid).rstrip(), + d = {'id': encodestring(tid).rstrip(), 'time': TimeStamp(tid).timeTime(), 'user_name': u, 'size': tl, Index: src/ZODB/blob.py =================================================================== --- src/ZODB/blob.py (revision 103608) +++ src/ZODB/blob.py (working copy) @@ -290,7 +290,13 @@ self._p_blob_uncommitted = self._p_blob_ref = None return filename -class BlobFile(file): +if sys.version_info <= (3,): + base_file = file +else: + import io + base_file = io.FileIO + +class BlobFile(base_file): """A BlobFile that holds a file handle to actual blob data. It is a file that can be used within a transaction boundary; a BlobFile is Index: src/ZODB/ConflictResolution.py =================================================================== --- src/ZODB/ConflictResolution.py (revision 103608) +++ src/ZODB/ConflictResolution.py (working copy) @@ -13,7 +13,13 @@ ############################################################################## import logging -from cStringIO import StringIO +import sys +if sys.version_info <= (3,): + from cStringIO import StringIO + _protocol = 1 +else: + from io import BytesIO as StringIO + _protocol = 3 from cPickle import Unpickler, Pickler from pickle import PicklingError Index: setup.py =================================================================== --- setup.py (revision 103608) +++ setup.py (working copy) @@ -22,16 +22,19 @@ VERSION = "3.9.0c2" -from ez_setup import use_setuptools -use_setuptools() +import sys +if sys.version_info <= (3,): + from ez_setup import use_setuptools + use_setuptools() from setuptools import setup, find_packages from setuptools.extension import Extension +import setuptools; setuptools.run_2to3=True import os import sys if sys.version_info < (2, 4, 2): - print "This version of ZODB requires Python 2.4.2 or higher" + print("This version of ZODB requires Python 2.4.2 or higher") sys.exit(0) # The (non-obvious!) choices for the Trove Development Status line: @@ -179,8 +182,21 @@ def read_file(*path): base_dir = os.path.dirname(__file__) file_path = (base_dir, ) + tuple(path) - return file(os.path.join(*file_path)).read() + return open(os.path.join(*file_path)).read() +try: + import zope.fixers + from lib2to3.refactor import get_fixers_from_package + from distutils.command.build_py import build_py +except ImportError: + pass +else: + build_py.fixer_names = get_fixers_from_package('lib2to3.fixes') + \ + get_fixers_from_package('zope.fixers') + from lib2to3.fixes import fix_imports, fix_renames + fix_renames.MAPPING['UserDict'] = {'IterableUserDict':'UserDict'} + fix_imports.MAPPING['UserDict'] = 'collections' # missing in 3.1.1 + setup(name="ZODB3", version=VERSION, maintainer="Zope Foundation and Contributors", @@ -204,14 +220,15 @@ 'zope.testing', ], install_requires = [ - 'transaction', - 'zc.lockfile', - 'ZConfig', - 'zdaemon', - 'zope.event', - 'zope.interface', - 'zope.proxy', - 'zope.testing', + # XXX don't let setuptool override our own installation + #'transaction', + #'zc.lockfile', + #'ZConfig', + #'zdaemon', + #'zope.event', + #'zope.interface', + #'zope.proxy', + #'zope.testing', ], zip_safe = False, entry_points = """