deprecate `wrap_pyfunction` with `py` argument (#3954)

* deprecate `wrap_pyfunction` with `py` argument

The Python token in `wrap_pyfunction` is not handled automatically by
`WrapPyFunctionArg`, for backwards compatibility. This uses deref
specialization to deprecate this variant.

* merge `Extractor`s

* add deprecation ui test, revert closure variant due to test failure

* fix nightly
This commit is contained in:
Icxolu 2024-03-12 23:57:03 +01:00 committed by GitHub
parent a7fa1bdf22
commit ee89b2e8e2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 127 additions and 80 deletions

View File

@ -499,7 +499,7 @@ _without_ having a unique python type.
```rust
use pyo3::prelude::*;
# #[allow(dead_code)]
struct MyPyObjectWrapper(PyObject);
impl IntoPy<PyObject> for MyPyObjectWrapper {

View File

@ -436,7 +436,7 @@ impl SomeClass {
When converting from `anyhow::Error` or `eyre::Report` to `PyErr`, if the inner error is a "simple" `PyErr` (with no source error), then the inner error will be used directly as the `PyErr` instead of wrapping it in a new `PyRuntimeError` with the original information converted into a string.
```rust
```rust,ignore
# #[cfg(feature = "anyhow")]
# #[allow(dead_code)]
# mod anyhow_only {
@ -597,9 +597,9 @@ fn function_with_defaults(a: i32, b: i32, c: i32) {}
# fn main() {
# Python::with_gil(|py| {
# let simple = wrap_pyfunction!(simple_function, py).unwrap();
# let simple = wrap_pyfunction_bound!(simple_function, py).unwrap();
# assert_eq!(simple.getattr("__text_signature__").unwrap().to_string(), "(a, b, c)");
# let defaulted = wrap_pyfunction!(function_with_defaults, py).unwrap();
# let defaulted = wrap_pyfunction_bound!(function_with_defaults, py).unwrap();
# assert_eq!(defaulted.getattr("__text_signature__").unwrap().to_string(), "(a, b=1, c=2)");
# })
# }
@ -1090,6 +1090,7 @@ impl FromPy<MyPyObjectWrapper> for PyObject {
After
```rust
# use pyo3::prelude::*;
# #[allow(dead_code)]
struct MyPyObjectWrapper(PyObject);
impl IntoPy<PyObject> for MyPyObjectWrapper {

View File

@ -1,11 +1,13 @@
use pyo3::{pyclass, pyfunction, pymodule, types::PyModule, wrap_pyfunction, Bound, PyResult};
use pyo3::{
pyclass, pyfunction, pymodule, types::PyModule, wrap_pyfunction_bound, Bound, PyResult,
};
#[pymodule]
pub fn enums(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<SimpleEnum>()?;
m.add_class::<ComplexEnum>()?;
m.add_wrapped(wrap_pyfunction!(do_simple_stuff))?;
m.add_wrapped(wrap_pyfunction!(do_complex_stuff))?;
m.add_wrapped(wrap_pyfunction_bound!(do_simple_stuff))?;
m.add_wrapped(wrap_pyfunction_bound!(do_complex_stuff))?;
Ok(())
}

View File

@ -96,6 +96,7 @@ pub trait ToPyObject {
/// ```rust
/// use pyo3::prelude::*;
///
/// # #[allow(dead_code)]
/// struct Number {
/// value: i32,
/// }

View File

@ -35,7 +35,6 @@
//!
//! ```rust
//! use pyo3::prelude::*;
//! use pyo3::wrap_pyfunction;
//! use std::path::PathBuf;
//!
//! // A wrapper around a Rust function.
@ -48,7 +47,7 @@
//!
//! fn main() {
//! let error = Python::with_gil(|py| -> PyResult<Vec<u8>> {
//! let fun = wrap_pyfunction!(py_open, py)?;
//! let fun = wrap_pyfunction_bound!(py_open, py)?;
//! let text = fun.call1(("foo.txt",))?.extract::<Vec<u8>>()?;
//! Ok(text)
//! }).unwrap_err();

View File

@ -34,7 +34,6 @@
//!
//! ```rust
//! use pyo3::prelude::*;
//! use pyo3::wrap_pyfunction;
//! use std::path::PathBuf;
//!
//! // A wrapper around a Rust function.
@ -47,7 +46,7 @@
//!
//! fn main() {
//! let error = Python::with_gil(|py| -> PyResult<Vec<u8>> {
//! let fun = wrap_pyfunction!(py_open, py)?;
//! let fun = wrap_pyfunction_bound!(py_open, py)?;
//! let text = fun.call1(("foo.txt",))?.extract::<Vec<u8>>()?;
//! Ok(text)
//! }).unwrap_err();

View File

@ -1,7 +1,7 @@
use crate::sync::GILOnceCell;
use crate::types::any::PyAnyMethods;
use crate::types::PyCFunction;
use crate::{intern, wrap_pyfunction, Bound, Py, PyAny, PyObject, PyResult, Python};
use crate::{intern, wrap_pyfunction_bound, Bound, Py, PyAny, PyObject, PyResult, Python};
use pyo3_macros::pyfunction;
use std::sync::Arc;
use std::task::Wake;
@ -70,8 +70,9 @@ impl LoopAndFuture {
fn set_result(&self, py: Python<'_>) -> PyResult<()> {
static RELEASE_WAITER: GILOnceCell<Py<PyCFunction>> = GILOnceCell::new();
let release_waiter = RELEASE_WAITER
.get_or_try_init(py, || wrap_pyfunction!(release_waiter, py).map(Into::into))?;
let release_waiter = RELEASE_WAITER.get_or_try_init(py, || {
wrap_pyfunction_bound!(release_waiter, py).map(Bound::unbind)
})?;
// `Future.set_result` must be called in event loop thread,
// so it requires `call_soon_threadsafe`
let call_soon_threadsafe = self.event_loop.call_method1(

View File

@ -145,7 +145,7 @@ impl PyErr {
/// }
/// #
/// # Python::with_gil(|py| {
/// # let fun = pyo3::wrap_pyfunction!(always_throws, py).unwrap();
/// # let fun = pyo3::wrap_pyfunction_bound!(always_throws, py).unwrap();
/// # let err = fun.call0().expect_err("called a function that should always return an error but the return value was Ok");
/// # assert!(err.is_instance_of::<PyTypeError>(py))
/// # });
@ -163,7 +163,7 @@ impl PyErr {
/// }
/// #
/// # Python::with_gil(|py| {
/// # let fun = pyo3::wrap_pyfunction!(always_throws, py).unwrap();
/// # let fun = pyo3::wrap_pyfunction_bound!(always_throws, py).unwrap();
/// # let err = fun.call0().expect_err("called a function that should always return an error but the return value was Ok");
/// # assert!(err.is_instance_of::<PyTypeError>(py))
/// # });

View File

@ -171,7 +171,7 @@ macro_rules! import_exception {
/// }
/// # fn main() -> PyResult<()> {
/// # Python::with_gil(|py| -> PyResult<()> {
/// # let fun = wrap_pyfunction!(raise_myerror, py)?;
/// # let fun = wrap_pyfunction_bound!(raise_myerror, py)?;
/// # let locals = pyo3::types::PyDict::new_bound(py);
/// # locals.set_item("MyError", py.get_type_bound::<MyError>())?;
/// # locals.set_item("raise_myerror", fun)?;
@ -322,7 +322,7 @@ fn always_throws() -> PyResult<()> {
}
#
# Python::with_gil(|py| {
# let fun = pyo3::wrap_pyfunction!(always_throws, py).unwrap();
# let fun = pyo3::wrap_pyfunction_bound!(always_throws, py).unwrap();
# let err = fun.call0().expect_err(\"called a function that should always return an error but the return value was Ok\");
# assert!(err.is_instance_of::<Py", $name, ">(py))
# });

View File

@ -599,6 +599,14 @@ impl<T> Extractor<T> {
}
}
impl Extractor<Python<'_>> {
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(since = "0.21.0", note = "use `wrap_pyfunction_bound!` instead")
)]
pub fn is_python(&self) {}
}
impl<T: IsGilRef> Extractor<T> {
#[cfg_attr(
not(feature = "gil-refs"),
@ -612,6 +620,7 @@ impl<T: IsGilRef> Extractor<T> {
impl<T> NotAGilRef<T> {
pub fn extract_gil_ref(&self) {}
pub fn is_python(&self) {}
}
impl<T> std::ops::Deref for Extractor<T> {

View File

@ -144,8 +144,10 @@ macro_rules! wrap_pyfunction {
};
($function:path, $py_or_module:expr) => {{
use $function as wrapped_pyfunction;
let (py_or_module, e) = $crate::impl_::pymethods::inspect_type($py_or_module);
e.is_python();
$crate::impl_::pyfunction::WrapPyFunctionArg::wrap_pyfunction(
$py_or_module,
py_or_module,
&wrapped_pyfunction::DEF,
)
}};

View File

@ -509,7 +509,7 @@ impl<'py> Python<'py> {
/// #
/// # fn main() -> PyResult<()> {
/// # Python::with_gil(|py| -> PyResult<()> {
/// # let fun = pyo3::wrap_pyfunction!(sum_numbers, py)?;
/// # let fun = pyo3::wrap_pyfunction_bound!(sum_numbers, py)?;
/// # let res = fun.call1((vec![1_u32, 2, 3],))?;
/// # assert_eq!(res.extract::<u32>()?, 6_u32);
/// # Ok(())

View File

@ -132,7 +132,7 @@
//! # let n = Py::new(py, Number{inner: 35}).unwrap();
//! # let n2 = n.clone_ref(py);
//! # assert!(n.is(&n2));
//! # let fun = pyo3::wrap_pyfunction!(swap_numbers, py).unwrap();
//! # let fun = pyo3::wrap_pyfunction_bound!(swap_numbers, py).unwrap();
//! # fun.call1((n, n2)).expect_err("Managed to create overlapping mutable references. Note: this is undefined behaviour.");
//! # });
//! # }
@ -170,7 +170,7 @@
//! # let n = Py::new(py, Number{inner: 35}).unwrap();
//! # let n2 = n.clone_ref(py);
//! # assert!(n.is(&n2));
//! # let fun = pyo3::wrap_pyfunction!(swap_numbers, py).unwrap();
//! # let fun = pyo3::wrap_pyfunction_bound!(swap_numbers, py).unwrap();
//! # fun.call1((n, n2)).unwrap();
//! # });
//! #
@ -179,7 +179,7 @@
//! # let n = Py::new(py, Number{inner: 35}).unwrap();
//! # let n2 = Py::new(py, Number{inner: 42}).unwrap();
//! # assert!(!n.is(&n2));
//! # let fun = pyo3::wrap_pyfunction!(swap_numbers, py).unwrap();
//! # let fun = pyo3::wrap_pyfunction_bound!(swap_numbers, py).unwrap();
//! # fun.call1((&n, &n2)).unwrap();
//! # let n: u32 = n.borrow(py).inner;
//! # let n2: u32 = n2.borrow(py).inner;

View File

@ -220,7 +220,7 @@ impl GILOnceCell<Py<PyType>> {
///
/// ```
/// use pyo3::intern;
/// # use pyo3::{pyfunction, types::PyDict, wrap_pyfunction, PyResult, Python, prelude::PyDictMethods, Bound};
/// # use pyo3::{prelude::*, types::PyDict};
///
/// #[pyfunction]
/// fn create_dict(py: Python<'_>) -> PyResult<Bound<'_, PyDict>> {
@ -241,10 +241,10 @@ impl GILOnceCell<Py<PyType>> {
/// }
/// #
/// # Python::with_gil(|py| {
/// # let fun_slow = wrap_pyfunction!(create_dict, py).unwrap();
/// # let fun_slow = wrap_pyfunction_bound!(create_dict, py).unwrap();
/// # let dict = fun_slow.call0().unwrap();
/// # assert!(dict.contains("foo").unwrap());
/// # let fun = wrap_pyfunction!(create_dict_faster, py).unwrap();
/// # let fun = wrap_pyfunction_bound!(create_dict_faster, py).unwrap();
/// # let dict = fun.call0().unwrap();
/// # assert!(dict.contains("foo").unwrap());
/// # });

View File

@ -10,6 +10,7 @@ fn do_something(x: i32) -> crate::PyResult<i32> {
#[test]
fn invoke_wrap_pyfunction() {
crate::Python::with_gil(|py| {
#[allow(deprecated)]
let func = crate::wrap_pyfunction!(do_something)(py).unwrap();
crate::py_run!(py, func, r#"func(5)"#);
});

View File

@ -193,7 +193,7 @@ impl PyByteArray {
/// }
/// # fn main() -> PyResult<()> {
/// # Python::with_gil(|py| -> PyResult<()> {
/// # let fun = wrap_pyfunction!(a_valid_function, py)?;
/// # let fun = wrap_pyfunction_bound!(a_valid_function, py)?;
/// # let locals = pyo3::types::PyDict::new_bound(py);
/// # locals.set_item("a_valid_function", fun)?;
/// #
@ -355,7 +355,7 @@ pub trait PyByteArrayMethods<'py>: crate::sealed::Sealed {
/// }
/// # fn main() -> PyResult<()> {
/// # Python::with_gil(|py| -> PyResult<()> {
/// # let fun = wrap_pyfunction!(a_valid_function, py)?;
/// # let fun = wrap_pyfunction_bound!(a_valid_function, py)?;
/// # let locals = pyo3::types::PyDict::new_bound(py);
/// # locals.set_item("a_valid_function", fun)?;
/// #

View File

@ -1,8 +1,10 @@
#![cfg(feature = "anyhow")]
use pyo3::wrap_pyfunction_bound;
#[test]
fn test_anyhow_py_function_ok_result() {
use pyo3::{py_run, pyfunction, wrap_pyfunction, Python};
use pyo3::{py_run, pyfunction, Python};
#[pyfunction]
#[allow(clippy::unnecessary_wraps)]
@ -11,7 +13,7 @@ fn test_anyhow_py_function_ok_result() {
}
Python::with_gil(|py| {
let func = wrap_pyfunction!(produce_ok_result)(py).unwrap();
let func = wrap_pyfunction_bound!(produce_ok_result)(py).unwrap();
py_run!(
py,
@ -26,7 +28,7 @@ fn test_anyhow_py_function_ok_result() {
#[test]
fn test_anyhow_py_function_err_result() {
use pyo3::prelude::PyDictMethods;
use pyo3::{pyfunction, types::PyDict, wrap_pyfunction, Python};
use pyo3::{pyfunction, types::PyDict, Python};
#[pyfunction]
fn produce_err_result() -> anyhow::Result<String> {
@ -34,7 +36,7 @@ fn test_anyhow_py_function_err_result() {
}
Python::with_gil(|py| {
let func = wrap_pyfunction!(produce_err_result)(py).unwrap();
let func = wrap_pyfunction_bound!(produce_err_result)(py).unwrap();
let locals = PyDict::new_bound(py);
locals.set_item("func", func).unwrap();

View File

@ -14,7 +14,7 @@ fn bytes_pybytes_conversion(bytes: &[u8]) -> &[u8] {
#[test]
fn test_pybytes_bytes_conversion() {
Python::with_gil(|py| {
let f = wrap_pyfunction!(bytes_pybytes_conversion)(py).unwrap();
let f = wrap_pyfunction_bound!(bytes_pybytes_conversion)(py).unwrap();
py_assert!(py, f, "f(b'Hello World') == b'Hello World'");
});
}
@ -27,7 +27,7 @@ fn bytes_vec_conversion(py: Python<'_>, bytes: Vec<u8>) -> Bound<'_, PyBytes> {
#[test]
fn test_pybytes_vec_conversion() {
Python::with_gil(|py| {
let f = wrap_pyfunction!(bytes_vec_conversion)(py).unwrap();
let f = wrap_pyfunction_bound!(bytes_vec_conversion)(py).unwrap();
py_assert!(py, f, "f(b'Hello World') == b'Hello World'");
});
}
@ -35,7 +35,7 @@ fn test_pybytes_vec_conversion() {
#[test]
fn test_bytearray_vec_conversion() {
Python::with_gil(|py| {
let f = wrap_pyfunction!(bytes_vec_conversion)(py).unwrap();
let f = wrap_pyfunction_bound!(bytes_vec_conversion)(py).unwrap();
py_assert!(py, f, "f(bytearray(b'Hello World')) == b'Hello World'");
});
}

View File

@ -30,7 +30,7 @@ fn noop_coroutine() {
42
}
Python::with_gil(|gil| {
let noop = wrap_pyfunction!(noop, gil).unwrap();
let noop = wrap_pyfunction_bound!(noop, gil).unwrap();
let test = "import asyncio; assert asyncio.run(noop()) == 42";
py_run!(gil, noop, &handle_windows(test));
})
@ -68,7 +68,10 @@ fn test_coroutine_qualname() {
let locals = [
(
"my_fn",
wrap_pyfunction!(my_fn, gil).unwrap().as_borrowed().as_any(),
wrap_pyfunction_bound!(my_fn, gil)
.unwrap()
.as_borrowed()
.as_any(),
),
("MyClass", gil.get_type_bound::<MyClass>().as_any()),
]
@ -93,7 +96,7 @@ fn sleep_0_like_coroutine() {
.await
}
Python::with_gil(|gil| {
let sleep_0 = wrap_pyfunction!(sleep_0, gil).unwrap();
let sleep_0 = wrap_pyfunction_bound!(sleep_0, gil).unwrap();
let test = "import asyncio; assert asyncio.run(sleep_0()) == 42";
py_run!(gil, sleep_0, &handle_windows(test));
})
@ -112,7 +115,7 @@ async fn sleep(seconds: f64) -> usize {
#[test]
fn sleep_coroutine() {
Python::with_gil(|gil| {
let sleep = wrap_pyfunction!(sleep, gil).unwrap();
let sleep = wrap_pyfunction_bound!(sleep, gil).unwrap();
let test = r#"import asyncio; assert asyncio.run(sleep(0.1)) == 42"#;
py_run!(gil, sleep, &handle_windows(test));
})
@ -121,7 +124,7 @@ fn sleep_coroutine() {
#[test]
fn cancelled_coroutine() {
Python::with_gil(|gil| {
let sleep = wrap_pyfunction!(sleep, gil).unwrap();
let sleep = wrap_pyfunction_bound!(sleep, gil).unwrap();
let test = r#"
import asyncio
async def main():
@ -160,7 +163,7 @@ fn coroutine_cancel_handle() {
}
}
Python::with_gil(|gil| {
let cancellable_sleep = wrap_pyfunction!(cancellable_sleep, gil).unwrap();
let cancellable_sleep = wrap_pyfunction_bound!(cancellable_sleep, gil).unwrap();
let test = r#"
import asyncio;
async def main():
@ -192,7 +195,7 @@ fn coroutine_is_cancelled() {
}
}
Python::with_gil(|gil| {
let sleep_loop = wrap_pyfunction!(sleep_loop, gil).unwrap();
let sleep_loop = wrap_pyfunction_bound!(sleep_loop, gil).unwrap();
let test = r#"
import asyncio;
async def main():
@ -220,7 +223,7 @@ fn coroutine_panic() {
panic!("test panic");
}
Python::with_gil(|gil| {
let panic = wrap_pyfunction!(panic, gil).unwrap();
let panic = wrap_pyfunction_bound!(panic, gil).unwrap();
let test = r#"
import asyncio
coro = panic()

View File

@ -1,7 +1,7 @@
#![cfg(feature = "macros")]
use pyo3::prelude::*;
use pyo3::{py_run, wrap_pyfunction};
use pyo3::py_run;
#[path = "../src/tests/common.rs"]
mod common;
@ -30,7 +30,7 @@ fn return_enum() -> MyEnum {
#[test]
fn test_return_enum() {
Python::with_gil(|py| {
let f = wrap_pyfunction!(return_enum)(py).unwrap();
let f = wrap_pyfunction_bound!(return_enum)(py).unwrap();
let mynum = py.get_type_bound::<MyEnum>();
py_run!(py, f mynum, "assert f() == mynum.Variant")
@ -45,7 +45,7 @@ fn enum_arg(e: MyEnum) {
#[test]
fn test_enum_arg() {
Python::with_gil(|py| {
let f = wrap_pyfunction!(enum_arg)(py).unwrap();
let f = wrap_pyfunction_bound!(enum_arg)(py).unwrap();
let mynum = py.get_type_bound::<MyEnum>();
py_run!(py, f mynum, "f(mynum.OtherVariant)")

View File

@ -22,7 +22,7 @@ fn fail_to_open_file() -> PyResult<()> {
#[cfg(not(target_os = "windows"))]
fn test_filenotfounderror() {
Python::with_gil(|py| {
let fail_to_open_file = wrap_pyfunction!(fail_to_open_file)(py).unwrap();
let fail_to_open_file = wrap_pyfunction_bound!(fail_to_open_file)(py).unwrap();
py_run!(
py,
@ -68,7 +68,7 @@ fn call_fail_with_custom_error() -> PyResult<()> {
fn test_custom_error() {
Python::with_gil(|py| {
let call_fail_with_custom_error =
wrap_pyfunction!(call_fail_with_custom_error)(py).unwrap();
wrap_pyfunction_bound!(call_fail_with_custom_error)(py).unwrap();
py_run!(
py,

View File

@ -76,7 +76,7 @@ fn test_macro_rules_interactions() {
let my_base = py.get_type_bound::<MyBaseClass>();
py_assert!(py, my_base, "my_base.__name__ == 'MyClass'");
let my_func = wrap_pyfunction!(my_function_in_macro, py).unwrap();
let my_func = wrap_pyfunction_bound!(my_function_in_macro, py).unwrap();
py_assert!(
py,
my_func,

View File

@ -1124,7 +1124,7 @@ fn test_option_pyclass_arg() {
}
Python::with_gil(|py| {
let f = wrap_pyfunction!(option_class_arg, py).unwrap();
let f = wrap_pyfunction_bound!(option_class_arg, py).unwrap();
assert!(f.call0().unwrap().is_none());
let obj = Py::new(py, SomePyClass {}).unwrap();
assert!(f

View File

@ -23,7 +23,7 @@ fn optional_bool(arg: Option<bool>) -> String {
fn test_optional_bool() {
// Regression test for issue #932
Python::with_gil(|py| {
let f = wrap_pyfunction!(optional_bool)(py).unwrap();
let f = wrap_pyfunction_bound!(optional_bool)(py).unwrap();
py_assert!(py, f, "f() == 'Some(true)'");
py_assert!(py, f, "f(True) == 'Some(true)'");
@ -47,7 +47,7 @@ fn buffer_inplace_add(py: Python<'_>, x: PyBuffer<i32>, y: PyBuffer<i32>) {
#[test]
fn test_buffer_add() {
Python::with_gil(|py| {
let f = wrap_pyfunction!(buffer_inplace_add)(py).unwrap();
let f = wrap_pyfunction_bound!(buffer_inplace_add)(py).unwrap();
py_expect_exception!(
py,
@ -89,8 +89,8 @@ fn function_with_pycfunction_arg(fun: &PyCFunction) -> PyResult<&PyAny> {
#[test]
fn test_functions_with_function_args() {
Python::with_gil(|py| {
let py_cfunc_arg = wrap_pyfunction!(function_with_pycfunction_arg)(py).unwrap();
let bool_to_string = wrap_pyfunction!(optional_bool)(py).unwrap();
let py_cfunc_arg = wrap_pyfunction_bound!(function_with_pycfunction_arg)(py).unwrap();
let bool_to_string = wrap_pyfunction_bound!(optional_bool)(py).unwrap();
pyo3::py_run!(
py,
@ -103,7 +103,7 @@ fn test_functions_with_function_args() {
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
{
let py_func_arg = wrap_pyfunction!(function_with_pyfunction_arg)(py).unwrap();
let py_func_arg = wrap_pyfunction_bound!(function_with_pyfunction_arg)(py).unwrap();
pyo3::py_run!(
py,
@ -137,7 +137,7 @@ fn function_with_custom_conversion(
#[test]
fn test_function_with_custom_conversion() {
Python::with_gil(|py| {
let custom_conv_func = wrap_pyfunction!(function_with_custom_conversion)(py).unwrap();
let custom_conv_func = wrap_pyfunction_bound!(function_with_custom_conversion)(py).unwrap();
pyo3::py_run!(
py,
@ -156,7 +156,7 @@ fn test_function_with_custom_conversion() {
#[test]
fn test_function_with_custom_conversion_error() {
Python::with_gil(|py| {
let custom_conv_func = wrap_pyfunction!(function_with_custom_conversion)(py).unwrap();
let custom_conv_func = wrap_pyfunction_bound!(function_with_custom_conversion)(py).unwrap();
py_expect_exception!(
py,
@ -190,13 +190,13 @@ fn test_from_py_with_defaults() {
}
Python::with_gil(|py| {
let f = wrap_pyfunction!(from_py_with_option)(py).unwrap();
let f = wrap_pyfunction_bound!(from_py_with_option)(py).unwrap();
assert_eq!(f.call0().unwrap().extract::<i32>().unwrap(), 0);
assert_eq!(f.call1((123,)).unwrap().extract::<i32>().unwrap(), 123);
assert_eq!(f.call1((999,)).unwrap().extract::<i32>().unwrap(), 999);
let f2 = wrap_pyfunction!(from_py_with_default)(py).unwrap();
let f2 = wrap_pyfunction_bound!(from_py_with_default)(py).unwrap();
assert_eq!(f2.call0().unwrap().extract::<usize>().unwrap(), 0);
assert_eq!(f2.call1(("123",)).unwrap().extract::<usize>().unwrap(), 3);
@ -228,7 +228,7 @@ fn conversion_error(
#[test]
fn test_conversion_error() {
Python::with_gil(|py| {
let conversion_error = wrap_pyfunction!(conversion_error)(py).unwrap();
let conversion_error = wrap_pyfunction_bound!(conversion_error)(py).unwrap();
py_expect_exception!(
py,
conversion_error,
@ -473,12 +473,12 @@ fn use_pyfunction() {
use function_in_module::foo;
// check imported name can be wrapped
let f = wrap_pyfunction!(foo, py).unwrap();
let f = wrap_pyfunction_bound!(foo, py).unwrap();
assert_eq!(f.call1((5,)).unwrap().extract::<i32>().unwrap(), 5);
assert_eq!(f.call1((42,)).unwrap().extract::<i32>().unwrap(), 42);
// check path import can be wrapped
let f2 = wrap_pyfunction!(function_in_module::foo, py).unwrap();
let f2 = wrap_pyfunction_bound!(function_in_module::foo, py).unwrap();
assert_eq!(f2.call1((5,)).unwrap().extract::<i32>().unwrap(), 5);
assert_eq!(f2.call1((42,)).unwrap().extract::<i32>().unwrap(), 42);
})
@ -506,7 +506,7 @@ fn return_value_borrows_from_arguments<'py>(
#[test]
fn test_return_value_borrows_from_arguments() {
Python::with_gil(|py| {
let function = wrap_pyfunction!(return_value_borrows_from_arguments, py).unwrap();
let function = wrap_pyfunction_bound!(return_value_borrows_from_arguments, py).unwrap();
let key = Py::new(py, Key("key".to_owned())).unwrap();
let value = Py::new(py, Value(42)).unwrap();
@ -530,7 +530,7 @@ fn test_some_wrap_arguments() {
}
Python::with_gil(|py| {
let function = wrap_pyfunction!(some_wrap_arguments, py).unwrap();
let function = wrap_pyfunction_bound!(some_wrap_arguments, py).unwrap();
py_assert!(py, function, "function() == [1, 2, None, None]");
})
}
@ -546,7 +546,7 @@ fn test_reference_to_bound_arguments() {
}
Python::with_gil(|py| {
let function = wrap_pyfunction!(reference_args, py).unwrap();
let function = wrap_pyfunction_bound!(reference_args, py).unwrap();
py_assert!(py, function, "function(1) == 1");
py_assert!(py, function, "function(1, 2) == 3");
})

View File

@ -11,7 +11,7 @@ fn take_str(_s: &str) {}
#[test]
fn test_unicode_encode_error() {
Python::with_gil(|py| {
let take_str = wrap_pyfunction!(take_str)(py).unwrap();
let take_str = wrap_pyfunction_bound!(take_str)(py).unwrap();
py_expect_exception!(
py,
take_str,

View File

@ -101,7 +101,7 @@ fn test_function() {
}
Python::with_gil(|py| {
let f = wrap_pyfunction!(my_function)(py).unwrap();
let f = wrap_pyfunction_bound!(my_function)(py).unwrap();
py_assert!(py, f, "f.__text_signature__ == '(a, b=None, *, c=42)'");
});
@ -147,42 +147,42 @@ fn test_auto_test_signature_function() {
}
Python::with_gil(|py| {
let f = wrap_pyfunction!(my_function)(py).unwrap();
let f = wrap_pyfunction_bound!(my_function)(py).unwrap();
py_assert!(
py,
f,
"f.__text_signature__ == '(a, b, c)', f.__text_signature__"
);
let f = wrap_pyfunction!(my_function_2)(py).unwrap();
let f = wrap_pyfunction_bound!(my_function_2)(py).unwrap();
py_assert!(
py,
f,
"f.__text_signature__ == '($module, a, b, c)', f.__text_signature__"
);
let f = wrap_pyfunction!(my_function_3)(py).unwrap();
let f = wrap_pyfunction_bound!(my_function_3)(py).unwrap();
py_assert!(
py,
f,
"f.__text_signature__ == '(a, /, b=None, *, c=5)', f.__text_signature__"
);
let f = wrap_pyfunction!(my_function_4)(py).unwrap();
let f = wrap_pyfunction_bound!(my_function_4)(py).unwrap();
py_assert!(
py,
f,
"f.__text_signature__ == '(a, /, b=None, *args, c, d=5, **kwargs)', f.__text_signature__"
);
let f = wrap_pyfunction!(my_function_5)(py).unwrap();
let f = wrap_pyfunction_bound!(my_function_5)(py).unwrap();
py_assert!(
py,
f,
"f.__text_signature__ == '(a=1, /, b=None, c=1.5, d=5, e=\"pyo3\", f=\\'f\\', h=True)', f.__text_signature__"
);
let f = wrap_pyfunction!(my_function_6)(py).unwrap();
let f = wrap_pyfunction_bound!(my_function_6)(py).unwrap();
py_assert!(
py,
f,
@ -317,10 +317,10 @@ fn test_auto_test_signature_opt_out() {
}
Python::with_gil(|py| {
let f = wrap_pyfunction!(my_function)(py).unwrap();
let f = wrap_pyfunction_bound!(my_function)(py).unwrap();
py_assert!(py, f, "f.__text_signature__ == None");
let f = wrap_pyfunction!(my_function_2)(py).unwrap();
let f = wrap_pyfunction_bound!(my_function_2)(py).unwrap();
py_assert!(py, f, "f.__text_signature__ == None");
let cls = py.get_type_bound::<MyClass>();

View File

@ -56,7 +56,7 @@ fn return_custom_class() {
assert_eq!(get_zero().value, 0);
// Using from python
let get_zero = wrap_pyfunction!(get_zero)(py).unwrap();
let get_zero = wrap_pyfunction_bound!(get_zero)(py).unwrap();
py_assert!(py, get_zero, "get_zero().value == 0");
});
}
@ -201,6 +201,6 @@ fn result_conversion_function() -> Result<(), MyError> {
#[test]
fn test_result_conversion() {
Python::with_gil(|py| {
wrap_pyfunction!(result_conversion_function)(py).unwrap();
wrap_pyfunction_bound!(result_conversion_function)(py).unwrap();
});
}

View File

@ -11,6 +11,7 @@ pub fn add_wrapped(wrapper: &impl Fn(Python<'_>) -> PyResult<&PyCFunction>) {
#[test]
fn wrap_pyfunction_deduction() {
#[allow(deprecated)]
add_wrapped(wrap_pyfunction!(f));
}

View File

@ -72,3 +72,19 @@ fn module_bound_by_value(m: Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(double, &m)?)?;
Ok(())
}
fn test_wrap_pyfunction(py: Python<'_>, m: &Bound<'_, PyModule>) {
// should lint
let _ = wrap_pyfunction!(double, py);
// should lint but currently does not
let _ = wrap_pyfunction!(double)(py);
// should not lint
let _ = wrap_pyfunction!(double, m);
let _ = wrap_pyfunction!(double)(m);
let _ = wrap_pyfunction!(double, m.as_gil_ref());
let _ = wrap_pyfunction!(double)(m.as_gil_ref());
let _ = wrap_pyfunction_bound!(double, py);
let _ = wrap_pyfunction_bound!(double)(py);
}

View File

@ -45,3 +45,11 @@ error: use of deprecated method `pyo3::methods::Extractor::<T>::extract_gil_ref`
|
53 | fn module_gil_ref_with_explicit_py_arg(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
| ^
error: use of deprecated method `pyo3::methods::Extractor::<pyo3::Python<'_>>::is_python`: use `wrap_pyfunction_bound!` instead
--> tests/ui/deprecations.rs:78:13
|
78 | 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)

View File

@ -20,11 +20,13 @@ impl fmt::Display for MyError {
#[pyfunction]
fn should_not_work() -> Result<(), MyError> {
Err(MyError { descr: "something went wrong" })
Err(MyError {
descr: "something went wrong",
})
}
fn main() {
Python::with_gil(|py|{
wrap_pyfunction!(should_not_work)(py);
Python::with_gil(|py| {
wrap_pyfunction_bound!(should_not_work)(py);
});
}