Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drop support for PyPy 3.7 and 3.8 #4582

Merged
merged 3 commits into from
Sep 30, 2024
Merged
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
14 changes: 6 additions & 8 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -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:
2 changes: 0 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -242,8 +242,6 @@ jobs:
"3.11",
"3.12",
"3.13-dev",
"pypy3.7",
"pypy3.8",
"pypy3.9",
"pypy3.10",
"graalpy24.0",
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.

4 changes: 2 additions & 2 deletions guide/src/building-and-distribution.md
Original file line number Diff line number Diff line change
@@ -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`.
1 change: 1 addition & 0 deletions newsfragments/4582.packaging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Drop support for PyPy 3.7 and 3.8.
6 changes: 3 additions & 3 deletions noxfile.py
Original file line number Diff line number Diff line change
@@ -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
56 changes: 28 additions & 28 deletions pyo3-build-config/src/impl_.rs
Original file line number Diff line number Diff line change
@@ -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(),
]
2 changes: 1 addition & 1 deletion pyo3-ffi/ACKNOWLEDGEMENTS
Original file line number Diff line number Diff line change
@@ -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
9 changes: 6 additions & 3 deletions pyo3-ffi/README.md
Original file line number Diff line number Diff line change
@@ -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

4 changes: 2 additions & 2 deletions pyo3-ffi/build.rs
Original file line number Diff line number Diff line change
@@ -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."
9 changes: 0 additions & 9 deletions pyo3-ffi/src/cpython/object.rs
Original file line number Diff line number Diff line change
@@ -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,
5 changes: 0 additions & 5 deletions pyo3-ffi/src/datetime.rs
Original file line number Diff line number Diff line change
@@ -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};
7 changes: 4 additions & 3 deletions pyo3-ffi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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
//!
4 changes: 0 additions & 4 deletions pyo3-ffi/src/pystate.rs
Original file line number Diff line number Diff line change
@@ -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;
16 changes: 0 additions & 16 deletions src/impl_/pymodule.rs
Original file line number Diff line number Diff line change
@@ -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<Py<PyModule>> {
#[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.
//
9 changes: 6 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -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
//!
4 changes: 2 additions & 2 deletions src/types/function.rs
Original file line number Diff line number Diff line change
@@ -222,8 +222,8 @@ unsafe impl<F: Send> Send for ClosureDestructor<F> {}
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
/// [`Py<PyFunction>`][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);