From 4079c8b5ea3d7b66ceb8712c58fb58a3633f5ac6 Mon Sep 17 00:00:00 2001 From: messense Date: Tue, 15 Mar 2022 20:47:39 +0800 Subject: [PATCH 01/27] Limit concurrency on GitHub Actions https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency --- .github/workflows/bench.yml | 4 ++++ .github/workflows/ci.yml | 4 ++++ .github/workflows/guide.yml | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 012d57792e3..97aa715afa6 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -4,6 +4,10 @@ on: - main pull_request: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + name: Benchmark jobs: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 46c04767081..55a6c852010 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,10 @@ on: - main pull_request: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + env: CARGO_TERM_COLOR: always diff --git a/.github/workflows/guide.yml b/.github/workflows/guide.yml index 923fedd1f5f..1ce637c0cd9 100644 --- a/.github/workflows/guide.yml +++ b/.github/workflows/guide.yml @@ -8,6 +8,10 @@ on: release: types: [published] +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + env: CARGO_TERM_COLOR: always From ddf37fdc9f2250b5e432d52ab81cabbf57293f26 Mon Sep 17 00:00:00 2001 From: messense Date: Tue, 15 Mar 2022 23:46:02 +0800 Subject: [PATCH 02/27] CI: keep going on failure only if `CI-no-fail-fast` label is present --- .github/workflows/ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55a6c852010..7558b849a8b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,7 +45,8 @@ jobs: needs: [fmt] runs-on: ubuntu-latest strategy: - fail-fast: false # If one platform fails, allow the rest to keep testing. + # If one platform fails, allow the rest to keep testing if `CI-no-fail-fast` label is present + fail-fast: ${{ !contains(github.event.pull_request.labels.*.name, 'CI-no-fail-fast') }} matrix: target: [powerpc64le-unknown-linux-gnu, s390x-unknown-linux-gnu, wasm32-wasi] name: check-${{ matrix.target }} @@ -77,7 +78,8 @@ jobs: name: python${{ matrix.python-version }}-${{ matrix.platform.python-architecture }} ${{ matrix.platform.os }} ${{ matrix.msrv }} runs-on: ${{ matrix.platform.os }} strategy: - fail-fast: false # If one platform fails, allow the rest to keep testing. + # If one platform fails, allow the rest to keep testing if `CI-no-fail-fast` label is present + fail-fast: ${{ !contains(github.event.pull_request.labels.*.name, 'CI-no-fail-fast') }} matrix: rust: [stable] python-version: [3.6, 3.7, 3.8, 3.9, "3.10", pypy-3.6, pypy-3.7, pypy-3.8] From f11322731aca55c1e4b7cea2b49a6dc4d828cd2c Mon Sep 17 00:00:00 2001 From: messense Date: Thu, 31 Mar 2022 18:14:25 +0800 Subject: [PATCH 03/27] Test 32-bit Windows only with the latest Python version --- .github/workflows/ci.yml | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7558b849a8b..8c5cdd7b856 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -100,24 +100,7 @@ jobs: python-architecture: "x64", rust-target: "x86_64-pc-windows-msvc", }, - { - os: "windows-latest", - python-architecture: "x86", - rust-target: "i686-pc-windows-msvc", - }, ] - exclude: - # PyPy 3.6 is EOL and not working on macos-latest (now macos-11) - - python-version: pypy-3.6 - platform: { os: "macos-latest", python-architecture: "x64" } - # There is no 64-bit pypy on windows for pypy-3.6 - - python-version: pypy-3.6 - platform: { os: "windows-latest", python-architecture: "x64" } - # PyPy 3.7 on Windows doesn't release 32-bit builds any more - - python-version: pypy-3.7 - platform: { os: "windows-latest", python-architecture: "x86" } - - python-version: pypy-3.8 - platform: { os: "windows-latest", python-architecture: "x86" } include: # PyPy3.6 still runs on macos-10.15 - rust: stable @@ -138,6 +121,15 @@ jobs: rust-target: "x86_64-unknown-linux-gnu", } msrv: "MSRV" + # Test 32-bit Windows only with the latest Python version + - rust: stable + python-version: "3.10" + platform: + { + os: "windows-latest", + python-architecture: "x86", + rust-target: "i686-pc-windows-msvc", + } steps: - uses: actions/checkout@v2 From 6d4b363a14e7c0c127a1d6b2d1650e67577579b7 Mon Sep 17 00:00:00 2001 From: messense Date: Thu, 31 Mar 2022 18:16:13 +0800 Subject: [PATCH 04/27] Add pypy-3.9 to CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c5cdd7b856..5c973d76c7c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,7 +82,7 @@ jobs: fail-fast: ${{ !contains(github.event.pull_request.labels.*.name, 'CI-no-fail-fast') }} matrix: rust: [stable] - python-version: [3.6, 3.7, 3.8, 3.9, "3.10", pypy-3.6, pypy-3.7, pypy-3.8] + python-version: [3.6, 3.7, 3.8, 3.9, "3.10", pypy-3.6, pypy-3.7, pypy-3.8, pypy-3.9] platform: [ { From 48fe21cde31ad0313c7661f47dcf02542386fde6 Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Thu, 24 Feb 2022 19:41:09 +0000 Subject: [PATCH 05/27] pypy: include minor version in library on Python 3.9 --- pyo3-build-config/src/impl_.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/pyo3-build-config/src/impl_.rs b/pyo3-build-config/src/impl_.rs index 6a73b3b97d6..72ddc5f54e3 100644 --- a/pyo3-build-config/src/impl_.rs +++ b/pyo3-build-config/src/impl_.rs @@ -1062,7 +1062,16 @@ fn default_lib_name_unix( Some(ld_version) => format!("python{}", ld_version), None => format!("python{}.{}", version.major, version.minor), }, - PythonImplementation::PyPy => format!("pypy{}-c", version.major), + 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) + } + } } } @@ -1472,11 +1481,17 @@ mod tests { "python3.7md", ); - // PyPy ignores ldversion + // PyPy 3.7 ignores ldversion assert_eq!( - super::default_lib_name_unix(PythonVersion { major: 3, minor: 9 }, PyPy, Some("3.7md")), + super::default_lib_name_unix(PythonVersion { major: 3, minor: 7 }, PyPy, Some("3.7md")), "pypy3-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", + ); } #[test] From d1c5af98c1db479cb45d61753173cfe95fcefa6e Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Thu, 24 Feb 2022 23:05:58 +0000 Subject: [PATCH 06/27] ffi: add missing definition PyCMethod_New --- src/ffi/methodobject.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/ffi/methodobject.rs b/src/ffi/methodobject.rs index b1b435d7c51..c1bc431f89f 100644 --- a/src/ffi/methodobject.rs +++ b/src/ffi/methodobject.rs @@ -83,6 +83,7 @@ impl Default for PyMethodDef { } } +#[cfg(not(Py_3_9))] extern "C" { #[cfg_attr(PyPy, link_name = "PyPyCFunction_New")] pub fn PyCFunction_New(ml: *mut PyMethodDef, slf: *mut PyObject) -> *mut PyObject; @@ -95,7 +96,32 @@ extern "C" { ) -> *mut PyObject; } -// skipped non-limited / 3.9 PyCMethod_New +#[cfg(Py_3_9)] +#[inline] +pub unsafe fn PyCFunction_New(ml: *mut PyMethodDef, slf: *mut PyObject) -> *mut PyObject { + PyCFunction_NewEx(ml, slf, std::ptr::null_mut()) +} + +#[cfg(Py_3_9)] +#[inline] +pub unsafe fn PyCFunction_NewEx( + ml: *mut PyMethodDef, + slf: *mut PyObject, + module: *mut PyObject, +) -> *mut PyObject { + PyCMethod_New(ml, slf, module, std::ptr::null_mut()) +} + +#[cfg(Py_3_9)] +extern "C" { + #[cfg_attr(PyPy, link_name = "PyPyCMethod_New")] + pub fn PyCMethod_New( + ml: *mut PyMethodDef, + slf: *mut PyObject, + module: *mut PyObject, + cls: *mut PyTypeObject, + ) -> *mut PyObject; +} /* Flag passed to newmethodobject */ pub const METH_VARARGS: c_int = 0x0001; From fb8960085a51db4564a3e1629dd9b26baa9e4cb6 Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Fri, 25 Feb 2022 00:08:48 +0000 Subject: [PATCH 07/27] pypy: don't allow abi to be adjusted by abi3 flag --- pyo3-build-config/src/impl_.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyo3-build-config/src/impl_.rs b/pyo3-build-config/src/impl_.rs index 72ddc5f54e3..821ae04ce90 100644 --- a/pyo3-build-config/src/impl_.rs +++ b/pyo3-build-config/src/impl_.rs @@ -1177,6 +1177,11 @@ fn fixup_config_for_abi3( config: &mut InterpreterConfig, abi3_version: Option, ) -> Result<()> { + // PyPy doesn't support abi3; don't adjust the version + if config.implementation.is_pypy() { + return Ok(()); + } + if let Some(version) = abi3_version { ensure!( version <= config.version, From c18e60f92894173e7ff6fa1ce0d6ecd002ebc824 Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Thu, 31 Mar 2022 18:26:16 +0800 Subject: [PATCH 08/27] pypy: support 7.3.8 Co-authored-by: messense --- src/callback.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/callback.rs b/src/callback.rs index e29f07e0979..a9dc1429db8 100644 --- a/src/callback.rs +++ b/src/callback.rs @@ -244,6 +244,21 @@ where let unwind_safe_py = AssertUnwindSafe(pool.python()); let panic_result = panic::catch_unwind(move || -> PyResult<_> { let py = *unwind_safe_py; + #[cfg(all(PyPy, not(Py_3_8)))] + { + 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.", + ))?; + } + } body(py) }); From 7b4b77b6d6a223146642bc26d675cf5e811e7eb2 Mon Sep 17 00:00:00 2001 From: messense Date: Thu, 31 Mar 2022 18:29:58 +0800 Subject: [PATCH 09/27] Update black to 22.3.0 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5c973d76c7c..20e2273e7ab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 - - run: pip install black==20.8b1 + - run: pip install black==22.3.0 - uses: actions-rs/toolchain@v1 with: toolchain: stable From cc594a27868a35721cbc1d9be045b4295ed91eb6 Mon Sep 17 00:00:00 2001 From: messense Date: Thu, 31 Mar 2022 18:32:04 +0800 Subject: [PATCH 10/27] black format --- examples/pyo3-pytests/tests/test_othermod.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/pyo3-pytests/tests/test_othermod.py b/examples/pyo3-pytests/tests/test_othermod.py index 08ac367a4e9..ff67bba435c 100644 --- a/examples/pyo3-pytests/tests/test_othermod.py +++ b/examples/pyo3-pytests/tests/test_othermod.py @@ -3,14 +3,14 @@ from pyo3_pytests import othermod -INTEGER32_ST = st.integers(min_value=(-(2 ** 31)), max_value=(2 ** 31 - 1)) +INTEGER32_ST = st.integers(min_value=(-(2**31)), max_value=(2**31 - 1)) USIZE_ST = st.integers(min_value=othermod.USIZE_MIN, max_value=othermod.USIZE_MAX) @given(x=INTEGER32_ST) def test_double(x): expected = x * 2 - assume(-(2 ** 31) <= expected <= (2 ** 31 - 1)) + assume(-(2**31) <= expected <= (2**31 - 1)) assert othermod.double(x) == expected From b16335f4dd6ef2f88e536193772054d04db68f66 Mon Sep 17 00:00:00 2001 From: messense Date: Thu, 31 Mar 2022 18:46:03 +0800 Subject: [PATCH 11/27] Fix some clippy warnings --- examples/pyo3-benchmarks/src/lib.rs | 1 + examples/pyo3-pytests/src/datetime.rs | 1 + pyo3-build-config/src/impl_.rs | 2 +- pyo3-macros-backend/src/utils.rs | 6 +----- src/buffer.rs | 4 ++++ src/conversion.rs | 4 ++++ src/err/mod.rs | 2 +- src/gil.rs | 1 + src/instance.rs | 4 ++++ src/type_object.rs | 15 +++++++++++++++ tests/hygiene/pymethods.rs | 1 + tests/test_frompyobject.rs | 1 + tests/test_mapping.rs | 1 + tests/test_methods.rs | 1 + tests/test_sequence.rs | 1 + 15 files changed, 38 insertions(+), 7 deletions(-) diff --git a/examples/pyo3-benchmarks/src/lib.rs b/examples/pyo3-benchmarks/src/lib.rs index e649fd1c65d..362e83713e9 100644 --- a/examples/pyo3-benchmarks/src/lib.rs +++ b/examples/pyo3-benchmarks/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(clippy::needless_option_as_deref)] use pyo3::prelude::*; use pyo3::types::{PyDict, PyTuple}; diff --git a/examples/pyo3-pytests/src/datetime.rs b/examples/pyo3-pytests/src/datetime.rs index a3522b4845e..2977d83b12b 100644 --- a/examples/pyo3-pytests/src/datetime.rs +++ b/examples/pyo3-pytests/src/datetime.rs @@ -1,3 +1,4 @@ +#![allow(clippy::needless_option_as_deref)] use pyo3::prelude::*; use pyo3::types::{ PyDate, PyDateAccess, PyDateTime, PyDelta, PyDeltaAccess, PyTime, PyTimeAccess, PyTuple, diff --git a/pyo3-build-config/src/impl_.rs b/pyo3-build-config/src/impl_.rs index 821ae04ce90..0fa3bddb4a7 100644 --- a/pyo3-build-config/src/impl_.rs +++ b/pyo3-build-config/src/impl_.rs @@ -911,7 +911,7 @@ fn search_lib_dir(path: impl AsRef, cross: &CrossCompileConfig) -> Vec vec![f.path()], diff --git a/pyo3-macros-backend/src/utils.rs b/pyo3-macros-backend/src/utils.rs index b0353cdc16a..28a8b9200df 100644 --- a/pyo3-macros-backend/src/utils.rs +++ b/pyo3-macros-backend/src/utils.rs @@ -79,11 +79,7 @@ pub fn get_doc( syn::token::Bracket(Span::call_site()).surround(&mut tokens, |tokens| { if let Some((python_name, text_signature)) = text_signature { // create special doc string lines to set `__text_signature__` - let signature_lines = format!( - "{}{}\n--\n\n", - python_name.to_string(), - text_signature.lit.value() - ); + let signature_lines = format!("{}{}\n--\n\n", python_name, text_signature.lit.value()); signature_lines.to_tokens(tokens); comma.to_tokens(tokens); } diff --git a/src/buffer.rs b/src/buffer.rs index 07f6321aecd..9a7a404bdcf 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -168,6 +168,10 @@ fn is_matching_endian(c: u8) -> bool { } /// Trait implemented for possible element types of `PyBuffer`. +/// +/// # Safety +/// +/// This trait must only be implemented for types which represent valid elements of Python buffers. pub unsafe trait Element: Copy { /// Gets whether the element specified in the format string is potentially compatible. /// Alignment and size are checked separately from this function. diff --git a/src/conversion.rs b/src/conversion.rs index e1238edc80e..ccd690bee15 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -463,6 +463,10 @@ impl IntoPy> for () { } /// Raw level conversion between `*mut ffi::PyObject` and PyO3 types. +/// +/// # Safety +/// +/// See safety notes on individual functions. pub unsafe trait FromPyPointer<'p>: Sized { /// Convert from an arbitrary `PyObject`. /// diff --git a/src/err/mod.rs b/src/err/mod.rs index db23c6782c5..c2583372842 100644 --- a/src/err/mod.rs +++ b/src/err/mod.rs @@ -437,7 +437,7 @@ impl PyErr { pub fn cause(&self, py: Python) -> Option { let ptr = unsafe { ffi::PyException_GetCause(self.pvalue(py).as_ptr()) }; let obj = unsafe { py.from_owned_ptr_or_opt::(ptr) }; - obj.map(|x| Self::from_instance(x)) + obj.map(Self::from_instance) } /// Set the cause associated with the exception, pass `None` to clear it. diff --git a/src/gil.rs b/src/gil.rs index 588d45f1fe6..57ba4fc52f9 100644 --- a/src/gil.rs +++ b/src/gil.rs @@ -704,6 +704,7 @@ mod tests { assert!(gil_is_acquired()); } + #[allow(clippy::needless_late_init)] #[test] fn dropping_gil_does_not_invalidate_references() { // Acquiring GIL for the second time should be safe - see #864 diff --git a/src/instance.rs b/src/instance.rs index 269d22f3107..6b24335868c 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -17,6 +17,10 @@ use std::ptr::NonNull; /// PyO3 is designed in a way that all references to those types are bound /// to the GIL, which is why you can get a token from all references of those /// types. +/// +/// # Safety +/// +/// This trait must only be implemented for types which cannot be accessed without the GIL. pub unsafe trait PyNativeType: Sized { /// Returns a GIL marker constrained to the lifetime of this type. #[inline] diff --git a/src/type_object.rs b/src/type_object.rs index 0f16f566f99..588ffb9d3d9 100644 --- a/src/type_object.rs +++ b/src/type_object.rs @@ -16,6 +16,11 @@ use std::thread::{self, ThreadId}; /// is of `PyAny`. /// /// This trait is intended to be used internally. +/// +/// # Safety +/// +/// Implementations must provide an implementation for `type_object_raw` which infallibly produces a +/// non-null pointer to the corresponding Python type object. pub unsafe trait PyLayout {} /// `T: PySizedLayout` represents that `T` is not a instance of @@ -31,6 +36,11 @@ pub trait PySizedLayout: PyLayout + Sized {} /// - the return value of type_object must always point to the same PyTypeObject instance /// /// It is safely implemented by the `pyclass` macro. +/// +/// # Safety +/// +/// Implementations must provide an implementation for `type_object_raw` which infallibly produces a +/// non-null pointer to the corresponding Python type object. pub unsafe trait PyTypeInfo: Sized { /// Class name. const NAME: &'static str; @@ -60,6 +70,11 @@ pub unsafe trait PyTypeInfo: Sized { /// This trait is marked unsafe because not fulfilling the contract for type_object /// leads to UB. /// +/// # Safety +/// +/// This trait is marked unsafe because not fulfilling the contract for type_object +/// leads to UB. +/// /// See also [PyTypeInfo::type_object_raw](trait.PyTypeInfo.html#tymethod.type_object_raw). pub unsafe trait PyTypeObject { /// Returns the safe abstraction over the type object. diff --git a/tests/hygiene/pymethods.rs b/tests/hygiene/pymethods.rs index 37a916f9c6b..c901834ad86 100644 --- a/tests/hygiene/pymethods.rs +++ b/tests/hygiene/pymethods.rs @@ -1,5 +1,6 @@ #![no_implicit_prelude] #![allow(unused_variables)] +#![allow(clippy::needless_option_as_deref)] #[::pyo3::pyclass] pub struct Dummy; diff --git a/tests/test_frompyobject.rs b/tests/test_frompyobject.rs index 54f6e322e0f..889ed13f0a3 100644 --- a/tests/test_frompyobject.rs +++ b/tests/test_frompyobject.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] use pyo3::exceptions::PyValueError; use pyo3::prelude::*; use pyo3::types::{PyDict, PyString, PyTuple}; diff --git a/tests/test_mapping.rs b/tests/test_mapping.rs index 42710094e76..194e25562e2 100644 --- a/tests/test_mapping.rs +++ b/tests/test_mapping.rs @@ -1,4 +1,5 @@ #![allow(deprecated)] // for deprecated protocol methods +#![allow(clippy::needless_option_as_deref)] use std::collections::HashMap; diff --git a/tests/test_methods.rs b/tests/test_methods.rs index 1032acf9a0d..0199d9efd8e 100644 --- a/tests/test_methods.rs +++ b/tests/test_methods.rs @@ -1,3 +1,4 @@ +#![allow(clippy::needless_option_as_deref)] use pyo3::prelude::*; use pyo3::py_run; use pyo3::types::{IntoPyDict, PyDict, PyList, PySet, PyString, PyTuple, PyType}; diff --git a/tests/test_sequence.rs b/tests/test_sequence.rs index 0cb467ee648..f32acfe2d60 100644 --- a/tests/test_sequence.rs +++ b/tests/test_sequence.rs @@ -1,3 +1,4 @@ +#![allow(clippy::needless_option_as_deref)] use pyo3::class::PySequenceProtocol; use pyo3::exceptions::{PyIndexError, PyValueError}; use pyo3::prelude::*; From 2b696e38eb37b3a66059d09b79e7ea13c5ea424e Mon Sep 17 00:00:00 2001 From: messense Date: Thu, 31 Mar 2022 18:51:24 +0800 Subject: [PATCH 12/27] Add serde with derive feature to dev dependencies --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index fb90960b470..99d094b447a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,7 @@ trybuild = "1.0.49" rustversion = "1.0" # 1.0.0 requires Rust 1.50 proptest = { version = "0.10.1", default-features = false, features = ["std"] } +serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.61" # features needed to run the PyO3 test suite From cb8ec38a1512fb8208d274499fea650abd7803aa Mon Sep 17 00:00:00 2001 From: messense Date: Thu, 31 Mar 2022 19:22:12 +0800 Subject: [PATCH 13/27] cargo update -p clap --precise 2.33.4 --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 20e2273e7ab..e777fa9a013 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -182,6 +182,7 @@ jobs: run: | cargo update -p indexmap --precise 1.6.2 cargo update -p hashbrown:0.11.2 --precise 0.9.1 + cargo update -p clap --precise 2.33.4 - name: Build docs run: cargo doc --no-deps --no-default-features --features "${{ steps.settings.outputs.all_additive_features }}" From f6cf4c362d58f65fdd7269df8cd688831ec493fa Mon Sep 17 00:00:00 2001 From: messense Date: Thu, 31 Mar 2022 19:28:44 +0800 Subject: [PATCH 14/27] Remove link_name PyPyUnicode_FromFormatV --- src/ffi/unicodeobject.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ffi/unicodeobject.rs b/src/ffi/unicodeobject.rs index 61a60f8c101..22dd20bfa7e 100644 --- a/src/ffi/unicodeobject.rs +++ b/src/ffi/unicodeobject.rs @@ -78,9 +78,6 @@ extern "C" { #[cfg_attr(PyPy, link_name = "PyPyUnicode_FromObject")] pub fn PyUnicode_FromObject(obj: *mut PyObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyUnicode_FromFormat")] - #[cfg_attr(PyPy, link_name = "PyPyUnicode_FromFormatV")] - //pub fn PyUnicode_FromFormatV(format: *const c_char, - // vargs: va_list) -> *mut PyObject; pub fn PyUnicode_FromFormat(format: *const c_char, ...) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyUnicode_InternInPlace")] pub fn PyUnicode_InternInPlace(arg1: *mut *mut PyObject); From 74517b9c273d1a3cc23a4ea8034f0283351b6972 Mon Sep 17 00:00:00 2001 From: messense Date: Thu, 31 Mar 2022 20:03:05 +0800 Subject: [PATCH 15/27] Bless ui tests --- tests/ui/invalid_pyfunctions.stderr | 2 +- tests/ui/invalid_pymethod_receiver.stderr | 31 ++++++++++------------- tests/ui/invalid_pymethods.stderr | 2 +- tests/ui/missing_clone.stderr | 17 ++++++++----- tests/ui/static_ref.stderr | 2 +- tests/ui/wrong_aspyref_lifetimes.stderr | 4 +-- 6 files changed, 29 insertions(+), 29 deletions(-) diff --git a/tests/ui/invalid_pyfunctions.stderr b/tests/ui/invalid_pyfunctions.stderr index 00bf963faed..6587535ac55 100644 --- a/tests/ui/invalid_pyfunctions.stderr +++ b/tests/ui/invalid_pyfunctions.stderr @@ -12,7 +12,7 @@ error: Python functions cannot have `impl Trait` arguments error: `async fn` is not yet supported for Python functions. -Additional crates such as `pyo3-asyncio` can be used to integrate async Rust and Python. For more information, see https://github.com/PyO3/pyo3/issues/1632 + Additional crates such as `pyo3-asyncio` can be used to integrate async Rust and Python. For more information, see https://github.com/PyO3/pyo3/issues/1632 --> tests/ui/invalid_pyfunctions.rs:10:1 | 10 | async fn async_function() {} diff --git a/tests/ui/invalid_pymethod_receiver.stderr b/tests/ui/invalid_pymethod_receiver.stderr index 395c2acd68f..09057ae71b4 100644 --- a/tests/ui/invalid_pymethod_receiver.stderr +++ b/tests/ui/invalid_pymethod_receiver.stderr @@ -1,19 +1,14 @@ error[E0277]: the trait bound `i32: From<&PyCell>` is not satisfied - --> tests/ui/invalid_pymethod_receiver.rs:8:43 - | -8 | fn method_with_invalid_self_type(slf: i32, py: Python, index: u32) {} - | ^^^ the trait `From<&PyCell>` is not implemented for `i32` - | - = help: the following implementations were found: - > - > - > - > - and 2 others - = note: required because of the requirements on the impl of `Into` for `&PyCell` - = note: required because of the requirements on the impl of `TryFrom<&PyCell>` for `i32` -note: required by `std::convert::TryFrom::try_from` - --> $RUST/core/src/convert/mod.rs - | - | fn try_from(value: T) -> Result; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/ui/invalid_pymethod_receiver.rs:8:43 + | +8 | fn method_with_invalid_self_type(slf: i32, py: Python, index: u32) {} + | ^^^ the trait `From<&PyCell>` is not implemented for `i32` + | + = help: the following implementations were found: + > + > + > + > + and 2 others + = note: required because of the requirements on the impl of `Into` for `&PyCell` + = note: required because of the requirements on the impl of `TryFrom<&PyCell>` for `i32` diff --git a/tests/ui/invalid_pymethods.stderr b/tests/ui/invalid_pymethods.stderr index 3556c2722eb..bc11faba722 100644 --- a/tests/ui/invalid_pymethods.stderr +++ b/tests/ui/invalid_pymethods.stderr @@ -90,7 +90,7 @@ error: Python functions cannot have `impl Trait` arguments error: `async fn` is not yet supported for Python functions. -Additional crates such as `pyo3-asyncio` can be used to integrate async Rust and Python. For more information, see https://github.com/PyO3/pyo3/issues/1632 + Additional crates such as `pyo3-asyncio` can be used to integrate async Rust and Python. For more information, see https://github.com/PyO3/pyo3/issues/1632 --> tests/ui/invalid_pymethods.rs:107:5 | 107 | async fn async_method(&self) {} diff --git a/tests/ui/missing_clone.stderr b/tests/ui/missing_clone.stderr index edb82e47b83..ee82c71d94c 100644 --- a/tests/ui/missing_clone.stderr +++ b/tests/ui/missing_clone.stderr @@ -1,7 +1,12 @@ error[E0277]: the trait bound `TestClass: Clone` is not satisfied - --> tests/ui/missing_clone.rs:15:32 - | -15 | let t: TestClass = pyvalue.extract(py).unwrap(); - | ^^^^^^^ the trait `Clone` is not implemented for `TestClass` - | - = note: required because of the requirements on the impl of `pyo3::FromPyObject<'_>` for `TestClass` + --> tests/ui/missing_clone.rs:15:32 + | +15 | let t: TestClass = pyvalue.extract(py).unwrap(); + | ^^^^^^^ the trait `Clone` is not implemented for `TestClass` + | + = note: required because of the requirements on the impl of `pyo3::FromPyObject<'_>` for `TestClass` +note: required by a bound in `pyo3::Py::::extract` + --> src/instance.rs:518:12 + | +518 | D: FromPyObject<'p>, + | ^^^^^^^^^^^^^^^^ required by this bound in `pyo3::Py::::extract` diff --git a/tests/ui/static_ref.stderr b/tests/ui/static_ref.stderr index 58fc6a532ec..9165f63a03f 100644 --- a/tests/ui/static_ref.stderr +++ b/tests/ui/static_ref.stderr @@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'py` 4 | #[pyfunction] | ^^^^^^^^^^^^^ | -note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 4:1... +note: first, the lifetime cannot outlive the anonymous lifetime #1 defined here... --> tests/ui/static_ref.rs:4:1 | 4 | #[pyfunction] diff --git a/tests/ui/wrong_aspyref_lifetimes.stderr b/tests/ui/wrong_aspyref_lifetimes.stderr index 319f4ee5f3a..0042bc6b9fd 100644 --- a/tests/ui/wrong_aspyref_lifetimes.stderr +++ b/tests/ui/wrong_aspyref_lifetimes.stderr @@ -2,9 +2,9 @@ error[E0505]: cannot move out of `gil` because it is borrowed --> tests/ui/wrong_aspyref_lifetimes.rs:7:10 | 6 | let dict: &PyDict = dict.as_ref(gil.python()); - | --- borrow of `gil` occurs here + | ------------ borrow of `gil` occurs here 7 | drop(gil); | ^^^ move out of `gil` occurs here 8 | 9 | let _py: Python = dict.py(); // Obtain a Python<'p> without GIL. - | ---- borrow later used here + | --------- borrow later used here From 991c8426c2706d1f940694c128126e881b4e0b8c Mon Sep 17 00:00:00 2001 From: messense Date: Thu, 31 Mar 2022 21:50:28 +0800 Subject: [PATCH 16/27] Use `compare` instead of `lt` --- src/callback.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/callback.rs b/src/callback.rs index a9dc1429db8..77928406313 100644 --- a/src/callback.rs +++ b/src/callback.rs @@ -251,7 +251,9 @@ where .import("sys")? .getattr("implementation")? .getattr("version")?; - if version.lt(crate::types::PyTuple::new(py, &PYPY_GOOD_VERSION))? { + if version.compare(crate::types::PyTuple::new(py, &PYPY_GOOD_VERSION))? + == std::cmp::Ordering::Less + { let warn = py.import("warnings")?.getattr("warn")?; warn.call1(( "PyPy 3.7 versions older than 7.3.8 are known to have binary \ From b402c5c5af487d70779bf3ca23a5e9b0adf88365 Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Sat, 5 Feb 2022 00:31:37 +0000 Subject: [PATCH 17/27] chore: cleanup old todo --- src/instance.rs | 24 +++++++++++++++++++----- src/types/any.rs | 6 ++---- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/instance.rs b/src/instance.rs index 6b24335868c..583dadd76ca 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -565,12 +565,10 @@ impl Py { /// This is equivalent to the Python expression `self()`. pub fn call0(&self, py: Python) -> PyResult { cfg_if::cfg_if! { - // TODO: Use PyObject_CallNoArgs instead after https://bugs.python.org/issue42415. - // Once the issue is resolved, we can enable this optimization for limited API. - if #[cfg(all(Py_3_9, not(Py_LIMITED_API)))] { + if #[cfg(Py_3_9)] { // Optimized path on python 3.9+ unsafe { - PyObject::from_owned_ptr_or_err(py, ffi::_PyObject_CallNoArg(self.as_ptr())) + PyObject::from_owned_ptr_or_err(py, ffi::PyObject_CallNoArgs(self.as_ptr())) } } else { self.call(py, (), None) @@ -908,7 +906,23 @@ impl PyObject { mod tests { use super::{Py, PyObject}; use crate::types::PyDict; - use crate::Python; + use crate::{Python, ToPyObject}; + + #[test] + fn test_call0() { + Python::with_gil(|py| { + let obj = py.get_type::().to_object(py); + assert_eq!( + obj.call0(py) + .unwrap() + .as_ref(py) + .repr() + .unwrap() + .to_string_lossy(), + "{}" + ); + }) + } #[test] fn test_call_for_non_existing_method() { diff --git a/src/types/any.rs b/src/types/any.rs index 8fc8640d4e3..2fedd412e3c 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -333,12 +333,10 @@ impl PyAny { /// This is equivalent to the Python expression `help()`. pub fn call0(&self) -> PyResult<&PyAny> { cfg_if::cfg_if! { - // TODO: Use PyObject_CallNoArgs instead after https://bugs.python.org/issue42415. - // Once the issue is resolved, we can enable this optimization for limited API. - if #[cfg(all(Py_3_9, not(Py_LIMITED_API)))] { + if #[cfg(Py_3_9)] { // Optimized path on python 3.9+ unsafe { - self.py().from_owned_ptr_or_err(ffi::_PyObject_CallNoArg(self.as_ptr())) + self.py().from_owned_ptr_or_err(ffi::PyObject_CallNoArgs(self.as_ptr())) } } else { self.call((), None) From b96a3f786713ade0c0e76d04c031b11b537c7a9f Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Wed, 23 Feb 2022 08:14:52 +0000 Subject: [PATCH 18/27] pypy: support released 3.9 --- src/instance.rs | 4 ++-- src/types/any.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/instance.rs b/src/instance.rs index 583dadd76ca..330e409967e 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -565,7 +565,7 @@ impl Py { /// This is equivalent to the Python expression `self()`. pub fn call0(&self, py: Python) -> PyResult { cfg_if::cfg_if! { - if #[cfg(Py_3_9)] { + if #[cfg(all(Py_3_9, not(PyPy)))] { // Optimized path on python 3.9+ unsafe { PyObject::from_owned_ptr_or_err(py, ffi::PyObject_CallNoArgs(self.as_ptr())) @@ -618,7 +618,7 @@ impl Py { /// This is equivalent to the Python expression `self.name()`. pub fn call_method0(&self, py: Python, name: &str) -> PyResult { cfg_if::cfg_if! { - if #[cfg(all(Py_3_9, not(Py_LIMITED_API)))] { + if #[cfg(all(Py_3_9, not(any(Py_LIMITED_API, PyPy))))] { // Optimized path on python 3.9+ unsafe { let name = name.into_py(py); diff --git a/src/types/any.rs b/src/types/any.rs index 2fedd412e3c..0eb7d837524 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -333,7 +333,7 @@ impl PyAny { /// This is equivalent to the Python expression `help()`. pub fn call0(&self) -> PyResult<&PyAny> { cfg_if::cfg_if! { - if #[cfg(Py_3_9)] { + if #[cfg(all(Py_3_9, not(PyPy)))] { // Optimized path on python 3.9+ unsafe { self.py().from_owned_ptr_or_err(ffi::PyObject_CallNoArgs(self.as_ptr())) @@ -461,7 +461,7 @@ impl PyAny { /// ``` pub fn call_method0(&self, name: &str) -> PyResult<&PyAny> { cfg_if::cfg_if! { - if #[cfg(all(Py_3_9, not(Py_LIMITED_API)))] { + if #[cfg(all(Py_3_9, not(any(Py_LIMITED_API, PyPy))))] { // Optimized path on python 3.9+ unsafe { let name = name.into_py(self.py()); From 54de02968ac358f971ffe3e493aa57f9f444509b Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Thu, 24 Feb 2022 20:17:05 +0000 Subject: [PATCH 19/27] rust: clippy fixes 1.59 --- src/gil.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/gil.rs b/src/gil.rs index 57ba4fc52f9..b0a4bef45a1 100644 --- a/src/gil.rs +++ b/src/gil.rs @@ -704,16 +704,14 @@ mod tests { assert!(gil_is_acquired()); } - #[allow(clippy::needless_late_init)] #[test] fn dropping_gil_does_not_invalidate_references() { // Acquiring GIL for the second time should be safe - see #864 let gil = Python::acquire_gil(); let py = gil.python(); - let obj; let gil2 = Python::acquire_gil(); - obj = py.eval("object()", None, None).unwrap(); + let obj = py.eval("object()", None, None).unwrap(); drop(gil2); // After gil2 drops, obj should still have a reference count of one From 1f88c84ae9ec0823081871f1d46653b1d8cdd3c5 Mon Sep 17 00:00:00 2001 From: mejrs Date: Tue, 12 Apr 2022 16:56:07 +0200 Subject: [PATCH 20/27] Bless ui test and pin clap --- Cargo.toml | 2 ++ tests/test_compile_error.rs | 25 ++++++++++----------- tests/ui/invalid_argument_attributes.stderr | 4 ++-- tests/ui/invalid_frompy_derive.stderr | 12 +++++----- tests/ui/invalid_pymethod_receiver.stderr | 2 +- 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 99d094b447a..331e5acd8e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,8 @@ serde = { version = "1.0", optional = true } 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" +# 2.34 uses the matches! macro, which isn't compatible with Rust 1.41 +clap = "=2.33" # 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" diff --git a/tests/test_compile_error.rs b/tests/test_compile_error.rs index 4751f774d0e..87492944b3f 100644 --- a/tests/test_compile_error.rs +++ b/tests/test_compile_error.rs @@ -19,17 +19,14 @@ fn _test_compile_errors() { t.compile_fail("tests/ui/invalid_need_module_arg_position.rs"); t.compile_fail("tests/ui/invalid_property_args.rs"); t.compile_fail("tests/ui/invalid_pyclass_args.rs"); - t.compile_fail("tests/ui/invalid_pyfunctions.rs"); - 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/reject_generics.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); + tests_rust_1_60(&t); #[rustversion::since(1.48)] fn tests_rust_1_48(t: &trybuild::TestCases) { @@ -48,20 +45,11 @@ fn _test_compile_errors() { #[rustversion::since(1.54)] fn tests_rust_1_54(t: &trybuild::TestCases) { - t.compile_fail("tests/ui/invalid_frompy_derive.rs"); t.compile_fail("tests/ui/static_ref.rs"); } #[rustversion::before(1.54)] fn tests_rust_1_54(_t: &trybuild::TestCases) {} - #[rustversion::since(1.55)] - fn tests_rust_1_55(t: &trybuild::TestCases) { - t.compile_fail("tests/ui/invalid_pymethod_receiver.rs"); - } - - #[rustversion::before(1.55)] - fn tests_rust_1_55(_t: &trybuild::TestCases) {} - #[rustversion::since(1.56)] fn tests_rust_1_56(t: &trybuild::TestCases) { t.compile_fail("tests/ui/invalid_closure.rs"); @@ -74,4 +62,15 @@ fn _test_compile_errors() { #[rustversion::before(1.56)] fn tests_rust_1_56(_t: &trybuild::TestCases) {} + + + #[rustversion::since(1.60)] + fn tests_rust_1_60(t: &trybuild::TestCases) { + t.compile_fail("tests/ui/invalid_pymethod_receiver.rs"); + t.compile_fail("tests/ui/invalid_argument_attributes.rs"); + t.compile_fail("tests/ui/invalid_frompy_derive.rs"); + } + + #[rustversion::before(1.60)] + fn tests_rust_1_60(_t: &trybuild::TestCases) {} } diff --git a/tests/ui/invalid_argument_attributes.stderr b/tests/ui/invalid_argument_attributes.stderr index dd830a3ec04..ed6479d5512 100644 --- a/tests/ui/invalid_argument_attributes.stderr +++ b/tests/ui/invalid_argument_attributes.stderr @@ -5,10 +5,10 @@ error: expected `from_py_with` | ^^^ error: expected `=` - --> tests/ui/invalid_argument_attributes.rs:7:32 + --> tests/ui/invalid_argument_attributes.rs:7:45 | 7 | fn from_py_with_no_value(#[pyo3(from_py_with)] param: String) {} - | ^^^^^^^^^^^^^^ + | ^ error: expected `from_py_with` --> tests/ui/invalid_argument_attributes.rs:10:31 diff --git a/tests/ui/invalid_frompy_derive.stderr b/tests/ui/invalid_frompy_derive.stderr index b5cb180dcee..d16c082f9f5 100644 --- a/tests/ui/invalid_frompy_derive.stderr +++ b/tests/ui/invalid_frompy_derive.stderr @@ -109,10 +109,10 @@ error: attribute name cannot be empty | ^^ error: unexpected end of input, expected string literal - --> tests/ui/invalid_frompy_derive.rs:100:21 + --> tests/ui/invalid_frompy_derive.rs:100:22 | 100 | #[pyo3(attribute())] - | ^^ + | ^ error: expected at most one argument: `item` or `item(key)` --> tests/ui/invalid_frompy_derive.rs:106:20 @@ -121,10 +121,10 @@ error: expected at most one argument: `item` or `item(key)` | ^ error: unexpected end of input, expected literal - --> tests/ui/invalid_frompy_derive.rs:112:16 + --> tests/ui/invalid_frompy_derive.rs:112:17 | 112 | #[pyo3(item())] - | ^^ + | ^ error: only one of `attribute` or `item` can be provided --> tests/ui/invalid_frompy_derive.rs:118:5 @@ -171,10 +171,10 @@ error: cannot derive FromPyObject for empty structs and variants = note: this error originates in the derive macro `FromPyObject` (in Nightly builds, run with -Z macro-backtrace for more info) error: expected `=` - --> tests/ui/invalid_frompy_derive.rs:158:11 + --> tests/ui/invalid_frompy_derive.rs:158:24 | 158 | #[pyo3(from_py_with)] - | ^^^^^^^^^^^^^^ + | ^ error: expected string literal --> tests/ui/invalid_frompy_derive.rs:164:27 diff --git a/tests/ui/invalid_pymethod_receiver.stderr b/tests/ui/invalid_pymethod_receiver.stderr index 09057ae71b4..fb3587f5e30 100644 --- a/tests/ui/invalid_pymethod_receiver.stderr +++ b/tests/ui/invalid_pymethod_receiver.stderr @@ -9,6 +9,6 @@ error[E0277]: the trait bound `i32: From<&PyCell>` is not satisfied > > > - and 2 others + and 71 others = note: required because of the requirements on the impl of `Into` for `&PyCell` = note: required because of the requirements on the impl of `TryFrom<&PyCell>` for `i32` From 3725b3172421f1597078393fa10052fd00e43c9c Mon Sep 17 00:00:00 2001 From: mejrs Date: Tue, 12 Apr 2022 17:33:15 +0200 Subject: [PATCH 21/27] Make clippy happy --- examples/pyo3-pytests/src/buf_and_str.rs | 12 ++++++++---- pyo3-macros-backend/src/lib.rs | 1 - pyo3-macros-backend/src/method.rs | 11 ++++------- pyo3-macros-backend/src/params.rs | 4 ++-- pyo3-macros-backend/src/pyimpl.rs | 2 +- pyo3-macros-backend/src/pymethod.rs | 4 +--- pyo3-macros-backend/src/pyproto.rs | 2 +- src/conversion.rs | 2 -- src/ffi/pyhash.rs | 2 +- src/instance.rs | 4 ---- src/lib.rs | 1 - src/panic.rs | 2 +- tests/test_compile_error.rs | 1 - 13 files changed, 19 insertions(+), 29 deletions(-) diff --git a/examples/pyo3-pytests/src/buf_and_str.rs b/examples/pyo3-pytests/src/buf_and_str.rs index 76e530935a7..b5ce584dec1 100644 --- a/examples/pyo3-pytests/src/buf_and_str.rs +++ b/examples/pyo3-pytests/src/buf_and_str.rs @@ -14,22 +14,26 @@ impl BytesExtractor { BytesExtractor {} } - pub fn from_bytes(&mut self, bytes: &PyBytes) -> PyResult { + #[staticmethod] + pub fn from_bytes(bytes: &PyBytes) -> PyResult { let byte_vec: Vec = bytes.extract()?; Ok(byte_vec.len()) } - pub fn from_str(&mut self, string: &PyString) -> PyResult { + #[staticmethod] + pub fn from_str(string: &PyString) -> PyResult { let rust_string: String = string.extract()?; Ok(rust_string.len()) } - pub fn from_str_lossy(&mut self, string: &PyString) -> PyResult { + #[staticmethod] + pub fn from_str_lossy(string: &PyString) -> PyResult { let rust_string_lossy: String = string.to_string_lossy().to_string(); Ok(rust_string_lossy.len()) } - pub fn from_buffer(&mut self, buf: &PyAny) -> PyResult { + #[staticmethod] + pub fn from_buffer(buf: &PyAny) -> PyResult { let buf = PyBuffer::::get(buf)?; Ok(buf.item_count()) } diff --git a/pyo3-macros-backend/src/lib.rs b/pyo3-macros-backend/src/lib.rs index f42bd3b9a6f..14d1c2565b5 100644 --- a/pyo3-macros-backend/src/lib.rs +++ b/pyo3-macros-backend/src/lib.rs @@ -3,7 +3,6 @@ #![cfg_attr(docsrs, feature(doc_cfg))] #![recursion_limit = "1024"] - // Listed first so that macros in this module are available in the rest of the crate. #[macro_use] mod utils; diff --git a/pyo3-macros-backend/src/method.rs b/pyo3-macros-backend/src/method.rs index e57ef33780b..2858338fd00 100644 --- a/pyo3-macros-backend/src/method.rs +++ b/pyo3-macros-backend/src/method.rs @@ -29,9 +29,7 @@ impl<'a> FnArg<'a> { /// Transforms a rust fn arg parsed with syn into a method::FnArg pub fn parse(arg: &'a mut syn::FnArg) -> Result { match arg { - syn::FnArg::Receiver(recv) => { - bail_spanned!(recv.span() => "unexpected receiver") - } // checked in parse_fn_type + syn::FnArg::Receiver(recv) => bail_spanned!(recv.span() => "unexpected receiver"), // checked in parse_fn_type syn::FnArg::Typed(cap) => { if let syn::Type::ImplTrait(_) = &*cap.ty { bail_spanned!(cap.ty.span() => IMPL_TRAIT_ERR); @@ -101,9 +99,7 @@ impl FnType { cls.expect("no class given for Fn with a \"self\" receiver"), error_mode, ), - FnType::FnNew | FnType::FnStatic | FnType::ClassAttribute => { - quote!() - } + FnType::FnNew | FnType::FnStatic | FnType::ClassAttribute => quote!(), FnType::FnClass => { quote! { let _slf = ::pyo3::types::PyType::from_type_ptr(_py, _slf as *mut ::pyo3::ffi::PyTypeObject); @@ -352,7 +348,8 @@ impl<'a> FnSpec<'a> { parse_method_receiver(first_arg) }; - #[allow(clippy::manual_strip)] // for strip_prefix replacement supporting rust < 1.45 + #[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(); diff --git a/pyo3-macros-backend/src/params.rs b/pyo3-macros-backend/src/params.rs index 1bbbb4727d8..c06c64e6de2 100644 --- a/pyo3-macros-backend/src/params.rs +++ b/pyo3-macros-backend/src/params.rs @@ -266,7 +266,7 @@ fn impl_arg_param( } }; - return if let syn::Type::Reference(tref) = unwrap_ty_group(arg.optional.unwrap_or(ty)) { + if let syn::Type::Reference(tref) = unwrap_ty_group(arg.optional.unwrap_or(ty)) { let mut tref = remove_lifetime(tref); if let Some(cls) = self_ { replace_self(&mut tref.elem, cls); @@ -298,5 +298,5 @@ fn impl_arg_param( Ok(quote_arg_span! { let #arg_name = #arg_value_or_default; }) - }; + } } diff --git a/pyo3-macros-backend/src/pyimpl.rs b/pyo3-macros-backend/src/pyimpl.rs index 54e248c9593..e0dcebd6e74 100644 --- a/pyo3-macros-backend/src/pyimpl.rs +++ b/pyo3-macros-backend/src/pyimpl.rs @@ -36,7 +36,7 @@ pub fn build_py_methods( pub fn impl_methods( ty: &syn::Type, - impls: &mut Vec, + impls: &mut [syn::ImplItem], methods_type: PyClassMethodsType, ) -> syn::Result { let mut trait_impls = Vec::new(); diff --git a/pyo3-macros-backend/src/pymethod.rs b/pyo3-macros-backend/src/pymethod.rs index 13a49f92734..8cdb2e06dc2 100644 --- a/pyo3-macros-backend/src/pymethod.rs +++ b/pyo3-macros-backend/src/pymethod.rs @@ -138,9 +138,7 @@ pub fn gen_py_method( cls, PropertyType::Function { self_type, spec }, )?), - (_, FnType::FnModule) => { - unreachable!("methods cannot be FnModule") - } + (_, FnType::FnModule) => unreachable!("methods cannot be FnModule"), }) } diff --git a/pyo3-macros-backend/src/pyproto.rs b/pyo3-macros-backend/src/pyproto.rs index 23e5d8a5d5d..6c02fb57367 100644 --- a/pyo3-macros-backend/src/pyproto.rs +++ b/pyo3-macros-backend/src/pyproto.rs @@ -45,7 +45,7 @@ pub fn build_py_proto(ast: &mut syn::ItemImpl) -> syn::Result { fn impl_proto_impl( ty: &syn::Type, - impls: &mut Vec, + impls: &mut [syn::ImplItem], proto: &defs::Proto, ) -> syn::Result { let mut trait_impls = TokenStream::new(); diff --git a/src/conversion.rs b/src/conversion.rs index ccd690bee15..e7cee002337 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -195,7 +195,6 @@ where /// } /// } /// } -/// # fn main() { /// # Python::with_gil(|py| { /// # let v = Value::Integer(73).into_py(py); /// # let v = v.extract::(py).unwrap(); @@ -206,7 +205,6 @@ where /// # let v = Value::None.into_py(py); /// # let v = v.extract::>>(py).unwrap(); /// # }); -/// # } /// ``` /// Python code will see this as any of the `int`, `string` or `None` objects. #[cfg_attr(docsrs, doc(alias = "IntoPyCallbackOutput"))] diff --git a/src/ffi/pyhash.rs b/src/ffi/pyhash.rs index 703f6245467..736f115ea54 100644 --- a/src/ffi/pyhash.rs +++ b/src/ffi/pyhash.rs @@ -14,7 +14,7 @@ extern "C" { pub fn _Py_HashBytes(src: *const c_void, len: Py_ssize_t) -> Py_hash_t; } -pub const _PyHASH_MULTIPLIER: c_ulong = 1000003; +pub const _PyHASH_MULTIPLIER: c_ulong = 1_000_003; // skipped _PyHASH_BITS diff --git a/src/instance.rs b/src/instance.rs index 330e409967e..472f6bef7f8 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -172,7 +172,6 @@ pub unsafe trait PyNativeType: Sized { /// use pyo3::prelude::*; /// use pyo3::types::PyDict; /// -/// # fn main() { /// Python::with_gil(|py| { /// let first: Py = PyDict::new(py).into(); /// @@ -190,7 +189,6 @@ pub unsafe trait PyNativeType: Sized { /// assert_eq!(fourth.as_ptr(), fifth.as_ptr()); /// assert_eq!(second.as_ptr(), fourth.as_ptr()); /// }); -/// # } /// ``` /// /// # Preventing reference cycles @@ -479,7 +477,6 @@ impl Py { /// use pyo3::prelude::*; /// use pyo3::types::PyDict; /// - /// # fn main() { /// Python::with_gil(|py| { /// let first: Py = PyDict::new(py).into(); /// let second = Py::clone_ref(&first, py); @@ -487,7 +484,6 @@ impl Py { /// // Both point to the same object /// assert_eq!(first.as_ptr(), second.as_ptr()); /// }); - /// # } /// ``` #[inline] pub fn clone_ref(&self, py: Python) -> Py { diff --git a/src/lib.rs b/src/lib.rs index 14bc7466d3e..2c676ad9e32 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,6 @@ // Deny some lints in doctests. // Use `#[allow(...)]` locally to override. #![doc(test(attr(deny(warnings), allow(unused_variables, unused_assignments))))] - //! Rust bindings to the Python interpreter. //! //! PyO3 can be used to write native Python modules or run Python code and modules from Rust. diff --git a/src/panic.rs b/src/panic.rs index cf1dd3701e3..da612e8ae9e 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -21,7 +21,7 @@ impl PanicException { if let Some(string) = payload.downcast_ref::() { Self::new_err((string.clone(),)) } else if let Some(s) = payload.downcast_ref::<&str>() { - Self::new_err((s.to_string(),)) + Self::new_err(((*s).to_string(),)) } else { Self::new_err(("panic from Rust code",)) } diff --git a/tests/test_compile_error.rs b/tests/test_compile_error.rs index 87492944b3f..bafaf065751 100644 --- a/tests/test_compile_error.rs +++ b/tests/test_compile_error.rs @@ -63,7 +63,6 @@ fn _test_compile_errors() { #[rustversion::before(1.56)] fn tests_rust_1_56(_t: &trybuild::TestCases) {} - #[rustversion::since(1.60)] fn tests_rust_1_60(t: &trybuild::TestCases) { t.compile_fail("tests/ui/invalid_pymethod_receiver.rs"); From 48aba84f926ff781ee72b03771439d539fbab2a7 Mon Sep 17 00:00:00 2001 From: mejrs Date: Tue, 12 Apr 2022 17:43:27 +0200 Subject: [PATCH 22/27] Fix UI test --- tests/test_compile_error.rs | 2 +- tests/ui/missing_clone.stderr | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_compile_error.rs b/tests/test_compile_error.rs index bafaf065751..1fd0f9c2c99 100644 --- a/tests/test_compile_error.rs +++ b/tests/test_compile_error.rs @@ -30,7 +30,6 @@ fn _test_compile_errors() { #[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)] @@ -68,6 +67,7 @@ fn _test_compile_errors() { t.compile_fail("tests/ui/invalid_pymethod_receiver.rs"); t.compile_fail("tests/ui/invalid_argument_attributes.rs"); t.compile_fail("tests/ui/invalid_frompy_derive.rs"); + t.compile_fail("tests/ui/missing_clone.rs"); } #[rustversion::before(1.60)] diff --git a/tests/ui/missing_clone.stderr b/tests/ui/missing_clone.stderr index ee82c71d94c..59c1f324ff2 100644 --- a/tests/ui/missing_clone.stderr +++ b/tests/ui/missing_clone.stderr @@ -6,7 +6,7 @@ error[E0277]: the trait bound `TestClass: Clone` is not satisfied | = note: required because of the requirements on the impl of `pyo3::FromPyObject<'_>` for `TestClass` note: required by a bound in `pyo3::Py::::extract` - --> src/instance.rs:518:12 + --> src/instance.rs | -518 | D: FromPyObject<'p>, + | D: FromPyObject<'p>, | ^^^^^^^^^^^^^^^^ required by this bound in `pyo3::Py::::extract` From f774dbf59f6385ea90719ef33dcee23838010133 Mon Sep 17 00:00:00 2001 From: mejrs Date: Tue, 12 Apr 2022 18:09:55 +0200 Subject: [PATCH 23/27] Fix abi3 ui test --- tests/ui/abi3_nativetype_inheritance.stderr | 29 +++++++-------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/tests/ui/abi3_nativetype_inheritance.stderr b/tests/ui/abi3_nativetype_inheritance.stderr index a90d40442f5..762250a4c1f 100644 --- a/tests/ui/abi3_nativetype_inheritance.stderr +++ b/tests/ui/abi3_nativetype_inheritance.stderr @@ -1,22 +1,11 @@ error[E0277]: the trait bound `PyDict: PyClass` is not satisfied - --> tests/ui/abi3_nativetype_inheritance.rs:5:1 - | -5 | #[pyclass(extends=PyDict)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PyClass` is not implemented for `PyDict` - | - = 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 - | -766 | / pub trait PyClassBaseType: Sized { -767 | | type Dict; -768 | | type WeakRef; -769 | | type LayoutAsBase: PyCellLayout; -... | -772 | | type Initializer: PyObjectInit; -773 | | } - | |_^ 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) + --> tests/ui/abi3_nativetype_inheritance.rs:5:1 + | +5 | #[pyclass(extends=PyDict)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PyClass` is not implemented for `PyDict` + | + = note: required because of the requirements on the impl of `PyClassBaseType` for `PyDict` + = note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `PyDict: PyClass` is not satisfied --> tests/ui/abi3_nativetype_inheritance.rs:5:1 @@ -26,8 +15,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(PhantomData, U::ThreadChecker); + | pub struct ThreadCheckerInherited(PhantomData, 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) From 72867d9ff5bcb25e71df1e6ea316d7b71b084a82 Mon Sep 17 00:00:00 2001 From: mejrs Date: Tue, 12 Apr 2022 18:14:49 +0200 Subject: [PATCH 24/27] Don't test 32 bit on windows --- .github/workflows/ci.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e777fa9a013..bcb977d1955 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -101,6 +101,18 @@ jobs: rust-target: "x86_64-pc-windows-msvc", }, ] + exclude: + # PyPy 3.6 is EOL and not working on macos-latest (now macos-11) + - python-version: pypy-3.6 + platform: { os: "macos-latest", python-architecture: "x64" } + # There is no 64-bit pypy on windows for pypy-3.6 + - python-version: pypy-3.6 + platform: { os: "windows-latest", python-architecture: "x64" } + # PyPy doesn't release 32-bit Windows builds any more + - python-version: pypy-3.7 + platform: { os: "windows-latest", python-architecture: "x86" } + - python-version: pypy-3.8 + platform: { os: "windows-latest", python-architecture: "x86" } include: # PyPy3.6 still runs on macos-10.15 - rust: stable From bf3d7a07ab9602103d996e195369e9ef4e989b87 Mon Sep 17 00:00:00 2001 From: mejrs Date: Tue, 12 Apr 2022 19:44:59 +0200 Subject: [PATCH 25/27] Name a more iconic trio: pypy, datetime, segfaults --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bcb977d1955..67b7421d2a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,7 +82,7 @@ jobs: fail-fast: ${{ !contains(github.event.pull_request.labels.*.name, 'CI-no-fail-fast') }} matrix: rust: [stable] - python-version: [3.6, 3.7, 3.8, 3.9, "3.10", pypy-3.6, pypy-3.7, pypy-3.8, pypy-3.9] + python-version: [3.6, 3.7, 3.8, 3.9, "3.10", pypy-3.6, pypy-3.7-v7.3.7, pypy-3.8, pypy-3.9] platform: [ { @@ -109,7 +109,7 @@ jobs: - python-version: pypy-3.6 platform: { os: "windows-latest", python-architecture: "x64" } # PyPy doesn't release 32-bit Windows builds any more - - python-version: pypy-3.7 + - python-version: pypy-3.7-v7.3.7 platform: { os: "windows-latest", python-architecture: "x86" } - python-version: pypy-3.8 platform: { os: "windows-latest", python-architecture: "x86" } From 97230d1415b965b1008912b2a5c84edbcac3effd Mon Sep 17 00:00:00 2001 From: mejrs Date: Wed, 13 Apr 2022 11:26:10 +0200 Subject: [PATCH 26/27] Move 7.3.8 warning over to `make_module` --- src/callback.rs | 17 ----------------- src/derive_utils.rs | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/callback.rs b/src/callback.rs index 77928406313..e29f07e0979 100644 --- a/src/callback.rs +++ b/src/callback.rs @@ -244,23 +244,6 @@ where let unwind_safe_py = AssertUnwindSafe(pool.python()); let panic_result = panic::catch_unwind(move || -> PyResult<_> { let py = *unwind_safe_py; - #[cfg(all(PyPy, not(Py_3_8)))] - { - const PYPY_GOOD_VERSION: [u8; 3] = [7, 3, 8]; - let version = py - .import("sys")? - .getattr("implementation")? - .getattr("version")?; - if version.compare(crate::types::PyTuple::new(py, &PYPY_GOOD_VERSION))? - == std::cmp::Ordering::Less - { - 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.", - ))?; - } - } body(py) }); diff --git a/src/derive_utils.rs b/src/derive_utils.rs index 6d79b2c4dad..cfb9a816627 100644 --- a/src/derive_utils.rs +++ b/src/derive_utils.rs @@ -319,6 +319,24 @@ impl ModuleDef { py: Python, initializer: impl Fn(Python, &PyModule) -> PyResult<()>, ) -> PyResult<*mut ffi::PyObject> { + #[cfg(all(PyPy, not(Py_3_8)))] + { + const PYPY_GOOD_VERSION: [u8; 3] = [7, 3, 8]; + let version = py + .import("sys")? + .getattr("implementation")? + .getattr("version")?; + if version.compare(crate::types::PyTuple::new(py, &PYPY_GOOD_VERSION))? + == std::cmp::Ordering::Less + { + 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.", + ))?; + } + } + let module = unsafe { py.from_owned_ptr_or_err::(ffi::PyModule_Create(self.0.get()))? }; initializer(py, module)?; From 501620252304414b89eb47202cc7081657143e95 Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Wed, 13 Apr 2022 19:36:01 +0100 Subject: [PATCH 27/27] support pypy-3.7-v7.3.8+ --- .github/workflows/ci.yml | 4 ++-- src/ffi/datetime.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 67b7421d2a6..bcb977d1955 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,7 +82,7 @@ jobs: fail-fast: ${{ !contains(github.event.pull_request.labels.*.name, 'CI-no-fail-fast') }} matrix: rust: [stable] - python-version: [3.6, 3.7, 3.8, 3.9, "3.10", pypy-3.6, pypy-3.7-v7.3.7, pypy-3.8, pypy-3.9] + python-version: [3.6, 3.7, 3.8, 3.9, "3.10", pypy-3.6, pypy-3.7, pypy-3.8, pypy-3.9] platform: [ { @@ -109,7 +109,7 @@ jobs: - python-version: pypy-3.6 platform: { os: "windows-latest", python-architecture: "x64" } # PyPy doesn't release 32-bit Windows builds any more - - python-version: pypy-3.7-v7.3.7 + - python-version: pypy-3.7 platform: { os: "windows-latest", python-architecture: "x86" } - python-version: pypy-3.8 platform: { os: "windows-latest", python-architecture: "x86" } diff --git a/src/ffi/datetime.rs b/src/ffi/datetime.rs index 8510b96edc4..6c23122b846 100644 --- a/src/ffi/datetime.rs +++ b/src/ffi/datetime.rs @@ -361,7 +361,7 @@ pub struct PyDateTime_CAPI { pub TimeType: *mut PyTypeObject, pub DeltaType: *mut PyTypeObject, pub TZInfoType: *mut PyTypeObject, - #[cfg(all(Py_3_7, any(not(PyPy), Py_3_8)))] + #[cfg(Py_3_7)] pub TimeZone_UTC: *mut PyObject, pub Date_FromDate: unsafe extern "C" fn( year: c_int, @@ -395,7 +395,7 @@ pub struct PyDateTime_CAPI { normalize: c_int, cls: *mut PyTypeObject, ) -> *mut PyObject, - #[cfg(all(Py_3_7, any(not(PyPy), Py_3_8)))] + #[cfg(Py_3_7)] pub TimeZone_FromTimeZone: unsafe extern "C" fn(offset: *mut PyObject, name: *mut PyObject) -> *mut PyObject,