msrv: bump to 1.48
This commit is contained in:
parent
f29a8e1b91
commit
6a65f98bd2
|
@ -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:
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
13
Cargo.toml
13
Cargo.toml
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -52,7 +52,6 @@ extern "C" {
|
|||
fn _Py_CheckRecursiveCall(_where: *mut c_char) -> c_int;
|
||||
}
|
||||
|
||||
// TODO
|
||||
// skipped Py_EnterRecursiveCall
|
||||
// skipped Py_LeaveRecursiveCall
|
||||
|
||||
|
|
13
src/gil.rs
13
src/gil.rs
|
@ -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 don’t 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();
|
||||
|
|
|
@ -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
|
||||
//!
|
||||
|
|
|
@ -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])),
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -50,6 +50,3 @@ fn my_module(_py: Python, m: &PyModule) -> PyResult<()> {
|
|||
fn main() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// TODO: ensure name deprecated on #[pyfunction] and #[pymodule]
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue