From 8a6855e1ab20ac5a30525485a4615d18181a267d Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Mon, 30 Sep 2024 21:00:38 +0100 Subject: [PATCH] drop support for PyPy 3.7 and 3.8 (#4582) * drop support for PyPy 3.7 and 3.8 * newsfragment --- .github/workflows/build.yml | 14 +++---- .github/workflows/ci.yml | 2 - README.md | 9 +++-- guide/src/building-and-distribution.md | 4 +- newsfragments/4582.packaging.md | 1 + noxfile.py | 6 +-- pyo3-build-config/src/impl_.rs | 56 +++++++++++++------------- pyo3-ffi/ACKNOWLEDGEMENTS | 2 +- pyo3-ffi/README.md | 9 +++-- pyo3-ffi/build.rs | 4 +- pyo3-ffi/src/cpython/object.rs | 9 ----- pyo3-ffi/src/datetime.rs | 5 --- pyo3-ffi/src/lib.rs | 7 ++-- pyo3-ffi/src/pystate.rs | 4 -- src/impl_/pymodule.rs | 16 -------- src/lib.rs | 9 +++-- src/types/function.rs | 4 +- 17 files changed, 67 insertions(+), 94 deletions(-) create mode 100644 newsfragments/4582.packaging.md diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 077ca08cf4e..ed24957ad2a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,7 @@ on: jobs: build: - continue-on-error: ${{ endsWith(inputs.python-version, '-dev') || contains(fromJSON('["3.7", "pypy3.7"]'), inputs.python-version) || inputs.rust == 'beta' || inputs.rust == 'nightly' }} + continue-on-error: ${{ endsWith(inputs.python-version, '-dev') || contains(fromJSON('["3.7", "3.8"]'), inputs.python-version) || contains(fromJSON('["beta", "nightly"]'), inputs.rust) }} runs-on: ${{ inputs.os }} if: ${{ !(startsWith(inputs.python-version, 'graalpy') && startsWith(inputs.os, 'windows')) }} steps: @@ -95,8 +95,8 @@ jobs: run: cargo build --lib --tests --no-default-features --features "multiple-pymethods full $MAYBE_NIGHTLY" - if: ${{ startsWith(inputs.python-version, 'pypy') }} - name: Build PyPy (abi3-py37) - run: cargo build --lib --tests --no-default-features --features "multiple-pymethods abi3-py37 full $MAYBE_NIGHTLY" + name: Build PyPy (abi3-py39) + run: cargo build --lib --tests --no-default-features --features "multiple-pymethods abi3-py39 full $MAYBE_NIGHTLY" # Run tests (except on PyPy, because no embedding API). - if: ${{ !startsWith(inputs.python-version, 'pypy') && !startsWith(inputs.python-version, 'graalpy') }} @@ -131,8 +131,7 @@ jobs: CARGO_TARGET_DIR: ${{ github.workspace }}/target - uses: dorny/paths-filter@v3 - # pypy 3.7 and 3.8 are not PEP 3123 compliant so fail checks here - if: ${{ inputs.rust == 'stable' && inputs.python-version != 'pypy3.7' && inputs.python-version != 'pypy3.8' && !startsWith(inputs.python-version, 'graalpy') }} + if: ${{ inputs.rust == 'stable' && !startsWith(inputs.python-version, 'graalpy') }} id: ffi-changes with: base: ${{ github.event.pull_request.base.ref || github.event.merge_group.base_ref }} @@ -145,9 +144,8 @@ jobs: - '.github/workflows/build.yml' - name: Run pyo3-ffi-check - # pypy 3.7 and 3.8 are not PEP 3123 compliant so fail checks here, nor - # is pypy 3.9 on windows - if: ${{ endsWith(inputs.python-version, '-dev') || (steps.ffi-changes.outputs.changed == 'true' && inputs.rust == 'stable' && inputs.python-version != 'pypy3.7' && inputs.python-version != 'pypy3.8' && !startsWith(inputs.python-version, 'graalpy') && !(inputs.python-version == 'pypy3.9' && contains(inputs.os, 'windows'))) }} + # pypy 3.9 on windows is not PEP 3123 compliant, nor is graalpy + if: ${{ endsWith(inputs.python-version, '-dev') || (steps.ffi-changes.outputs.changed == 'true' && inputs.rust == 'stable' && !startsWith(inputs.python-version, 'graalpy') && !(inputs.python-version == 'pypy3.9' && contains(inputs.os, 'windows'))) }} run: nox -s ffi-check env: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9ceb4dd64c7..3e085f9dbab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -242,8 +242,6 @@ jobs: "3.11", "3.12", "3.13-dev", - "pypy3.7", - "pypy3.8", "pypy3.9", "pypy3.10", "graalpy24.0", diff --git a/README.md b/README.md index 28f9c0af0b6..94b7fa49f70 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,12 @@ ## Usage -PyO3 supports the following software versions: - - Python 3.7 and up (CPython, PyPy, and GraalPy) - - Rust 1.63 and up +Requires Rust 1.63 or greater. + +PyO3 supports the following Python distributions: + - CPython 3.7 or greater + - PyPy 7.3 (Python 3.9+) + - GraalPy 24.0 or greater (Python 3.10+) You can use PyO3 to write a native Python module in Rust, or to embed Python in a Rust binary. The following sections explain each of these in turn. diff --git a/guide/src/building-and-distribution.md b/guide/src/building-and-distribution.md index 699f6561828..1a806304d22 100644 --- a/guide/src/building-and-distribution.md +++ b/guide/src/building-and-distribution.md @@ -105,9 +105,9 @@ Rather than using just the `.so` or `.pyd` extension suggested above (depending # CPython 3.10 on macOS .cpython-310-darwin.so -# PyPy 7.3 (Python 3.8) on Linux +# PyPy 7.3 (Python 3.9) on Linux $ python -c 'import sysconfig; print(sysconfig.get_config_var("EXT_SUFFIX"))' -.pypy38-pp73-x86_64-linux-gnu.so +.pypy39-pp73-x86_64-linux-gnu.so ``` So, for example, a valid module library name on CPython 3.10 for macOS is `your_module.cpython-310-darwin.so`, and its equivalent when compiled for PyPy 7.3 on Linux would be `your_module.pypy38-pp73-x86_64-linux-gnu.so`. diff --git a/newsfragments/4582.packaging.md b/newsfragments/4582.packaging.md new file mode 100644 index 00000000000..524ee02e017 --- /dev/null +++ b/newsfragments/4582.packaging.md @@ -0,0 +1 @@ +Drop support for PyPy 3.7 and 3.8. diff --git a/noxfile.py b/noxfile.py index 7f012ce2fc5..b526c71f2f3 100644 --- a/noxfile.py +++ b/noxfile.py @@ -31,7 +31,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.7", "3.8", "3.9", "3.10") +PYPY_VERSIONS = ("3.9", "3.10") @nox.session(venv_backend="none") @@ -646,8 +646,8 @@ def test_version_limits(session: nox.Session): env["PYO3_USE_ABI3_FORWARD_COMPATIBILITY"] = "1" _run_cargo(session, "check", env=env) - assert "3.6" not in PYPY_VERSIONS - config_file.set("PyPy", "3.6") + assert "3.8" not in PYPY_VERSIONS + config_file.set("PyPy", "3.8") _run_cargo(session, "check", env=env, expect_error=True) assert "3.11" not in PYPY_VERSIONS diff --git a/pyo3-build-config/src/impl_.rs b/pyo3-build-config/src/impl_.rs index a7ae4254bbe..571f9cb5a0c 100644 --- a/pyo3-build-config/src/impl_.rs +++ b/pyo3-build-config/src/impl_.rs @@ -1648,16 +1648,11 @@ fn default_lib_name_unix( } } }, - PythonImplementation::PyPy => { - if version >= (PythonVersion { major: 3, minor: 9 }) { - match ld_version { - Some(ld_version) => format!("pypy{}-c", ld_version), - None => format!("pypy{}.{}-c", version.major, version.minor), - } - } else { - format!("pypy{}-c", version.major) - } - } + PythonImplementation::PyPy => match ld_version { + Some(ld_version) => format!("pypy{}-c", ld_version), + None => format!("pypy{}.{}-c", version.major, version.minor), + }, + PythonImplementation::GraalPy => "python-native".to_string(), } } @@ -2348,17 +2343,17 @@ mod tests { use PythonImplementation::*; assert_eq!( super::default_lib_name_windows( - PythonVersion { major: 3, minor: 7 }, + PythonVersion { major: 3, minor: 9 }, CPython, false, false, false, ), - "python37", + "python39", ); assert_eq!( super::default_lib_name_windows( - PythonVersion { major: 3, minor: 7 }, + PythonVersion { major: 3, minor: 9 }, CPython, true, false, @@ -2368,17 +2363,17 @@ mod tests { ); assert_eq!( super::default_lib_name_windows( - PythonVersion { major: 3, minor: 7 }, + PythonVersion { major: 3, minor: 9 }, CPython, false, true, false, ), - "python3.7", + "python3.9", ); assert_eq!( super::default_lib_name_windows( - PythonVersion { major: 3, minor: 7 }, + PythonVersion { major: 3, minor: 9 }, CPython, true, true, @@ -2388,35 +2383,35 @@ mod tests { ); assert_eq!( super::default_lib_name_windows( - PythonVersion { major: 3, minor: 7 }, + PythonVersion { major: 3, minor: 9 }, PyPy, true, false, false, ), - "python37", + "python39", ); assert_eq!( super::default_lib_name_windows( - PythonVersion { major: 3, minor: 7 }, + PythonVersion { major: 3, minor: 9 }, CPython, false, false, true, ), - "python37_d", + "python39_d", ); // abi3 debug builds on windows use version-specific lib // to workaround https://github.com/python/cpython/issues/101614 assert_eq!( super::default_lib_name_windows( - PythonVersion { major: 3, minor: 7 }, + PythonVersion { major: 3, minor: 9 }, CPython, true, false, true, ), - "python37_d", + "python39_d", ); } @@ -2447,13 +2442,12 @@ mod tests { "python3.7md", ); - // PyPy 3.7 ignores ldversion + // PyPy 3.9 includes ldversion assert_eq!( - super::default_lib_name_unix(PythonVersion { major: 3, minor: 7 }, PyPy, Some("3.7md")), - "pypy3-c", + super::default_lib_name_unix(PythonVersion { major: 3, minor: 9 }, PyPy, None), + "pypy3.9-c", ); - // PyPy 3.9 includes ldversion assert_eq!( super::default_lib_name_unix(PythonVersion { major: 3, minor: 9 }, PyPy, Some("3.9d")), "pypy3.9d-c", @@ -2692,7 +2686,7 @@ mod tests { fn test_build_script_outputs_base() { let interpreter_config = InterpreterConfig { implementation: PythonImplementation::CPython, - version: PythonVersion { major: 3, minor: 8 }, + version: PythonVersion { major: 3, minor: 9 }, shared: true, abi3: false, lib_name: Some("python3".into()), @@ -2708,6 +2702,7 @@ mod tests { [ "cargo:rustc-cfg=Py_3_7".to_owned(), "cargo:rustc-cfg=Py_3_8".to_owned(), + "cargo:rustc-cfg=Py_3_9".to_owned(), ] ); @@ -2720,6 +2715,7 @@ mod tests { [ "cargo:rustc-cfg=Py_3_7".to_owned(), "cargo:rustc-cfg=Py_3_8".to_owned(), + "cargo:rustc-cfg=Py_3_9".to_owned(), "cargo:rustc-cfg=PyPy".to_owned(), ] ); @@ -2729,7 +2725,7 @@ mod tests { fn test_build_script_outputs_abi3() { let interpreter_config = InterpreterConfig { implementation: PythonImplementation::CPython, - version: PythonVersion { major: 3, minor: 7 }, + version: PythonVersion { major: 3, minor: 9 }, shared: true, abi3: true, lib_name: Some("python3".into()), @@ -2745,6 +2741,8 @@ mod tests { interpreter_config.build_script_outputs(), [ "cargo:rustc-cfg=Py_3_7".to_owned(), + "cargo:rustc-cfg=Py_3_8".to_owned(), + "cargo:rustc-cfg=Py_3_9".to_owned(), "cargo:rustc-cfg=Py_LIMITED_API".to_owned(), ] ); @@ -2757,6 +2755,8 @@ mod tests { interpreter_config.build_script_outputs(), [ "cargo:rustc-cfg=Py_3_7".to_owned(), + "cargo:rustc-cfg=Py_3_8".to_owned(), + "cargo:rustc-cfg=Py_3_9".to_owned(), "cargo:rustc-cfg=PyPy".to_owned(), "cargo:rustc-cfg=Py_LIMITED_API".to_owned(), ] diff --git a/pyo3-ffi/ACKNOWLEDGEMENTS b/pyo3-ffi/ACKNOWLEDGEMENTS index 4502d7774e0..8b20727dece 100644 --- a/pyo3-ffi/ACKNOWLEDGEMENTS +++ b/pyo3-ffi/ACKNOWLEDGEMENTS @@ -3,4 +3,4 @@ for binary compatibility, with additional metadata to support PyPy. For original implementations please see: - https://github.com/python/cpython - - https://foss.heptapod.net/pypy/pypy + - https://github.com/pypy/pypy diff --git a/pyo3-ffi/README.md b/pyo3-ffi/README.md index 75a34b6e72a..c5acc96ed3b 100644 --- a/pyo3-ffi/README.md +++ b/pyo3-ffi/README.md @@ -12,9 +12,12 @@ Manual][capi] for up-to-date documentation. # Minimum supported Rust and Python versions -PyO3 supports the following software versions: - - Python 3.7 and up (CPython and PyPy) - - Rust 1.63 and up +Requires Rust 1.63 or greater. + +`pyo3-ffi` supports the following Python distributions: + - CPython 3.7 or greater + - PyPy 7.3 (Python 3.9+) + - GraalPy 24.0 or greater (Python 3.10+) # Example: Building Python Native modules diff --git a/pyo3-ffi/build.rs b/pyo3-ffi/build.rs index b0f1c28d448..622c2707110 100644 --- a/pyo3-ffi/build.rs +++ b/pyo3-ffi/build.rs @@ -23,7 +23,7 @@ const SUPPORTED_VERSIONS_CPYTHON: SupportedVersions = SupportedVersions { }; const SUPPORTED_VERSIONS_PYPY: SupportedVersions = SupportedVersions { - min: PythonVersion { major: 3, minor: 7 }, + min: PythonVersion { major: 3, minor: 9 }, max: PythonVersion { major: 3, minor: 10, @@ -110,7 +110,7 @@ fn ensure_python_version(interpreter_config: &InterpreterConfig) -> Result<()> { PythonImplementation::CPython => {} PythonImplementation::PyPy => warn!( "PyPy does not yet support abi3 so the build artifacts will be version-specific. \ - See https://foss.heptapod.net/pypy/pypy/-/issues/3397 for more information." + See https://github.com/pypy/pypy/issues/3397 for more information." ), PythonImplementation::GraalPy => warn!( "GraalPy does not support abi3 so the build artifacts will be version-specific." diff --git a/pyo3-ffi/src/cpython/object.rs b/pyo3-ffi/src/cpython/object.rs index 23d7f94081e..35ddf25a2de 100644 --- a/pyo3-ffi/src/cpython/object.rs +++ b/pyo3-ffi/src/cpython/object.rs @@ -210,15 +210,6 @@ pub type printfunc = #[repr(C)] #[derive(Debug)] pub struct PyTypeObject { - #[cfg(all(PyPy, not(Py_3_9)))] - pub ob_refcnt: Py_ssize_t, - #[cfg(all(PyPy, not(Py_3_9)))] - pub ob_pypy_link: Py_ssize_t, - #[cfg(all(PyPy, not(Py_3_9)))] - pub ob_type: *mut PyTypeObject, - #[cfg(all(PyPy, not(Py_3_9)))] - pub ob_size: Py_ssize_t, - #[cfg(not(all(PyPy, not(Py_3_9))))] pub ob_base: object::PyVarObject, #[cfg(GraalPy)] pub ob_size: Py_ssize_t, diff --git a/pyo3-ffi/src/datetime.rs b/pyo3-ffi/src/datetime.rs index bbee057d561..7283b6d4e52 100644 --- a/pyo3-ffi/src/datetime.rs +++ b/pyo3-ffi/src/datetime.rs @@ -3,11 +3,6 @@ //! This is the unsafe thin wrapper around the [CPython C API](https://docs.python.org/3/c-api/datetime.html), //! and covers the various date and time related objects in the Python `datetime` //! standard library module. -//! -//! A note regarding PyPy (cpyext) support: -//! -//! Support for `PyDateTime_CAPI` is limited as of PyPy 7.0.0. -//! `DateTime_FromTimestamp` and `Date_FromTimestamp` are currently not supported. #[cfg(GraalPy)] use crate::{PyLong_AsLong, PyLong_Check, PyObject_GetAttrString, Py_DecRef}; diff --git a/pyo3-ffi/src/lib.rs b/pyo3-ffi/src/lib.rs index 1e3f804b1f4..c6157401124 100644 --- a/pyo3-ffi/src/lib.rs +++ b/pyo3-ffi/src/lib.rs @@ -50,9 +50,10 @@ //! //! # Minimum supported Rust and Python versions //! -//! PyO3 supports the following software versions: -//! - Python 3.7 and up (CPython and PyPy) -//! - Rust 1.63 and up +//! `pyo3-ffi` supports the following Python distributions: +//! - CPython 3.7 or greater +//! - PyPy 7.3 (Python 3.9+) +//! - GraalPy 24.0 or greater (Python 3.10+) //! //! # Example: Building Python Native modules //! diff --git a/pyo3-ffi/src/pystate.rs b/pyo3-ffi/src/pystate.rs index d2fd39e497d..23aeea3a1de 100644 --- a/pyo3-ffi/src/pystate.rs +++ b/pyo3-ffi/src/pystate.rs @@ -1,4 +1,3 @@ -#[cfg(any(not(PyPy), Py_3_9))] use crate::moduleobject::PyModuleDef; use crate::object::PyObject; use std::os::raw::c_int; @@ -28,15 +27,12 @@ extern "C" { #[cfg(not(PyPy))] pub fn PyInterpreterState_GetID(arg1: *mut PyInterpreterState) -> i64; - #[cfg(any(not(PyPy), Py_3_9))] // only on PyPy since 3.9 #[cfg_attr(PyPy, link_name = "PyPyState_AddModule")] pub fn PyState_AddModule(arg1: *mut PyObject, arg2: *mut PyModuleDef) -> c_int; - #[cfg(any(not(PyPy), Py_3_9))] // only on PyPy since 3.9 #[cfg_attr(PyPy, link_name = "PyPyState_RemoveModule")] pub fn PyState_RemoveModule(arg1: *mut PyModuleDef) -> c_int; - #[cfg(any(not(PyPy), Py_3_9))] // only on PyPy since 3.9 // only has PyPy prefix since 3.10 #[cfg_attr(all(PyPy, Py_3_10), link_name = "PyPyState_FindModule")] pub fn PyState_FindModule(arg1: *mut PyModuleDef) -> *mut PyObject; diff --git a/src/impl_/pymodule.rs b/src/impl_/pymodule.rs index ab38bc49e8e..97eb2103dfe 100644 --- a/src/impl_/pymodule.rs +++ b/src/impl_/pymodule.rs @@ -89,22 +89,6 @@ impl ModuleDef { } /// Builds a module using user given initializer. Used for [`#[pymodule]`][crate::pymodule]. pub fn make_module(&'static self, py: Python<'_>) -> PyResult> { - #[cfg(all(PyPy, not(Py_3_8)))] - { - use crate::types::any::PyAnyMethods; - const PYPY_GOOD_VERSION: [u8; 3] = [7, 3, 8]; - let version = py - .import("sys")? - .getattr("implementation")? - .getattr("version")?; - if version.lt(crate::types::PyTuple::new(py, PYPY_GOOD_VERSION)?)? { - let warn = py.import("warnings")?.getattr("warn")?; - warn.call1(( - "PyPy 3.7 versions older than 7.3.8 are known to have binary \ - compatibility issues which may cause segfaults. Please upgrade.", - ))?; - } - } // Check the interpreter ID has not changed, since we currently have no way to guarantee // that static data is not reused across interpreters. // diff --git a/src/lib.rs b/src/lib.rs index 7f1329c9ea5..8181afb4347 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -131,9 +131,12 @@ //! //! # Minimum supported Rust and Python versions //! -//! PyO3 supports the following software versions: -//! - Python 3.7 and up (CPython and PyPy) -//! - Rust 1.63 and up +//! Requires Rust 1.63 or greater. +//! +//! PyO3 supports the following Python distributions: +//! - CPython 3.7 or greater +//! - PyPy 7.3 (Python 3.9+) +//! - GraalPy 24.0 or greater (Python 3.10+) //! //! # Example: Building a native Python module //! diff --git a/src/types/function.rs b/src/types/function.rs index 8d226a9e792..936176add22 100644 --- a/src/types/function.rs +++ b/src/types/function.rs @@ -222,8 +222,8 @@ unsafe impl Send for ClosureDestructor {} /// Values of this type are accessed via PyO3's smart pointers, e.g. as /// [`Py`][crate::Py] or [`Bound<'py, PyFunction>`][Bound]. #[repr(transparent)] -#[cfg(all(not(Py_LIMITED_API), not(all(PyPy, not(Py_3_8)))))] +#[cfg(not(Py_LIMITED_API))] pub struct PyFunction(PyAny); -#[cfg(all(not(Py_LIMITED_API), not(all(PyPy, not(Py_3_8)))))] +#[cfg(not(Py_LIMITED_API))] pyobject_native_type_core!(PyFunction, pyobject_native_static_type_object!(ffi::PyFunction_Type), #checkfunction=ffi::PyFunction_Check);