Skip to content

Commit

Permalink
Update MSRV to 1.63 (#4129)
Browse files Browse the repository at this point in the history
* Bump MSRV to 1.63

* Drop parking_lot in favor of std::sync

* Make portable-atomic dep conditional

* Remove no longer required cfg
  • Loading branch information
alex authored Apr 28, 2024
1 parent 6fb972b commit 9e1960e
Show file tree
Hide file tree
Showing 18 changed files with 67 additions and 80 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
name: Prepare LD_LIBRARY_PATH (Ubuntu only)
run: echo LD_LIBRARY_PATH=${pythonLocation}/lib >> $GITHUB_ENV

- if: inputs.rust == '1.56.0'
- if: inputs.rust == '1.63.0'
name: Prepare minimal package versions (MSRV only)
run: nox -s set-minimal-package-versions

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: 1.56.0
toolchain: 1.63.0
targets: x86_64-unknown-linux-gnu
components: rust-src
- uses: actions/setup-python@v5
Expand Down Expand Up @@ -255,7 +255,7 @@ jobs:
]
include:
# Test minimal supported Rust version
- rust: 1.56.0
- rust: 1.63.0
python-version: "3.12"
platform:
{
Expand Down
7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,12 @@ categories = ["api-bindings", "development-tools::ffi"]
license = "MIT OR Apache-2.0"
exclude = ["/.gitignore", ".cargo/config", "/codecov.yml", "/Makefile", "/pyproject.toml", "/noxfile.py", "/.github", "/tests/test_compile_error.rs", "/tests/ui"]
edition = "2021"
rust-version = "1.56"
rust-version = "1.63"

[dependencies]
cfg-if = "1.0"
libc = "0.2.62"
parking_lot = ">= 0.11, < 0.13"
memoffset = "0.9"
portable-atomic = "1.0"

# ffi bindings to the python interpreter, split into a separate crate so they can be used independently
pyo3-ffi = { path = "pyo3-ffi", version = "=0.21.2" }
Expand All @@ -46,6 +44,9 @@ rust_decimal = { version = "1.0.0", default-features = false, optional = true }
serde = { version = "1.0", optional = true }
smallvec = { version = "1.0", optional = true }

[target.'cfg(not(target_has_atomic = "64"))'.dependencies]
portable-atomic = "1.0"

[dev-dependencies]
assert_approx_eq = "1.1.0"
chrono = "0.4.25"
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![benchmark](https://img.shields.io/badge/benchmark-✓-Green?logo=github)](https://pyo3.rs/dev/bench/)
[![codecov](https://img.shields.io/codecov/c/gh/PyO3/pyo3?logo=codecov)](https://codecov.io/gh/PyO3/pyo3)
[![crates.io](https://img.shields.io/crates/v/pyo3?logo=rust)](https://crates.io/crates/pyo3)
[![minimum rustc 1.56](https://img.shields.io/badge/rustc-1.56+-blue?logo=rust)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
[![minimum rustc 1.63](https://img.shields.io/badge/rustc-1.63+-blue?logo=rust)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
[![discord server](https://img.shields.io/discord/1209263839632424990?logo=discord)](https://discord.gg/33kcChzH7f)
[![contributing notes](https://img.shields.io/badge/contribute-on%20github-Green?logo=github)](https://github.com/PyO3/pyo3/blob/main/Contributing.md)

Expand All @@ -18,7 +18,7 @@

PyO3 supports the following software versions:
- Python 3.7 and up (CPython, PyPy, and GraalPy)
- Rust 1.56 and up
- Rust 1.63 and up

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.

Expand Down
2 changes: 1 addition & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ fn configure_pyo3() -> Result<()> {
println!("{}", cfg)
}

// Emit cfgs like `thread_local_const_init`
// Emit cfgs like `invalid_from_utf8_lint`
print_feature_cfgs();

Ok(())
Expand Down
2 changes: 1 addition & 1 deletion guide/src/building-and-distribution.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ rustflags = [
]
```

Alternatively, on rust >= 1.56, one can include in `build.rs`:
Alternatively, one can include in `build.rs`:

```rust
fn main() {
Expand Down
2 changes: 1 addition & 1 deletion guide/src/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ To get started using PyO3 you will need three things: a Rust toolchain, a Python
## Rust

First, make sure you have Rust installed on your system. If you haven't already done so, try following the instructions [here](https://www.rust-lang.org/tools/install). PyO3 runs on both the `stable` and `nightly` versions so you can choose whichever one fits you best. The minimum required Rust version is 1.56.
First, make sure you have Rust installed on your system. If you haven't already done so, try following the instructions [here](https://www.rust-lang.org/tools/install). PyO3 runs on both the `stable` and `nightly` versions so you can choose whichever one fits you best. The minimum required Rust version is 1.63.

If you can run `rustc --version` and the version is new enough you're good to go!

Expand Down
1 change: 1 addition & 0 deletions newsfragments/4129.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Raised the MSRV to 1.63
21 changes: 5 additions & 16 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,22 +557,11 @@ def set_minimal_package_versions(session: nox.Session):
"examples/word-count",
)
min_pkg_versions = {
"rust_decimal": "1.26.1",
"csv": "1.1.6",
"indexmap": "1.6.2",
"hashbrown": "0.9.1",
"log": "0.4.17",
"once_cell": "1.17.2",
"rayon": "1.6.1",
"rayon-core": "1.10.2",
"regex": "1.7.3",
"proptest": "1.0.0",
"chrono": "0.4.25",
"byteorder": "1.4.3",
"crossbeam-channel": "0.5.8",
"crossbeam-deque": "0.8.3",
"crossbeam-epoch": "0.9.15",
"crossbeam-utils": "0.8.16",
"regex": "1.9.6",
"proptest": "1.2.0",
"trybuild": "1.0.89",
"eyre": "0.6.8",
"allocator-api2": "0.2.10",
}

# run cargo update first to ensure that everything is at highest
Expand Down
5 changes: 0 additions & 5 deletions pyo3-build-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,6 @@ pub fn print_feature_cfgs() {

let rustc_minor_version = rustc_minor_version().unwrap_or(0);

// Enable use of const initializer for thread_local! on Rust 1.59 and greater
if rustc_minor_version >= 59 {
println!("cargo:rustc-cfg=thread_local_const_init");
}

// invalid_from_utf8 lint was added in Rust 1.74
if rustc_minor_version >= 74 {
println!("cargo:rustc-cfg=invalid_from_utf8_lint");
Expand Down
2 changes: 1 addition & 1 deletion pyo3-ffi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Manual][capi] for up-to-date documentation.

PyO3 supports the following software versions:
- Python 3.7 and up (CPython and PyPy)
- Rust 1.56 and up
- Rust 1.63 and up

# Example: Building Python Native modules

Expand Down
2 changes: 1 addition & 1 deletion pyo3-ffi/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ fn configure_pyo3() -> Result<()> {
println!("{}", line);
}

// Emit cfgs like `thread_local_const_init`
// Emit cfgs like `invalid_from_utf8_lint`
print_feature_cfgs();

Ok(())
Expand Down
2 changes: 1 addition & 1 deletion pyo3-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
//!
//! PyO3 supports the following software versions:
//! - Python 3.7 and up (CPython and PyPy)
//! - Rust 1.56 and up
//! - Rust 1.63 and up
//!
//! # Example: Building Python Native modules
//!
Expand Down
9 changes: 4 additions & 5 deletions src/coroutine/cancel.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use crate::{Py, PyAny, PyObject};
use parking_lot::Mutex;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use std::task::{Context, Poll, Waker};

#[derive(Debug, Default)]
Expand All @@ -25,12 +24,12 @@ impl CancelHandle {

/// Returns whether the associated coroutine has been cancelled.
pub fn is_cancelled(&self) -> bool {
self.0.lock().exception.is_some()
self.0.lock().unwrap().exception.is_some()
}

/// Poll to retrieve the exception thrown in the associated coroutine.
pub fn poll_cancelled(&mut self, cx: &mut Context<'_>) -> Poll<PyObject> {
let mut inner = self.0.lock();
let mut inner = self.0.lock().unwrap();
if let Some(exc) = inner.exception.take() {
return Poll::Ready(exc);
}
Expand Down Expand Up @@ -69,7 +68,7 @@ pub struct ThrowCallback(Arc<Mutex<Inner>>);

impl ThrowCallback {
pub(super) fn throw(&self, exc: Py<PyAny>) {
let mut inner = self.0.lock();
let mut inner = self.0.lock().unwrap();
inner.exception = Some(exc);
if let Some(waker) = inner.waker.take() {
waker.wake();
Expand Down
67 changes: 29 additions & 38 deletions src/gil.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,16 @@

use crate::impl_::not_send::{NotSend, NOT_SEND};
use crate::{ffi, Python};
use parking_lot::{const_mutex, Mutex, Once};
use std::cell::Cell;
#[cfg(debug_assertions)]
use std::cell::RefCell;
#[cfg(not(debug_assertions))]
use std::cell::UnsafeCell;
use std::{mem, ptr::NonNull};
use std::{mem, ptr::NonNull, sync};

static START: Once = Once::new();
static START: sync::Once = sync::Once::new();

cfg_if::cfg_if! {
if #[cfg(thread_local_const_init)] {
use std::thread_local as thread_local_const_init;
} else {
macro_rules! thread_local_const_init {
($($(#[$attr:meta])* static $name:ident: $ty:ty = const { $init:expr };)*) => (
thread_local! { $($(#[$attr])* static $name: $ty = $init;)* }
)
}
}
}

thread_local_const_init! {
std::thread_local! {
/// This is an internal counter in pyo3 monitoring whether this thread has the GIL.
///
/// It will be incremented whenever a GILGuard or GILPool is created, and decremented whenever
Expand Down Expand Up @@ -249,26 +236,26 @@ type PyObjVec = Vec<NonNull<ffi::PyObject>>;
/// Thread-safe storage for objects which were inc_ref / dec_ref while the GIL was not held.
struct ReferencePool {
// .0 is INCREFs, .1 is DECREFs
pointer_ops: Mutex<(PyObjVec, PyObjVec)>,
pointer_ops: sync::Mutex<(PyObjVec, PyObjVec)>,
}

impl ReferencePool {
const fn new() -> Self {
Self {
pointer_ops: const_mutex((Vec::new(), Vec::new())),
pointer_ops: sync::Mutex::new((Vec::new(), Vec::new())),
}
}

fn register_incref(&self, obj: NonNull<ffi::PyObject>) {
self.pointer_ops.lock().0.push(obj);
self.pointer_ops.lock().unwrap().0.push(obj);
}

fn register_decref(&self, obj: NonNull<ffi::PyObject>) {
self.pointer_ops.lock().1.push(obj);
self.pointer_ops.lock().unwrap().1.push(obj);
}

fn update_counts(&self, _py: Python<'_>) {
let mut ops = self.pointer_ops.lock();
let mut ops = self.pointer_ops.lock().unwrap();
if ops.0.is_empty() && ops.1.is_empty() {
return;
}
Expand Down Expand Up @@ -523,9 +510,9 @@ mod tests {
use super::{gil_is_acquired, GIL_COUNT, OWNED_OBJECTS, POOL};
use crate::types::any::PyAnyMethods;
use crate::{ffi, gil, PyObject, Python};
#[cfg(not(target_arch = "wasm32"))]
use parking_lot::{const_mutex, Condvar, Mutex};
use std::ptr::NonNull;
#[cfg(not(target_arch = "wasm32"))]
use std::sync;

fn get_object(py: Python<'_>) -> PyObject {
py.eval_bound("object()", None, None).unwrap().unbind()
Expand All @@ -543,6 +530,7 @@ mod tests {
!POOL
.pointer_ops
.lock()
.unwrap()
.0
.contains(&unsafe { NonNull::new_unchecked(obj.as_ptr()) })
}
Expand All @@ -551,6 +539,7 @@ mod tests {
!POOL
.pointer_ops
.lock()
.unwrap()
.1
.contains(&unsafe { NonNull::new_unchecked(obj.as_ptr()) })
}
Expand All @@ -559,6 +548,7 @@ mod tests {
fn pool_dec_refs_contains(obj: &PyObject) -> bool {
POOL.pointer_ops
.lock()
.unwrap()
.1
.contains(&unsafe { NonNull::new_unchecked(obj.as_ptr()) })
}
Expand Down Expand Up @@ -671,8 +661,8 @@ mod tests {
Python::with_gil(|py| {
assert_eq!(obj.get_refcnt(py), 1);
let non_null = unsafe { NonNull::new_unchecked(obj.as_ptr()) };
assert!(!POOL.pointer_ops.lock().0.contains(&non_null));
assert!(!POOL.pointer_ops.lock().1.contains(&non_null));
assert!(!POOL.pointer_ops.lock().unwrap().0.contains(&non_null));
assert!(!POOL.pointer_ops.lock().unwrap().1.contains(&non_null));
});
}

Expand Down Expand Up @@ -770,29 +760,30 @@ mod tests {

#[cfg(not(target_arch = "wasm32"))]
struct Event {
set: Mutex<bool>,
wait: Condvar,
set: sync::Mutex<bool>,
wait: sync::Condvar,
}

#[cfg(not(target_arch = "wasm32"))]
impl Event {
const fn new() -> Self {
Self {
set: const_mutex(false),
wait: Condvar::new(),
set: sync::Mutex::new(false),
wait: sync::Condvar::new(),
}
}

fn set(&self) {
*self.set.lock() = true;
*self.set.lock().unwrap() = true;
self.wait.notify_all();
}

fn wait(&self) {
let mut set = self.set.lock();
while !*set {
self.wait.wait(&mut set);
}
drop(
self.wait
.wait_while(self.set.lock().unwrap(), |s| !*s)
.unwrap(),
);
}
}

Expand Down Expand Up @@ -891,16 +882,16 @@ mod tests {

// The pointer should appear once in the incref pool, and once in the
// decref pool (for the clone being created and also dropped)
assert!(POOL.pointer_ops.lock().0.contains(&ptr));
assert!(POOL.pointer_ops.lock().1.contains(&ptr));
assert!(POOL.pointer_ops.lock().unwrap().0.contains(&ptr));
assert!(POOL.pointer_ops.lock().unwrap().1.contains(&ptr));

(obj, count, ptr)
});

Python::with_gil(|py| {
// Acquiring the gil clears the pool
assert!(!POOL.pointer_ops.lock().0.contains(&ptr));
assert!(!POOL.pointer_ops.lock().1.contains(&ptr));
assert!(!POOL.pointer_ops.lock().unwrap().0.contains(&ptr));
assert!(!POOL.pointer_ops.lock().unwrap().1.contains(&ptr));

// Overall count is still unchanged
assert_eq!(count, obj.get_refcnt(py));
Expand Down
10 changes: 9 additions & 1 deletion src/impl_/pymodule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,17 @@ use std::{cell::UnsafeCell, marker::PhantomData};
#[cfg(all(
not(any(PyPy, GraalPy)),
Py_3_9,
not(all(windows, Py_LIMITED_API, not(Py_3_10)))
not(all(windows, Py_LIMITED_API, not(Py_3_10))),
not(target_has_atomic = "64"),
))]
use portable_atomic::{AtomicI64, Ordering};
#[cfg(all(
not(any(PyPy, GraalPy)),
Py_3_9,
not(all(windows, Py_LIMITED_API, not(Py_3_10))),
target_has_atomic = "64",
))]
use std::sync::atomic::{AtomicI64, Ordering};

#[cfg(not(any(PyPy, GraalPy)))]
use crate::exceptions::PyImportError;
Expand Down
Loading

0 comments on commit 9e1960e

Please sign in to comment.