msrv: bump to 1.48

This commit is contained in:
David Hewitt 2021-11-18 11:38:47 +00:00
parent f29a8e1b91
commit 6a65f98bd2
20 changed files with 82 additions and 113 deletions

View File

@ -123,7 +123,7 @@ jobs:
rust-target: "x86_64-apple-darwin",
}
# Test minimal supported Rust version
- rust: 1.41.1
- rust: 1.48.0
python-version: "3.10"
platform:
{

View File

@ -6,6 +6,14 @@ PyO3 versions, please see the [migration guide](https://pyo3.rs/latest/migration
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Packaging
- Update MSRV to Rust 1.48. [#2004](https://github.com/PyO3/pyo3/pull/2004)
- Update `indoc` optional dependency to 1.0. [#2004](https://github.com/PyO3/pyo3/pull/2004)
- Update `paste` optional dependency to 1.0. [#2004](https://github.com/PyO3/pyo3/pull/2004)
## [0.15.1] - 2021-11-19
### Added

View File

@ -21,9 +21,8 @@ parking_lot = "0.11.0"
# support crates for macros feature
pyo3-macros = { path = "pyo3-macros", version = "=0.15.1", optional = true }
# indoc must stay at 0.3.x for Rust 1.41 compatibility
indoc = { version = "0.3.6", optional = true }
paste = { version = "0.1.18", optional = true }
indoc = { version = "1.0.3", optional = true }
paste = { version = "1.0.6", optional = true }
unindent = { version = "0.1.4", optional = true }
# support crate for multiple-pymethods feature
@ -32,7 +31,7 @@ inventory = { version = "0.1.4", optional = true }
# crate integrations that can be added using the eponymous features
anyhow = { version = "1.0", optional = true }
eyre = { version = ">= 0.4, < 0.7" , optional = true }
eyre = { version = ">= 0.4, < 0.7", optional = true }
hashbrown = { version = ">= 0.9, < 0.12", optional = true }
indexmap = { version = ">= 1.6, < 1.8", optional = true }
num-bigint = { version = "0.4", optional = true }
@ -41,11 +40,7 @@ serde = { version = "1.0", optional = true }
[dev-dependencies]
assert_approx_eq = "1.1.0"
# O.3.5 uses the matches! macro, which isn't compatible with Rust 1.41
criterion = "=0.3.4"
# half and bitflags use if/match in const fn, which isn't compatible with Rust 1.41
half = "=1.7.1"
bitflags = "=1.2.1"
criterion = "0.3.5"
trybuild = "1.0.49"
rustversion = "1.0"
# 1.0.0 requires Rust 1.50

View File

@ -4,7 +4,7 @@
[![benchmark](https://github.com/PyO3/pyo3/actions/workflows/bench.yml/badge.svg)](https://pyo3.rs/dev/bench/)
[![codecov](https://codecov.io/gh/PyO3/pyo3/branch/main/graph/badge.svg)](https://codecov.io/gh/PyO3/pyo3)
[![crates.io](https://img.shields.io/crates/v/pyo3)](https://crates.io/crates/pyo3)
[![minimum rustc 1.41](https://img.shields.io/badge/rustc-1.41+-blue.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
[![minimum rustc 1.48](https://img.shields.io/badge/rustc-1.48+-blue.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
[![dev chat](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/PyO3/Lobby)
[![contributing notes](https://img.shields.io/badge/contribute-on%20github-Green)](https://github.com/PyO3/pyo3/blob/main/Contributing.md)
@ -18,7 +18,7 @@
PyO3 supports the following software versions:
- Python 3.6 and up (CPython and PyPy)
- Rust 1.41 and up
- Rust 1.48 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.

View File

@ -352,15 +352,12 @@ impl<'a> FnSpec<'a> {
parse_method_receiver(first_arg)
};
#[allow(clippy::manual_strip)] // for strip_prefix replacement supporting rust < 1.45
// strip get_ or set_
let strip_fn_name = |prefix: &'static str| {
let ident = name.unraw().to_string();
if ident.starts_with(prefix) {
Some(syn::Ident::new(&ident[prefix.len()..], ident.span()))
} else {
None
}
name.unraw()
.to_string()
.strip_prefix(prefix)
.map(|stripped| syn::Ident::new(stripped, name.span()))
};
let (fn_type, skip_first_arg, fixed_convention) = match fn_type_attr {

View File

@ -15,13 +15,11 @@ pub struct MethodProto {
}
impl MethodProto {
// TODO: workaround for no unsized casts in const fn on Rust 1.45 (stable in 1.46)
const EMPTY_ARGS: &'static [&'static str] = &[];
pub const fn new(name: &'static str, proto: &'static str) -> Self {
MethodProto {
name,
proto,
args: MethodProto::EMPTY_ARGS,
args: &[],
with_self: false,
with_result: true,
}

View File

@ -399,14 +399,9 @@ pub fn impl_py_getter_def(cls: &syn::Type, property_type: PropertyType) -> Resul
/// Split an argument of pyo3::Python from the front of the arg list, if present
fn split_off_python_arg<'a>(args: &'a [FnArg<'a>]) -> (Option<&FnArg>, &[FnArg]) {
if args
.get(0)
.map(|py| utils::is_python(py.ty))
.unwrap_or(false)
{
(Some(&args[0]), &args[1..])
} else {
(None, args)
match args {
[py, args @ ..] if utils::is_python(py.ty) => (Some(py), args),
args => (None, args),
}
}

View File

@ -62,8 +62,6 @@ pub fn option_type_argument(ty: &syn::Type) -> Option<&syn::Type> {
#[derive(Clone)]
pub struct PythonDoc(TokenStream);
// TODO(#1782) use strip_prefix on Rust 1.45 or greater
#[allow(clippy::manual_strip)]
/// Collects all #[doc = "..."] attributes into a TokenStream evaluating to a null-terminated string
/// e.g. concat!("...", "\n", "\0")
pub fn get_doc(
@ -107,11 +105,11 @@ pub fn get_doc(
// Strip single left space from literal strings, if needed.
// e.g. `/// Hello world` expands to #[doc = " Hello world"]
let doc_line = lit_str.value();
if doc_line.starts_with(' ') {
syn::LitStr::new(&doc_line[1..], lit_str.span()).to_tokens(tokens)
} else {
lit_str.to_tokens(tokens)
}
doc_line
.strip_prefix(' ')
.map(|stripped| syn::LitStr::new(stripped, lit_str.span()))
.unwrap_or(lit_str)
.to_tokens(tokens);
} else {
// This is probably a macro doc from Rust 1.54, e.g. #[doc = include_str!(...)]
token_stream.to_tokens(tokens)

View File

@ -75,12 +75,7 @@ impl ElementType {
pub fn from_format(format: &CStr) -> ElementType {
match format.to_bytes() {
[char] | [b'@', char] => native_element_type_from_type_char(*char),
[modifier, char]
if (*modifier == b'='
|| *modifier == b'<'
|| *modifier == b'>'
|| *modifier == b'!') =>
{
[modifier, char] if matches!(modifier, b'=' | b'<' | b'>' | b'!') => {
standard_element_type_from_type_char(*char)
}
_ => ElementType::Unknown,

View File

@ -542,7 +542,6 @@ pub unsafe extern "C" fn alloc_with_freelist<T: PyClassWithFreeList>(
/// # Safety
/// - `obj` must be a valid pointer to an instance of T (not a subclass).
/// - The GIL must be held.
#[allow(clippy::collapsible_if)] // for if cfg!
pub unsafe extern "C" fn free_with_freelist<T: PyClassWithFreeList>(obj: *mut c_void) {
let obj = obj as *mut ffi::PyObject;
debug_assert_eq!(
@ -560,12 +559,11 @@ pub unsafe extern "C" fn free_with_freelist<T: PyClassWithFreeList>(obj: *mut c_
};
free(obj as *mut c_void);
if cfg!(Py_3_8) {
#[cfg(Py_3_8)]
if ffi::PyType_HasFeature(ty, ffi::Py_TPFLAGS_HEAPTYPE) != 0 {
ffi::Py_DECREF(ty as *mut ffi::PyObject);
}
}
}
}
/// Workaround for Python issue 35810; no longer necessary in Python 3.8

View File

@ -52,7 +52,6 @@ extern "C" {
fn _Py_CheckRecursiveCall(_where: *mut c_char) -> c_int;
}
// TODO
// skipped Py_EnterRecursiveCall
// skipped Py_LeaveRecursiveCall

View File

@ -69,14 +69,15 @@ pub(crate) fn gil_is_acquired() -> bool {
/// # }
/// ```
#[cfg(not(PyPy))]
#[allow(clippy::collapsible_if)] // for if cfg!
pub fn prepare_freethreaded_python() {
// Protect against race conditions when Python is not yet initialized and multiple threads
// concurrently call 'prepare_freethreaded_python()'. Note that we do not protect against
// concurrent initialization of the Python runtime by other users of the Python C API.
START.call_once_force(|_| unsafe {
if cfg!(not(Py_3_7)) {
// Use call_once_force because if initialization panics, it's okay to try again.
// TODO(#1782) - Python 3.6 legacy code
#[cfg(not(Py_3_7))]
if ffi::Py_IsInitialized() != 0 {
if ffi::PyEval_ThreadsInitialized() == 0 {
// We can only safely initialize threads if this thread holds the GIL.
@ -94,8 +95,10 @@ pub fn prepare_freethreaded_python() {
// Release the GIL.
ffi::PyEval_SaveThread();
}
} else if ffi::Py_IsInitialized() == 0 {
// In Python 3.7 and up PyEval_InitThreads is irrelevant.
#[cfg(Py_3_7)]
if ffi::Py_IsInitialized() == 0 {
ffi::Py_InitializeEx(0);
// Release the GIL.
@ -134,7 +137,6 @@ pub fn prepare_freethreaded_python() {
/// # }
/// ```
#[cfg(not(PyPy))]
#[allow(clippy::collapsible_if)] // for if cfg!
pub unsafe fn with_embedded_python_interpreter<F, R>(f: F) -> R
where
F: for<'p> FnOnce(Python<'p>) -> R,
@ -149,11 +151,10 @@ where
// Changed in version 3.7: This function is now called by Py_Initialize(), so you dont have to
// call it yourself anymore.
if cfg!(not(Py_3_7)) {
#[cfg(not(Py_3_7))]
if ffi::PyEval_ThreadsInitialized() == 0 {
ffi::PyEval_InitThreads();
}
}
// Safe: the GIL is already held because of the Py_IntializeEx call.
let pool = GILPool::new();

View File

@ -111,7 +111,7 @@
//!
//! PyO3 supports the following software versions:
//! - Python 3.6 and up (CPython and PyPy)
//! - Rust 1.41 and up
//! - Rust 1.48 and up
//!
//! # Example: Building a native Python module
//!

View File

@ -83,7 +83,8 @@ where
slots.push(ffi::Py_tp_free, free as _);
}
if cfg!(Py_3_9) {
#[cfg(Py_3_9)]
{
let members = py_class_members::<T>();
if !members.is_empty() {
slots.push(ffi::Py_tp_members, into_raw(members))
@ -155,7 +156,8 @@ fn tp_init_additional<T: PyClass>(type_object: *mut ffi::PyTypeObject) {
// Setting buffer protocols via slots doesn't work until Python 3.9, so on older versions we
// must manually fixup the type object.
if cfg!(not(Py_3_9)) {
#[cfg(not(Py_3_9))]
{
if let Some(buffer) = T::get_buffer() {
unsafe {
(*(*type_object).tp_as_buffer).bf_getbuffer = buffer.bf_getbuffer;
@ -166,7 +168,8 @@ fn tp_init_additional<T: PyClass>(type_object: *mut ffi::PyTypeObject) {
// Setting tp_dictoffset and tp_weaklistoffset via slots doesn't work until Python 3.9, so on
// older versions again we must fixup the type object.
if cfg!(not(Py_3_9)) {
#[cfg(not(Py_3_9))]
{
// __dict__ support
if let Some(dict_offset) = PyCell::<T>::dict_offset() {
unsafe {
@ -258,12 +261,6 @@ fn py_class_members<T: PyClass>() -> Vec<ffi::structmember::PyMemberDef> {
members
}
// Stub needed since the `if cfg!()` above still compiles contained code.
#[cfg(not(Py_3_9))]
fn py_class_members<T: PyClass>() -> Vec<ffi::structmember::PyMemberDef> {
vec![]
}
const PY_GET_SET_DEF_INIT: ffi::PyGetSetDef = ffi::PyGetSetDef {
name: ptr::null_mut(),
get: None,
@ -272,7 +269,6 @@ const PY_GET_SET_DEF_INIT: ffi::PyGetSetDef = ffi::PyGetSetDef {
closure: ptr::null_mut(),
};
#[allow(clippy::collapsible_if)] // for if cfg!
fn py_class_properties(
is_dummy: bool,
for_each_method_def: &dyn Fn(&mut dyn FnMut(&[PyMethodDefType])),

View File

@ -227,8 +227,9 @@ impl PyString {
pub unsafe fn data(&self) -> PyResult<PyStringData<'_>> {
let ptr = self.as_ptr();
if cfg!(not(Py_3_12)) {
#[cfg(not(Py_3_12))]
#[allow(deprecated)]
{
let ready = ffi::PyUnicode_READY(ptr);
if ready != 0 {
// Exception was created on failure.

View File

@ -23,22 +23,15 @@ fn _test_compile_errors() {
t.compile_fail("tests/ui/invalid_pymethods.rs");
t.compile_fail("tests/ui/invalid_pymethod_names.rs");
t.compile_fail("tests/ui/invalid_argument_attributes.rs");
t.compile_fail("tests/ui/missing_clone.rs");
t.compile_fail("tests/ui/reject_generics.rs");
t.compile_fail("tests/ui/wrong_aspyref_lifetimes.rs");
tests_rust_1_48(&t);
tests_rust_1_49(&t);
tests_rust_1_54(&t);
tests_rust_1_55(&t);
tests_rust_1_56(&t);
#[rustversion::since(1.48)]
fn tests_rust_1_48(t: &trybuild::TestCases) {
t.compile_fail("tests/ui/missing_clone.rs");
t.compile_fail("tests/ui/wrong_aspyref_lifetimes.rs");
}
#[rustversion::before(1.48)]
fn tests_rust_1_48(_t: &trybuild::TestCases) {}
#[rustversion::since(1.49)]
fn tests_rust_1_49(t: &trybuild::TestCases) {
t.compile_fail("tests/ui/deprecations.rs");

View File

@ -2,9 +2,7 @@
//! but can't even be cfg-ed out on MSRV because the compiler doesn't support
//! the syntax.
// TODO(#1782) rustversion attribute can't go on modules until Rust 1.42, so this
// funky dance has to happen...
#[rustversion::since(1.54)]
mod requires_1_54 {
#[rustversion::since(1.54)]
include!("not_msrv/requires_1_54.rs");
}

View File

@ -6,15 +6,15 @@ error[E0277]: the trait bound `PyDict: PyClass` is not satisfied
|
= note: required because of the requirements on the impl of `PyClassBaseType` for `PyDict`
note: required by a bound in `PyClassBaseType`
--> src/class/impl_.rs:766:1
--> src/class/impl_.rs
|
766 | / pub trait PyClassBaseType: Sized {
767 | | type Dict;
768 | | type WeakRef;
769 | | type LayoutAsBase: PyCellLayout<Self>;
| / pub trait PyClassBaseType: Sized {
| | type Dict;
| | type WeakRef;
| | type LayoutAsBase: PyCellLayout<Self>;
... |
772 | | type Initializer: PyObjectInit<Self>;
773 | | }
| | type Initializer: PyObjectInit<Self>;
| | }
| |_^ required by this bound in `PyClassBaseType`
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)
@ -26,8 +26,8 @@ error[E0277]: the trait bound `PyDict: PyClass` is not satisfied
|
= note: required because of the requirements on the impl of `PyClassBaseType` for `PyDict`
note: required by a bound in `ThreadCheckerInherited`
--> src/class/impl_.rs:753:47
--> src/class/impl_.rs
|
753 | pub struct ThreadCheckerInherited<T: Send, U: PyClassBaseType>(PhantomData<T>, U::ThreadChecker);
| pub struct ThreadCheckerInherited<T: Send, U: PyClassBaseType>(PhantomData<T>, U::ThreadChecker);
| ^^^^^^^^^^^^^^^ required by this bound in `ThreadCheckerInherited`
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)

View File

@ -50,6 +50,3 @@ fn my_module(_py: Python, m: &PyModule) -> PyResult<()> {
fn main() {
}
// TODO: ensure name deprecated on #[pyfunction] and #[pymodule]

View File

@ -11,8 +11,8 @@ note: required because it appears within the type `NotThreadSafe`
5 | struct NotThreadSafe {
| ^^^^^^^^^^^^^
note: required by a bound in `ThreadCheckerStub`
--> src/class/impl_.rs:710:33
--> src/class/impl_.rs
|
710 | pub struct ThreadCheckerStub<T: Send>(PhantomData<T>);
| pub struct ThreadCheckerStub<T: Send>(PhantomData<T>);
| ^^^^ required by this bound in `ThreadCheckerStub`
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)