Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update extract_argument to use Bound APIs #3708

Merged
merged 12 commits into from
Feb 28, 2024
4 changes: 2 additions & 2 deletions guide/src/class.md
Original file line number Diff line number Diff line change
Expand Up @@ -1253,7 +1253,7 @@ impl<'a, 'py> pyo3::impl_::extract_argument::PyFunctionArgument<'a, 'py> for &'a
type Holder = ::std::option::Option<pyo3::PyRef<'py, MyClass>>;

#[inline]
fn extract(obj: &'py pyo3::PyAny, holder: &'a mut Self::Holder) -> pyo3::PyResult<Self> {
fn extract(obj: pyo3::impl_::extract_argument::PyArg<'py>, holder: &'a mut Self::Holder) -> pyo3::PyResult<Self> {
pyo3::impl_::extract_argument::extract_pyclass_ref(obj, holder)
}
}
Expand All @@ -1263,7 +1263,7 @@ impl<'a, 'py> pyo3::impl_::extract_argument::PyFunctionArgument<'a, 'py> for &'a
type Holder = ::std::option::Option<pyo3::PyRefMut<'py, MyClass>>;

#[inline]
fn extract(obj: &'py pyo3::PyAny, holder: &'a mut Self::Holder) -> pyo3::PyResult<Self> {
fn extract(obj: pyo3::impl_::extract_argument::PyArg<'py>, holder: &'a mut Self::Holder) -> pyo3::PyResult<Self> {
pyo3::impl_::extract_argument::extract_pyclass_ref_mut(obj, holder)
}
}
Expand Down
8 changes: 4 additions & 4 deletions pyo3-benches/benches/bench_comparisons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,17 @@ impl OrderedRichcmp {

fn bench_ordered_dunder_methods(b: &mut Bencher<'_>) {
Python::with_gil(|py| {
let obj1 = Py::new(py, OrderedDunderMethods(0)).unwrap().into_ref(py);
let obj2 = Py::new(py, OrderedDunderMethods(1)).unwrap().into_ref(py);
let obj1 = &Bound::new(py, OrderedDunderMethods(0)).unwrap().into_any();
let obj2 = &Bound::new(py, OrderedDunderMethods(1)).unwrap().into_any();

b.iter(|| obj2.gt(obj1).unwrap());
});
}

fn bench_ordered_richcmp(b: &mut Bencher<'_>) {
Python::with_gil(|py| {
let obj1 = Py::new(py, OrderedRichcmp(0)).unwrap().into_ref(py);
let obj2 = Py::new(py, OrderedRichcmp(1)).unwrap().into_ref(py);
let obj1 = &Bound::new(py, OrderedRichcmp(0)).unwrap().into_any();
let obj2 = &Bound::new(py, OrderedRichcmp(1)).unwrap().into_any();

b.iter(|| obj2.gt(obj1).unwrap());
});
Expand Down
2 changes: 1 addition & 1 deletion pyo3-macros-backend/src/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ impl SelfType {
});
error_mode.handle_error(quote_spanned! { *span =>
_pyo3::impl_::extract_argument::#method::<#cls>(
#py.from_borrowed_ptr::<_pyo3::PyAny>(#slf),
_pyo3::impl_::extract_argument::PyArg::from_ptr(#py, #slf),
&mut #holder,
)
})
Expand Down
14 changes: 8 additions & 6 deletions pyo3-macros-backend/src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ pub fn impl_arg_params(
.collect::<Result<_>>()?;
return Ok((
quote! {
let _args = py.from_borrowed_ptr::<_pyo3::types::PyTuple>(_args);
let _kwargs: ::std::option::Option<&_pyo3::types::PyDict> = py.from_borrowed_ptr_or_opt(_kwargs);
let _args = _pyo3::impl_::extract_argument::PyArg::from_ptr(py, _args);
let _kwargs = _pyo3::impl_::extract_argument::PyArg::from_ptr_or_opt(py, _kwargs);
},
arg_convert,
));
Expand Down Expand Up @@ -132,7 +132,7 @@ pub fn impl_arg_params(
keyword_only_parameters: &[#(#keyword_only_parameters),*],
};
let mut #args_array = [::std::option::Option::None; #num_params];
let (_args, _kwargs) = #extract_expression;
let (_args, _kwargs) = &#extract_expression;
},
param_conversion,
))
Expand Down Expand Up @@ -180,7 +180,8 @@ fn impl_arg_param(
let holder = push_holder();
return Ok(quote_arg_span! {
_pyo3::impl_::extract_argument::extract_argument(
_args,
#[allow(clippy::useless_conversion)]
::std::convert::From::from(_args),
&mut #holder,
#name_str
)?
Expand All @@ -193,7 +194,8 @@ fn impl_arg_param(
let holder = push_holder();
return Ok(quote_arg_span! {
_pyo3::impl_::extract_argument::extract_optional_argument(
_kwargs.map(::std::convert::AsRef::as_ref),
#[allow(clippy::useless_conversion, clippy::redundant_closure)]
_kwargs.as_ref().map(|kwargs| ::std::convert::From::from(kwargs)),
&mut #holder,
#name_str,
|| ::std::option::Option::None
Expand All @@ -217,7 +219,7 @@ fn impl_arg_param(
quote_arg_span! {
#[allow(clippy::redundant_closure)]
_pyo3::impl_::extract_argument::from_py_with_with_default(
#arg_value.map(_pyo3::PyNativeType::as_borrowed).as_deref(),
#arg_value.map(_pyo3::impl_::extract_argument::PyArg::as_borrowed).as_deref(),
#name_str,
#expr_path as fn(_) -> _,
|| #default
Expand Down
6 changes: 3 additions & 3 deletions pyo3-macros-backend/src/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1369,7 +1369,7 @@ impl<'a> PyClassImplsBuilder<'a> {
type Holder = ::std::option::Option<_pyo3::PyRef<'py, #cls>>;

#[inline]
fn extract(obj: &'py _pyo3::PyAny, holder: &'a mut Self::Holder) -> _pyo3::PyResult<Self> {
fn extract(obj: _pyo3::impl_::extract_argument::PyArg<'py>, holder: &'a mut Self::Holder) -> _pyo3::PyResult<Self> {
_pyo3::impl_::extract_argument::extract_pyclass_ref(obj, holder)
}
}
Expand All @@ -1381,7 +1381,7 @@ impl<'a> PyClassImplsBuilder<'a> {
type Holder = ::std::option::Option<_pyo3::PyRef<'py, #cls>>;

#[inline]
fn extract(obj: &'py _pyo3::PyAny, holder: &'a mut Self::Holder) -> _pyo3::PyResult<Self> {
fn extract(obj: _pyo3::impl_::extract_argument::PyArg<'py>, holder: &'a mut Self::Holder) -> _pyo3::PyResult<Self> {
_pyo3::impl_::extract_argument::extract_pyclass_ref(obj, holder)
}
}
Expand All @@ -1391,7 +1391,7 @@ impl<'a> PyClassImplsBuilder<'a> {
type Holder = ::std::option::Option<_pyo3::PyRefMut<'py, #cls>>;

#[inline]
fn extract(obj: &'py _pyo3::PyAny, holder: &'a mut Self::Holder) -> _pyo3::PyResult<Self> {
fn extract(obj: _pyo3::impl_::extract_argument::PyArg<'py>, holder: &'a mut Self::Holder) -> _pyo3::PyResult<Self> {
_pyo3::impl_::extract_argument::extract_pyclass_ref_mut(obj, holder)
}
}
Expand Down
28 changes: 10 additions & 18 deletions pyo3-macros-backend/src/pymethod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -930,39 +930,31 @@ impl Ty {
extract_error_mode,
holders,
&name_str,
quote! {
py.from_borrowed_ptr::<_pyo3::PyAny>(#ident)
},
quote! { #ident },
),
Ty::MaybeNullObject => extract_object(
extract_error_mode,
holders,
&name_str,
quote! {
py.from_borrowed_ptr::<_pyo3::PyAny>(
if #ident.is_null() {
_pyo3::ffi::Py_None()
} else {
#ident
}
)
if #ident.is_null() {
_pyo3::ffi::Py_None()
} else {
#ident
}
},
),
Ty::NonNullObject => extract_object(
extract_error_mode,
holders,
&name_str,
quote! {
py.from_borrowed_ptr::<_pyo3::PyAny>(#ident.as_ptr())
},
quote! { #ident.as_ptr() },
),
Ty::IPowModulo => extract_object(
extract_error_mode,
holders,
&name_str,
quote! {
#ident.to_borrowed_any(py)
},
quote! { #ident.as_ptr() },
),
Ty::CompareOp => extract_error_mode.handle_error(
quote! {
Expand All @@ -988,7 +980,7 @@ fn extract_object(
extract_error_mode: ExtractErrorMode,
holders: &mut Vec<TokenStream>,
name: &str,
source: TokenStream,
source_ptr: TokenStream,
) -> TokenStream {
let holder = syn::Ident::new(&format!("holder_{}", holders.len()), Span::call_site());
holders.push(quote! {
Expand All @@ -997,7 +989,7 @@ fn extract_object(
});
extract_error_mode.handle_error(quote! {
_pyo3::impl_::extract_argument::extract_argument(
#source,
_pyo3::impl_::extract_argument::PyArg::from_ptr(py, #source_ptr),
&mut #holder,
#name
)
Expand Down
74 changes: 39 additions & 35 deletions pytests/src/pyfunctions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,62 +4,66 @@ use pyo3::types::{PyDict, PyTuple};
#[pyfunction(signature = ())]
fn none() {}

type Any<'py> = Bound<'py, PyAny>;
type Dict<'py> = Bound<'py, PyDict>;
type Tuple<'py> = Bound<'py, PyTuple>;
Comment on lines +7 to +9
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clippy was warning about type complexity in the return value tuples without defining these aliases.


#[pyfunction(signature = (a, b = None, *, c = None))]
fn simple<'a>(
a: &'a PyAny,
b: Option<&'a PyAny>,
c: Option<&'a PyAny>,
) -> (&'a PyAny, Option<&'a PyAny>, Option<&'a PyAny>) {
fn simple<'py>(
a: Any<'py>,
b: Option<Any<'py>>,
c: Option<Any<'py>>,
) -> (Any<'py>, Option<Any<'py>>, Option<Any<'py>>) {
(a, b, c)
}

#[pyfunction(signature = (a, b = None, *args, c = None))]
fn simple_args<'a>(
a: &'a PyAny,
b: Option<&'a PyAny>,
args: &'a PyTuple,
c: Option<&'a PyAny>,
) -> (&'a PyAny, Option<&'a PyAny>, &'a PyTuple, Option<&'a PyAny>) {
fn simple_args<'py>(
a: Any<'py>,
b: Option<Any<'py>>,
args: Tuple<'py>,
c: Option<Any<'py>>,
) -> (Any<'py>, Option<Any<'py>>, Tuple<'py>, Option<Any<'py>>) {
(a, b, args, c)
}

#[pyfunction(signature = (a, b = None, c = None, **kwargs))]
fn simple_kwargs<'a>(
a: &'a PyAny,
b: Option<&'a PyAny>,
c: Option<&'a PyAny>,
kwargs: Option<&'a PyDict>,
fn simple_kwargs<'py>(
a: Any<'py>,
b: Option<Any<'py>>,
c: Option<Any<'py>>,
kwargs: Option<Dict<'py>>,
) -> (
&'a PyAny,
Option<&'a PyAny>,
Option<&'a PyAny>,
Option<&'a PyDict>,
Any<'py>,
Option<Any<'py>>,
Option<Any<'py>>,
Option<Dict<'py>>,
) {
(a, b, c, kwargs)
}

#[pyfunction(signature = (a, b = None, *args, c = None, **kwargs))]
fn simple_args_kwargs<'a>(
a: &'a PyAny,
b: Option<&'a PyAny>,
args: &'a PyTuple,
c: Option<&'a PyAny>,
kwargs: Option<&'a PyDict>,
fn simple_args_kwargs<'py>(
a: Any<'py>,
b: Option<Any<'py>>,
args: Tuple<'py>,
c: Option<Any<'py>>,
kwargs: Option<Dict<'py>>,
) -> (
&'a PyAny,
Option<&'a PyAny>,
&'a PyTuple,
Option<&'a PyAny>,
Option<&'a PyDict>,
Any<'py>,
Option<Any<'py>>,
Tuple<'py>,
Option<Any<'py>>,
Option<Dict<'py>>,
) {
(a, b, args, c, kwargs)
}

#[pyfunction(signature = (*args, **kwargs))]
fn args_kwargs<'a>(
args: &'a PyTuple,
kwargs: Option<&'a PyDict>,
) -> (&'a PyTuple, Option<&'a PyDict>) {
fn args_kwargs<'py>(
args: Tuple<'py>,
kwargs: Option<Dict<'py>>,
) -> (Tuple<'py>, Option<Dict<'py>>) {
(args, kwargs)
}

Expand Down
48 changes: 28 additions & 20 deletions src/err/mod.rs
davidhewitt marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
exceptions::{self, PyBaseException},
ffi,
};
use crate::{IntoPy, Py, PyAny, PyNativeType, PyObject, Python, ToPyObject};
use crate::{Borrowed, IntoPy, Py, PyAny, PyNativeType, PyObject, Python, ToPyObject};
use std::borrow::Cow;
use std::cell::UnsafeCell;
use std::ffi::CString;
Expand Down Expand Up @@ -46,34 +46,47 @@ unsafe impl Sync for PyErr {}
pub type PyResult<T> = Result<T, PyErr>;

/// Error that indicates a failure to convert a PyAny to a more specific Python type.
#[derive(Debug)]
pub struct PyDowncastError<'a> {
from: &'a PyAny,
to: Cow<'static, str>,
}
pub struct PyDowncastError<'py>(DowncastError<'py, 'py>);

impl<'a> PyDowncastError<'a> {
/// Create a new `PyDowncastError` representing a failure to convert the object
/// `from` into the type named in `to`.
pub fn new(from: &'a PyAny, to: impl Into<Cow<'static, str>>) -> Self {
PyDowncastError {
from,
to: to.into(),
}
PyDowncastError(DowncastError::new_from_borrowed(from.as_borrowed(), to))
}
}

impl std::fmt::Debug for PyDowncastError<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PyDowncastError")
.field("from", &self.0.from)
.field("to", &self.0.to)
.finish()
}
}

/// Error that indicates a failure to convert a PyAny to a more specific Python type.
#[derive(Debug)]
pub struct DowncastError<'a, 'py> {
from: &'a Bound<'py, PyAny>,
from: Borrowed<'a, 'py, PyAny>,
to: Cow<'static, str>,
}

impl<'a, 'py> DowncastError<'a, 'py> {
/// Create a new `PyDowncastError` representing a failure to convert the object
/// `from` into the type named in `to`.
pub fn new(from: &'a Bound<'py, PyAny>, to: impl Into<Cow<'static, str>>) -> Self {
DowncastError {
from: from.as_borrowed(),
to: to.into(),
}
davidhewitt marked this conversation as resolved.
Show resolved Hide resolved
}

/// Similar to [`DowncastError::new`], but from a `Borrowed` instead of a `Bound`.
pub(crate) fn new_from_borrowed(
from: Borrowed<'a, 'py, PyAny>,
to: impl Into<Cow<'static, str>>,
) -> Self {
DowncastError {
from,
to: to.into(),
Expand Down Expand Up @@ -933,20 +946,15 @@ impl PyErrArguments for PyDowncastErrorArguments {
/// Convert `PyDowncastError` to Python `TypeError`.
impl<'a> std::convert::From<PyDowncastError<'a>> for PyErr {
fn from(err: PyDowncastError<'_>) -> PyErr {
let args = PyDowncastErrorArguments {
from: err.from.get_type().into(),
to: err.to,
};

exceptions::PyTypeError::new_err(args)
PyErr::from(err.0)
}
}

impl<'a> std::error::Error for PyDowncastError<'a> {}

impl<'a> std::fmt::Display for PyDowncastError<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
display_downcast_error(f, &self.from.as_borrowed(), &self.to)
self.0.fmt(f)
}
}

Expand Down Expand Up @@ -986,13 +994,13 @@ impl std::error::Error for DowncastIntoError<'_> {}

impl std::fmt::Display for DowncastIntoError<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
display_downcast_error(f, &self.from, &self.to)
display_downcast_error(f, self.from.as_borrowed(), &self.to)
}
}

fn display_downcast_error(
f: &mut std::fmt::Formatter<'_>,
from: &Bound<'_, PyAny>,
from: Borrowed<'_, '_, PyAny>,
to: &str,
) -> std::fmt::Result {
write!(
Expand Down
Loading
Loading