diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d7d32e6e67..8d0e09bda0d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -254,6 +254,7 @@ jobs: "3.13", "pypy3.9", "pypy3.10", + "pypy3.11", "graalpy24.0", "graalpy24.1", ] diff --git a/newsfragments/4760.packaging.md b/newsfragments/4760.packaging.md new file mode 100644 index 00000000000..e7fe53099d1 --- /dev/null +++ b/newsfragments/4760.packaging.md @@ -0,0 +1 @@ +add support for PyPy3.11 diff --git a/noxfile.py b/noxfile.py index 9f94175ab16..cadd56a10cb 100644 --- a/noxfile.py +++ b/noxfile.py @@ -42,7 +42,7 @@ PYO3_GUIDE_TARGET = PYO3_TARGET / "guide" PYO3_DOCS_TARGET = PYO3_TARGET / "doc" PY_VERSIONS = ("3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13") -PYPY_VERSIONS = ("3.9", "3.10") +PYPY_VERSIONS = ("3.9", "3.10", "3.11") FREE_THREADED_BUILD = bool(sysconfig.get_config_var("Py_GIL_DISABLED")) @@ -689,8 +689,8 @@ def test_version_limits(session: nox.Session): config_file.set("PyPy", "3.8") _run_cargo(session, "check", env=env, expect_error=True) - assert "3.11" not in PYPY_VERSIONS - config_file.set("PyPy", "3.11") + assert "3.12" not in PYPY_VERSIONS + config_file.set("PyPy", "3.12") _run_cargo(session, "check", env=env, expect_error=True) diff --git a/pyo3-ffi/build.rs b/pyo3-ffi/build.rs index ea023de75fa..096614c7961 100644 --- a/pyo3-ffi/build.rs +++ b/pyo3-ffi/build.rs @@ -25,7 +25,7 @@ const SUPPORTED_VERSIONS_PYPY: SupportedVersions = SupportedVersions { min: PythonVersion { major: 3, minor: 9 }, max: PythonVersion { major: 3, - minor: 10, + minor: 11, }, }; diff --git a/pyo3-ffi/src/abstract_.rs b/pyo3-ffi/src/abstract_.rs index 82eecce05bd..6e0f44ddd6f 100644 --- a/pyo3-ffi/src/abstract_.rs +++ b/pyo3-ffi/src/abstract_.rs @@ -5,13 +5,19 @@ use libc::size_t; use std::os::raw::{c_char, c_int}; #[inline] -#[cfg(all(not(Py_3_13), not(PyPy)))] // CPython exposed as a function in 3.13, in object.h +#[cfg(all( + not(Py_3_13), // CPython exposed as a function in 3.13, in object.h + not(all(PyPy, not(Py_3_11))) // PyPy exposed as a function until PyPy 3.10, macro in 3.11+ +))] pub unsafe fn PyObject_DelAttrString(o: *mut PyObject, attr_name: *const c_char) -> c_int { PyObject_SetAttrString(o, attr_name, std::ptr::null_mut()) } #[inline] -#[cfg(all(not(Py_3_13), not(PyPy)))] // CPython exposed as a function in 3.13, in object.h +#[cfg(all( + not(Py_3_13), // CPython exposed as a function in 3.13, in object.h + not(all(PyPy, not(Py_3_11))) // PyPy exposed as a function until PyPy 3.10, macro in 3.11+ +))] pub unsafe fn PyObject_DelAttr(o: *mut PyObject, attr_name: *mut PyObject) -> c_int { PyObject_SetAttr(o, attr_name, std::ptr::null_mut()) } diff --git a/pyo3-ffi/src/cpython/abstract_.rs b/pyo3-ffi/src/cpython/abstract_.rs index 5c7b16ff0e8..6ada1a754ef 100644 --- a/pyo3-ffi/src/cpython/abstract_.rs +++ b/pyo3-ffi/src/cpython/abstract_.rs @@ -1,5 +1,5 @@ use crate::{PyObject, Py_ssize_t}; -#[cfg(not(all(Py_3_11, GraalPy)))] +#[cfg(any(all(Py_3_8, not(any(PyPy, GraalPy))), not(Py_3_11)))] use std::os::raw::c_char; use std::os::raw::c_int; diff --git a/pyo3-ffi/src/cpython/genobject.rs b/pyo3-ffi/src/cpython/genobject.rs index 4be310a8c88..c9d419e3782 100644 --- a/pyo3-ffi/src/cpython/genobject.rs +++ b/pyo3-ffi/src/cpython/genobject.rs @@ -2,7 +2,7 @@ use crate::object::*; use crate::PyFrameObject; #[cfg(not(any(PyPy, GraalPy)))] use crate::_PyErr_StackItem; -#[cfg(all(Py_3_11, not(GraalPy)))] +#[cfg(all(Py_3_11, not(any(PyPy, GraalPy))))] use std::os::raw::c_char; use std::os::raw::c_int; use std::ptr::addr_of_mut; diff --git a/pyo3-ffi/src/cpython/mod.rs b/pyo3-ffi/src/cpython/mod.rs index fe909f0ceeb..f09d51d0e4e 100644 --- a/pyo3-ffi/src/cpython/mod.rs +++ b/pyo3-ffi/src/cpython/mod.rs @@ -71,7 +71,7 @@ pub use self::object::*; pub use self::objimpl::*; pub use self::pydebug::*; pub use self::pyerrors::*; -#[cfg(Py_3_11)] +#[cfg(all(Py_3_11, not(PyPy)))] pub use self::pyframe::*; #[cfg(all(Py_3_8, not(PyPy)))] pub use self::pylifecycle::*; diff --git a/pyo3-ffi/src/cpython/object.rs b/pyo3-ffi/src/cpython/object.rs index 75eef11aae3..4e6932da789 100644 --- a/pyo3-ffi/src/cpython/object.rs +++ b/pyo3-ffi/src/cpython/object.rs @@ -310,9 +310,9 @@ pub struct PyHeapTypeObject { pub ht_cached_keys: *mut c_void, #[cfg(Py_3_9)] pub ht_module: *mut object::PyObject, - #[cfg(Py_3_11)] + #[cfg(all(Py_3_11, not(PyPy)))] _ht_tpname: *mut c_char, - #[cfg(Py_3_11)] + #[cfg(all(Py_3_11, not(PyPy)))] _spec_cache: _specialization_cache, } diff --git a/pyo3-ffi/src/cpython/objimpl.rs b/pyo3-ffi/src/cpython/objimpl.rs index 98a19abeb81..14f7121a202 100644 --- a/pyo3-ffi/src/cpython/objimpl.rs +++ b/pyo3-ffi/src/cpython/objimpl.rs @@ -1,4 +1,4 @@ -#[cfg(not(all(Py_3_11, GraalPy)))] +#[cfg(not(all(Py_3_11, any(PyPy, GraalPy))))] use libc::size_t; use std::os::raw::c_int; diff --git a/pyo3-ffi/src/cpython/pyframe.rs b/pyo3-ffi/src/cpython/pyframe.rs index d0cfa0a2c6d..5e1e16a7d08 100644 --- a/pyo3-ffi/src/cpython/pyframe.rs +++ b/pyo3-ffi/src/cpython/pyframe.rs @@ -1,2 +1,2 @@ -#[cfg(Py_3_11)] +#[cfg(all(Py_3_11, not(PyPy)))] opaque_struct!(_PyInterpreterFrame); diff --git a/pyo3-ffi/src/cpython/pystate.rs b/pyo3-ffi/src/cpython/pystate.rs index 5481265b55d..650cd6a1f7f 100644 --- a/pyo3-ffi/src/cpython/pystate.rs +++ b/pyo3-ffi/src/cpython/pystate.rs @@ -69,21 +69,21 @@ extern "C" { pub fn PyThreadState_DeleteCurrent(); } -#[cfg(all(Py_3_9, not(Py_3_11)))] +#[cfg(all(Py_3_9, not(any(Py_3_11, PyPy))))] pub type _PyFrameEvalFunction = extern "C" fn( *mut crate::PyThreadState, *mut crate::PyFrameObject, c_int, ) -> *mut crate::object::PyObject; -#[cfg(Py_3_11)] +#[cfg(all(Py_3_11, not(PyPy)))] pub type _PyFrameEvalFunction = extern "C" fn( *mut crate::PyThreadState, *mut crate::_PyInterpreterFrame, c_int, ) -> *mut crate::object::PyObject; -#[cfg(Py_3_9)] +#[cfg(all(Py_3_9, not(PyPy)))] extern "C" { /// Get the frame evaluation function. pub fn _PyInterpreterState_GetEvalFrameFunc( diff --git a/pyo3-ffi/src/cpython/unicodeobject.rs b/pyo3-ffi/src/cpython/unicodeobject.rs index fae626b8d25..3527a5aeadb 100644 --- a/pyo3-ffi/src/cpython/unicodeobject.rs +++ b/pyo3-ffi/src/cpython/unicodeobject.rs @@ -1,4 +1,4 @@ -#[cfg(not(PyPy))] +#[cfg(any(Py_3_11, not(PyPy)))] use crate::Py_hash_t; use crate::{PyObject, Py_UCS1, Py_UCS2, Py_UCS4, Py_ssize_t}; use libc::wchar_t; @@ -251,7 +251,7 @@ impl From for u32 { pub struct PyASCIIObject { pub ob_base: PyObject, pub length: Py_ssize_t, - #[cfg(not(PyPy))] + #[cfg(any(Py_3_11, not(PyPy)))] pub hash: Py_hash_t, /// A bit field with various properties. /// diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index 3f086ac1e92..087cd32920c 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -436,7 +436,7 @@ extern "C" { arg2: *const c_char, arg3: *mut PyObject, ) -> c_int; - #[cfg(any(Py_3_13, PyPy))] // CPython defined in 3.12 as an inline function in abstract.h + #[cfg(any(Py_3_13, all(PyPy, not(Py_3_11))))] // CPython defined in 3.12 as an inline function in abstract.h #[cfg_attr(PyPy, link_name = "PyPyObject_DelAttrString")] pub fn PyObject_DelAttrString(arg1: *mut PyObject, arg2: *const c_char) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyObject_HasAttrString")] @@ -460,7 +460,7 @@ extern "C" { #[cfg_attr(PyPy, link_name = "PyPyObject_SetAttr")] pub fn PyObject_SetAttr(arg1: *mut PyObject, arg2: *mut PyObject, arg3: *mut PyObject) -> c_int; - #[cfg(any(Py_3_13, PyPy))] // CPython defined in 3.12 as an inline function in abstract.h + #[cfg(any(Py_3_13, all(PyPy, not(Py_3_11))))] // CPython defined in 3.12 as an inline function in abstract.h #[cfg_attr(PyPy, link_name = "PyPyObject_DelAttr")] pub fn PyObject_DelAttr(arg1: *mut PyObject, arg2: *mut PyObject) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyObject_HasAttr")] diff --git a/pyo3-ffi/src/pybuffer.rs b/pyo3-ffi/src/pybuffer.rs index 50bf4e6109c..de7067599ff 100644 --- a/pyo3-ffi/src/pybuffer.rs +++ b/pyo3-ffi/src/pybuffer.rs @@ -103,7 +103,11 @@ extern "C" { } /// Maximum number of dimensions -pub const PyBUF_MAX_NDIM: c_int = if cfg!(PyPy) { 36 } else { 64 }; +pub const PyBUF_MAX_NDIM: usize = if cfg!(all(PyPy, not(Py_3_11))) { + 36 +} else { + 64 +}; /* Flags for getting buffers */ pub const PyBUF_SIMPLE: c_int = 0; diff --git a/pyo3-ffi/src/pyerrors.rs b/pyo3-ffi/src/pyerrors.rs index 6c9313c4ab0..d341239a07b 100644 --- a/pyo3-ffi/src/pyerrors.rs +++ b/pyo3-ffi/src/pyerrors.rs @@ -116,6 +116,7 @@ extern "C" { #[cfg_attr(PyPy, link_name = "PyPyExc_BaseException")] pub static mut PyExc_BaseException: *mut PyObject; #[cfg(Py_3_11)] + #[cfg_attr(PyPy, link_name = "PyPyExc_BaseExceptionGroup")] pub static mut PyExc_BaseExceptionGroup: *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyExc_Exception")] pub static mut PyExc_Exception: *mut PyObject; diff --git a/src/ffi/tests.rs b/src/ffi/tests.rs index 3396e409368..b2d9e4d39cd 100644 --- a/src/ffi/tests.rs +++ b/src/ffi/tests.rs @@ -121,7 +121,7 @@ fn ascii_object_bitfield() { let mut o = PyASCIIObject { ob_base, length: 0, - #[cfg(not(PyPy))] + #[cfg(any(Py_3_11, not(PyPy)))] hash: 0, state: 0u32, #[cfg(not(Py_3_12))]