diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3385d53..583db8c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,6 +43,7 @@ jobs: - "pypy3.9" - "pypy3.10" - "pypy3.11" + - "pypy3.12" # Old PyPy versions # See https://github.com/pypy/pypy/issues/3990 diff --git a/docs/api.rst b/docs/api.rst index ca19e6e..023b7ee 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -8,7 +8,7 @@ functions for old Python versions. Supported Python versions: * Python 3.6 - 3.15 -* PyPy 2.7 and PyPy 3.6 - 3.10 +* PyPy 3.6 - 3.12 C++03 and C++11 are supported on Python 3.6 and newer. @@ -239,6 +239,20 @@ Python 3.14 See `PyUnstable_Object_IsUniquelyReferenced() documentation `__. + Not available on PyPy. ``Py_REFCNT()`` semantics is different on PyPy. + +.. c:function:: int PyUnstable_TryIncRef(PyObject *op) + + See `PyUnstable_TryIncRef() documentation `__. + + Not available on PyPy. ``Py_REFCNT()`` semantics is different on PyPy. + +.. c:function:: void PyUnstable_EnableTryIncRef(PyObject *op) + + See `PyUnstable_EnableTryIncRef() documentation `__. + + Not available on PyPy. ``Py_REFCNT()`` semantics is different on PyPy. + Not supported: * ``PyConfig_Names()`` diff --git a/docs/changelog.rst b/docs/changelog.rst index f14932b..daa5c59 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,7 +1,10 @@ Changelog ========= -* 2026-09-22: Add initial support for PyPy3.12 v8.0.0, which provides +* 2026-09-23: ``PyUnstable_Object_IsUniquelyReferenced()``, + ``PyUnstable_TryIncRef()`` and ``PyUnstable_EnableTryIncRef()`` are no longer + available on PyPy. ``Py_REFCNT()`` semantics is different on PyPy. +* 2026-09-22: Add support for PyPy3.12 v8.0.0, which provides ``PyFrame_GetCode()`` and ``PyInterpreterState_Get()``. * 2026-09-07: Remove code to support Python 2.7, Python 3.5 and PyPy for Python 2.7 ("pypy2"). diff --git a/pythoncapi_compat.h b/pythoncapi_compat.h index 1a2d3dc..fa47980 100644 --- a/pythoncapi_compat.h +++ b/pythoncapi_compat.h @@ -2132,7 +2132,8 @@ PyConfig_GetInt(const char *name, int *value) // gh-133144 added PyUnstable_Object_IsUniquelyReferenced() to Python 3.14.0b1. // Adapted from _PyObject_IsUniquelyReferenced() implementation. -#if PY_VERSION_HEX < 0x030E00B0 +// Not available on PyPy: Py_REFCNT() semantics is different on PyPy. +#if PY_VERSION_HEX < 0x030E00B0 && !defined(PYPY_VERSION) static inline int PyUnstable_Object_IsUniquelyReferenced(PyObject *obj) { #if !defined(Py_GIL_DISABLED) @@ -2150,7 +2151,8 @@ static inline int PyUnstable_Object_IsUniquelyReferenced(PyObject *obj) // gh-128926 added PyUnstable_TryIncRef() and PyUnstable_EnableTryIncRef() to // Python 3.14.0a5. Adapted from _Py_TryIncref() and _PyObject_SetMaybeWeakref(). -#if PY_VERSION_HEX < 0x030E00A5 +// Not available on PyPy: Py_REFCNT() semantics is different on PyPy. +#if PY_VERSION_HEX < 0x030E00A5 && !defined(PYPY_VERSION) static inline int PyUnstable_TryIncRef(PyObject *op) { #ifndef Py_GIL_DISABLED @@ -2221,7 +2223,7 @@ static inline void PyUnstable_EnableTryIncRef(PyObject *op) (void)op; // unused argument #endif } -#endif +#endif // PY_VERSION_HEX < 0x030E00A5 && !defined(PYPY_VERSION) #if PY_VERSION_HEX < 0x030F0000 diff --git a/runtests.py b/runtests.py index bd9640c..2754616 100755 --- a/runtests.py +++ b/runtests.py @@ -48,6 +48,7 @@ "pypy3.9", "pypy3.10", "pypy3.11", + "pypy3.12", ) diff --git a/tests/test_pythoncapi_compat_cext.c b/tests/test_pythoncapi_compat_cext.c index 45fa04e..61f8580 100644 --- a/tests/test_pythoncapi_compat_cext.c +++ b/tests/test_pythoncapi_compat_cext.c @@ -1956,6 +1956,7 @@ test_unicodewriter_format(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) } #endif +#ifndef PYPY_VERSION static PyObject * test_uniquely_referenced(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) { @@ -1975,6 +1976,7 @@ test_uniquely_referenced(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) Py_RETURN_NONE; } +#endif // !PYPY_VERSION static PyObject * test_bytes(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) @@ -2419,7 +2421,9 @@ test_tuple(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) return test_tuple_fromarray(); } -// Test adapted from CPython's _testcapi/object.c +// Test adapted from CPython's _testcapi/object.c. +// PyUnstable_TryIncRef() is not available on PyPy. +#ifndef PYPY_VERSION static int TryIncref_dealloc_called = 0; static void @@ -2458,6 +2462,7 @@ test_try_incref(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) assert(TryIncref_dealloc_called == 1); Py_RETURN_NONE; } +#endif // !PYPY_VERSION #if 0x030D0000 <= PY_VERSION_HEX && !defined(PYPY_VERSION) static PyObject * @@ -2545,10 +2550,14 @@ static struct PyMethodDef methods[] = { {"test_config", test_config, METH_NOARGS, _Py_NULL}, #endif {"test_sys", test_sys, METH_NOARGS, _Py_NULL}, +#ifndef PYPY_VERSION {"test_uniquely_referenced", test_uniquely_referenced, METH_NOARGS, _Py_NULL}, +#endif {"test_byteswriter", test_byteswriter, METH_NOARGS, _Py_NULL}, {"test_tuple", test_tuple, METH_NOARGS, _Py_NULL}, +#ifndef PYPY_VERSION {"test_try_incref", test_try_incref, METH_NOARGS, _Py_NULL}, +#endif #if 0x030D0000 <= PY_VERSION_HEX && !defined(PYPY_VERSION) {"test_set_immortal", test_set_immortal, METH_NOARGS, _Py_NULL}, #endif @@ -2580,6 +2589,7 @@ module_exec(PyObject *module) return -1; } #endif +#ifndef PYPY_VERSION TryIncrefType.tp_name = "TryIncrefType"; TryIncrefType.tp_basicsize = sizeof(PyObject); TryIncrefType.tp_dealloc = TryIncref_dealloc; @@ -2587,6 +2597,7 @@ module_exec(PyObject *module) if (PyType_Ready(&TryIncrefType) < 0) { return -1; } +#endif return 0; }