diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c0ccb600..cae815a3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,7 +25,7 @@ jobs: - name: Install Rust uses: actions-rs/toolchain@v1 with: - toolchain: nightly + toolchain: stable default: true - run: rustup set default-host ${{ matrix.platform.rust-target }} - name: Build without default features diff --git a/.travis.yml b/.travis.yml index 5ab7b527..8f9d450d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ jobs: env: global: - - TRAVIS_RUST_VERSION=nightly + - TRAVIS_RUST_VERSION=stable - RUST_BACKTRACE=1 before_install: diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fe74cb0..883fcde2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] ### Added +- stable rust support - Add FFI definition `PyObject_AsFileDescriptor` [#938](https://github.com/PyO3/pyo3/pull/938) - Add `PyByteArray::data`, `PyByteArray::as_bytes`, and `PyByteArray::as_bytes_mut`. [#967](https://github.com/PyO3/pyo3/pull/967) - Add `Py::borrow`, `Py::borrow_mut`, `Py::try_borrow`, and `Py::try_borrow_mut` for accessing `#[pyclass]` values. [#976](https://github.com/PyO3/pyo3/pull/976) diff --git a/Cargo.toml b/Cargo.toml index d18cafd6..7fa6398f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,12 +34,10 @@ unindent = { version = "0.1.4", optional = true } assert_approx_eq = "1.1.0" trybuild = "1.0.23" -[build-dependencies] -version_check = "0.9.1" - [features] default = ["macros"] macros = ["ctor", "indoc", "inventory", "paste", "pyo3cls", "unindent"] +nightly = [] # this is no longer needed internally, but setuptools-rust assumes this feature python3 = [] diff --git a/README.md b/README.md index 37e1b79e..305b02f8 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,7 @@ A comparison with rust-cpython can be found [in the guide](https://pyo3.rs/maste ## Usage -PyO3 supports Python 3.5 and up. The minimum required Rust version is 1.42.0-nightly 2020-01-21. - -If you have never used nightly Rust, the official guide has -[a great section](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#rustup-and-the-role-of-rust-nightly) -about installing it. +PyO3 supports Python 3.5 and up. The minimum required Rust version is 1.44. PyPy is also supported (via cpyext) for Python 3.5 only, targeted PyPy version is 7.0.0. Please refer to the [pypy section in the guide](https://pyo3.rs/master/pypy.html). diff --git a/build.rs b/build.rs index 4459041d..15621c35 100644 --- a/build.rs +++ b/build.rs @@ -8,13 +8,6 @@ use std::{ process::{Command, Stdio}, str::FromStr, }; -use version_check::{Channel, Date, Version}; - -/// Specifies the minimum nightly version needed to compile pyo3. -/// Keep this synced up with the travis ci config, -/// But note that this is the rustc version which can be lower than the nightly version -const MIN_DATE: &str = "2020-01-20"; -const MIN_VERSION: &str = "1.42.0-nightly"; const PY3_MIN_MINOR: u8 = 5; const CFG_KEY: &str = "py_sys_config"; @@ -567,34 +560,7 @@ fn check_target_architecture(interpreter_config: &InterpreterConfig) -> Result<( Ok(()) } -fn check_rustc_version() -> Result<()> { - let channel = Channel::read().ok_or("Failed to determine rustc channel")?; - if !channel.supports_features() { - bail!("PyO3 requires a nightly or dev version of Rust."); - } - - let actual_version = Version::read().ok_or("Failed to determine the rustc version")?; - if !actual_version.at_least(MIN_VERSION) { - bail!( - "PyO3 requires at least rustc {}, while the current version is {}", - MIN_VERSION, - actual_version - ) - } - - let actual_date = Date::read().ok_or("Failed to determine the rustc date")?; - if !actual_date.at_least(MIN_DATE) { - bail!( - "PyO3 requires at least rustc {}, while the current rustc date is {}", - MIN_DATE, - actual_date - ) - } - Ok(()) -} - fn main() -> Result<()> { - check_rustc_version()?; // 1. Setup cfg variables so we can do conditional compilation in this library based on the // python interpeter's compilation flags. This is necessary for e.g. matching the right unicode // and threading interfaces. First check if we're cross compiling, if so, we cannot run the diff --git a/guide/src/rust_cpython.md b/guide/src/rust_cpython.md index e5912465..4eb670d2 100644 --- a/guide/src/rust_cpython.md +++ b/guide/src/rust_cpython.md @@ -6,7 +6,7 @@ This chapter is based on the discussion in [PyO3/pyo3#55](https://github.com/PyO ## Macros -While rust-cpython has a macro based dsl for declaring modules and classes, PyO3 uses proc macros and specialization. PyO3 also doesn't change your struct and functions so you can still use them as normal Rust functions. The disadvantage is that specialization currently only works on nightly. +While rust-cpython has a macro based dsl for declaring modules and classes, PyO3 uses proc macros and specialization. PyO3 also doesn't change your struct and functions so you can still use them as normal Rust functions. **rust-cpython** diff --git a/src/conversion.rs b/src/conversion.rs index 52e68439..8ec196f8 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -98,6 +98,7 @@ pub trait ToBorrowedObject: ToPyObject { F: FnOnce(*mut ffi::PyObject) -> R; } +#[cfg(feature = "nightly")] impl ToBorrowedObject for T where T: ToPyObject, @@ -115,6 +116,25 @@ where } } +#[cfg(not(feature = "nightly"))] +impl ToBorrowedObject for T +where + T: ToPyObject, +{ + fn with_borrowed_ptr(&self, py: Python, f: F) -> R + where + F: FnOnce(*mut ffi::PyObject) -> R, + { + let ptr = self.to_object(py).into_ptr(); + let result = f(ptr); + unsafe { + ffi::Py_XDECREF(ptr); + } + result + } +} + +#[cfg(feature = "nightly")] impl ToBorrowedObject for T where T: ToPyObject + AsPyPointer, diff --git a/src/lib.rs b/src/lib.rs index 92204145..948af9d6 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] +#![cfg_attr(nightly, feature(specialization))] #![allow(clippy::missing_safety_doc)] // FIXME (#698) //! Rust bindings to the Python interpreter. diff --git a/src/types/sequence.rs b/src/types/sequence.rs index 33a84a92..b8aedb3c 100644 --- a/src/types/sequence.rs +++ b/src/types/sequence.rs @@ -1,5 +1,6 @@ // Copyright (c) 2017-present PyO3 Project and Contributors +#[cfg(feature = "nightly")] use crate::buffer; use crate::err::{self, PyDowncastError, PyErr, PyResult}; use crate::exceptions; @@ -261,6 +262,7 @@ impl PySequence { macro_rules! array_impls { ($($N:expr),+) => { $( + #[cfg(feature = "nightly")] impl<'a, T> FromPyObject<'a> for [T; $N] where T: Copy + Default + FromPyObject<'a>, @@ -272,6 +274,19 @@ macro_rules! array_impls { } } + #[cfg(not(feature = "nightly"))] + impl<'a, T> FromPyObject<'a> for [T; $N] + where + T: Copy + Default + FromPyObject<'a>, + { + fn extract(obj: &'a PyAny) -> PyResult { + let mut array = [T::default(); $N]; + extract_sequence_into_slice(obj, &mut array)?; + Ok(array) + } + } + + #[cfg(feature = "nightly")] impl<'source, T> FromPyObject<'source> for [T; $N] where for<'a> T: Copy + Default + FromPyObject<'a> + buffer::Element, @@ -300,6 +315,17 @@ array_impls!( 26, 27, 28, 29, 30, 31, 32 ); +#[cfg(not(feature = "nightly"))] +impl<'a, T> FromPyObject<'a> for Vec +where + T: FromPyObject<'a>, +{ + fn extract(obj: &'a PyAny) -> PyResult { + extract_sequence(obj) + } +} + +#[cfg(feature = "nightly")] impl<'a, T> FromPyObject<'a> for Vec where T: FromPyObject<'a>, @@ -309,6 +335,7 @@ where } } +#[cfg(feature = "nightly")] impl<'source, T> FromPyObject<'source> for Vec where for<'a> T: FromPyObject<'a> + buffer::Element + Copy, diff --git a/tests/test_datetime.rs b/tests/test_datetime.rs index b5db6d08..81e2010f 100644 --- a/tests/test_datetime.rs +++ b/tests/test_datetime.rs @@ -1,5 +1,6 @@ -#![feature(concat_idents)] +#![cfg_attr(nightly, feature(concat_idents))] +#[cfg(feature = "nightly")] use pyo3::ffi::*; use pyo3::prelude::*; use pyo3::types::IntoPyDict; @@ -34,6 +35,7 @@ fn _get_subclasses<'p>( Ok((obj, sub_obj, sub_sub_obj)) } +#[cfg(feature = "nightly")] macro_rules! assert_check_exact { ($check_func:ident, $obj: expr) => { unsafe { @@ -44,6 +46,7 @@ macro_rules! assert_check_exact { }; } +#[cfg(feature = "nightly")] macro_rules! assert_check_only { ($check_func:ident, $obj: expr) => { unsafe { @@ -54,6 +57,7 @@ macro_rules! assert_check_only { }; } +#[cfg(feature = "nightly")] #[test] fn test_date_check() { let gil = Python::acquire_gil(); @@ -65,6 +69,7 @@ fn test_date_check() { assert_check_only!(PyDate_Check, sub_sub_obj); } +#[cfg(feature = "nightly")] #[test] fn test_time_check() { let gil = Python::acquire_gil(); @@ -76,6 +81,7 @@ fn test_time_check() { assert_check_only!(PyTime_Check, sub_sub_obj); } +#[cfg(feature = "nightly")] #[test] fn test_datetime_check() { let gil = Python::acquire_gil(); @@ -90,6 +96,7 @@ fn test_datetime_check() { assert_check_only!(PyDateTime_Check, sub_sub_obj); } +#[cfg(feature = "nightly")] #[test] fn test_delta_check() { let gil = Python::acquire_gil();