From a4aea230ed6087a5fccc415d6456c536645e0df1 Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Tue, 2 Apr 2024 18:43:51 +0100 Subject: [PATCH 01/13] fix compile error for multiple async method arguments (#4035) --- newsfragments/4035.fixed.md | 1 + pyo3-macros-backend/src/method.rs | 25 ++++-------- tests/test_coroutine.rs | 66 +++++++++++++++---------------- 3 files changed, 41 insertions(+), 51 deletions(-) create mode 100644 newsfragments/4035.fixed.md diff --git a/newsfragments/4035.fixed.md b/newsfragments/4035.fixed.md new file mode 100644 index 00000000000..5425c5cbaf7 --- /dev/null +++ b/newsfragments/4035.fixed.md @@ -0,0 +1 @@ +Fix compile error for `async fn` in `#[pymethods]` with a `&self` receiver and more than one additional argument. diff --git a/pyo3-macros-backend/src/method.rs b/pyo3-macros-backend/src/method.rs index 155c554025d..6af0ec97d04 100644 --- a/pyo3-macros-backend/src/method.rs +++ b/pyo3-macros-backend/src/method.rs @@ -522,33 +522,22 @@ impl<'a> FnSpec<'a> { Some(cls) => quote!(Some(<#cls as #pyo3_path::PyTypeInfo>::NAME)), None => quote!(None), }; - let evaluate_args = || -> (Vec, TokenStream) { - let mut arg_names = Vec::with_capacity(args.len()); - let mut evaluate_arg = quote! {}; - for arg in &args { - let arg_name = format_ident!("arg_{}", arg_names.len()); - arg_names.push(arg_name.clone()); - evaluate_arg.extend(quote! { - let #arg_name = #arg - }); - } - (arg_names, evaluate_arg) - }; + let arg_names = (0..args.len()) + .map(|i| format_ident!("arg_{}", i)) + .collect::>(); let future = match self.tp { FnType::Fn(SelfType::Receiver { mutable: false, .. }) => { - let (arg_name, evaluate_arg) = evaluate_args(); quote! {{ - #evaluate_arg; + #(let #arg_names = #args;)* let __guard = #pyo3_path::impl_::coroutine::RefGuard::<#cls>::new(&#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &_slf))?; - async move { function(&__guard, #(#arg_name),*).await } + async move { function(&__guard, #(#arg_names),*).await } }} } FnType::Fn(SelfType::Receiver { mutable: true, .. }) => { - let (arg_name, evaluate_arg) = evaluate_args(); quote! {{ - #evaluate_arg; + #(let #arg_names = #args;)* let mut __guard = #pyo3_path::impl_::coroutine::RefMutGuard::<#cls>::new(&#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &_slf))?; - async move { function(&mut __guard, #(#arg_name),*).await } + async move { function(&mut __guard, #(#arg_names),*).await } }} } _ => { diff --git a/tests/test_coroutine.rs b/tests/test_coroutine.rs index 0e698deb9af..4abba9f36b4 100644 --- a/tests/test_coroutine.rs +++ b/tests/test_coroutine.rs @@ -245,39 +245,6 @@ fn coroutine_panic() { }) } -#[test] -fn test_async_method_receiver_with_other_args() { - #[pyclass] - struct Value(i32); - #[pymethods] - impl Value { - #[new] - fn new() -> Self { - Self(0) - } - async fn get_value_plus_with(&self, v: i32) -> i32 { - self.0 + v - } - async fn set_value(&mut self, new_value: i32) -> i32 { - self.0 = new_value; - self.0 - } - } - - Python::with_gil(|gil| { - let test = r#" - import asyncio - - v = Value() - assert asyncio.run(v.get_value_plus_with(3)) == 3 - assert asyncio.run(v.set_value(10)) == 10 - assert asyncio.run(v.get_value_plus_with(1)) == 11 - "#; - let locals = [("Value", gil.get_type_bound::())].into_py_dict_bound(gil); - py_run!(gil, *locals, test); - }); -} - #[test] fn test_async_method_receiver() { #[pyclass] @@ -341,3 +308,36 @@ fn test_async_method_receiver() { assert!(IS_DROPPED.load(Ordering::SeqCst)); } + +#[test] +fn test_async_method_receiver_with_other_args() { + #[pyclass] + struct Value(i32); + #[pymethods] + impl Value { + #[new] + fn new() -> Self { + Self(0) + } + async fn get_value_plus_with(&self, v1: i32, v2: i32) -> i32 { + self.0 + v1 + v2 + } + async fn set_value(&mut self, new_value: i32) -> i32 { + self.0 = new_value; + self.0 + } + } + + Python::with_gil(|gil| { + let test = r#" + import asyncio + + v = Value() + assert asyncio.run(v.get_value_plus_with(3, 0)) == 3 + assert asyncio.run(v.set_value(10)) == 10 + assert asyncio.run(v.get_value_plus_with(1, 1)) == 12 + "#; + let locals = [("Value", gil.get_type_bound::())].into_py_dict_bound(gil); + py_run!(gil, *locals, test); + }); +} From 7a00b4d357c0250c2212e856782143f283a7c2bb Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Thu, 4 Apr 2024 21:08:51 +0200 Subject: [PATCH 02/13] add descriptive error msg for `__traverse__` receivers other than `&self` (#4045) * add descriptive error msg for `__traverse__` receivers other than `self` * add newsfragment * improve error message --- newsfragments/4045.fixed.md | 1 + pyo3-macros-backend/src/pymethod.rs | 21 ++++++++++-- tests/ui/traverse.rs | 50 ++++++++++++++++++++++++++--- tests/ui/traverse.stderr | 42 +++++++++++++----------- 4 files changed, 88 insertions(+), 26 deletions(-) create mode 100644 newsfragments/4045.fixed.md diff --git a/newsfragments/4045.fixed.md b/newsfragments/4045.fixed.md new file mode 100644 index 00000000000..6b2bbcfa01d --- /dev/null +++ b/newsfragments/4045.fixed.md @@ -0,0 +1 @@ +Add better error message on wrong receiver extraction in `__traverse__`. diff --git a/pyo3-macros-backend/src/pymethod.rs b/pyo3-macros-backend/src/pymethod.rs index ee7d3d7aaee..abe8c7ac8a3 100644 --- a/pyo3-macros-backend/src/pymethod.rs +++ b/pyo3-macros-backend/src/pymethod.rs @@ -434,9 +434,24 @@ fn impl_traverse_slot( let Ctx { pyo3_path } = ctx; if let (Some(py_arg), _) = split_off_python_arg(&spec.signature.arguments) { return Err(syn::Error::new_spanned(py_arg.ty, "__traverse__ may not take `Python`. \ - Usually, an implementation of `__traverse__` should do nothing but calls to `visit.call`. \ - Most importantly, safe access to the GIL is prohibited inside implementations of `__traverse__`, \ - i.e. `Python::with_gil` will panic.")); + Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` \ + should do nothing but calls to `visit.call`. Most importantly, safe access to the GIL is prohibited \ + inside implementations of `__traverse__`, i.e. `Python::with_gil` will panic.")); + } + + // check that the receiver does not try to smuggle an (implicit) `Python` token into here + if let FnType::Fn(SelfType::TryFromBoundRef(span)) + | FnType::Fn(SelfType::Receiver { + mutable: true, + span, + }) = spec.tp + { + bail_spanned! { span => + "__traverse__ may not take a receiver other than `&self`. Usually, an implementation of \ + `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` \ + should do nothing but calls to `visit.call`. Most importantly, safe access to the GIL is prohibited \ + inside implementations of `__traverse__`, i.e. `Python::with_gil` will panic." + } } let rust_fn_ident = spec.name; diff --git a/tests/ui/traverse.rs b/tests/ui/traverse.rs index 034224951c9..0cf7170db21 100644 --- a/tests/ui/traverse.rs +++ b/tests/ui/traverse.rs @@ -1,13 +1,55 @@ use pyo3::prelude::*; -use pyo3::PyVisit; use pyo3::PyTraverseError; +use pyo3::PyVisit; #[pyclass] struct TraverseTriesToTakePyRef {} #[pymethods] impl TraverseTriesToTakePyRef { - fn __traverse__(slf: PyRef, visit: PyVisit) {} + fn __traverse__(slf: PyRef, visit: PyVisit) -> Result<(), PyTraverseError> { + Ok(()) + } +} + +#[pyclass] +struct TraverseTriesToTakePyRefMut {} + +#[pymethods] +impl TraverseTriesToTakePyRefMut { + fn __traverse__(slf: PyRefMut, visit: PyVisit) -> Result<(), PyTraverseError> { + Ok(()) + } +} + +#[pyclass] +struct TraverseTriesToTakeBound {} + +#[pymethods] +impl TraverseTriesToTakeBound { + fn __traverse__(slf: Bound<'_, Self>, visit: PyVisit) -> Result<(), PyTraverseError> { + Ok(()) + } +} + +#[pyclass] +struct TraverseTriesToTakeMutSelf {} + +#[pymethods] +impl TraverseTriesToTakeMutSelf { + fn __traverse__(&mut self, visit: PyVisit) -> Result<(), PyTraverseError> { + Ok(()) + } +} + +#[pyclass] +struct TraverseTriesToTakeSelf {} + +#[pymethods] +impl TraverseTriesToTakeSelf { + fn __traverse__(&self, visit: PyVisit) -> Result<(), PyTraverseError> { + Ok(()) + } } #[pyclass] @@ -19,9 +61,7 @@ impl Class { Ok(()) } - fn __clear__(&mut self) { - } + fn __clear__(&mut self) {} } - fn main() {} diff --git a/tests/ui/traverse.stderr b/tests/ui/traverse.stderr index 4448e67e13a..5b1d1b6b2ec 100644 --- a/tests/ui/traverse.stderr +++ b/tests/ui/traverse.stderr @@ -1,23 +1,29 @@ -error: __traverse__ may not take `Python`. Usually, an implementation of `__traverse__` should do nothing but calls to `visit.call`. Most importantly, safe access to the GIL is prohibited inside implementations of `__traverse__`, i.e. `Python::with_gil` will panic. - --> tests/ui/traverse.rs:18:32 +error: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the GIL is prohibited inside implementations of `__traverse__`, i.e. `Python::with_gil` will panic. + --> tests/ui/traverse.rs:10:26 | -18 | fn __traverse__(&self, py: Python<'_>, visit: PyVisit<'_>) -> Result<(), PyTraverseError> { - | ^^^^^^^^^^ +10 | fn __traverse__(slf: PyRef, visit: PyVisit) -> Result<(), PyTraverseError> { + | ^^^^^ + +error: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the GIL is prohibited inside implementations of `__traverse__`, i.e. `Python::with_gil` will panic. + --> tests/ui/traverse.rs:20:26 + | +20 | fn __traverse__(slf: PyRefMut, visit: PyVisit) -> Result<(), PyTraverseError> { + | ^^^^^^^^ -error[E0308]: mismatched types - --> tests/ui/traverse.rs:9:6 +error: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the GIL is prohibited inside implementations of `__traverse__`, i.e. `Python::with_gil` will panic. + --> tests/ui/traverse.rs:30:26 | -8 | #[pymethods] - | ------------ arguments to this function are incorrect -9 | impl TraverseTriesToTakePyRef { - | ______^ -10 | | fn __traverse__(slf: PyRef, visit: PyVisit) {} - | |___________________^ expected fn pointer, found fn item +30 | fn __traverse__(slf: Bound<'_, Self>, visit: PyVisit) -> Result<(), PyTraverseError> { + | ^^^^^ + +error: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the GIL is prohibited inside implementations of `__traverse__`, i.e. `Python::with_gil` will panic. + --> tests/ui/traverse.rs:40:21 | - = note: expected fn pointer `for<'a, 'b> fn(&'a TraverseTriesToTakePyRef, PyVisit<'b>) -> Result<(), PyTraverseError>` - found fn item `for<'a, 'b> fn(pyo3::PyRef<'a, TraverseTriesToTakePyRef, >, PyVisit<'b>) {TraverseTriesToTakePyRef::__traverse__}` -note: function defined here - --> src/impl_/pymethods.rs +40 | fn __traverse__(&mut self, visit: PyVisit) -> Result<(), PyTraverseError> { + | ^ + +error: __traverse__ may not take `Python`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the GIL is prohibited inside implementations of `__traverse__`, i.e. `Python::with_gil` will panic. + --> tests/ui/traverse.rs:60:32 | - | pub unsafe fn _call_traverse( - | ^^^^^^^^^^^^^^ +60 | fn __traverse__(&self, py: Python<'_>, visit: PyVisit<'_>) -> Result<(), PyTraverseError> { + | ^^^^^^^^^^ From 2f0869a6d643e790e71dd5a676a30a7e539e5138 Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Sun, 7 Apr 2024 00:36:52 +0200 Subject: [PATCH 03/13] fix: allow impl of Ungil for deprecated PyCell in nightly (#4053) --- src/marker.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/marker.rs b/src/marker.rs index 67119b5e55e..b1f2d399209 100644 --- a/src/marker.rs +++ b/src/marker.rs @@ -280,6 +280,7 @@ mod nightly { impl !Ungil for crate::PyAny {} // All the borrowing wrappers + #[allow(deprecated)] impl !Ungil for crate::PyCell {} impl !Ungil for crate::PyRef<'_, T> {} impl !Ungil for crate::PyRefMut<'_, T> {} From 47f9ef41747ff1e7d89f584797ea9fc0d88dd1d5 Mon Sep 17 00:00:00 2001 From: "Jeong, Heon" Date: Thu, 11 Apr 2024 14:07:56 -0700 Subject: [PATCH 04/13] Fix typo (#4052) Fix incorrect closing brackets --- guide/src/ecosystem/async-await.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guide/src/ecosystem/async-await.md b/guide/src/ecosystem/async-await.md index 0319fa05063..9c0ad19bdef 100644 --- a/guide/src/ecosystem/async-await.md +++ b/guide/src/ecosystem/async-await.md @@ -120,7 +120,7 @@ Export an async function that makes use of `async-std`: use pyo3::{prelude::*, wrap_pyfunction}; #[pyfunction] -fn rust_sleep(py: Python<'_>) -> PyResult<&Bound<'_, PyAny>>> { +fn rust_sleep(py: Python<'_>) -> PyResult<&Bound<'_, PyAny>> { pyo3_asyncio::async_std::future_into_py(py, async { async_std::task::sleep(std::time::Duration::from_secs(1)).await; Ok(Python::with_gil(|py| py.None())) From 631c25f2f9ef2d2f73ea1510cc6aba0581b0af16 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Apr 2024 21:08:44 +0000 Subject: [PATCH 05/13] build(deps): bump peaceiris/actions-gh-pages from 3 to 4 (#4062) Bumps [peaceiris/actions-gh-pages](https://github.com/peaceiris/actions-gh-pages) from 3 to 4. - [Release notes](https://github.com/peaceiris/actions-gh-pages/releases) - [Changelog](https://github.com/peaceiris/actions-gh-pages/blob/main/CHANGELOG.md) - [Commits](https://github.com/peaceiris/actions-gh-pages/compare/v3...v4) --- updated-dependencies: - dependency-name: peaceiris/actions-gh-pages dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index a9a7669054a..a101eb6ad25 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -46,7 +46,7 @@ jobs: - name: Deploy docs and the guide if: ${{ github.event_name == 'release' }} - uses: peaceiris/actions-gh-pages@v3 + uses: peaceiris/actions-gh-pages@v4 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./target/guide/ From 9a6b1962d39c0acd6ddc42b186151611018cbd69 Mon Sep 17 00:00:00 2001 From: Liam Date: Thu, 11 Apr 2024 22:11:51 +0100 Subject: [PATCH 06/13] Minor: Fix a typo in Contributing.md (#4066) --- Contributing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Contributing.md b/Contributing.md index 29d1bb758a7..054099b431a 100644 --- a/Contributing.md +++ b/Contributing.md @@ -190,7 +190,7 @@ Second, there is a Python-based benchmark contained in the `pytests` subdirector You can view what code is and isn't covered by PyO3's tests. We aim to have 100% coverage - please check coverage and add tests if you notice a lack of coverage! -- First, ensure the llmv-cov cargo plugin is installed. You may need to run the plugin through cargo once before using it with `nox`. +- First, ensure the llvm-cov cargo plugin is installed. You may need to run the plugin through cargo once before using it with `nox`. ```shell cargo install cargo-llvm-cov cargo llvm-cov From c8b59d71176a371f9feaa8abfa884f9fd451fbb5 Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Fri, 12 Apr 2024 08:34:08 +0200 Subject: [PATCH 07/13] add `#[doc(hidden)]` to the Rust module created by `#[pymodule]` (#4067) * add `#[doc(hidden)]` to the Rust module created by `#[pymodule]` * add newsfragment --- newsfragments/4067.fixed.md | 1 + pyo3-macros-backend/src/module.rs | 1 + tests/test_compile_error.rs | 1 + tests/ui/pymodule_missing_docs.rs | 12 ++++++++++++ 4 files changed, 15 insertions(+) create mode 100644 newsfragments/4067.fixed.md create mode 100644 tests/ui/pymodule_missing_docs.rs diff --git a/newsfragments/4067.fixed.md b/newsfragments/4067.fixed.md new file mode 100644 index 00000000000..869b6addf15 --- /dev/null +++ b/newsfragments/4067.fixed.md @@ -0,0 +1 @@ +fixes `missing_docs` lint to trigger on documented `#[pymodule]` functions \ No newline at end of file diff --git a/pyo3-macros-backend/src/module.rs b/pyo3-macros-backend/src/module.rs index 080a279a88c..8ff720cc616 100644 --- a/pyo3-macros-backend/src/module.rs +++ b/pyo3-macros-backend/src/module.rs @@ -324,6 +324,7 @@ pub fn pymodule_function_impl(mut function: syn::ItemFn) -> Result Ok(quote! { #function + #[doc(hidden)] #vis mod #ident { #initialization } diff --git a/tests/test_compile_error.rs b/tests/test_compile_error.rs index 38b5c4727c6..44049620598 100644 --- a/tests/test_compile_error.rs +++ b/tests/test_compile_error.rs @@ -53,4 +53,5 @@ fn test_compile_errors() { #[cfg(feature = "experimental-async")] #[cfg(any(not(Py_LIMITED_API), Py_3_10))] // to avoid PyFunctionArgument for &str t.compile_fail("tests/ui/invalid_cancel_handle.rs"); + t.pass("tests/ui/pymodule_missing_docs.rs"); } diff --git a/tests/ui/pymodule_missing_docs.rs b/tests/ui/pymodule_missing_docs.rs new file mode 100644 index 00000000000..1b196fa65e0 --- /dev/null +++ b/tests/ui/pymodule_missing_docs.rs @@ -0,0 +1,12 @@ +#![deny(missing_docs)] +//! Some crate docs + +use pyo3::prelude::*; + +/// Some module documentation +#[pymodule] +pub fn python_module(_m: &Bound<'_, PyModule>) -> PyResult<()> { + Ok(()) +} + +fn main() {} From ee5216f406889a9b993bfbe2e9dd977027e57075 Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Fri, 12 Apr 2024 08:34:27 +0200 Subject: [PATCH 08/13] fix declarative-modules compile error (#4054) * fix declarative-modules compile error * add newsfragment --- newsfragments/4054.fixed.md | 1 + pyo3-macros-backend/src/pyclass.rs | 2 +- tests/test_declarative_module.rs | 11 +++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 newsfragments/4054.fixed.md diff --git a/newsfragments/4054.fixed.md b/newsfragments/4054.fixed.md new file mode 100644 index 00000000000..4b8da92ca4d --- /dev/null +++ b/newsfragments/4054.fixed.md @@ -0,0 +1 @@ +Fixes a compile error when exporting a `#[pyclass]` living in a different Rust module using the declarative-module feature. diff --git a/pyo3-macros-backend/src/pyclass.rs b/pyo3-macros-backend/src/pyclass.rs index cf8d9aae801..aff23b879f5 100644 --- a/pyo3-macros-backend/src/pyclass.rs +++ b/pyo3-macros-backend/src/pyclass.rs @@ -1614,7 +1614,7 @@ impl<'a> PyClassImplsBuilder<'a> { quote! { impl #cls { #[doc(hidden)] - const _PYO3_DEF: #pyo3_path::impl_::pymodule::AddClassToModule = #pyo3_path::impl_::pymodule::AddClassToModule::new(); + pub const _PYO3_DEF: #pyo3_path::impl_::pymodule::AddClassToModule = #pyo3_path::impl_::pymodule::AddClassToModule::new(); } } } diff --git a/tests/test_declarative_module.rs b/tests/test_declarative_module.rs index 5f8e2c9fa55..8e432c3ae58 100644 --- a/tests/test_declarative_module.rs +++ b/tests/test_declarative_module.rs @@ -9,6 +9,13 @@ use pyo3::types::PyBool; #[path = "../src/tests/common.rs"] mod common; +mod some_module { + use pyo3::prelude::*; + + #[pyclass] + pub struct SomePyClass; +} + #[pyclass] struct ValueClass { value: usize, @@ -50,6 +57,10 @@ mod declarative_module { #[pymodule_export] use super::{declarative_module2, double, MyError, ValueClass as Value}; + // test for #4036 + #[pymodule_export] + use super::some_module::SomePyClass; + #[pymodule] mod inner { use super::*; From 30348b4d3fc433508cdc9b71ae7a973ec5e40235 Mon Sep 17 00:00:00 2001 From: messense Date: Sat, 13 Apr 2024 15:43:06 +0800 Subject: [PATCH 09/13] Link libpython for AIX target (#4073) --- newsfragments/4073.fixed.md | 1 + pyo3-build-config/src/impl_.rs | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 newsfragments/4073.fixed.md diff --git a/newsfragments/4073.fixed.md b/newsfragments/4073.fixed.md new file mode 100644 index 00000000000..0f77647e42d --- /dev/null +++ b/newsfragments/4073.fixed.md @@ -0,0 +1 @@ +fixes undefined symbol errors when building extension module on AIX by linking `libpython` diff --git a/pyo3-build-config/src/impl_.rs b/pyo3-build-config/src/impl_.rs index d5373db9655..2ee68503faa 100644 --- a/pyo3-build-config/src/impl_.rs +++ b/pyo3-build-config/src/impl_.rs @@ -775,6 +775,8 @@ pub fn is_linking_libpython() -> bool { /// Must be called from a PyO3 crate build script. fn is_linking_libpython_for_target(target: &Triple) -> bool { target.operating_system == OperatingSystem::Windows + // See https://github.com/PyO3/pyo3/issues/4068#issuecomment-2051159852 + || target.operating_system == OperatingSystem::Aix || target.environment == Environment::Android || target.environment == Environment::Androideabi || !is_extension_module() From 4e5167db4241e9c003c922b148fefd870eb0edad Mon Sep 17 00:00:00 2001 From: Adam Reichold Date: Sat, 13 Apr 2024 09:57:13 +0200 Subject: [PATCH 10/13] Extend guide on interaction between method receivers and lifetime elision. (#4069) --- guide/src/class.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/guide/src/class.md b/guide/src/class.md index f353cc4787e..b5ef95cb2f7 100644 --- a/guide/src/class.md +++ b/guide/src/class.md @@ -998,6 +998,44 @@ impl MyClass { Note that `text_signature` on `#[new]` is not compatible with compilation in `abi3` mode until Python 3.10 or greater. +### Method receivers and lifetime elision + +PyO3 supports writing instance methods using the normal method receivers for shared `&self` and unique `&mut self` references. This interacts with [lifetime elision][lifetime-elision] insofar as the lifetime of a such a receiver is assigned to all elided output lifetime parameters. + +This is a good default for general Rust code where return values are more likely to borrow from the receiver than from the other arguments, if they contain any lifetimes at all. However, when returning bound references `Bound<'py, T>` in PyO3-based code, the GIL lifetime `'py` should usually be derived from a GIL token `py: Python<'py>` passed as an argument instead of the receiver. + +Specifically, signatures like + +```rust,ignore +fn frobnicate(&self, py: Python) -> Bound; +``` + +will not work as they are inferred as + +```rust,ignore +fn frobnicate<'a, 'py>(&'a self, py: Python<'py>) -> Bound<'a, Foo>; +``` + +instead of the intended + +```rust,ignore +fn frobnicate<'a, 'py>(&'a self, py: Python<'py>) -> Bound<'py, Foo>; +``` + +and should usually be written as + +```rust,ignore +fn frobnicate<'py>(&self, py: Python<'py>) -> Bound<'py, Foo>; +``` + +The same problem does not exist for `#[pyfunction]`s as the special case for receiver lifetimes does not apply and indeed a signature like + +```rust,ignore +fn frobnicate(bar: &Bar, py: Python) -> Bound; +``` + +will yield compiler error [E0106 "missing lifetime specifier"][compiler-error-e0106]. + ## `#[pyclass]` enums Enum support in PyO3 comes in two flavors, depending on what kind of variants the enum has: simple and complex. @@ -1329,3 +1367,6 @@ impl pyo3::impl_::pyclass::PyClassImpl for MyClass { [classattr]: https://docs.python.org/3/tutorial/classes.html#class-and-instance-variables [`multiple-pymethods`]: features.md#multiple-pymethods + +[lifetime-elision]: https://doc.rust-lang.org/reference/lifetime-elision.html +[compiler-error-e0106]: https://doc.rust-lang.org/error_codes/E0106.html From 721100a9e981391de784022bf564285f772314ea Mon Sep 17 00:00:00 2001 From: Adam Reichold Date: Sat, 13 Apr 2024 14:59:44 +0200 Subject: [PATCH 11/13] Suppress non_local_definitions lint as we often want the non-local effects in macro code (#4074) * Resolve references to legacy numerical constants and use the associated constants instead * Suppress non_local_definitions lint as we often want the non-local effects in macro code --- pyo3-ffi/src/pyport.rs | 4 ++-- pyo3-macros-backend/src/module.rs | 2 ++ pyo3-macros-backend/src/pyfunction.rs | 1 + pyo3-macros-backend/src/pymethod.rs | 1 + src/callback.rs | 7 +------ src/conversions/std/num.rs | 28 +++++++++++++-------------- src/impl_/pyclass.rs | 1 + src/pycell/impl_.rs | 2 +- src/types/any.rs | 1 + tests/test_proto_methods.rs | 2 +- 10 files changed, 25 insertions(+), 24 deletions(-) diff --git a/pyo3-ffi/src/pyport.rs b/pyo3-ffi/src/pyport.rs index 741b0db7bf8..a144c67fb1b 100644 --- a/pyo3-ffi/src/pyport.rs +++ b/pyo3-ffi/src/pyport.rs @@ -11,8 +11,8 @@ pub type Py_ssize_t = ::libc::ssize_t; pub type Py_hash_t = Py_ssize_t; pub type Py_uhash_t = ::libc::size_t; -pub const PY_SSIZE_T_MIN: Py_ssize_t = std::isize::MIN as Py_ssize_t; -pub const PY_SSIZE_T_MAX: Py_ssize_t = std::isize::MAX as Py_ssize_t; +pub const PY_SSIZE_T_MIN: Py_ssize_t = isize::MIN as Py_ssize_t; +pub const PY_SSIZE_T_MAX: Py_ssize_t = isize::MAX as Py_ssize_t; #[cfg(target_endian = "big")] pub const PY_BIG_ENDIAN: usize = 1; diff --git a/pyo3-macros-backend/src/module.rs b/pyo3-macros-backend/src/module.rs index 8ff720cc616..3153279a2b8 100644 --- a/pyo3-macros-backend/src/module.rs +++ b/pyo3-macros-backend/src/module.rs @@ -249,6 +249,7 @@ pub fn pymodule_module_impl(mut module: syn::ItemMod) -> Result { #initialization + #[allow(unknown_lints, non_local_definitions)] impl MakeDef { const fn make_def() -> #pyo3_path::impl_::pymodule::ModuleDef { use #pyo3_path::impl_::pymodule as impl_; @@ -333,6 +334,7 @@ pub fn pymodule_function_impl(mut function: syn::ItemFn) -> Result // this avoids complications around the fact that the generated module has a different scope // (and `super` doesn't always refer to the outer scope, e.g. if the `#[pymodule] is // inside a function body) + #[allow(unknown_lints, non_local_definitions)] impl #ident::MakeDef { const fn make_def() -> #pyo3_path::impl_::pymodule::ModuleDef { fn __pyo3_pymodule(module: &#pyo3_path::Bound<'_, #pyo3_path::types::PyModule>) -> #pyo3_path::PyResult<()> { diff --git a/pyo3-macros-backend/src/pyfunction.rs b/pyo3-macros-backend/src/pyfunction.rs index 9f9557a3664..7c355533b83 100644 --- a/pyo3-macros-backend/src/pyfunction.rs +++ b/pyo3-macros-backend/src/pyfunction.rs @@ -273,6 +273,7 @@ pub fn impl_wrap_pyfunction( // this avoids complications around the fact that the generated module has a different scope // (and `super` doesn't always refer to the outer scope, e.g. if the `#[pyfunction] is // inside a function body) + #[allow(unknown_lints, non_local_definitions)] impl #name::MakeDef { const _PYO3_DEF: #pyo3_path::impl_::pymethods::PyMethodDef = #methoddef; } diff --git a/pyo3-macros-backend/src/pymethod.rs b/pyo3-macros-backend/src/pymethod.rs index abe8c7ac8a3..7a4c54db9da 100644 --- a/pyo3-macros-backend/src/pymethod.rs +++ b/pyo3-macros-backend/src/pymethod.rs @@ -366,6 +366,7 @@ pub fn impl_py_method_def_new( #deprecations use #pyo3_path::impl_::pyclass::*; + #[allow(unknown_lints, non_local_definitions)] impl PyClassNewTextSignature<#cls> for PyClassImplCollector<#cls> { #[inline] fn new_text_signature(self) -> ::std::option::Option<&'static str> { diff --git a/src/callback.rs b/src/callback.rs index a56b268aa1e..1e446039904 100644 --- a/src/callback.rs +++ b/src/callback.rs @@ -4,7 +4,6 @@ use crate::err::{PyErr, PyResult}; use crate::exceptions::PyOverflowError; use crate::ffi::{self, Py_hash_t}; use crate::{IntoPy, PyObject, Python}; -use std::isize; use std::os::raw::c_int; /// A type which can be the return type of a python C-API callback @@ -85,11 +84,7 @@ impl IntoPyCallbackOutput<()> for () { impl IntoPyCallbackOutput for usize { #[inline] fn convert(self, _py: Python<'_>) -> PyResult { - if self <= (isize::MAX as usize) { - Ok(self as isize) - } else { - Err(PyOverflowError::new_err(())) - } + self.try_into().map_err(|_err| PyOverflowError::new_err(())) } } diff --git a/src/conversions/std/num.rs b/src/conversions/std/num.rs index 44843141440..e2072d210e0 100644 --- a/src/conversions/std/num.rs +++ b/src/conversions/std/num.rs @@ -445,7 +445,7 @@ mod test_128bit_integers { #[test] fn test_i128_max() { Python::with_gil(|py| { - let v = std::i128::MAX; + let v = i128::MAX; let obj = v.to_object(py); assert_eq!(v, obj.extract::(py).unwrap()); assert_eq!(v as u128, obj.extract::(py).unwrap()); @@ -456,7 +456,7 @@ mod test_128bit_integers { #[test] fn test_i128_min() { Python::with_gil(|py| { - let v = std::i128::MIN; + let v = i128::MIN; let obj = v.to_object(py); assert_eq!(v, obj.extract::(py).unwrap()); assert!(obj.extract::(py).is_err()); @@ -467,7 +467,7 @@ mod test_128bit_integers { #[test] fn test_u128_max() { Python::with_gil(|py| { - let v = std::u128::MAX; + let v = u128::MAX; let obj = v.to_object(py); assert_eq!(v, obj.extract::(py).unwrap()); assert!(obj.extract::(py).is_err()); @@ -495,7 +495,7 @@ mod test_128bit_integers { #[test] fn test_nonzero_i128_max() { Python::with_gil(|py| { - let v = NonZeroI128::new(std::i128::MAX).unwrap(); + let v = NonZeroI128::new(i128::MAX).unwrap(); let obj = v.to_object(py); assert_eq!(v, obj.extract::(py).unwrap()); assert_eq!( @@ -509,7 +509,7 @@ mod test_128bit_integers { #[test] fn test_nonzero_i128_min() { Python::with_gil(|py| { - let v = NonZeroI128::new(std::i128::MIN).unwrap(); + let v = NonZeroI128::new(i128::MIN).unwrap(); let obj = v.to_object(py); assert_eq!(v, obj.extract::(py).unwrap()); assert!(obj.extract::(py).is_err()); @@ -520,7 +520,7 @@ mod test_128bit_integers { #[test] fn test_nonzero_u128_max() { Python::with_gil(|py| { - let v = NonZeroU128::new(std::u128::MAX).unwrap(); + let v = NonZeroU128::new(u128::MAX).unwrap(); let obj = v.to_object(py); assert_eq!(v, obj.extract::(py).unwrap()); assert!(obj.extract::(py).is_err()); @@ -573,7 +573,7 @@ mod tests { #[test] fn test_u32_max() { Python::with_gil(|py| { - let v = std::u32::MAX; + let v = u32::MAX; let obj = v.to_object(py); assert_eq!(v, obj.extract::(py).unwrap()); assert_eq!(u64::from(v), obj.extract::(py).unwrap()); @@ -584,7 +584,7 @@ mod tests { #[test] fn test_i64_max() { Python::with_gil(|py| { - let v = std::i64::MAX; + let v = i64::MAX; let obj = v.to_object(py); assert_eq!(v, obj.extract::(py).unwrap()); assert_eq!(v as u64, obj.extract::(py).unwrap()); @@ -595,7 +595,7 @@ mod tests { #[test] fn test_i64_min() { Python::with_gil(|py| { - let v = std::i64::MIN; + let v = i64::MIN; let obj = v.to_object(py); assert_eq!(v, obj.extract::(py).unwrap()); assert!(obj.extract::(py).is_err()); @@ -606,7 +606,7 @@ mod tests { #[test] fn test_u64_max() { Python::with_gil(|py| { - let v = std::u64::MAX; + let v = u64::MAX; let obj = v.to_object(py); assert_eq!(v, obj.extract::(py).unwrap()); assert!(obj.extract::(py).is_err()); @@ -664,7 +664,7 @@ mod tests { #[test] fn test_nonzero_u32_max() { Python::with_gil(|py| { - let v = NonZeroU32::new(std::u32::MAX).unwrap(); + let v = NonZeroU32::new(u32::MAX).unwrap(); let obj = v.to_object(py); assert_eq!(v, obj.extract::(py).unwrap()); assert_eq!(NonZeroU64::from(v), obj.extract::(py).unwrap()); @@ -675,7 +675,7 @@ mod tests { #[test] fn test_nonzero_i64_max() { Python::with_gil(|py| { - let v = NonZeroI64::new(std::i64::MAX).unwrap(); + let v = NonZeroI64::new(i64::MAX).unwrap(); let obj = v.to_object(py); assert_eq!(v, obj.extract::(py).unwrap()); assert_eq!( @@ -689,7 +689,7 @@ mod tests { #[test] fn test_nonzero_i64_min() { Python::with_gil(|py| { - let v = NonZeroI64::new(std::i64::MIN).unwrap(); + let v = NonZeroI64::new(i64::MIN).unwrap(); let obj = v.to_object(py); assert_eq!(v, obj.extract::(py).unwrap()); assert!(obj.extract::(py).is_err()); @@ -700,7 +700,7 @@ mod tests { #[test] fn test_nonzero_u64_max() { Python::with_gil(|py| { - let v = NonZeroU64::new(std::u64::MAX).unwrap(); + let v = NonZeroU64::new(u64::MAX).unwrap(); let obj = v.to_object(py); assert_eq!(v, obj.extract::(py).unwrap()); assert!(obj.extract::(py).is_err()); diff --git a/src/impl_/pyclass.rs b/src/impl_/pyclass.rs index 1a144f736e0..1302834ca4b 100644 --- a/src/impl_/pyclass.rs +++ b/src/impl_/pyclass.rs @@ -852,6 +852,7 @@ slot_fragment_trait! { #[macro_export] macro_rules! generate_pyclass_richcompare_slot { ($cls:ty) => {{ + #[allow(unknown_lints, non_local_definitions)] impl $cls { #[allow(non_snake_case)] unsafe extern "C" fn __pymethod___richcmp____( diff --git a/src/pycell/impl_.rs b/src/pycell/impl_.rs index 378bec04993..1bdd44b9e9c 100644 --- a/src/pycell/impl_.rs +++ b/src/pycell/impl_.rs @@ -55,7 +55,7 @@ struct BorrowFlag(usize); impl BorrowFlag { pub(crate) const UNUSED: BorrowFlag = BorrowFlag(0); - const HAS_MUTABLE_BORROW: BorrowFlag = BorrowFlag(usize::max_value()); + const HAS_MUTABLE_BORROW: BorrowFlag = BorrowFlag(usize::MAX); const fn increment(self) -> Self { Self(self.0 + 1) } diff --git a/src/types/any.rs b/src/types/any.rs index ab4f5727623..a5ea4c80d4c 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -2491,6 +2491,7 @@ class SimpleClass: #[cfg(feature = "macros")] #[test] + #[allow(unknown_lints, non_local_definitions)] fn test_hasattr_error() { use crate::exceptions::PyValueError; use crate::prelude::*; diff --git a/tests/test_proto_methods.rs b/tests/test_proto_methods.rs index dd707990c0b..c5d7306086d 100644 --- a/tests/test_proto_methods.rs +++ b/tests/test_proto_methods.rs @@ -3,7 +3,7 @@ use pyo3::exceptions::{PyAttributeError, PyIndexError, PyValueError}; use pyo3::types::{PyDict, PyList, PyMapping, PySequence, PySlice, PyType}; use pyo3::{prelude::*, py_run}; -use std::{isize, iter}; +use std::iter; #[path = "../src/tests/common.rs"] mod common; From 4c515f164ea2bbe56c855be4f6da948e528da1ec Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Sun, 14 Apr 2024 22:38:40 +0100 Subject: [PATCH 12/13] Deprecate the `PySet::empty` gil-ref constructor (#4082) * Deprecate the `PySet::empty` gil-ref constructor * add newsfragment --- newsfragments/4082.changed.md | 1 + src/types/set.rs | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 newsfragments/4082.changed.md diff --git a/newsfragments/4082.changed.md b/newsfragments/4082.changed.md new file mode 100644 index 00000000000..231ea0ae576 --- /dev/null +++ b/newsfragments/4082.changed.md @@ -0,0 +1 @@ +Deprecate the `PySet::empty()` gil-ref constructor. diff --git a/src/types/set.rs b/src/types/set.rs index 4f1fcf8499f..f648bc2be1f 100644 --- a/src/types/set.rs +++ b/src/types/set.rs @@ -58,7 +58,14 @@ impl PySet { } /// Deprecated form of [`PySet::empty_bound`]. - pub fn empty(py: Python<'_>) -> PyResult<&'_ PySet> { + #[cfg_attr( + not(feature = "gil-refs"), + deprecated( + since = "0.21.2", + note = "`PySet::empty` will be replaced by `PySet::empty_bound` in a future PyO3 version" + ) + )] + pub fn empty(py: Python<'_>) -> PyResult<&PySet> { Self::empty_bound(py).map(Bound::into_gil_ref) } From c58c670d73c61c7a937327d7a5ed6ed4eb0f4d8f Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Sun, 14 Apr 2024 14:31:08 +0100 Subject: [PATCH 13/13] release: 0.21.2 --- CHANGELOG.md | 17 ++++++++++++++++- Cargo.toml | 8 ++++---- README.md | 4 ++-- examples/decorator/.template/pre-script.rhai | 2 +- .../maturin-starter/.template/pre-script.rhai | 2 +- examples/plugin/.template/pre-script.rhai | 2 +- .../.template/pre-script.rhai | 2 +- examples/word-count/.template/pre-script.rhai | 2 +- newsfragments/4035.fixed.md | 1 - newsfragments/4045.fixed.md | 1 - newsfragments/4054.fixed.md | 1 - newsfragments/4067.fixed.md | 1 - newsfragments/4073.fixed.md | 1 - newsfragments/4082.changed.md | 1 - pyo3-build-config/Cargo.toml | 2 +- pyo3-ffi/Cargo.toml | 4 ++-- pyo3-macros-backend/Cargo.toml | 4 ++-- pyo3-macros/Cargo.toml | 4 ++-- pyproject.toml | 2 +- 19 files changed, 35 insertions(+), 26 deletions(-) delete mode 100644 newsfragments/4035.fixed.md delete mode 100644 newsfragments/4045.fixed.md delete mode 100644 newsfragments/4054.fixed.md delete mode 100644 newsfragments/4067.fixed.md delete mode 100644 newsfragments/4073.fixed.md delete mode 100644 newsfragments/4082.changed.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f4ce218021..86055a9a80c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,20 @@ To see unreleased changes, please see the [CHANGELOG on the main branch guide](h +## [0.21.2] - 2024-04-16 + +### Changed + +- Deprecate the `PySet::empty()` gil-ref constructor. [#4082](https://github.com/PyO3/pyo3/pull/4082) + +### Fixed + +- Fix compile error for `async fn` in `#[pymethods]` with a `&self` receiver and more than one additional argument. [#4035](https://github.com/PyO3/pyo3/pull/4035) +- Improve error message for wrong receiver type in `__traverse__`. [#4045](https://github.com/PyO3/pyo3/pull/4045) +- Fix compile error when exporting a `#[pyclass]` living in a different Rust module using the `experimental-declarative-modules` feature. [#4054](https://github.com/PyO3/pyo3/pull/4054) +- Fix `missing_docs` lint triggering on documented `#[pymodule]` functions. [#4067](https://github.com/PyO3/pyo3/pull/4067) +- Fix undefined symbol errors for extension modules on AIX (by linking `libpython`). [#4073](https://github.com/PyO3/pyo3/pull/4073) + ## [0.21.1] - 2024-04-01 ### Added @@ -1731,7 +1745,8 @@ Yanked - Initial release -[Unreleased]: https://github.com/pyo3/pyo3/compare/v0.21.1...HEAD +[Unreleased]: https://github.com/pyo3/pyo3/compare/v0.21.2...HEAD +[0.21.2]: https://github.com/pyo3/pyo3/compare/v0.21.1...v0.21.2 [0.21.1]: https://github.com/pyo3/pyo3/compare/v0.21.0...v0.21.1 [0.21.0]: https://github.com/pyo3/pyo3/compare/v0.20.3...v0.21.0 [0.21.0-beta.0]: https://github.com/pyo3/pyo3/compare/v0.20.3...v0.21.0-beta.0 diff --git a/Cargo.toml b/Cargo.toml index fdd1fa9d29a..858df6587c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pyo3" -version = "0.21.1" +version = "0.21.2" description = "Bindings to Python interpreter" authors = ["PyO3 Project and Contributors "] readme = "README.md" @@ -22,10 +22,10 @@ memoffset = "0.9" portable-atomic = "1.0" # ffi bindings to the python interpreter, split into a separate crate so they can be used independently -pyo3-ffi = { path = "pyo3-ffi", version = "=0.21.1" } +pyo3-ffi = { path = "pyo3-ffi", version = "=0.21.2" } # support crates for macros feature -pyo3-macros = { path = "pyo3-macros", version = "=0.21.1", optional = true } +pyo3-macros = { path = "pyo3-macros", version = "=0.21.2", optional = true } indoc = { version = "2.0.1", optional = true } unindent = { version = "0.2.1", optional = true } @@ -60,7 +60,7 @@ rayon = "1.6.1" futures = "0.3.28" [build-dependencies] -pyo3-build-config = { path = "pyo3-build-config", version = "=0.21.1", features = ["resolve-config"] } +pyo3-build-config = { path = "pyo3-build-config", version = "=0.21.2", features = ["resolve-config"] } [features] default = ["macros"] diff --git a/README.md b/README.md index 8e7e2f75bca..4da2447e8c4 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ name = "string_sum" crate-type = ["cdylib"] [dependencies] -pyo3 = { version = "0.21.1", features = ["extension-module"] } +pyo3 = { version = "0.21.2", features = ["extension-module"] } ``` **`src/lib.rs`** @@ -137,7 +137,7 @@ Start a new project with `cargo new` and add `pyo3` to the `Cargo.toml` like th ```toml [dependencies.pyo3] -version = "0.21.1" +version = "0.21.2" features = ["auto-initialize"] ``` diff --git a/examples/decorator/.template/pre-script.rhai b/examples/decorator/.template/pre-script.rhai index 1dc689ef6d4..37372854cd8 100644 --- a/examples/decorator/.template/pre-script.rhai +++ b/examples/decorator/.template/pre-script.rhai @@ -1,4 +1,4 @@ -variable::set("PYO3_VERSION", "0.21.1"); +variable::set("PYO3_VERSION", "0.21.2"); file::rename(".template/Cargo.toml", "Cargo.toml"); file::rename(".template/pyproject.toml", "pyproject.toml"); file::delete(".template"); diff --git a/examples/maturin-starter/.template/pre-script.rhai b/examples/maturin-starter/.template/pre-script.rhai index 1dc689ef6d4..37372854cd8 100644 --- a/examples/maturin-starter/.template/pre-script.rhai +++ b/examples/maturin-starter/.template/pre-script.rhai @@ -1,4 +1,4 @@ -variable::set("PYO3_VERSION", "0.21.1"); +variable::set("PYO3_VERSION", "0.21.2"); file::rename(".template/Cargo.toml", "Cargo.toml"); file::rename(".template/pyproject.toml", "pyproject.toml"); file::delete(".template"); diff --git a/examples/plugin/.template/pre-script.rhai b/examples/plugin/.template/pre-script.rhai index 78adb883f43..7c2f375fbfb 100644 --- a/examples/plugin/.template/pre-script.rhai +++ b/examples/plugin/.template/pre-script.rhai @@ -1,4 +1,4 @@ -variable::set("PYO3_VERSION", "0.21.1"); +variable::set("PYO3_VERSION", "0.21.2"); file::rename(".template/Cargo.toml", "Cargo.toml"); file::rename(".template/plugin_api/Cargo.toml", "plugin_api/Cargo.toml"); file::delete(".template"); diff --git a/examples/setuptools-rust-starter/.template/pre-script.rhai b/examples/setuptools-rust-starter/.template/pre-script.rhai index 212f62f76fe..dd2950665eb 100644 --- a/examples/setuptools-rust-starter/.template/pre-script.rhai +++ b/examples/setuptools-rust-starter/.template/pre-script.rhai @@ -1,4 +1,4 @@ -variable::set("PYO3_VERSION", "0.21.1"); +variable::set("PYO3_VERSION", "0.21.2"); file::rename(".template/Cargo.toml", "Cargo.toml"); file::rename(".template/setup.cfg", "setup.cfg"); file::delete(".template"); diff --git a/examples/word-count/.template/pre-script.rhai b/examples/word-count/.template/pre-script.rhai index 1dc689ef6d4..37372854cd8 100644 --- a/examples/word-count/.template/pre-script.rhai +++ b/examples/word-count/.template/pre-script.rhai @@ -1,4 +1,4 @@ -variable::set("PYO3_VERSION", "0.21.1"); +variable::set("PYO3_VERSION", "0.21.2"); file::rename(".template/Cargo.toml", "Cargo.toml"); file::rename(".template/pyproject.toml", "pyproject.toml"); file::delete(".template"); diff --git a/newsfragments/4035.fixed.md b/newsfragments/4035.fixed.md deleted file mode 100644 index 5425c5cbaf7..00000000000 --- a/newsfragments/4035.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fix compile error for `async fn` in `#[pymethods]` with a `&self` receiver and more than one additional argument. diff --git a/newsfragments/4045.fixed.md b/newsfragments/4045.fixed.md deleted file mode 100644 index 6b2bbcfa01d..00000000000 --- a/newsfragments/4045.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Add better error message on wrong receiver extraction in `__traverse__`. diff --git a/newsfragments/4054.fixed.md b/newsfragments/4054.fixed.md deleted file mode 100644 index 4b8da92ca4d..00000000000 --- a/newsfragments/4054.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixes a compile error when exporting a `#[pyclass]` living in a different Rust module using the declarative-module feature. diff --git a/newsfragments/4067.fixed.md b/newsfragments/4067.fixed.md deleted file mode 100644 index 869b6addf15..00000000000 --- a/newsfragments/4067.fixed.md +++ /dev/null @@ -1 +0,0 @@ -fixes `missing_docs` lint to trigger on documented `#[pymodule]` functions \ No newline at end of file diff --git a/newsfragments/4073.fixed.md b/newsfragments/4073.fixed.md deleted file mode 100644 index 0f77647e42d..00000000000 --- a/newsfragments/4073.fixed.md +++ /dev/null @@ -1 +0,0 @@ -fixes undefined symbol errors when building extension module on AIX by linking `libpython` diff --git a/newsfragments/4082.changed.md b/newsfragments/4082.changed.md deleted file mode 100644 index 231ea0ae576..00000000000 --- a/newsfragments/4082.changed.md +++ /dev/null @@ -1 +0,0 @@ -Deprecate the `PySet::empty()` gil-ref constructor. diff --git a/pyo3-build-config/Cargo.toml b/pyo3-build-config/Cargo.toml index 1eb269c2132..22621c4a66a 100644 --- a/pyo3-build-config/Cargo.toml +++ b/pyo3-build-config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pyo3-build-config" -version = "0.21.1" +version = "0.21.2" description = "Build configuration for the PyO3 ecosystem" authors = ["PyO3 Project and Contributors "] keywords = ["pyo3", "python", "cpython", "ffi"] diff --git a/pyo3-ffi/Cargo.toml b/pyo3-ffi/Cargo.toml index 64753976fab..8f7767254f1 100644 --- a/pyo3-ffi/Cargo.toml +++ b/pyo3-ffi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pyo3-ffi" -version = "0.21.1" +version = "0.21.2" description = "Python-API bindings for the PyO3 ecosystem" authors = ["PyO3 Project and Contributors "] keywords = ["pyo3", "python", "cpython", "ffi"] @@ -38,7 +38,7 @@ abi3-py312 = ["abi3", "pyo3-build-config/abi3-py312"] generate-import-lib = ["pyo3-build-config/python3-dll-a"] [build-dependencies] -pyo3-build-config = { path = "../pyo3-build-config", version = "=0.21.1", features = ["resolve-config"] } +pyo3-build-config = { path = "../pyo3-build-config", version = "=0.21.2", features = ["resolve-config"] } [lints] workspace = true diff --git a/pyo3-macros-backend/Cargo.toml b/pyo3-macros-backend/Cargo.toml index 6ca4eeade8c..f2675f2b75e 100644 --- a/pyo3-macros-backend/Cargo.toml +++ b/pyo3-macros-backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pyo3-macros-backend" -version = "0.21.1" +version = "0.21.2" description = "Code generation for PyO3 package" authors = ["PyO3 Project and Contributors "] keywords = ["pyo3", "python", "cpython", "ffi"] @@ -16,7 +16,7 @@ edition = "2021" [dependencies] heck = "0.4" proc-macro2 = { version = "1", default-features = false } -pyo3-build-config = { path = "../pyo3-build-config", version = "=0.21.1", features = ["resolve-config"] } +pyo3-build-config = { path = "../pyo3-build-config", version = "=0.21.2", features = ["resolve-config"] } quote = { version = "1", default-features = false } [dependencies.syn] diff --git a/pyo3-macros/Cargo.toml b/pyo3-macros/Cargo.toml index 39a4b9198c6..690924c76a5 100644 --- a/pyo3-macros/Cargo.toml +++ b/pyo3-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pyo3-macros" -version = "0.21.1" +version = "0.21.2" description = "Proc macros for PyO3 package" authors = ["PyO3 Project and Contributors "] keywords = ["pyo3", "python", "cpython", "ffi"] @@ -22,7 +22,7 @@ experimental-declarative-modules = [] proc-macro2 = { version = "1", default-features = false } quote = "1" syn = { version = "2", features = ["full", "extra-traits"] } -pyo3-macros-backend = { path = "../pyo3-macros-backend", version = "=0.21.1" } +pyo3-macros-backend = { path = "../pyo3-macros-backend", version = "=0.21.2" } [lints] workspace = true diff --git a/pyproject.toml b/pyproject.toml index d474753ccd1..9a70116f301 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ [tool.towncrier] filename = "CHANGELOG.md" -version = "0.21.1" +version = "0.21.2" start_string = "\n" template = ".towncrier.template.md" title_format = "## [{version}] - {project_date}"