Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ jobs:
- "pypy3.9"
- "pypy3.10"
- "pypy3.11"
- "pypy3.12"

# Old PyPy versions
# See https://github.com/pypy/pypy/issues/3990
Expand Down
16 changes: 15 additions & 1 deletion docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -239,6 +239,20 @@ Python 3.14

See `PyUnstable_Object_IsUniquelyReferenced() documentation <https://docs.python.org/dev/c-api/object.html#c.PyUnstable_Object_IsUniquelyReferenced>`__.

Not available on PyPy. ``Py_REFCNT()`` semantics is different on PyPy.

.. c:function:: int PyUnstable_TryIncRef(PyObject *op)

See `PyUnstable_TryIncRef() documentation <https://docs.python.org/dev/c-api/object.html#c.PyUnstable_TryIncRef>`__.

Not available on PyPy. ``Py_REFCNT()`` semantics is different on PyPy.

.. c:function:: void PyUnstable_EnableTryIncRef(PyObject *op)

See `PyUnstable_EnableTryIncRef() documentation <https://docs.python.org/dev/c-api/object.html#c.PyUnstable_EnableTryIncRef>`__.

Not available on PyPy. ``Py_REFCNT()`` semantics is different on PyPy.

Not supported:

* ``PyConfig_Names()``
Expand Down
5 changes: 4 additions & 1 deletion docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -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").
Expand Down
8 changes: 5 additions & 3 deletions pythoncapi_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions runtests.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"pypy3.9",
"pypy3.10",
"pypy3.11",
"pypy3.12",
)


Expand Down
13 changes: 12 additions & 1 deletion tests/test_pythoncapi_compat_cext.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
{
Expand All @@ -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))
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 *
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -2580,13 +2589,15 @@ module_exec(PyObject *module)
return -1;
}
#endif
#ifndef PYPY_VERSION
TryIncrefType.tp_name = "TryIncrefType";
TryIncrefType.tp_basicsize = sizeof(PyObject);
TryIncrefType.tp_dealloc = TryIncref_dealloc;
TryIncrefType.tp_free = PyObject_Del;
if (PyType_Ready(&TryIncrefType) < 0) {
return -1;
}
#endif
return 0;
}

Expand Down
Loading