From 9a808c35c69ffc9b37976cc43c8589a2a7f0fae8 Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Wed, 1 May 2024 21:05:51 +0200 Subject: [PATCH 01/10] fix `clippy-beta` ci workflow (#4147) --- pyo3-build-config/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pyo3-build-config/src/lib.rs b/pyo3-build-config/src/lib.rs index 5b1cfdaf322..1aa15d7d62a 100644 --- a/pyo3-build-config/src/lib.rs +++ b/pyo3-build-config/src/lib.rs @@ -86,6 +86,8 @@ pub fn get() -> &'static InterpreterConfig { .map(|path| path.exists()) .unwrap_or(false); + // CONFIG_FILE is generated in build.rs, so it's content can vary + #[allow(unknown_lints, clippy::const_is_empty)] if let Some(interpreter_config) = InterpreterConfig::from_cargo_dep_env() { interpreter_config } else if !CONFIG_FILE.is_empty() { @@ -177,6 +179,8 @@ pub mod pyo3_build_script_impl { /// correct value for CARGO_CFG_TARGET_OS). #[cfg(feature = "resolve-config")] pub fn resolve_interpreter_config() -> Result { + // CONFIG_FILE is generated in build.rs, so it's content can vary + #[allow(unknown_lints, clippy::const_is_empty)] if !CONFIG_FILE.is_empty() { let mut interperter_config = InterpreterConfig::from_reader(Cursor::new(CONFIG_FILE))?; interperter_config.generate_import_libs()?; From cd3f3ed67c963b758cb7e399e6f582d027a76707 Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Fri, 3 May 2024 09:42:30 +0200 Subject: [PATCH 02/10] ci: updates for Rust 1.78 (#4150) * ci: updates for Rust 1.78 * ci: fix clippy * restrict `invalid_pymethods_duplicates` to unlimited api with `full` --- pytests/src/othermod.rs | 4 +- src/pyclass/create_type_object.rs | 6 +- tests/test_compile_error.rs | 2 + tests/ui/abi3_nativetype_inheritance.stderr | 6 +- tests/ui/invalid_argument_attributes.rs | 10 +- tests/ui/invalid_argument_attributes.stderr | 10 +- tests/ui/invalid_cancel_handle.stderr | 10 +- tests/ui/invalid_intern_arg.rs | 4 +- tests/ui/invalid_intern_arg.stderr | 13 ++- tests/ui/invalid_property_args.rs | 6 +- tests/ui/invalid_property_args.stderr | 14 +-- tests/ui/invalid_proto_pymethods.rs | 4 +- tests/ui/invalid_proto_pymethods.stderr | 36 +++++++ tests/ui/invalid_pyfunction_signatures.rs | 1 + tests/ui/invalid_pyfunction_signatures.stderr | 12 +-- tests/ui/invalid_pyfunctions.rs | 18 ++-- tests/ui/invalid_pyfunctions.stderr | 28 ++--- tests/ui/invalid_pymethod_receiver.rs | 2 +- tests/ui/invalid_pymethod_receiver.stderr | 9 +- tests/ui/invalid_pymethods.rs | 10 +- tests/ui/invalid_pymethods.stderr | 21 ++-- tests/ui/invalid_pymethods_duplicates.stderr | 102 ++++++++++++++++++ tests/ui/missing_intopy.stderr | 13 +-- tests/ui/pyclass_send.rs | 2 +- tests/ui/traverse.rs | 12 +-- tests/ui/traverse.stderr | 26 ++--- 26 files changed, 264 insertions(+), 117 deletions(-) diff --git a/pytests/src/othermod.rs b/pytests/src/othermod.rs index 29ca8121890..36ad4b5e23e 100644 --- a/pytests/src/othermod.rs +++ b/pytests/src/othermod.rs @@ -34,8 +34,8 @@ pub fn othermod(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; - m.add("USIZE_MIN", usize::min_value())?; - m.add("USIZE_MAX", usize::max_value())?; + m.add("USIZE_MIN", usize::MIN)?; + m.add("USIZE_MAX", usize::MAX)?; Ok(()) } diff --git a/src/pyclass/create_type_object.rs b/src/pyclass/create_type_object.rs index 52e346212f0..e90c5736e5c 100644 --- a/src/pyclass/create_type_object.rs +++ b/src/pyclass/create_type_object.rs @@ -145,12 +145,14 @@ impl PyTypeBuilder { #[cfg(all(not(Py_3_9), not(Py_LIMITED_API)))] ffi::Py_bf_getbuffer => { // Safety: slot.pfunc is a valid function pointer - self.buffer_procs.bf_getbuffer = Some(std::mem::transmute(pfunc)); + self.buffer_procs.bf_getbuffer = + Some(std::mem::transmute::<*mut T, ffi::getbufferproc>(pfunc)); } #[cfg(all(not(Py_3_9), not(Py_LIMITED_API)))] ffi::Py_bf_releasebuffer => { // Safety: slot.pfunc is a valid function pointer - self.buffer_procs.bf_releasebuffer = Some(std::mem::transmute(pfunc)); + self.buffer_procs.bf_releasebuffer = + Some(std::mem::transmute::<*mut T, ffi::releasebufferproc>(pfunc)); } _ => {} } diff --git a/tests/test_compile_error.rs b/tests/test_compile_error.rs index 44049620598..30e77888cfd 100644 --- a/tests/test_compile_error.rs +++ b/tests/test_compile_error.rs @@ -13,6 +13,8 @@ fn test_compile_errors() { t.compile_fail("tests/ui/invalid_pyfunction_signatures.rs"); #[cfg(any(not(Py_LIMITED_API), Py_3_11))] t.compile_fail("tests/ui/invalid_pymethods_buffer.rs"); + // The output is not stable across abi3 / not abi3 and features + #[cfg(all(not(Py_LIMITED_API), feature = "full"))] t.compile_fail("tests/ui/invalid_pymethods_duplicates.rs"); t.compile_fail("tests/ui/invalid_pymethod_enum.rs"); t.compile_fail("tests/ui/invalid_pymethod_names.rs"); diff --git a/tests/ui/abi3_nativetype_inheritance.stderr b/tests/ui/abi3_nativetype_inheritance.stderr index 784da4f55ba..f9ca7c61b89 100644 --- a/tests/ui/abi3_nativetype_inheritance.stderr +++ b/tests/ui/abi3_nativetype_inheritance.stderr @@ -1,12 +1,10 @@ -error[E0277]: the trait bound `PyDict: PyClass` is not satisfied +error[E0277]: the trait bound `PyDict: PyClassBaseType` is not satisfied --> tests/ui/abi3_nativetype_inheritance.rs:5:19 | 5 | #[pyclass(extends=PyDict)] | ^^^^^^ the trait `PyClass` is not implemented for `PyDict`, which is required by `PyDict: PyClassBaseType` | - = help: the following other types implement trait `PyClass`: - TestClass - pyo3::coroutine::Coroutine + = help: the trait `PyClassBaseType` is implemented for `PyAny` = note: required for `PyDict` to implement `PyClassBaseType` note: required by a bound in `PyClassImpl::BaseType` --> src/impl_/pyclass.rs diff --git a/tests/ui/invalid_argument_attributes.rs b/tests/ui/invalid_argument_attributes.rs index 311c6c03e0e..6797642d77b 100644 --- a/tests/ui/invalid_argument_attributes.rs +++ b/tests/ui/invalid_argument_attributes.rs @@ -1,18 +1,18 @@ use pyo3::prelude::*; #[pyfunction] -fn invalid_attribute(#[pyo3(get)] param: String) {} +fn invalid_attribute(#[pyo3(get)] _param: String) {} #[pyfunction] -fn from_py_with_no_value(#[pyo3(from_py_with)] param: String) {} +fn from_py_with_no_value(#[pyo3(from_py_with)] _param: String) {} #[pyfunction] -fn from_py_with_string(#[pyo3("from_py_with")] param: String) {} +fn from_py_with_string(#[pyo3("from_py_with")] _param: String) {} #[pyfunction] -fn from_py_with_value_not_a_string(#[pyo3(from_py_with = func)] param: String) {} +fn from_py_with_value_not_a_string(#[pyo3(from_py_with = func)] _param: String) {} #[pyfunction] -fn from_py_with_repeated(#[pyo3(from_py_with = "func", from_py_with = "func")] param: String) {} +fn from_py_with_repeated(#[pyo3(from_py_with = "func", from_py_with = "func")] _param: String) {} fn main() {} diff --git a/tests/ui/invalid_argument_attributes.stderr b/tests/ui/invalid_argument_attributes.stderr index d27c25fd179..e6c42f82a87 100644 --- a/tests/ui/invalid_argument_attributes.stderr +++ b/tests/ui/invalid_argument_attributes.stderr @@ -1,29 +1,29 @@ error: expected `cancel_handle` or `from_py_with` --> tests/ui/invalid_argument_attributes.rs:4:29 | -4 | fn invalid_attribute(#[pyo3(get)] param: String) {} +4 | fn invalid_attribute(#[pyo3(get)] _param: String) {} | ^^^ error: expected `=` --> tests/ui/invalid_argument_attributes.rs:7:45 | -7 | fn from_py_with_no_value(#[pyo3(from_py_with)] param: String) {} +7 | fn from_py_with_no_value(#[pyo3(from_py_with)] _param: String) {} | ^ error: expected `cancel_handle` or `from_py_with` --> tests/ui/invalid_argument_attributes.rs:10:31 | -10 | fn from_py_with_string(#[pyo3("from_py_with")] param: String) {} +10 | fn from_py_with_string(#[pyo3("from_py_with")] _param: String) {} | ^^^^^^^^^^^^^^ error: expected string literal --> tests/ui/invalid_argument_attributes.rs:13:58 | -13 | fn from_py_with_value_not_a_string(#[pyo3(from_py_with = func)] param: String) {} +13 | fn from_py_with_value_not_a_string(#[pyo3(from_py_with = func)] _param: String) {} | ^^^^ error: `from_py_with` may only be specified once per argument --> tests/ui/invalid_argument_attributes.rs:16:56 | -16 | fn from_py_with_repeated(#[pyo3(from_py_with = "func", from_py_with = "func")] param: String) {} +16 | fn from_py_with_repeated(#[pyo3(from_py_with = "func", from_py_with = "func")] _param: String) {} | ^^^^^^^^^^^^ diff --git a/tests/ui/invalid_cancel_handle.stderr b/tests/ui/invalid_cancel_handle.stderr index 41a2c0854b7..f6452611679 100644 --- a/tests/ui/invalid_cancel_handle.stderr +++ b/tests/ui/invalid_cancel_handle.stderr @@ -38,13 +38,17 @@ note: function defined here | ^^^^^^^^^^^^^^^^^^^^^^^^ -------------- = note: this error originates in the attribute macro `pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `CancelHandle: PyClass` is not satisfied +error[E0277]: the trait bound `CancelHandle: PyFunctionArgument<'_, '_>` is not satisfied --> tests/ui/invalid_cancel_handle.rs:20:50 | 20 | async fn missing_cancel_handle_attribute(_param: pyo3::coroutine::CancelHandle) {} | ^^^^ the trait `PyClass` is not implemented for `CancelHandle`, which is required by `CancelHandle: PyFunctionArgument<'_, '_>` | - = help: the trait `PyClass` is implemented for `pyo3::coroutine::Coroutine` + = help: the following other types implement trait `PyFunctionArgument<'a, 'py>`: + Option<&'a pyo3::Bound<'py, T>> + &'a pyo3::Bound<'py, T> + &'a pyo3::coroutine::Coroutine + &'a mut pyo3::coroutine::Coroutine = note: required for `CancelHandle` to implement `FromPyObject<'_>` = note: required for `CancelHandle` to implement `FromPyObjectBound<'_, '_>` = note: required for `CancelHandle` to implement `PyFunctionArgument<'_, '_>` @@ -57,7 +61,7 @@ note: required by a bound in `extract_argument` | T: PyFunctionArgument<'a, 'py>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `extract_argument` -error[E0277]: the trait bound `CancelHandle: Clone` is not satisfied +error[E0277]: the trait bound `CancelHandle: PyFunctionArgument<'_, '_>` is not satisfied --> tests/ui/invalid_cancel_handle.rs:20:50 | 20 | async fn missing_cancel_handle_attribute(_param: pyo3::coroutine::CancelHandle) {} diff --git a/tests/ui/invalid_intern_arg.rs b/tests/ui/invalid_intern_arg.rs index 3c7bd592175..eb479431b90 100644 --- a/tests/ui/invalid_intern_arg.rs +++ b/tests/ui/invalid_intern_arg.rs @@ -1,6 +1,6 @@ use pyo3::Python; fn main() { - let foo = if true { "foo" } else { "bar" }; - Python::with_gil(|py| py.import_bound(pyo3::intern!(py, foo)).unwrap()); + let _foo = if true { "foo" } else { "bar" }; + Python::with_gil(|py| py.import_bound(pyo3::intern!(py, _foo)).unwrap()); } diff --git a/tests/ui/invalid_intern_arg.stderr b/tests/ui/invalid_intern_arg.stderr index dce2d85bf09..5d2131bd845 100644 --- a/tests/ui/invalid_intern_arg.stderr +++ b/tests/ui/invalid_intern_arg.stderr @@ -1,8 +1,17 @@ error[E0435]: attempt to use a non-constant value in a constant --> tests/ui/invalid_intern_arg.rs:5:61 | -5 | Python::with_gil(|py| py.import_bound(pyo3::intern!(py, foo)).unwrap()); - | ------------------^^^- +5 | Python::with_gil(|py| py.import_bound(pyo3::intern!(py, _foo)).unwrap()); + | ------------------^^^^- | | | | | non-constant value | help: consider using `let` instead of `static`: `let INTERNED` + +error: lifetime may not live long enough + --> tests/ui/invalid_intern_arg.rs:5:27 + | +5 | Python::with_gil(|py| py.import_bound(pyo3::intern!(py, _foo)).unwrap()); + | --- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2` + | | | + | | return type of closure is pyo3::Bound<'2, pyo3::prelude::PyModule> + | has type `pyo3::Python<'1>` diff --git a/tests/ui/invalid_property_args.rs b/tests/ui/invalid_property_args.rs index 3f335952235..b5eba27eb60 100644 --- a/tests/ui/invalid_property_args.rs +++ b/tests/ui/invalid_property_args.rs @@ -6,7 +6,7 @@ struct ClassWithGetter {} #[pymethods] impl ClassWithGetter { #[getter] - fn getter_with_arg(&self, py: Python<'_>, index: u32) {} + fn getter_with_arg(&self, _py: Python<'_>, _index: u32) {} } #[pyclass] @@ -15,13 +15,13 @@ struct ClassWithSetter {} #[pymethods] impl ClassWithSetter { #[setter] - fn setter_with_no_arg(&mut self, py: Python<'_>) {} + fn setter_with_no_arg(&mut self, _py: Python<'_>) {} } #[pymethods] impl ClassWithSetter { #[setter] - fn setter_with_too_many_args(&mut self, py: Python<'_>, foo: u32, bar: u32) {} + fn setter_with_too_many_args(&mut self, _py: Python<'_>, _foo: u32, _bar: u32) {} } #[pyclass] diff --git a/tests/ui/invalid_property_args.stderr b/tests/ui/invalid_property_args.stderr index a41b6c79b3a..dea2e3fb2b4 100644 --- a/tests/ui/invalid_property_args.stderr +++ b/tests/ui/invalid_property_args.stderr @@ -1,20 +1,20 @@ error: getter function can only have one argument (of type pyo3::Python) - --> tests/ui/invalid_property_args.rs:9:54 + --> tests/ui/invalid_property_args.rs:9:56 | -9 | fn getter_with_arg(&self, py: Python<'_>, index: u32) {} - | ^^^ +9 | fn getter_with_arg(&self, _py: Python<'_>, _index: u32) {} + | ^^^ error: setter function expected to have one argument --> tests/ui/invalid_property_args.rs:18:8 | -18 | fn setter_with_no_arg(&mut self, py: Python<'_>) {} +18 | fn setter_with_no_arg(&mut self, _py: Python<'_>) {} | ^^^^^^^^^^^^^^^^^^ error: setter function can have at most two arguments ([pyo3::Python,] and value) - --> tests/ui/invalid_property_args.rs:24:76 + --> tests/ui/invalid_property_args.rs:24:79 | -24 | fn setter_with_too_many_args(&mut self, py: Python<'_>, foo: u32, bar: u32) {} - | ^^^ +24 | fn setter_with_too_many_args(&mut self, _py: Python<'_>, _foo: u32, _bar: u32) {} + | ^^^ error: `get` and `set` with tuple struct fields require `name` --> tests/ui/invalid_property_args.rs:28:50 diff --git a/tests/ui/invalid_proto_pymethods.rs b/tests/ui/invalid_proto_pymethods.rs index d370c4fddb5..c40790c3168 100644 --- a/tests/ui/invalid_proto_pymethods.rs +++ b/tests/ui/invalid_proto_pymethods.rs @@ -54,11 +54,11 @@ struct EqAndRichcmp; #[pymethods] impl EqAndRichcmp { - fn __eq__(&self, other: &Self) -> bool { + fn __eq__(&self, _other: &Self) -> bool { true } - fn __richcmp__(&self, other: &Self, op: CompareOp) -> bool { + fn __richcmp__(&self, _other: &Self, _op: CompareOp) -> bool { true } } diff --git a/tests/ui/invalid_proto_pymethods.stderr b/tests/ui/invalid_proto_pymethods.stderr index c9f6adff3a1..82c99c2ddc3 100644 --- a/tests/ui/invalid_proto_pymethods.stderr +++ b/tests/ui/invalid_proto_pymethods.stderr @@ -22,6 +22,24 @@ error: `text_signature` cannot be used with magic method `__bool__` 46 | #[pyo3(name = "__bool__", text_signature = "")] | ^^^^^^^^^^^^^^ +error[E0034]: multiple applicable items in scope + --> tests/ui/invalid_proto_pymethods.rs:55:1 + | +55 | #[pymethods] + | ^^^^^^^^^^^^ multiple `__pymethod___richcmp____` found + | +note: candidate #1 is defined in an impl for the type `EqAndRichcmp` + --> tests/ui/invalid_proto_pymethods.rs:55:1 + | +55 | #[pymethods] + | ^^^^^^^^^^^^ +note: candidate #2 is defined in an impl for the type `EqAndRichcmp` + --> tests/ui/invalid_proto_pymethods.rs:55:1 + | +55 | #[pymethods] + | ^^^^^^^^^^^^ + = note: this error originates in the macro `::pyo3::impl_::pyclass::generate_pyclass_richcompare_slot` which comes from the expansion of the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0592]: duplicate definitions with name `__pymethod___richcmp____` --> tests/ui/invalid_proto_pymethods.rs:55:1 | @@ -32,3 +50,21 @@ error[E0592]: duplicate definitions with name `__pymethod___richcmp____` | other definition for `__pymethod___richcmp____` | = note: this error originates in the macro `::pyo3::impl_::pyclass::generate_pyclass_richcompare_slot` which comes from the expansion of the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0034]: multiple applicable items in scope + --> tests/ui/invalid_proto_pymethods.rs:55:1 + | +55 | #[pymethods] + | ^^^^^^^^^^^^ multiple `__pymethod___richcmp____` found + | +note: candidate #1 is defined in an impl for the type `EqAndRichcmp` + --> tests/ui/invalid_proto_pymethods.rs:55:1 + | +55 | #[pymethods] + | ^^^^^^^^^^^^ +note: candidate #2 is defined in an impl for the type `EqAndRichcmp` + --> tests/ui/invalid_proto_pymethods.rs:55:1 + | +55 | #[pymethods] + | ^^^^^^^^^^^^ + = note: this error originates in the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/invalid_pyfunction_signatures.rs b/tests/ui/invalid_pyfunction_signatures.rs index f5a9bee4e6c..86033aa12ea 100644 --- a/tests/ui/invalid_pyfunction_signatures.rs +++ b/tests/ui/invalid_pyfunction_signatures.rs @@ -35,6 +35,7 @@ fn function_with_args_sep_after_args_sep() {} #[pyo3(signature = (**kwargs, *args))] fn function_with_args_after_kwargs(kwargs: Option<&PyDict>, args: &PyTuple) { let _ = args; + let _ = kwargs; } #[pyfunction] diff --git a/tests/ui/invalid_pyfunction_signatures.stderr b/tests/ui/invalid_pyfunction_signatures.stderr index dbca169d8ea..97d0fd3b4af 100644 --- a/tests/ui/invalid_pyfunction_signatures.stderr +++ b/tests/ui/invalid_pyfunction_signatures.stderr @@ -41,19 +41,19 @@ error: `*args` not allowed after `**kwargs` | ^ error: `**kwargs_b` not allowed after `**kwargs_a` - --> tests/ui/invalid_pyfunction_signatures.rs:41:33 + --> tests/ui/invalid_pyfunction_signatures.rs:42:33 | -41 | #[pyo3(signature = (**kwargs_a, **kwargs_b))] +42 | #[pyo3(signature = (**kwargs_a, **kwargs_b))] | ^ error: arguments of type `Python` must not be part of the signature - --> tests/ui/invalid_pyfunction_signatures.rs:47:27 + --> tests/ui/invalid_pyfunction_signatures.rs:48:27 | -47 | #[pyfunction(signature = (py))] +48 | #[pyfunction(signature = (py))] | ^^ error: cannot find attribute `args` in this scope - --> tests/ui/invalid_pyfunction_signatures.rs:57:7 + --> tests/ui/invalid_pyfunction_signatures.rs:58:7 | -57 | #[args(x)] +58 | #[args(x)] | ^^^^ diff --git a/tests/ui/invalid_pyfunctions.rs b/tests/ui/invalid_pyfunctions.rs index 1a95c9e4a34..1c0c45d6b95 100644 --- a/tests/ui/invalid_pyfunctions.rs +++ b/tests/ui/invalid_pyfunctions.rs @@ -2,35 +2,39 @@ use pyo3::prelude::*; use pyo3::types::{PyDict, PyString, PyTuple}; #[pyfunction] -fn generic_function(value: T) {} +fn generic_function(_value: T) {} #[pyfunction] -fn impl_trait_function(impl_trait: impl AsRef) {} +fn impl_trait_function(_impl_trait: impl AsRef) {} #[pyfunction] fn wildcard_argument(_: i32) {} #[pyfunction] -fn destructured_argument((a, b): (i32, i32)) {} +fn destructured_argument((_a, _b): (i32, i32)) {} #[pyfunction] fn function_with_required_after_option(_opt: Option, _x: i32) {} #[pyfunction] #[pyo3(signature=(*args))] -fn function_with_optional_args(args: Option>) {} +fn function_with_optional_args(args: Option>) { + let _ = args; +} #[pyfunction] #[pyo3(signature=(**kwargs))] -fn function_with_required_kwargs(kwargs: Bound<'_, PyDict>) {} +fn function_with_required_kwargs(kwargs: Bound<'_, PyDict>) { + let _ = kwargs; +} #[pyfunction(pass_module)] fn pass_module_but_no_arguments<'py>() {} #[pyfunction(pass_module)] fn first_argument_not_module<'a, 'py>( - string: &str, - module: &'a Bound<'_, PyModule>, + _string: &str, + module: &'a Bound<'py, PyModule>, ) -> PyResult> { module.name() } diff --git a/tests/ui/invalid_pyfunctions.stderr b/tests/ui/invalid_pyfunctions.stderr index 893d7cbec2c..830f17ee877 100644 --- a/tests/ui/invalid_pyfunctions.stderr +++ b/tests/ui/invalid_pyfunctions.stderr @@ -1,14 +1,14 @@ error: Python functions cannot have generic type parameters --> tests/ui/invalid_pyfunctions.rs:5:21 | -5 | fn generic_function(value: T) {} +5 | fn generic_function(_value: T) {} | ^ error: Python functions cannot have `impl Trait` arguments - --> tests/ui/invalid_pyfunctions.rs:8:36 + --> tests/ui/invalid_pyfunctions.rs:8:37 | -8 | fn impl_trait_function(impl_trait: impl AsRef) {} - | ^^^^ +8 | fn impl_trait_function(_impl_trait: impl AsRef) {} + | ^^^^ error: wildcard argument names are not supported --> tests/ui/invalid_pyfunctions.rs:11:22 @@ -19,8 +19,8 @@ error: wildcard argument names are not supported error: destructuring in arguments is not supported --> tests/ui/invalid_pyfunctions.rs:14:26 | -14 | fn destructured_argument((a, b): (i32, i32)) {} - | ^^^^^^ +14 | fn destructured_argument((_a, _b): (i32, i32)) {} + | ^^^^^^^^ error: required arguments after an `Option<_>` argument are ambiguous = help: add a `#[pyo3(signature)]` annotation on this function to unambiguously specify the default values for all optional parameters @@ -32,26 +32,26 @@ error: required arguments after an `Option<_>` argument are ambiguous error: args cannot be optional --> tests/ui/invalid_pyfunctions.rs:21:32 | -21 | fn function_with_optional_args(args: Option>) {} +21 | fn function_with_optional_args(args: Option>) { | ^^^^ error: kwargs must be Option<_> - --> tests/ui/invalid_pyfunctions.rs:25:34 + --> tests/ui/invalid_pyfunctions.rs:27:34 | -25 | fn function_with_required_kwargs(kwargs: Bound<'_, PyDict>) {} +27 | fn function_with_required_kwargs(kwargs: Bound<'_, PyDict>) { | ^^^^^^ error: expected `&PyModule` or `Py` as first argument with `pass_module` - --> tests/ui/invalid_pyfunctions.rs:28:37 + --> tests/ui/invalid_pyfunctions.rs:32:37 | -28 | fn pass_module_but_no_arguments<'py>() {} +32 | fn pass_module_but_no_arguments<'py>() {} | ^^ error[E0277]: the trait bound `&str: From>` is not satisfied - --> tests/ui/invalid_pyfunctions.rs:32:13 + --> tests/ui/invalid_pyfunctions.rs:36:14 | -32 | string: &str, - | ^ the trait `From>` is not implemented for `&str`, which is required by `BoundRef<'_, '_, pyo3::prelude::PyModule>: Into<_>` +36 | _string: &str, + | ^ the trait `From>` is not implemented for `&str`, which is required by `BoundRef<'_, '_, pyo3::prelude::PyModule>: Into<_>` | = help: the following other types implement trait `From`: > diff --git a/tests/ui/invalid_pymethod_receiver.rs b/tests/ui/invalid_pymethod_receiver.rs index 77832e12857..4949ff96022 100644 --- a/tests/ui/invalid_pymethod_receiver.rs +++ b/tests/ui/invalid_pymethod_receiver.rs @@ -5,7 +5,7 @@ struct MyClass {} #[pymethods] impl MyClass { - fn method_with_invalid_self_type(slf: i32, py: Python<'_>, index: u32) {} + fn method_with_invalid_self_type(_slf: i32, _py: Python<'_>, _index: u32) {} } fn main() {} diff --git a/tests/ui/invalid_pymethod_receiver.stderr b/tests/ui/invalid_pymethod_receiver.stderr index a79e289716a..2c8ec045819 100644 --- a/tests/ui/invalid_pymethod_receiver.stderr +++ b/tests/ui/invalid_pymethod_receiver.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `i32: From>` is not satisfied - --> tests/ui/invalid_pymethod_receiver.rs:8:43 +error[E0277]: the trait bound `i32: TryFrom>` is not satisfied + --> tests/ui/invalid_pymethod_receiver.rs:8:44 | -8 | fn method_with_invalid_self_type(slf: i32, py: Python<'_>, index: u32) {} - | ^^^ the trait `From>` is not implemented for `i32`, which is required by `i32: TryFrom>` +8 | fn method_with_invalid_self_type(_slf: i32, _py: Python<'_>, _index: u32) {} + | ^^^ the trait `From>` is not implemented for `i32`, which is required by `i32: TryFrom>` | = help: the following other types implement trait `From`: > @@ -10,6 +10,5 @@ error[E0277]: the trait bound `i32: From>` is not sati > > > - >> = note: required for `BoundRef<'_, '_, MyClass>` to implement `Into` = note: required for `i32` to implement `TryFrom>` diff --git a/tests/ui/invalid_pymethods.rs b/tests/ui/invalid_pymethods.rs index 00bddfe2fad..41786cd7895 100644 --- a/tests/ui/invalid_pymethods.rs +++ b/tests/ui/invalid_pymethods.rs @@ -6,7 +6,7 @@ struct MyClass {} #[pymethods] impl MyClass { #[classattr] - fn class_attr_with_args(foo: i32) {} + fn class_attr_with_args(_foo: i32) {} } #[pymethods] @@ -164,23 +164,23 @@ impl MyClass { #[pymethods] impl MyClass { - fn generic_method(value: T) {} + fn generic_method(_value: T) {} } #[pymethods] impl MyClass { - fn impl_trait_method_first_arg(impl_trait: impl AsRef) {} + fn impl_trait_method_first_arg(_impl_trait: impl AsRef) {} } #[pymethods] impl MyClass { - fn impl_trait_method_second_arg(&self, impl_trait: impl AsRef) {} + fn impl_trait_method_second_arg(&self, _impl_trait: impl AsRef) {} } #[pymethods] impl MyClass { #[pyo3(pass_module)] - fn method_cannot_pass_module(&self, m: &PyModule) {} + fn method_cannot_pass_module(&self, _m: &PyModule) {} } #[pymethods] diff --git a/tests/ui/invalid_pymethods.stderr b/tests/ui/invalid_pymethods.stderr index 5bcb6aa1be6..9b090e31adc 100644 --- a/tests/ui/invalid_pymethods.stderr +++ b/tests/ui/invalid_pymethods.stderr @@ -1,8 +1,8 @@ error: #[classattr] can only have one argument (of type pyo3::Python) - --> tests/ui/invalid_pymethods.rs:9:34 + --> tests/ui/invalid_pymethods.rs:9:35 | -9 | fn class_attr_with_args(foo: i32) {} - | ^^^ +9 | fn class_attr_with_args(_foo: i32) {} + | ^^^ error: `#[classattr]` does not take any arguments --> tests/ui/invalid_pymethods.rs:14:5 @@ -144,20 +144,20 @@ error: `#[classattr]` does not take any arguments error: Python functions cannot have generic type parameters --> tests/ui/invalid_pymethods.rs:167:23 | -167 | fn generic_method(value: T) {} +167 | fn generic_method(_value: T) {} | ^ error: Python functions cannot have `impl Trait` arguments - --> tests/ui/invalid_pymethods.rs:172:48 + --> tests/ui/invalid_pymethods.rs:172:49 | -172 | fn impl_trait_method_first_arg(impl_trait: impl AsRef) {} - | ^^^^ +172 | fn impl_trait_method_first_arg(_impl_trait: impl AsRef) {} + | ^^^^ error: Python functions cannot have `impl Trait` arguments - --> tests/ui/invalid_pymethods.rs:177:56 + --> tests/ui/invalid_pymethods.rs:177:57 | -177 | fn impl_trait_method_second_arg(&self, impl_trait: impl AsRef) {} - | ^^^^ +177 | fn impl_trait_method_second_arg(&self, _impl_trait: impl AsRef) {} + | ^^^^ error: `pass_module` cannot be used on Python methods --> tests/ui/invalid_pymethods.rs:182:12 @@ -191,5 +191,4 @@ error[E0277]: the trait bound `i32: From>` is not satis > > > - >> = note: required for `BoundRef<'_, '_, PyType>` to implement `Into` diff --git a/tests/ui/invalid_pymethods_duplicates.stderr b/tests/ui/invalid_pymethods_duplicates.stderr index 38bb6f8655b..753c4b1b8dc 100644 --- a/tests/ui/invalid_pymethods_duplicates.stderr +++ b/tests/ui/invalid_pymethods_duplicates.stderr @@ -9,6 +9,40 @@ error[E0119]: conflicting implementations of trait `pyo3::impl_::pyclass::PyClas | = note: this error originates in the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0277]: the trait bound `TwoNew: PyTypeInfo` is not satisfied + --> tests/ui/invalid_pymethods_duplicates.rs:9:6 + | +9 | impl TwoNew { + | ^^^^^^ the trait `PyTypeInfo` is not implemented for `TwoNew` + | + = help: the following other types implement trait `PyTypeInfo`: + PyAny + PyBool + PyByteArray + PyBytes + PyCapsule + PyCode + PyComplex + PyDate + and $N others + +error[E0277]: the trait bound `TwoNew: HasPyGilRef` is not satisfied + --> tests/ui/invalid_pymethods_duplicates.rs:9:6 + | +9 | impl TwoNew { + | ^^^^^^ the trait `PyNativeType` is not implemented for `TwoNew`, which is required by `TwoNew: HasPyGilRef` + | + = help: the trait `HasPyGilRef` is implemented for `pyo3::coroutine::Coroutine` + = note: required for `TwoNew` to implement `HasPyGilRef` +note: required by a bound in `pyo3::PyTypeInfo::NAME` + --> src/type_object.rs + | + | pub unsafe trait PyTypeInfo: Sized + HasPyGilRef { + | ^^^^^^^^^^^ required by this bound in `PyTypeInfo::NAME` + | /// Class name. + | const NAME: &'static str; + | ---- required by a bound in this associated constant + error[E0592]: duplicate definitions with name `__pymethod___new____` --> tests/ui/invalid_pymethods_duplicates.rs:8:1 | @@ -30,3 +64,71 @@ error[E0592]: duplicate definitions with name `__pymethod_func__` | other definition for `__pymethod_func__` | = note: this error originates in the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `TwoNew: PyClass` is not satisfied + --> tests/ui/invalid_pymethods_duplicates.rs:8:1 + | +8 | #[pymethods] + | ^^^^^^^^^^^^ the trait `PyClass` is not implemented for `TwoNew` + | + = help: the trait `PyClass` is implemented for `pyo3::coroutine::Coroutine` +note: required by a bound in `PyClassInitializer` + --> src/pyclass_init.rs + | + | pub struct PyClassInitializer(PyClassInitializerImpl); + | ^^^^^^^ required by this bound in `PyClassInitializer` + = note: this error originates in the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0599]: no method named `convert` found for struct `TwoNew` in the current scope + --> tests/ui/invalid_pymethods_duplicates.rs:8:1 + | +6 | struct TwoNew {} + | ------------- method `convert` not found for this struct +7 | +8 | #[pymethods] + | ^^^^^^^^^^^^ method not found in `TwoNew` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `convert`, perhaps you need to implement it: + candidate #1: `IntoPyCallbackOutput` + = note: this error originates in the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `DuplicateMethod: PyClass` is not satisfied + --> tests/ui/invalid_pymethods_duplicates.rs:26:15 + | +26 | fn func_a(&self) {} + | ^ the trait `PyClass` is not implemented for `DuplicateMethod` + | + = help: the trait `PyClass` is implemented for `pyo3::coroutine::Coroutine` +note: required by a bound in `extract_pyclass_ref` + --> src/impl_/extract_argument.rs + | + | pub fn extract_pyclass_ref<'a, 'py: 'a, T: PyClass>( + | ^^^^^^^ required by this bound in `extract_pyclass_ref` + +error[E0277]: the trait bound `DuplicateMethod: PyClass` is not satisfied + --> tests/ui/invalid_pymethods_duplicates.rs:23:1 + | +23 | #[pymethods] + | ^^^^^^^^^^^^ the trait `PyClass` is not implemented for `DuplicateMethod` + | + = help: the trait `PyClass` is implemented for `pyo3::coroutine::Coroutine` +note: required by a bound in `PyRef` + --> src/pycell.rs + | + | pub struct PyRef<'p, T: PyClass> { + | ^^^^^^^ required by this bound in `PyRef` + = note: this error originates in the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `DuplicateMethod: PyClass` is not satisfied + --> tests/ui/invalid_pymethods_duplicates.rs:29:15 + | +29 | fn func_b(&self) {} + | ^ the trait `PyClass` is not implemented for `DuplicateMethod` + | + = help: the trait `PyClass` is implemented for `pyo3::coroutine::Coroutine` +note: required by a bound in `extract_pyclass_ref` + --> src/impl_/extract_argument.rs + | + | pub fn extract_pyclass_ref<'a, 'py: 'a, T: PyClass>( + | ^^^^^^^ required by this bound in `extract_pyclass_ref` diff --git a/tests/ui/missing_intopy.stderr b/tests/ui/missing_intopy.stderr index 1d233b28b6c..c0a60143671 100644 --- a/tests/ui/missing_intopy.stderr +++ b/tests/ui/missing_intopy.stderr @@ -1,18 +1,9 @@ -error[E0277]: the trait bound `Blah: IntoPy>` is not satisfied +error[E0277]: the trait bound `Blah: OkWrap` is not satisfied --> tests/ui/missing_intopy.rs:3:1 | 3 | #[pyo3::pyfunction] | ^^^^^^^^^^^^^^^^^^^ the trait `IntoPy>` is not implemented for `Blah`, which is required by `Blah: OkWrap<_>` | - = help: the following other types implement trait `IntoPy`: - >> - >> - >> - >> - >> - >> - >> - >> - and $N others + = help: the trait `OkWrap` is implemented for `Result` = note: required for `Blah` to implement `OkWrap` = note: this error originates in the attribute macro `pyo3::pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/pyclass_send.rs b/tests/ui/pyclass_send.rs index 2747c2cb3bb..a587c071f51 100644 --- a/tests/ui/pyclass_send.rs +++ b/tests/ui/pyclass_send.rs @@ -10,7 +10,7 @@ fn main() { let obj = Python::with_gil(|py| { Bound::new(py, NotThreadSafe { data: Rc::new(5) }) .unwrap() - .unbind(py) + .unbind() }); std::thread::spawn(move || { diff --git a/tests/ui/traverse.rs b/tests/ui/traverse.rs index 0cf7170db21..faa7b5c041d 100644 --- a/tests/ui/traverse.rs +++ b/tests/ui/traverse.rs @@ -7,7 +7,7 @@ struct TraverseTriesToTakePyRef {} #[pymethods] impl TraverseTriesToTakePyRef { - fn __traverse__(slf: PyRef, visit: PyVisit) -> Result<(), PyTraverseError> { + fn __traverse__(_slf: PyRef, _visit: PyVisit) -> Result<(), PyTraverseError> { Ok(()) } } @@ -17,7 +17,7 @@ struct TraverseTriesToTakePyRefMut {} #[pymethods] impl TraverseTriesToTakePyRefMut { - fn __traverse__(slf: PyRefMut, visit: PyVisit) -> Result<(), PyTraverseError> { + fn __traverse__(_slf: PyRefMut, _visit: PyVisit) -> Result<(), PyTraverseError> { Ok(()) } } @@ -27,7 +27,7 @@ struct TraverseTriesToTakeBound {} #[pymethods] impl TraverseTriesToTakeBound { - fn __traverse__(slf: Bound<'_, Self>, visit: PyVisit) -> Result<(), PyTraverseError> { + fn __traverse__(_slf: Bound<'_, Self>, _visit: PyVisit) -> Result<(), PyTraverseError> { Ok(()) } } @@ -37,7 +37,7 @@ struct TraverseTriesToTakeMutSelf {} #[pymethods] impl TraverseTriesToTakeMutSelf { - fn __traverse__(&mut self, visit: PyVisit) -> Result<(), PyTraverseError> { + fn __traverse__(&mut self, _visit: PyVisit) -> Result<(), PyTraverseError> { Ok(()) } } @@ -47,7 +47,7 @@ struct TraverseTriesToTakeSelf {} #[pymethods] impl TraverseTriesToTakeSelf { - fn __traverse__(&self, visit: PyVisit) -> Result<(), PyTraverseError> { + fn __traverse__(&self, _visit: PyVisit) -> Result<(), PyTraverseError> { Ok(()) } } @@ -57,7 +57,7 @@ struct Class; #[pymethods] impl Class { - fn __traverse__(&self, py: Python<'_>, visit: PyVisit<'_>) -> Result<(), PyTraverseError> { + fn __traverse__(&self, _py: Python<'_>, _visit: PyVisit<'_>) -> Result<(), PyTraverseError> { Ok(()) } diff --git a/tests/ui/traverse.stderr b/tests/ui/traverse.stderr index 5b1d1b6b2ec..504a6dfa671 100644 --- a/tests/ui/traverse.stderr +++ b/tests/ui/traverse.stderr @@ -1,29 +1,29 @@ 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 + --> tests/ui/traverse.rs:10:27 | -10 | fn __traverse__(slf: PyRef, 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 + --> tests/ui/traverse.rs:20:27 | -20 | fn __traverse__(slf: PyRefMut, visit: PyVisit) -> Result<(), PyTraverseError> { - | ^^^^^^^^ +20 | fn __traverse__(_slf: PyRefMut, _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:30:26 + --> tests/ui/traverse.rs:30:27 | -30 | fn __traverse__(slf: Bound<'_, Self>, visit: PyVisit) -> Result<(), PyTraverseError> { - | ^^^^^ +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 | -40 | fn __traverse__(&mut self, visit: PyVisit) -> Result<(), PyTraverseError> { +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 + --> tests/ui/traverse.rs:60:33 | -60 | fn __traverse__(&self, py: Python<'_>, visit: PyVisit<'_>) -> Result<(), PyTraverseError> { - | ^^^^^^^^^^ +60 | fn __traverse__(&self, _py: Python<'_>, _visit: PyVisit<'_>) -> Result<(), PyTraverseError> { + | ^^^^^^^^^^ From 7cbb85476c920cb80d2906b08b2a25d96fe4b5c8 Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Fri, 3 May 2024 12:17:14 +0200 Subject: [PATCH 03/10] fix `check-guide` ci workflow (#4146) --- noxfile.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/noxfile.py b/noxfile.py index c8d2ead63d3..84676b1ff0c 100644 --- a/noxfile.py +++ b/noxfile.py @@ -415,10 +415,11 @@ def check_guide(session: nox.Session): _run( session, "lychee", - PYO3_DOCS_TARGET, + str(PYO3_DOCS_TARGET), f"--remap=https://pyo3.rs/main/ file://{PYO3_GUIDE_TARGET}/", f"--remap=https://pyo3.rs/latest/ file://{PYO3_GUIDE_TARGET}/", f"--exclude=file://{PYO3_DOCS_TARGET}", + "--exclude=http://www.adobe.com/", *session.posargs, ) From 93cfb51ebbdfb598e4a08539155ac4d9e9194a28 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 3 May 2024 12:02:19 -0400 Subject: [PATCH 04/10] feature gate deprecated APIs for `PyMemoryView` (#4152) --- src/types/memoryview.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/types/memoryview.rs b/src/types/memoryview.rs index c04a98e7886..ffc1c81efa0 100644 --- a/src/types/memoryview.rs +++ b/src/types/memoryview.rs @@ -11,12 +11,10 @@ pyobject_native_type_core!(PyMemoryView, pyobject_native_static_type_object!(ffi impl PyMemoryView { /// Deprecated form of [`PyMemoryView::from_bound`] - #[cfg_attr( - not(feature = "gil-refs"), - deprecated( - since = "0.21.0", - note = "`PyMemoryView::from` will be replaced by `PyMemoryView::from_bound` in a future PyO3 version" - ) + #[cfg(feature = "gil-refs")] + #[deprecated( + since = "0.21.0", + note = "`PyMemoryView::from` will be replaced by `PyMemoryView::from_bound` in a future PyO3 version" )] pub fn from(src: &PyAny) -> PyResult<&PyMemoryView> { PyMemoryView::from_bound(&src.as_borrowed()).map(Bound::into_gil_ref) From f3ab62cb7ec17752e776334957b00894ede97d37 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 3 May 2024 13:10:49 -0400 Subject: [PATCH 05/10] feature gate deprecated APIs for `PyModule` (#4151) --- .../python-from-rust/calling-existing-code.md | 12 +++---- src/marker.rs | 2 +- src/types/module.rs | 31 +++++++------------ 3 files changed, 19 insertions(+), 26 deletions(-) diff --git a/guide/src/python-from-rust/calling-existing-code.md b/guide/src/python-from-rust/calling-existing-code.md index 53051d4ce51..572f4b4414f 100644 --- a/guide/src/python-from-rust/calling-existing-code.md +++ b/guide/src/python-from-rust/calling-existing-code.md @@ -2,9 +2,9 @@ If you already have some existing Python code that you need to execute from Rust, the following FAQs can help you select the right PyO3 functionality for your situation: -## Want to access Python APIs? Then use `PyModule::import`. +## Want to access Python APIs? Then use `PyModule::import_bound`. -[`Pymodule::import`]({{#PYO3_DOCS_URL}}/pyo3/types/struct.PyModule.html#method.import) can +[`PyModule::import_bound`]({{#PYO3_DOCS_URL}}/pyo3/types/struct.PyModule.html#method.import_bound) can be used to get handle to a Python module from Rust. You can use this to import and use any Python module available in your environment. @@ -95,9 +95,9 @@ assert userdata.as_tuple() == userdata_as_tuple # } ``` -## You have a Python file or code snippet? Then use `PyModule::from_code`. +## You have a Python file or code snippet? Then use `PyModule::from_code_bound`. -[`PyModule::from_code`]({{#PYO3_DOCS_URL}}/pyo3/types/struct.PyModule.html#method.from_code) +[`PyModule::from_code_bound`]({{#PYO3_DOCS_URL}}/pyo3/types/struct.PyModule.html#method.from_code_bound) can be used to generate a Python module which can then be used just as if it was imported with `PyModule::import`. @@ -171,7 +171,7 @@ fn main() -> PyResult<()> { ``` If `append_to_inittab` cannot be used due to constraints in the program, -an alternative is to create a module using [`PyModule::new`] +an alternative is to create a module using [`PyModule::new_bound`] and insert it manually into `sys.modules`: ```rust @@ -394,4 +394,4 @@ Python::with_gil(|py| -> PyResult<()> { ``` -[`PyModule::new`]: {{#PYO3_DOCS_URL}}/pyo3/types/struct.PyModule.html#method.new +[`PyModule::new_bound`]: {{#PYO3_DOCS_URL}}/pyo3/types/struct.PyModule.html#method.new_bound diff --git a/src/marker.rs b/src/marker.rs index 29aae69d4f2..c975a4a338e 100644 --- a/src/marker.rs +++ b/src/marker.rs @@ -352,7 +352,7 @@ pub use nightly::Ungil; /// # Releasing and freeing memory /// /// The [`Python`] type can be used to create references to variables owned by the Python -/// interpreter, using functions such as [`Python::eval`] and [`PyModule::import`]. These +/// interpreter, using functions such as [`Python::eval`] and `PyModule::import`. These /// references are tied to a [`GILPool`] whose references are not cleared until it is dropped. /// This can cause apparent "memory leaks" if it is kept around for a long time. /// diff --git a/src/types/module.rs b/src/types/module.rs index 11afcf76c83..c8b2cf04551 100644 --- a/src/types/module.rs +++ b/src/types/module.rs @@ -27,12 +27,10 @@ pyobject_native_type_core!(PyModule, pyobject_native_static_type_object!(ffi::Py impl PyModule { /// Deprecated form of [`PyModule::new_bound`]. #[inline] - #[cfg_attr( - not(feature = "gil-refs"), - deprecated( - since = "0.21.0", - note = "`PyModule::new` will be replaced by `PyModule::new_bound` in a future PyO3 version" - ) + #[cfg(feature = "gil-refs")] + #[deprecated( + since = "0.21.0", + note = "`PyModule::new` will be replaced by `PyModule::new_bound` in a future PyO3 version" )] pub fn new<'py>(py: Python<'py>, name: &str) -> PyResult<&'py PyModule> { Self::new_bound(py, name).map(Bound::into_gil_ref) @@ -66,12 +64,10 @@ impl PyModule { /// Deprecated form of [`PyModule::import_bound`]. #[inline] - #[cfg_attr( - not(feature = "gil-refs"), - deprecated( - since = "0.21.0", - note = "`PyModule::import` will be replaced by `PyModule::import_bound` in a future PyO3 version" - ) + #[cfg(feature = "gil-refs")] + #[deprecated( + since = "0.21.0", + note = "`PyModule::import` will be replaced by `PyModule::import_bound` in a future PyO3 version" )] pub fn import(py: Python<'_>, name: N) -> PyResult<&PyModule> where @@ -112,12 +108,10 @@ impl PyModule { /// Deprecated form of [`PyModule::from_code_bound`]. #[inline] - #[cfg_attr( - not(feature = "gil-refs"), - deprecated( - since = "0.21.0", - note = "`PyModule::from_code` will be replaced by `PyModule::from_code_bound` in a future PyO3 version" - ) + #[cfg(feature = "gil-refs")] + #[deprecated( + since = "0.21.0", + note = "`PyModule::from_code` will be replaced by `PyModule::from_code_bound` in a future PyO3 version" )] pub fn from_code<'py>( py: Python<'py>, @@ -722,7 +716,6 @@ fn __name__(py: Python<'_>) -> &Bound<'_, PyString> { } #[cfg(test)] -#[cfg_attr(not(feature = "gil-refs"), allow(deprecated))] mod tests { use crate::{ types::{module::PyModuleMethods, string::PyStringMethods, PyModule}, From c08f6c77a60be2c5cdfc5216aa8869ff48738d51 Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Fri, 3 May 2024 20:15:25 +0200 Subject: [PATCH 06/10] feature gate deprecated APIs for `marshal` (#4149) --- src/marshal.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/marshal.rs b/src/marshal.rs index 9526813976b..3978f4873e1 100644 --- a/src/marshal.rs +++ b/src/marshal.rs @@ -13,12 +13,10 @@ use std::os::raw::c_int; pub const VERSION: i32 = 4; /// Deprecated form of [`dumps_bound`] -#[cfg_attr( - not(feature = "gil-refs"), - deprecated( - since = "0.21.0", - note = "`dumps` will be replaced by `dumps_bound` in a future PyO3 version" - ) +#[cfg(feature = "gil-refs")] +#[deprecated( + since = "0.21.0", + note = "`dumps` will be replaced by `dumps_bound` in a future PyO3 version" )] pub fn dumps<'py>( py: Python<'py>, @@ -61,12 +59,10 @@ pub fn dumps_bound<'py>( } /// Deprecated form of [`loads_bound`] -#[cfg_attr( - not(feature = "gil-refs"), - deprecated( - since = "0.21.0", - note = "`loads` will be replaced by `loads_bound` in a future PyO3 version" - ) +#[cfg(feature = "gil-refs")] +#[deprecated( + since = "0.21.0", + note = "`loads` will be replaced by `loads_bound` in a future PyO3 version" )] pub fn loads<'py, B>(py: Python<'py>, data: &B) -> PyResult<&'py PyAny> where From d1a0c7278f16925c9075101c763d73bbc5f673c5 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 3 May 2024 15:50:38 -0400 Subject: [PATCH 07/10] feature gate deprecated APIs for `PyCFunction` (#4154) --- src/types/function.rs | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/types/function.rs b/src/types/function.rs index f5305e31886..09c5004b77b 100644 --- a/src/types/function.rs +++ b/src/types/function.rs @@ -1,14 +1,17 @@ +#[cfg(feature = "gil-refs")] use crate::derive_utils::PyFunctionArguments; use crate::ffi_ptr_ext::FfiPtrExt; use crate::py_result_ext::PyResultExt; use crate::types::capsule::PyCapsuleMethods; use crate::types::module::PyModuleMethods; +#[cfg(feature = "gil-refs")] +use crate::PyNativeType; use crate::{ ffi, impl_::pymethods::{self, PyMethodDef, PyMethodDefDestructor}, types::{PyCapsule, PyDict, PyModule, PyString, PyTuple}, }; -use crate::{Bound, IntoPy, Py, PyAny, PyNativeType, PyResult, Python}; +use crate::{Bound, IntoPy, Py, PyAny, PyResult, Python}; use std::cell::UnsafeCell; use std::ffi::CStr; @@ -20,12 +23,10 @@ pyobject_native_type_core!(PyCFunction, pyobject_native_static_type_object!(ffi: impl PyCFunction { /// Deprecated form of [`PyCFunction::new_with_keywords_bound`] - #[cfg_attr( - not(feature = "gil-refs"), - deprecated( - since = "0.21.0", - note = "`PyCFunction::new_with_keywords` will be replaced by `PyCFunction::new_with_keywords_bound` in a future PyO3 version" - ) + #[cfg(feature = "gil-refs")] + #[deprecated( + since = "0.21.0", + note = "`PyCFunction::new_with_keywords` will be replaced by `PyCFunction::new_with_keywords_bound` in a future PyO3 version" )] pub fn new_with_keywords<'a>( fun: ffi::PyCFunctionWithKeywords, @@ -66,12 +67,10 @@ impl PyCFunction { } /// Deprecated form of [`PyCFunction::new`] - #[cfg_attr( - not(feature = "gil-refs"), - deprecated( - since = "0.21.0", - note = "`PyCFunction::new` will be replaced by `PyCFunction::new_bound` in a future PyO3 version" - ) + #[cfg(feature = "gil-refs")] + #[deprecated( + since = "0.21.0", + note = "`PyCFunction::new` will be replaced by `PyCFunction::new_bound` in a future PyO3 version" )] pub fn new<'a>( fun: ffi::PyCFunction, @@ -104,12 +103,10 @@ impl PyCFunction { } /// Deprecated form of [`PyCFunction::new_closure`] - #[cfg_attr( - not(feature = "gil-refs"), - deprecated( - since = "0.21.0", - note = "`PyCFunction::new_closure` will be replaced by `PyCFunction::new_closure_bound` in a future PyO3 version" - ) + #[cfg(feature = "gil-refs")] + #[deprecated( + since = "0.21.0", + note = "`PyCFunction::new_closure` will be replaced by `PyCFunction::new_closure_bound` in a future PyO3 version" )] pub fn new_closure<'a, F, R>( py: Python<'a>, From c10c7429d8b5f16a6c28650b21e214f35cbbfe48 Mon Sep 17 00:00:00 2001 From: Heran Lin Date: Sat, 4 May 2024 15:32:27 +0800 Subject: [PATCH 08/10] docs: Remove out-dated information for pyenv (#4138) --- guide/src/building-and-distribution.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guide/src/building-and-distribution.md b/guide/src/building-and-distribution.md index b7aa2d2abc2..33280a5a180 100644 --- a/guide/src/building-and-distribution.md +++ b/guide/src/building-and-distribution.md @@ -232,7 +232,7 @@ not work when compiling for `abi3`. These are: If you want to embed the Python interpreter inside a Rust program, there are two modes in which this can be done: dynamically and statically. We'll cover each of these modes in the following sections. Each of them affect how you must distribute your program. Instead of learning how to do this yourself, you might want to consider using a project like [PyOxidizer] to ship your application and all of its dependencies in a single file. -PyO3 automatically switches between the two linking modes depending on whether the Python distribution you have configured PyO3 to use ([see above](#configuring-the-python-version)) contains a shared library or a static library. The static library is most often seen in Python distributions compiled from source without the `--enable-shared` configuration option. For example, this is the default for `pyenv` on macOS. +PyO3 automatically switches between the two linking modes depending on whether the Python distribution you have configured PyO3 to use ([see above](#configuring-the-python-version)) contains a shared library or a static library. The static library is most often seen in Python distributions compiled from source without the `--enable-shared` configuration option. ### Dynamically embedding the Python interpreter From e835ff0ec30e0e391fdfcbef017241004ed9d896 Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Sat, 4 May 2024 09:39:40 +0200 Subject: [PATCH 09/10] handle `#[pyo3(from_py_with = ...)]` on dunder (`__magic__`) methods (#4117) * handle `#[pyo3(from_py_with = ...)]` on dunder (__magic__) methods * add newsfragment --- newsfragments/4117.fixed.md | 1 + pyo3-macros-backend/src/params.rs | 34 +++++++++++++++++--- pyo3-macros-backend/src/pymethod.rs | 42 ++++++++++++++---------- tests/test_class_basics.rs | 11 +++++++ tests/ui/deprecations.rs | 8 +++++ tests/ui/deprecations.stderr | 50 ++++++++++++++++------------- 6 files changed, 103 insertions(+), 43 deletions(-) create mode 100644 newsfragments/4117.fixed.md diff --git a/newsfragments/4117.fixed.md b/newsfragments/4117.fixed.md new file mode 100644 index 00000000000..c3bb4c144b6 --- /dev/null +++ b/newsfragments/4117.fixed.md @@ -0,0 +1 @@ +Correctly handle `#[pyo3(from_py_with = ...)]` attribute on dunder (`__magic__`) method arguments instead of silently ignoring it. diff --git a/pyo3-macros-backend/src/params.rs b/pyo3-macros-backend/src/params.rs index d9f77fa07bc..cab9d2a7d29 100644 --- a/pyo3-macros-backend/src/params.rs +++ b/pyo3-macros-backend/src/params.rs @@ -10,7 +10,7 @@ use syn::spanned::Spanned; pub struct Holders { holders: Vec, - gil_refs_checkers: Vec, + gil_refs_checkers: Vec, } impl Holders { @@ -32,14 +32,28 @@ impl Holders { &format!("gil_refs_checker_{}", self.gil_refs_checkers.len()), span, ); - self.gil_refs_checkers.push(gil_refs_checker.clone()); + self.gil_refs_checkers + .push(GilRefChecker::FunctionArg(gil_refs_checker.clone())); + gil_refs_checker + } + + pub fn push_from_py_with_checker(&mut self, span: Span) -> syn::Ident { + let gil_refs_checker = syn::Ident::new( + &format!("gil_refs_checker_{}", self.gil_refs_checkers.len()), + span, + ); + self.gil_refs_checkers + .push(GilRefChecker::FromPyWith(gil_refs_checker.clone())); gil_refs_checker } pub fn init_holders(&self, ctx: &Ctx) -> TokenStream { let Ctx { pyo3_path } = ctx; let holders = &self.holders; - let gil_refs_checkers = &self.gil_refs_checkers; + let gil_refs_checkers = self.gil_refs_checkers.iter().map(|checker| match checker { + GilRefChecker::FunctionArg(ident) => ident, + GilRefChecker::FromPyWith(ident) => ident, + }); quote! { #[allow(clippy::let_unit_value)] #(let mut #holders = #pyo3_path::impl_::extract_argument::FunctionArgumentHolder::INIT;)* @@ -50,11 +64,23 @@ impl Holders { pub fn check_gil_refs(&self) -> TokenStream { self.gil_refs_checkers .iter() - .map(|e| quote_spanned! { e.span() => #e.function_arg(); }) + .map(|checker| match checker { + GilRefChecker::FunctionArg(ident) => { + quote_spanned! { ident.span() => #ident.function_arg(); } + } + GilRefChecker::FromPyWith(ident) => { + quote_spanned! { ident.span() => #ident.from_py_with_arg(); } + } + }) .collect() } } +enum GilRefChecker { + FunctionArg(syn::Ident), + FromPyWith(syn::Ident), +} + /// Return true if the argument list is simply (*args, **kwds). pub fn is_forwarded_args(signature: &FunctionSignature<'_>) -> bool { matches!( diff --git a/pyo3-macros-backend/src/pymethod.rs b/pyo3-macros-backend/src/pymethod.rs index aac804316f8..1ef137cfcc8 100644 --- a/pyo3-macros-backend/src/pymethod.rs +++ b/pyo3-macros-backend/src/pymethod.rs @@ -1053,20 +1053,18 @@ impl Ty { ctx: &Ctx, ) -> TokenStream { let Ctx { pyo3_path } = ctx; - let name_str = arg.name().unraw().to_string(); match self { Ty::Object => extract_object( extract_error_mode, holders, - &name_str, + arg, quote! { #ident }, - arg.ty().span(), ctx ), Ty::MaybeNullObject => extract_object( extract_error_mode, holders, - &name_str, + arg, quote! { if #ident.is_null() { #pyo3_path::ffi::Py_None() @@ -1074,23 +1072,20 @@ impl Ty { #ident } }, - arg.ty().span(), ctx ), Ty::NonNullObject => extract_object( extract_error_mode, holders, - &name_str, + arg, quote! { #ident.as_ptr() }, - arg.ty().span(), ctx ), Ty::IPowModulo => extract_object( extract_error_mode, holders, - &name_str, + arg, quote! { #ident.as_ptr() }, - arg.ty().span(), ctx ), Ty::CompareOp => extract_error_mode.handle_error( @@ -1118,24 +1113,37 @@ impl Ty { fn extract_object( extract_error_mode: ExtractErrorMode, holders: &mut Holders, - name: &str, + arg: &FnArg<'_>, source_ptr: TokenStream, - span: Span, ctx: &Ctx, ) -> TokenStream { let Ctx { pyo3_path } = ctx; - let holder = holders.push_holder(Span::call_site()); - let gil_refs_checker = holders.push_gil_refs_checker(span); - let extracted = extract_error_mode.handle_error( + let gil_refs_checker = holders.push_gil_refs_checker(arg.ty().span()); + let name = arg.name().unraw().to_string(); + + let extract = if let Some(from_py_with) = + arg.from_py_with().map(|from_py_with| &from_py_with.value) + { + let from_py_with_checker = holders.push_from_py_with_checker(from_py_with.span()); + quote! { + #pyo3_path::impl_::extract_argument::from_py_with( + #pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &#source_ptr).0, + #name, + #pyo3_path::impl_::deprecations::inspect_fn(#from_py_with, &#from_py_with_checker) as fn(_) -> _, + ) + } + } else { + let holder = holders.push_holder(Span::call_site()); quote! { #pyo3_path::impl_::extract_argument::extract_argument( #pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &#source_ptr).0, &mut #holder, #name ) - }, - ctx, - ); + } + }; + + let extracted = extract_error_mode.handle_error(extract, ctx); quote! { #pyo3_path::impl_::deprecations::inspect_type(#extracted, &#gil_refs_checker) } diff --git a/tests/test_class_basics.rs b/tests/test_class_basics.rs index 8c6a1c04915..8ff61bd2d6b 100644 --- a/tests/test_class_basics.rs +++ b/tests/test_class_basics.rs @@ -290,6 +290,10 @@ fn get_length(obj: &Bound<'_, PyAny>) -> PyResult { Ok(length) } +fn is_even(obj: &Bound<'_, PyAny>) -> PyResult { + obj.extract::().map(|i| i % 2 == 0) +} + #[pyclass] struct ClassWithFromPyWithMethods {} @@ -319,6 +323,10 @@ impl ClassWithFromPyWithMethods { fn staticmethod(#[pyo3(from_py_with = "get_length")] argument: usize) -> usize { argument } + + fn __contains__(&self, #[pyo3(from_py_with = "is_even")] obj: bool) -> bool { + obj + } } #[test] @@ -339,6 +347,9 @@ fn test_pymethods_from_py_with() { if has_gil_refs: assert instance.classmethod_gil_ref(arg) == 2 assert instance.staticmethod(arg) == 2 + + assert 42 in instance + assert 73 not in instance "# ); }) diff --git a/tests/ui/deprecations.rs b/tests/ui/deprecations.rs index dcc9b7b1d84..96f652d9679 100644 --- a/tests/ui/deprecations.rs +++ b/tests/ui/deprecations.rs @@ -38,6 +38,14 @@ impl MyClass { #[setter] fn set_bar_bound(&self, _value: &Bound<'_, PyAny>) {} + + fn __eq__(&self, #[pyo3(from_py_with = "extract_gil_ref")] _other: i32) -> bool { + true + } + + fn __contains__(&self, #[pyo3(from_py_with = "extract_bound")] _value: i32) -> bool { + true + } } fn main() {} diff --git a/tests/ui/deprecations.stderr b/tests/ui/deprecations.stderr index e692702f23e..2b75ee23e10 100644 --- a/tests/ui/deprecations.stderr +++ b/tests/ui/deprecations.stderr @@ -16,6 +16,12 @@ error: use of deprecated struct `pyo3::PyCell`: `PyCell` was merged into `Bound` 23 | fn method_gil_ref(_slf: &PyCell) {} | ^^^^^^ +error: use of deprecated method `pyo3::deprecations::GilRefs::::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor + --> tests/ui/deprecations.rs:42:44 + | +42 | fn __eq__(&self, #[pyo3(from_py_with = "extract_gil_ref")] _other: i32) -> bool { + | ^^^^^^^^^^^^^^^^^ + error: use of deprecated method `pyo3::deprecations::GilRefs::::function_arg`: use `&Bound<'_, T>` instead for this function argument --> tests/ui/deprecations.rs:18:33 | @@ -47,69 +53,69 @@ error: use of deprecated method `pyo3::deprecations::GilRefs::::function_arg` | ^ error: use of deprecated method `pyo3::deprecations::GilRefs::::function_arg`: use `&Bound<'_, T>` instead for this function argument - --> tests/ui/deprecations.rs:53:43 + --> tests/ui/deprecations.rs:61:43 | -53 | fn pyfunction_with_module_gil_ref(module: &PyModule) -> PyResult<&str> { +61 | fn pyfunction_with_module_gil_ref(module: &PyModule) -> PyResult<&str> { | ^ error: use of deprecated method `pyo3::deprecations::GilRefs::::function_arg`: use `&Bound<'_, T>` instead for this function argument - --> tests/ui/deprecations.rs:63:19 + --> tests/ui/deprecations.rs:71:19 | -63 | fn module_gil_ref(m: &PyModule) -> PyResult<()> { +71 | fn module_gil_ref(m: &PyModule) -> PyResult<()> { | ^ error: use of deprecated method `pyo3::deprecations::GilRefs::::function_arg`: use `&Bound<'_, T>` instead for this function argument - --> tests/ui/deprecations.rs:69:57 + --> tests/ui/deprecations.rs:77:57 | -69 | fn module_gil_ref_with_explicit_py_arg(_py: Python<'_>, m: &PyModule) -> PyResult<()> { +77 | fn module_gil_ref_with_explicit_py_arg(_py: Python<'_>, m: &PyModule) -> PyResult<()> { | ^ error: use of deprecated method `pyo3::deprecations::GilRefs::::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor - --> tests/ui/deprecations.rs:102:27 + --> tests/ui/deprecations.rs:110:27 | -102 | #[pyo3(from_py_with = "extract_gil_ref")] _gil_ref: i32, +110 | #[pyo3(from_py_with = "extract_gil_ref")] _gil_ref: i32, | ^^^^^^^^^^^^^^^^^ error: use of deprecated method `pyo3::deprecations::GilRefs::::function_arg`: use `&Bound<'_, T>` instead for this function argument - --> tests/ui/deprecations.rs:108:29 + --> tests/ui/deprecations.rs:116:29 | -108 | fn pyfunction_gil_ref(_any: &PyAny) {} +116 | fn pyfunction_gil_ref(_any: &PyAny) {} | ^ error: use of deprecated method `pyo3::deprecations::OptionGilRefs::>::function_arg`: use `Option<&Bound<'_, T>>` instead for this function argument - --> tests/ui/deprecations.rs:111:36 + --> tests/ui/deprecations.rs:119:36 | -111 | fn pyfunction_option_gil_ref(_any: Option<&PyAny>) {} +119 | fn pyfunction_option_gil_ref(_any: Option<&PyAny>) {} | ^^^^^^ error: use of deprecated method `pyo3::deprecations::GilRefs::::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor - --> tests/ui/deprecations.rs:118:27 + --> tests/ui/deprecations.rs:126:27 | -118 | #[pyo3(from_py_with = "PyAny::len", item("my_object"))] +126 | #[pyo3(from_py_with = "PyAny::len", item("my_object"))] | ^^^^^^^^^^^^ error: use of deprecated method `pyo3::deprecations::GilRefs::::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor - --> tests/ui/deprecations.rs:128:27 + --> tests/ui/deprecations.rs:136:27 | -128 | #[pyo3(from_py_with = "PyAny::len")] usize, +136 | #[pyo3(from_py_with = "PyAny::len")] usize, | ^^^^^^^^^^^^ error: use of deprecated method `pyo3::deprecations::GilRefs::::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor - --> tests/ui/deprecations.rs:134:31 + --> tests/ui/deprecations.rs:142:31 | -134 | Zip(#[pyo3(from_py_with = "extract_gil_ref")] i32), +142 | Zip(#[pyo3(from_py_with = "extract_gil_ref")] i32), | ^^^^^^^^^^^^^^^^^ error: use of deprecated method `pyo3::deprecations::GilRefs::::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor - --> tests/ui/deprecations.rs:141:27 + --> tests/ui/deprecations.rs:149:27 | -141 | #[pyo3(from_py_with = "extract_gil_ref")] +149 | #[pyo3(from_py_with = "extract_gil_ref")] | ^^^^^^^^^^^^^^^^^ error: use of deprecated method `pyo3::deprecations::GilRefs::>::is_python`: use `wrap_pyfunction_bound!` instead - --> tests/ui/deprecations.rs:154:13 + --> tests/ui/deprecations.rs:162:13 | -154 | let _ = wrap_pyfunction!(double, py); +162 | let _ = wrap_pyfunction!(double, py); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `wrap_pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info) From ef13bc66e9ffb4493085082bde0222eb00ba8b33 Mon Sep 17 00:00:00 2001 From: deedy5 <65482418+deedy5@users.noreply.github.com> Date: Sat, 4 May 2024 10:48:15 +0300 Subject: [PATCH 10/10] Add `pyreqwest_impersonate` to example projects (#4123) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 72653e8fc77..5e34f35489d 100644 --- a/README.md +++ b/README.md @@ -210,6 +210,7 @@ about this topic. - [pyheck](https://github.com/kevinheavey/pyheck) _Fast case conversion library, built by wrapping [heck](https://github.com/withoutboats/heck)._ - Quite easy to follow as there's not much code. - [pyre](https://github.com/Project-Dream-Weaver/pyre-http) _Fast Python HTTP server written in Rust._ +- [pyreqwest_impersonate](https://github.com/deedy5/pyreqwest_impersonate) _The fastest python HTTP client that can impersonate web browsers by mimicking their headers and TLS/JA3/JA4/HTTP2 fingerprints._ - [ril-py](https://github.com/Cryptex-github/ril-py) _A performant and high-level image processing library for Python written in Rust._ - [river](https://github.com/online-ml/river) _Online machine learning in python, the computationally heavy statistics algorithms are implemented in Rust._ - [rust-python-coverage](https://github.com/cjermain/rust-python-coverage) _Example PyO3 project with automated test coverage for Rust and Python._