Skip to content

Commit

Permalink
Add support for Python 3.9.
Browse files Browse the repository at this point in the history
Guard use of the internal functions _Py_*Reference behind correct ifdefs.

Also fix use of deprecated function PyEval_CallObject to be PyObject_CallObject.

Fixes #124
  • Loading branch information
jamadden committed Feb 19, 2020
1 parent a6a18ea commit 0e957a4
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 20 deletions.
4 changes: 4 additions & 0 deletions CHANGES.rst
Expand Up @@ -19,6 +19,10 @@
``PersistentMapping.popitem`` to no longer mark the object as
changed if it was empty.

- Add support for Python 3.9a3+ by updating references to deprecated
and moved functions. See `issue 124 <https://github.com/zopefoundation/persistent/issues/124>`_.


4.5.1 (2019-11-06)
------------------

Expand Down
2 changes: 1 addition & 1 deletion persistent/cPersistence.c
Expand Up @@ -290,7 +290,7 @@ changed(cPersistentObject *self)
}
Py_INCREF(self);
PyTuple_SET_ITEM(arg, 0, (PyObject *)self);
result = PyEval_CallObject(meth, arg);
result = PyObject_CallObject(meth, arg);
Py_DECREF(arg);
Py_DECREF(meth);
if (result == NULL)
Expand Down
41 changes: 24 additions & 17 deletions persistent/cPickleCache.c
Expand Up @@ -614,54 +614,61 @@ cc_oid_unreferenced(ccobject *self, PyObject *oid)
not release the global interpreter lock until this is
complete. */

PyObject *v;
PyObject *dead_pers_obj;

/* If the cache has been cleared by GC, data will be NULL. */
if (!self->data)
return;

v = PyDict_GetItem(self->data, oid);
assert(v);
assert(v->ob_refcnt == 0);
dead_pers_obj = PyDict_GetItem(self->data, oid);
assert(dead_pers_obj);
assert(dead_pers_obj->ob_refcnt == 0);
/* Need to be very hairy here because a dictionary is about
to decref an already deleted object.
*/

#ifdef Py_TRACE_REFS
#if defined(Py_TRACE_REFS) && !defined(Py_LIMITED_API)
/* This is called from the deallocation function after the
interpreter has untracked the reference. Track it again.
Starting in 3.9, these functions aren't available with the
stable (limited) API.
XXX: Why? Why not simply INCREF it? The CPython documentation
explicitly states these functions are for internal use only.
*/
_Py_NewReference(v);
_Py_NewReference(dead_pers_obj);
/* Don't increment total refcount as a result of the
shenanigans played in this function. The _Py_NewReference()
call above creates artificial references to v.
*/
_Py_RefTotal--;
assert(v->ob_type);
assert(dead_pers_obj->ob_type);
#else
Py_INCREF(v);
Py_INCREF(dead_pers_obj);
#endif
assert(v->ob_refcnt == 1);
assert(dead_pers_obj->ob_refcnt == 1);
/* Incremement the refcount again, because delitem is going to
DECREF it. If it's refcount reached zero again, we'd call back to
DECREF it. If its refcount reached zero again, we'd call back to
the dealloc function that called us.
*/
Py_INCREF(v);
Py_INCREF(dead_pers_obj);

/* TODO: Should we call _Py_ForgetReference() on error exit? */
if (PyDict_DelItem(self->data, oid) < 0)
return;
Py_DECREF((ccobject *)((cPersistentObject *)v)->cache);
((cPersistentObject *)v)->cache = NULL;
Py_DECREF((ccobject *)((cPersistentObject *)dead_pers_obj)->cache);
((cPersistentObject *)dead_pers_obj)->cache = NULL;

assert(v->ob_refcnt == 1);
assert(dead_pers_obj->ob_refcnt == 1);

/* Undo the temporary resurrection.
Don't DECREF the object, because this function is called from
/* Don't DECREF the object, because this function is called from
the object's dealloc function. If the refcnt reaches zero, it
will all be invoked recursively.
*/
_Py_ForgetReference(v);
#if defined(Py_TRACE_REFS) && !defined(Py_LIMITED_API)
/* But we need to undo the temporary resurrection. */
_Py_ForgetReference(dead_pers_obj);
#endif
}

static PyObject *
Expand Down
13 changes: 11 additions & 2 deletions setup.py
Expand Up @@ -44,6 +44,12 @@ def _read_file(filename):
ext_modules = []
headers = []
else:
define_macros = (
# We currently use macros like PyBytes_AS_STRING
# and internal functions like _PyObject_GetDictPtr
# that make it impossible to use the stable (limited) API.
# ('Py_LIMITED_API', '0x03050000'),
)
ext_modules = [
Extension(
name='persistent.cPersistence',
Expand All @@ -55,7 +61,8 @@ def _read_file(filename):
'persistent/cPersistence.h',
'persistent/ring.h',
'persistent/ring.c',
]
],
define_macros=list(define_macros),
),
Extension(
name='persistent.cPickleCache',
Expand All @@ -67,13 +74,15 @@ def _read_file(filename):
'persistent/cPersistence.h',
'persistent/ring.h',
'persistent/ring.c',
]
],
define_macros=list(define_macros),
),
Extension(
name='persistent._timestamp',
sources=[
'persistent/_timestamp.c',
],
define_macros=list(define_macros),
),
]
headers = [
Expand Down

0 comments on commit 0e957a4

Please sign in to comment.