From 2a741a21e6384846654f70c3dc6296485ab7fea4 Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Wed, 29 Nov 2023 11:10:36 +0000 Subject: [PATCH 1/2] migrate many `FromPyObject` implementations to `Bound` API --- pyo3-benches/benches/bench_dict.rs | 10 ++++---- pyo3-benches/benches/bench_list.rs | 9 +++---- pyo3-benches/benches/bench_tuple.rs | 2 +- src/buffer.rs | 5 ++-- src/conversions/chrono.rs | 39 ++++++++++++++--------------- src/conversions/chrono_tz.rs | 7 ++++-- src/conversions/either.rs | 5 ++-- src/conversions/hashbrown.rs | 21 +++++++++------- src/conversions/indexmap.rs | 12 +++++---- src/conversions/num_bigint.rs | 39 +++++++++++++++++++---------- src/conversions/rust_decimal.rs | 16 +++++++----- src/conversions/smallvec.rs | 14 ++++++----- src/conversions/std/array.rs | 19 ++++++++------ src/conversions/std/ipaddr.rs | 7 ++++-- src/conversions/std/map.rs | 20 ++++++++------- src/conversions/std/num.rs | 26 ++++++++++--------- src/conversions/std/osstr.rs | 12 ++++++--- src/conversions/std/path.rs | 13 +++++----- src/conversions/std/set.rs | 17 +++++++------ src/conversions/std/slice.rs | 3 +-- src/conversions/std/string.rs | 22 ++++++++-------- src/conversions/std/time.rs | 11 +++++--- src/coroutine.rs | 2 +- src/types/float.rs | 4 +-- src/types/mod.rs | 4 +-- src/types/module.rs | 4 +-- src/types/sequence.rs | 15 +++++------ src/types/tuple.rs | 4 +-- 28 files changed, 206 insertions(+), 156 deletions(-) diff --git a/pyo3-benches/benches/bench_dict.rs b/pyo3-benches/benches/bench_dict.rs index d1c23466..06559519 100644 --- a/pyo3-benches/benches/bench_dict.rs +++ b/pyo3-benches/benches/bench_dict.rs @@ -3,6 +3,7 @@ use codspeed_criterion_compat::{criterion_group, criterion_main, Bencher, Criter use pyo3::types::IntoPyDict; use pyo3::{prelude::*, types::PyMapping}; use std::collections::{BTreeMap, HashMap}; +use std::hint::black_box; fn iter_dict(b: &mut Bencher<'_>) { Python::with_gil(|py| { @@ -71,13 +72,12 @@ fn extract_hashbrown_map(b: &mut Bencher<'_>) { fn mapping_from_dict(b: &mut Bencher<'_>) { Python::with_gil(|py| { const LEN: usize = 100_000; - let dict = (0..LEN as u64) + let dict = &(0..LEN as u64) .map(|i| (i, i * 2)) .into_py_dict(py) - .to_object(py); - b.iter(|| { - let _: &PyMapping = dict.extract(py).unwrap(); - }); + .to_object(py) + .into_bound(py); + b.iter(|| black_box(dict).downcast::().unwrap()); }); } diff --git a/pyo3-benches/benches/bench_list.rs b/pyo3-benches/benches/bench_list.rs index f4f746f6..e0f238c5 100644 --- a/pyo3-benches/benches/bench_list.rs +++ b/pyo3-benches/benches/bench_list.rs @@ -1,3 +1,5 @@ +use std::hint::black_box; + use codspeed_criterion_compat::{criterion_group, criterion_main, Bencher, Criterion}; use pyo3::prelude::*; @@ -56,11 +58,8 @@ fn list_get_item_unchecked(b: &mut Bencher<'_>) { fn sequence_from_list(b: &mut Bencher<'_>) { Python::with_gil(|py| { const LEN: usize = 50_000; - let list = PyList::new_bound(py, 0..LEN).to_object(py); - b.iter(|| { - let seq: &PySequence = list.extract(py).unwrap(); - seq - }); + let list = &PyList::new_bound(py, 0..LEN); + b.iter(|| black_box(list).downcast::().unwrap()); }); } diff --git a/pyo3-benches/benches/bench_tuple.rs b/pyo3-benches/benches/bench_tuple.rs index 9af95efc..24f32fac 100644 --- a/pyo3-benches/benches/bench_tuple.rs +++ b/pyo3-benches/benches/bench_tuple.rs @@ -93,7 +93,7 @@ fn sequence_from_tuple(b: &mut Bencher<'_>) { Python::with_gil(|py| { const LEN: usize = 50_000; let tuple = PyTuple::new_bound(py, 0..LEN).to_object(py); - b.iter(|| tuple.extract::<&PySequence>(py).unwrap()); + b.iter(|| tuple.downcast::(py).unwrap()); }); } diff --git a/src/buffer.rs b/src/buffer.rs index 4ff2c1d9..40bf1a1e 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -18,6 +18,7 @@ // DEALINGS IN THE SOFTWARE. //! `PyBuffer` implementation +use crate::instance::Bound; use crate::{err, exceptions::PyBufferError, ffi, FromPyObject, PyAny, PyResult, Python}; use std::marker::PhantomData; use std::os::raw; @@ -182,8 +183,8 @@ pub unsafe trait Element: Copy { } impl<'source, T: Element> FromPyObject<'source> for PyBuffer { - fn extract(obj: &PyAny) -> PyResult> { - Self::get(obj) + fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult> { + Self::get(obj.as_gil_ref()) } } diff --git a/src/conversions/chrono.rs b/src/conversions/chrono.rs index 0d9a79c7..4a00d8a3 100644 --- a/src/conversions/chrono.rs +++ b/src/conversions/chrono.rs @@ -42,7 +42,6 @@ use crate::exceptions::{PyTypeError, PyUserWarning, PyValueError}; #[cfg(Py_LIMITED_API)] use crate::sync::GILOnceCell; -#[cfg(not(Py_LIMITED_API))] use crate::types::any::PyAnyMethods; #[cfg(not(Py_LIMITED_API))] use crate::types::datetime::timezone_from_offset; @@ -52,9 +51,9 @@ use crate::types::{ PyTzInfo, PyTzInfoAccess, }; #[cfg(Py_LIMITED_API)] -use crate::{intern, PyDowncastError}; +use crate::{intern, DowncastError}; use crate::{ - FromPyObject, IntoPy, PyAny, PyErr, PyNativeType, PyObject, PyResult, Python, ToPyObject, + Bound, FromPyObject, IntoPy, PyAny, PyErr, PyNativeType, PyObject, PyResult, Python, ToPyObject, }; use chrono::offset::{FixedOffset, Utc}; use chrono::{ @@ -109,14 +108,14 @@ impl IntoPy for Duration { } impl FromPyObject<'_> for Duration { - fn extract(ob: &PyAny) -> PyResult { + fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult { // Python size are much lower than rust size so we do not need bound checks. // 0 <= microseconds < 1000000 // 0 <= seconds < 3600*24 // -999999999 <= days <= 999999999 #[cfg(not(Py_LIMITED_API))] let (days, seconds, microseconds) = { - let delta: &PyDelta = ob.downcast()?; + let delta = ob.downcast::()?; ( delta.get_days().into(), delta.get_seconds().into(), @@ -166,10 +165,10 @@ impl IntoPy for NaiveDate { } impl FromPyObject<'_> for NaiveDate { - fn extract(ob: &PyAny) -> PyResult { + fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult { #[cfg(not(Py_LIMITED_API))] { - let date: &PyDate = ob.downcast()?; + let date = ob.downcast::()?; py_date_to_naive_date(date) } #[cfg(Py_LIMITED_API)] @@ -211,10 +210,10 @@ impl IntoPy for NaiveTime { } impl FromPyObject<'_> for NaiveTime { - fn extract(ob: &PyAny) -> PyResult { + fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult { #[cfg(not(Py_LIMITED_API))] { - let time: &PyTime = ob.downcast()?; + let time = ob.downcast::()?; py_time_to_naive_time(time) } #[cfg(Py_LIMITED_API)] @@ -238,9 +237,9 @@ impl IntoPy for NaiveDateTime { } impl FromPyObject<'_> for NaiveDateTime { - fn extract(dt: &PyAny) -> PyResult { + fn extract_bound(dt: &Bound<'_, PyAny>) -> PyResult { #[cfg(not(Py_LIMITED_API))] - let dt: &PyDateTime = dt.downcast()?; + let dt = dt.downcast::()?; #[cfg(Py_LIMITED_API)] check_type(dt, &DatetimeTypes::get(dt.py()).datetime, "PyDateTime")?; @@ -277,9 +276,9 @@ impl IntoPy for DateTime { } impl FromPyObject<'a>> FromPyObject<'_> for DateTime { - fn extract(dt: &PyAny) -> PyResult> { + fn extract_bound(dt: &Bound<'_, PyAny>) -> PyResult> { #[cfg(not(Py_LIMITED_API))] - let dt: &PyDateTime = dt.downcast()?; + let dt = dt.downcast::()?; #[cfg(Py_LIMITED_API)] check_type(dt, &DatetimeTypes::get(dt.py()).datetime, "PyDateTime")?; @@ -339,7 +338,7 @@ impl FromPyObject<'_> for FixedOffset { /// /// Note that the conversion will result in precision lost in microseconds as chrono offset /// does not supports microseconds. - fn extract(ob: &PyAny) -> PyResult { + fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult { #[cfg(not(Py_LIMITED_API))] let ob: &PyTzInfo = ob.extract()?; #[cfg(Py_LIMITED_API)] @@ -378,7 +377,7 @@ impl IntoPy for Utc { } impl FromPyObject<'_> for Utc { - fn extract(ob: &PyAny) -> PyResult { + fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult { let py_utc = timezone_utc(ob.py()); if ob.eq(py_utc)? { Ok(Utc) @@ -480,7 +479,7 @@ fn py_date_to_naive_date(py_date: &impl PyDateAccess) -> PyResult { } #[cfg(Py_LIMITED_API)] -fn py_date_to_naive_date(py_date: &PyAny) -> PyResult { +fn py_date_to_naive_date(py_date: &Bound<'_, PyAny>) -> PyResult { NaiveDate::from_ymd_opt( py_date.getattr(intern!(py_date.py(), "year"))?.extract()?, py_date.getattr(intern!(py_date.py(), "month"))?.extract()?, @@ -501,7 +500,7 @@ fn py_time_to_naive_time(py_time: &impl PyTimeAccess) -> PyResult { } #[cfg(Py_LIMITED_API)] -fn py_time_to_naive_time(py_time: &PyAny) -> PyResult { +fn py_time_to_naive_time(py_time: &Bound<'_, PyAny>) -> PyResult { NaiveTime::from_hms_micro_opt( py_time.getattr(intern!(py_time.py(), "hour"))?.extract()?, py_time @@ -518,9 +517,9 @@ fn py_time_to_naive_time(py_time: &PyAny) -> PyResult { } #[cfg(Py_LIMITED_API)] -fn check_type(value: &PyAny, t: &PyObject, type_name: &'static str) -> PyResult<()> { - if !value.is_instance(t.as_ref(value.py()))? { - return Err(PyDowncastError::new(value, type_name).into()); +fn check_type(value: &Bound<'_, PyAny>, t: &PyObject, type_name: &'static str) -> PyResult<()> { + if !value.is_instance(t.bind(value.py()))? { + return Err(DowncastError::new(value, type_name).into()); } Ok(()) } diff --git a/src/conversions/chrono_tz.rs b/src/conversions/chrono_tz.rs index 8740d0bd..108dae25 100644 --- a/src/conversions/chrono_tz.rs +++ b/src/conversions/chrono_tz.rs @@ -35,8 +35,11 @@ //! ``` use crate::exceptions::PyValueError; use crate::sync::GILOnceCell; +use crate::types::any::PyAnyMethods; use crate::types::PyType; -use crate::{intern, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject}; +use crate::{ + intern, Bound, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject, +}; use chrono_tz::Tz; use std::str::FromStr; @@ -59,7 +62,7 @@ impl IntoPy for Tz { } impl FromPyObject<'_> for Tz { - fn extract(ob: &PyAny) -> PyResult { + fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult { Tz::from_str(ob.getattr(intern!(ob.py(), "key"))?.extract()?) .map_err(|e| PyValueError::new_err(e.to_string())) } diff --git a/src/conversions/either.rs b/src/conversions/either.rs index 759b282e..897369e5 100644 --- a/src/conversions/either.rs +++ b/src/conversions/either.rs @@ -46,7 +46,8 @@ #[cfg(feature = "experimental-inspect")] use crate::inspect::types::TypeInfo; use crate::{ - exceptions::PyTypeError, FromPyObject, IntoPy, PyAny, PyObject, PyResult, Python, ToPyObject, + exceptions::PyTypeError, types::any::PyAnyMethods, Bound, FromPyObject, IntoPy, PyAny, + PyObject, PyResult, Python, ToPyObject, }; use either::Either; @@ -87,7 +88,7 @@ where R: FromPyObject<'source>, { #[inline] - fn extract(obj: &'source PyAny) -> PyResult { + fn extract_bound(obj: &Bound<'source, PyAny>) -> PyResult { if let Ok(l) = obj.extract::() { Ok(Either::Left(l)) } else if let Ok(r) = obj.extract::() { diff --git a/src/conversions/hashbrown.rs b/src/conversions/hashbrown.rs index a315a274..f8260037 100644 --- a/src/conversions/hashbrown.rs +++ b/src/conversions/hashbrown.rs @@ -17,9 +17,12 @@ //! Note that you must use compatible versions of hashbrown and PyO3. //! The required hashbrown version may vary based on the version of PyO3. use crate::{ - types::set::new_from_iter, + types::any::PyAnyMethods, + types::dict::PyDictMethods, + types::frozenset::PyFrozenSetMethods, + types::set::{new_from_iter, PySetMethods}, types::{IntoPyDict, PyDict, PyFrozenSet, PySet}, - FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, + Bound, FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, }; use std::{cmp, hash}; @@ -54,11 +57,11 @@ where V: FromPyObject<'source>, S: hash::BuildHasher + Default, { - fn extract(ob: &'source PyAny) -> Result { - let dict: &PyDict = ob.downcast()?; + fn extract_bound(ob: &Bound<'source, PyAny>) -> Result { + let dict = ob.downcast::()?; let mut ret = hashbrown::HashMap::with_capacity_and_hasher(dict.len(), S::default()); - for (k, v) in dict { - ret.insert(K::extract(k)?, V::extract(v)?); + for (k, v) in dict.iter() { + ret.insert(k.extract()?, v.extract()?); } Ok(ret) } @@ -92,12 +95,12 @@ where K: FromPyObject<'source> + cmp::Eq + hash::Hash, S: hash::BuildHasher + Default, { - fn extract(ob: &'source PyAny) -> PyResult { + fn extract_bound(ob: &Bound<'source, PyAny>) -> PyResult { match ob.downcast::() { - Ok(set) => set.iter().map(K::extract).collect(), + Ok(set) => set.iter().map(|any| any.extract()).collect(), Err(err) => { if let Ok(frozen_set) = ob.downcast::() { - frozen_set.iter().map(K::extract).collect() + frozen_set.iter().map(|any| any.extract()).collect() } else { Err(PyErr::from(err)) } diff --git a/src/conversions/indexmap.rs b/src/conversions/indexmap.rs index 7c7303e6..1bd638da 100644 --- a/src/conversions/indexmap.rs +++ b/src/conversions/indexmap.rs @@ -87,8 +87,10 @@ //! # if another hash table was used, the order could be random //! ``` +use crate::types::any::PyAnyMethods; +use crate::types::dict::PyDictMethods; use crate::types::*; -use crate::{FromPyObject, IntoPy, PyErr, PyObject, Python, ToPyObject}; +use crate::{Bound, FromPyObject, IntoPy, PyErr, PyObject, Python, ToPyObject}; use std::{cmp, hash}; impl ToPyObject for indexmap::IndexMap @@ -122,11 +124,11 @@ where V: FromPyObject<'source>, S: hash::BuildHasher + Default, { - fn extract(ob: &'source PyAny) -> Result { - let dict: &PyDict = ob.downcast()?; + fn extract_bound(ob: &Bound<'source, PyAny>) -> Result { + let dict = ob.downcast::()?; let mut ret = indexmap::IndexMap::with_capacity_and_hasher(dict.len(), S::default()); - for (k, v) in dict { - ret.insert(K::extract(k)?, V::extract(v)?); + for (k, v) in dict.iter() { + ret.insert(k.extract()?, v.extract()?); } Ok(ret) } diff --git a/src/conversions/num_bigint.rs b/src/conversions/num_bigint.rs index 893d3b9d..41845814 100644 --- a/src/conversions/num_bigint.rs +++ b/src/conversions/num_bigint.rs @@ -47,8 +47,13 @@ //! assert n + 1 == value //! ``` +#[cfg(Py_LIMITED_API)] +use crate::types::bytes::PyBytesMethods; use crate::{ - ffi, types::*, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject, + ffi, + instance::Bound, + types::{any::PyAnyMethods, *}, + FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject, }; use num_bigint::{BigInt, BigUint}; @@ -107,7 +112,7 @@ bigint_conversion!(BigInt, 1, BigInt::to_signed_bytes_le); #[cfg_attr(docsrs, doc(cfg(feature = "num-bigint")))] impl<'source> FromPyObject<'source> for BigInt { - fn extract(ob: &'source PyAny) -> PyResult { + fn extract_bound(ob: &Bound<'source, PyAny>) -> PyResult { let py = ob.py(); // fast path - checking for subclass of `int` just checks a bit in the type object let num_owned: Py; @@ -115,7 +120,7 @@ impl<'source> FromPyObject<'source> for BigInt { long } else { num_owned = unsafe { Py::from_owned_ptr_or_err(py, ffi::PyNumber_Index(ob.as_ptr()))? }; - num_owned.as_ref(py) + num_owned.bind(py) }; let n_bits = int_n_bits(num)?; if n_bits == 0 { @@ -155,7 +160,7 @@ impl<'source> FromPyObject<'source> for BigInt { #[cfg_attr(docsrs, doc(cfg(feature = "num-bigint")))] impl<'source> FromPyObject<'source> for BigUint { - fn extract(ob: &'source PyAny) -> PyResult { + fn extract_bound(ob: &Bound<'source, PyAny>) -> PyResult { let py = ob.py(); // fast path - checking for subclass of `int` just checks a bit in the type object let num_owned: Py; @@ -163,7 +168,7 @@ impl<'source> FromPyObject<'source> for BigUint { long } else { num_owned = unsafe { Py::from_owned_ptr_or_err(py, ffi::PyNumber_Index(ob.as_ptr()))? }; - num_owned.as_ref(py) + num_owned.bind(py) }; let n_bits = int_n_bits(num)?; if n_bits == 0 { @@ -184,7 +189,11 @@ impl<'source> FromPyObject<'source> for BigUint { #[cfg(not(Py_LIMITED_API))] #[inline] -fn int_to_u32_vec(long: &PyLong, n_digits: usize, is_signed: bool) -> PyResult> { +fn int_to_u32_vec( + long: &Bound<'_, PyLong>, + n_digits: usize, + is_signed: bool, +) -> PyResult> { let mut buffer = Vec::with_capacity(n_digits); unsafe { crate::err::error_on_minusone( @@ -207,11 +216,15 @@ fn int_to_u32_vec(long: &PyLong, n_digits: usize, is_signed: bool) -> PyResult PyResult<&PyBytes> { +fn int_to_py_bytes<'py>( + long: &Bound<'py, PyLong>, + n_bytes: usize, + is_signed: bool, +) -> PyResult> { use crate::intern; let py = long.py(); let kwargs = if is_signed { - let kwargs = PyDict::new(py); + let kwargs = PyDict::new_bound(py); kwargs.set_item(intern!(py, "signed"), true)?; Some(kwargs) } else { @@ -220,13 +233,13 @@ fn int_to_py_bytes(long: &PyLong, n_bytes: usize, is_signed: bool) -> PyResult<& let bytes = long.call_method( intern!(py, "to_bytes"), (n_bytes, intern!(py, "little")), - kwargs, + kwargs.as_ref(), )?; - Ok(bytes.downcast()?) + Ok(bytes.downcast_into()?) } #[inline] -fn int_n_bits(long: &PyLong) -> PyResult { +fn int_n_bits(long: &Bound<'_, PyLong>) -> PyResult { let py = long.py(); #[cfg(not(Py_LIMITED_API))] { @@ -242,7 +255,7 @@ fn int_n_bits(long: &PyLong) -> PyResult { { // slow path long.call_method0(crate::intern!(py, "bit_length")) - .and_then(PyAny::extract) + .and_then(|any| any.extract()) } } @@ -330,7 +343,7 @@ mod tests { let locals = PyDict::new(py); locals.set_item("index", index).unwrap(); let ob = py.eval("index.C(10)", None, Some(locals)).unwrap(); - let _: BigInt = FromPyObject::extract(ob).unwrap(); + let _: BigInt = ob.extract().unwrap(); }); } diff --git a/src/conversions/rust_decimal.rs b/src/conversions/rust_decimal.rs index 173e5785..2e38e780 100644 --- a/src/conversions/rust_decimal.rs +++ b/src/conversions/rust_decimal.rs @@ -51,18 +51,22 @@ use crate::exceptions::PyValueError; use crate::sync::GILOnceCell; +use crate::types::any::PyAnyMethods; +use crate::types::string::PyStringMethods; use crate::types::PyType; -use crate::{intern, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject}; +use crate::{ + intern, Bound, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject, +}; use rust_decimal::Decimal; use std::str::FromStr; impl FromPyObject<'_> for Decimal { - fn extract(obj: &PyAny) -> PyResult { + fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult { // use the string representation to not be lossy if let Ok(val) = obj.extract() { Ok(Decimal::new(val, 0)) } else { - Decimal::from_str(obj.str()?.to_str()?) + Decimal::from_str(&obj.str()?.to_cow()?) .map_err(|e| PyValueError::new_err(e.to_string())) } } @@ -131,7 +135,7 @@ mod test_rust_decimal { .unwrap(); // Checks if Python Decimal -> Rust Decimal conversion is correct let py_dec = locals.get_item("py_dec").unwrap().unwrap(); - let py_result: Decimal = FromPyObject::extract(py_dec).unwrap(); + let py_result: Decimal = py_dec.extract().unwrap(); assert_eq!(rs_orig, py_result); }) } @@ -193,7 +197,7 @@ mod test_rust_decimal { ) .unwrap(); let py_dec = locals.get_item("py_dec").unwrap().unwrap(); - let roundtripped: Result = FromPyObject::extract(py_dec); + let roundtripped: Result = py_dec.extract(); assert!(roundtripped.is_err()); }) } @@ -209,7 +213,7 @@ mod test_rust_decimal { ) .unwrap(); let py_dec = locals.get_item("py_dec").unwrap().unwrap(); - let roundtripped: Result = FromPyObject::extract(py_dec); + let roundtripped: Result = py_dec.extract(); assert!(roundtripped.is_err()); }) } diff --git a/src/conversions/smallvec.rs b/src/conversions/smallvec.rs index 37ae0922..d9ed8419 100644 --- a/src/conversions/smallvec.rs +++ b/src/conversions/smallvec.rs @@ -18,10 +18,12 @@ use crate::exceptions::PyTypeError; #[cfg(feature = "experimental-inspect")] use crate::inspect::types::TypeInfo; +use crate::types::any::PyAnyMethods; use crate::types::list::new_from_iter; use crate::types::{PySequence, PyString}; use crate::{ - ffi, FromPyObject, IntoPy, PyAny, PyDowncastError, PyObject, PyResult, Python, ToPyObject, + err::DowncastError, ffi, Bound, FromPyObject, IntoPy, PyAny, PyObject, PyResult, Python, + ToPyObject, }; use smallvec::{Array, SmallVec}; @@ -57,7 +59,7 @@ where A: Array, A::Item: FromPyObject<'a>, { - fn extract(obj: &'a PyAny) -> PyResult { + fn extract_bound(obj: &Bound<'a, PyAny>) -> PyResult { if obj.is_instance_of::() { return Err(PyTypeError::new_err("Can't extract `str` to `SmallVec`")); } @@ -70,18 +72,18 @@ where } } -fn extract_sequence<'s, A>(obj: &'s PyAny) -> PyResult> +fn extract_sequence<'s, A>(obj: &Bound<'s, PyAny>) -> PyResult> where A: Array, A::Item: FromPyObject<'s>, { // Types that pass `PySequence_Check` usually implement enough of the sequence protocol // to support this function and if not, we will only fail extraction safely. - let seq: &PySequence = unsafe { + let seq = unsafe { if ffi::PySequence_Check(obj.as_ptr()) != 0 { - obj.downcast_unchecked() + obj.downcast_unchecked::() } else { - return Err(PyDowncastError::new(obj, "Sequence").into()); + return Err(DowncastError::new(obj, "Sequence").into()); } }; diff --git a/src/conversions/std/array.rs b/src/conversions/std/array.rs index 167f8070..e5e1744e 100644 --- a/src/conversions/std/array.rs +++ b/src/conversions/std/array.rs @@ -1,8 +1,11 @@ +use crate::instance::Bound; +use crate::types::any::PyAnyMethods; use crate::types::PySequence; -use crate::{exceptions, PyErr}; use crate::{ - ffi, FromPyObject, IntoPy, Py, PyAny, PyDowncastError, PyObject, PyResult, Python, ToPyObject, + err::DowncastError, ffi, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, + ToPyObject, }; +use crate::{exceptions, PyErr}; impl IntoPy for [T; N] where @@ -46,29 +49,29 @@ impl<'a, T, const N: usize> FromPyObject<'a> for [T; N] where T: FromPyObject<'a>, { - fn extract(obj: &'a PyAny) -> PyResult { + fn extract_bound(obj: &Bound<'a, PyAny>) -> PyResult { create_array_from_obj(obj) } } -fn create_array_from_obj<'s, T, const N: usize>(obj: &'s PyAny) -> PyResult<[T; N]> +fn create_array_from_obj<'s, T, const N: usize>(obj: &Bound<'s, PyAny>) -> PyResult<[T; N]> where T: FromPyObject<'s>, { // Types that pass `PySequence_Check` usually implement enough of the sequence protocol // to support this function and if not, we will only fail extraction safely. - let seq: &PySequence = unsafe { + let seq = unsafe { if ffi::PySequence_Check(obj.as_ptr()) != 0 { - obj.downcast_unchecked() + obj.downcast_unchecked::() } else { - return Err(PyDowncastError::new(obj, "Sequence").into()); + return Err(DowncastError::new(obj, "Sequence").into()); } }; let seq_len = seq.len()?; if seq_len != N { return Err(invalid_sequence_length(N, seq_len)); } - array_try_from_fn(|idx| seq.get_item(idx).and_then(PyAny::extract)) + array_try_from_fn(|idx| seq.get_item(idx).and_then(|any| any.extract())) } // TODO use std::array::try_from_fn, if that stabilises: diff --git a/src/conversions/std/ipaddr.rs b/src/conversions/std/ipaddr.rs index 713de0af..5e313cd7 100755 --- a/src/conversions/std/ipaddr.rs +++ b/src/conversions/std/ipaddr.rs @@ -1,12 +1,15 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use crate::exceptions::PyValueError; +use crate::instance::Bound; use crate::sync::GILOnceCell; +use crate::types::any::PyAnyMethods; +use crate::types::string::PyStringMethods; use crate::types::PyType; use crate::{intern, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject}; impl FromPyObject<'_> for IpAddr { - fn extract(obj: &PyAny) -> PyResult { + fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult { match obj.getattr(intern!(obj.py(), "packed")) { Ok(packed) => { if let Ok(packed) = packed.extract::<[u8; 4]>() { @@ -19,7 +22,7 @@ impl FromPyObject<'_> for IpAddr { } Err(_) => { // We don't have a .packed attribute, so we try to construct an IP from str(). - obj.str()?.to_str()?.parse().map_err(PyValueError::new_err) + obj.str()?.to_cow()?.parse().map_err(PyValueError::new_err) } } } diff --git a/src/conversions/std/map.rs b/src/conversions/std/map.rs index a53b0ce9..1b47c870 100644 --- a/src/conversions/std/map.rs +++ b/src/conversions/std/map.rs @@ -3,7 +3,9 @@ use std::{cmp, collections, hash}; #[cfg(feature = "experimental-inspect")] use crate::inspect::types::TypeInfo; use crate::{ - types::{IntoPyDict, PyDict}, + instance::Bound, + types::dict::PyDictMethods, + types::{any::PyAnyMethods, IntoPyDict, PyDict}, FromPyObject, IntoPy, PyAny, PyErr, PyObject, Python, ToPyObject, }; @@ -71,11 +73,11 @@ where V: FromPyObject<'source>, S: hash::BuildHasher + Default, { - fn extract(ob: &'source PyAny) -> Result { - let dict: &PyDict = ob.downcast()?; + fn extract_bound(ob: &Bound<'source, PyAny>) -> Result { + let dict = ob.downcast::()?; let mut ret = collections::HashMap::with_capacity_and_hasher(dict.len(), S::default()); - for (k, v) in dict { - ret.insert(K::extract(k)?, V::extract(v)?); + for (k, v) in dict.iter() { + ret.insert(k.extract()?, v.extract()?); } Ok(ret) } @@ -91,11 +93,11 @@ where K: FromPyObject<'source> + cmp::Ord, V: FromPyObject<'source>, { - fn extract(ob: &'source PyAny) -> Result { - let dict: &PyDict = ob.downcast()?; + fn extract_bound(ob: &Bound<'source, PyAny>) -> Result { + let dict = ob.downcast::()?; let mut ret = collections::BTreeMap::new(); - for (k, v) in dict { - ret.insert(K::extract(k)?, V::extract(v)?); + for (k, v) in dict.iter() { + ret.insert(k.extract()?, v.extract()?); } Ok(ret) } diff --git a/src/conversions/std/num.rs b/src/conversions/std/num.rs index e5c72b98..1ced6cbb 100644 --- a/src/conversions/std/num.rs +++ b/src/conversions/std/num.rs @@ -1,7 +1,9 @@ #[cfg(feature = "experimental-inspect")] use crate::inspect::types::TypeInfo; +use crate::types::any::PyAnyMethods; use crate::{ - exceptions, ffi, FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, + exceptions, ffi, Bound, FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, + ToPyObject, }; use std::convert::TryFrom; use std::num::{ @@ -29,8 +31,8 @@ macro_rules! int_fits_larger_int { } } - impl<'source> FromPyObject<'source> for $rust_type { - fn extract(obj: &'source PyAny) -> PyResult { + impl FromPyObject<'_> for $rust_type { + fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult { let val: $larger_type = obj.extract()?; <$rust_type>::try_from(val) .map_err(|e| exceptions::PyOverflowError::new_err(e.to_string())) @@ -94,8 +96,8 @@ macro_rules! int_convert_u64_or_i64 { TypeInfo::builtin("int") } } - impl<'source> FromPyObject<'source> for $rust_type { - fn extract(obj: &'source PyAny) -> PyResult<$rust_type> { + impl FromPyObject<'_> for $rust_type { + fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult<$rust_type> { extract_int!(obj, !0, $pylong_as_ll_or_ull, $force_index_call) } @@ -126,7 +128,7 @@ macro_rules! int_fits_c_long { } impl<'source> FromPyObject<'source> for $rust_type { - fn extract(obj: &'source PyAny) -> PyResult { + fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult { let val: c_long = extract_int!(obj, -1, ffi::PyLong_AsLong)?; <$rust_type>::try_from(val) .map_err(|e| exceptions::PyOverflowError::new_err(e.to_string())) @@ -210,8 +212,8 @@ mod fast_128bit_int_conversion { } } - impl<'source> FromPyObject<'source> for $rust_type { - fn extract(ob: &'source PyAny) -> PyResult<$rust_type> { + impl FromPyObject<'_> for $rust_type { + fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult<$rust_type> { let num = unsafe { PyObject::from_owned_ptr_or_err(ob.py(), ffi::PyNumber_Index(ob.as_ptr()))? }; @@ -279,8 +281,8 @@ mod slow_128bit_int_conversion { } } - impl<'source> FromPyObject<'source> for $rust_type { - fn extract(ob: &'source PyAny) -> PyResult<$rust_type> { + impl FromPyObject<'_> for $rust_type { + fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult<$rust_type> { let py = ob.py(); unsafe { let lower = err_if_invalid_value( @@ -338,8 +340,8 @@ macro_rules! nonzero_int_impl { } } - impl<'source> FromPyObject<'source> for $nonzero_type { - fn extract(obj: &'source PyAny) -> PyResult { + impl FromPyObject<'_> for $nonzero_type { + fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult { let val: $primitive_type = obj.extract()?; <$nonzero_type>::try_from(val) .map_err(|_| exceptions::PyValueError::new_err("invalid zero value")) diff --git a/src/conversions/std/osstr.rs b/src/conversions/std/osstr.rs index b2c14386..be337959 100644 --- a/src/conversions/std/osstr.rs +++ b/src/conversions/std/osstr.rs @@ -1,3 +1,5 @@ +use crate::instance::Bound; +use crate::types::any::PyAnyMethods; use crate::types::PyString; use crate::{ffi, FromPyObject, IntoPy, PyAny, PyObject, PyResult, Python, ToPyObject}; use std::borrow::Cow; @@ -51,8 +53,8 @@ impl ToPyObject for OsStr { // be impossible to implement on Windows. Hence it's omitted entirely impl FromPyObject<'_> for OsString { - fn extract(ob: &PyAny) -> PyResult { - let pystring: &PyString = ob.downcast()?; + fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult { + let pystring = ob.downcast::()?; #[cfg(not(windows))] { @@ -79,9 +81,11 @@ impl FromPyObject<'_> for OsString { #[cfg(windows)] { + use crate::types::string::PyStringMethods; + // Take the quick and easy shortcut if UTF-8 - if let Ok(utf8_string) = pystring.to_str() { - return Ok(utf8_string.to_owned().into()); + if let Ok(utf8_string) = pystring.to_cow() { + return Ok(utf8_string.into_owned().into()); } // Get an owned allocated wide char buffer from PyString, which we have to deallocate diff --git a/src/conversions/std/path.rs b/src/conversions/std/path.rs index cc579e49..5d832e89 100644 --- a/src/conversions/std/path.rs +++ b/src/conversions/std/path.rs @@ -1,6 +1,7 @@ -use crate::{ - ffi, FromPyObject, FromPyPointer, IntoPy, PyAny, PyObject, PyResult, Python, ToPyObject, -}; +use crate::ffi_ptr_ext::FfiPtrExt; +use crate::instance::Bound; +use crate::types::any::PyAnyMethods; +use crate::{ffi, FromPyObject, IntoPy, PyAny, PyObject, PyResult, Python, ToPyObject}; use std::borrow::Cow; use std::ffi::OsString; use std::path::{Path, PathBuf}; @@ -14,10 +15,10 @@ impl ToPyObject for Path { // See osstr.rs for why there's no FromPyObject impl for &Path impl FromPyObject<'_> for PathBuf { - fn extract(ob: &PyAny) -> PyResult { + fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult { // We use os.fspath to get the underlying path as bytes or str - let path = unsafe { PyAny::from_owned_ptr_or_err(ob.py(), ffi::PyOS_FSPath(ob.as_ptr())) }?; - Ok(OsString::extract(path)?.into()) + let path = unsafe { ffi::PyOS_FSPath(ob.as_ptr()).assume_owned_or_err(ob.py())? }; + Ok(path.extract::()?.into()) } } diff --git a/src/conversions/std/set.rs b/src/conversions/std/set.rs index 020b2505..7d1b91c5 100644 --- a/src/conversions/std/set.rs +++ b/src/conversions/std/set.rs @@ -3,7 +3,10 @@ use std::{cmp, collections, hash}; #[cfg(feature = "experimental-inspect")] use crate::inspect::types::TypeInfo; use crate::{ - types::set::new_from_iter, + instance::Bound, + types::any::PyAnyMethods, + types::frozenset::PyFrozenSetMethods, + types::set::{new_from_iter, PySetMethods}, types::{PyFrozenSet, PySet}, FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, }; @@ -53,12 +56,12 @@ where K: FromPyObject<'source> + cmp::Eq + hash::Hash, S: hash::BuildHasher + Default, { - fn extract(ob: &'source PyAny) -> PyResult { + fn extract_bound(ob: &Bound<'source, PyAny>) -> PyResult { match ob.downcast::() { - Ok(set) => set.iter().map(K::extract).collect(), + Ok(set) => set.iter().map(|any| any.extract()).collect(), Err(err) => { if let Ok(frozen_set) = ob.downcast::() { - frozen_set.iter().map(K::extract).collect() + frozen_set.iter().map(|any| any.extract()).collect() } else { Err(PyErr::from(err)) } @@ -92,12 +95,12 @@ impl<'source, K> FromPyObject<'source> for collections::BTreeSet where K: FromPyObject<'source> + cmp::Ord, { - fn extract(ob: &'source PyAny) -> PyResult { + fn extract_bound(ob: &Bound<'source, PyAny>) -> PyResult { match ob.downcast::() { - Ok(set) => set.iter().map(K::extract).collect(), + Ok(set) => set.iter().map(|any| any.extract()).collect(), Err(err) => { if let Ok(frozen_set) = ob.downcast::() { - frozen_set.iter().map(K::extract).collect() + frozen_set.iter().map(|any| any.extract()).collect() } else { Err(PyErr::from(err)) } diff --git a/src/conversions/std/slice.rs b/src/conversions/std/slice.rs index 3d9351f8..f77cd661 100644 --- a/src/conversions/std/slice.rs +++ b/src/conversions/std/slice.rs @@ -26,14 +26,13 @@ impl<'a> FromPyObject<'a> for &'a [u8] { #[cfg(test)] mod tests { - use crate::FromPyObject; use crate::Python; #[test] fn test_extract_bytes() { Python::with_gil(|py| { let py_bytes = py.eval("b'Hello Python'", None, None).unwrap(); - let bytes: &[u8] = FromPyObject::extract(py_bytes).unwrap(); + let bytes: &[u8] = py_bytes.extract().unwrap(); assert_eq!(bytes, b"Hello Python"); }); } diff --git a/src/conversions/std/string.rs b/src/conversions/std/string.rs index b43e5422..2ac08855 100644 --- a/src/conversions/std/string.rs +++ b/src/conversions/std/string.rs @@ -3,7 +3,9 @@ use std::borrow::Cow; #[cfg(feature = "experimental-inspect")] use crate::inspect::types::TypeInfo; use crate::{ - types::PyString, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject, + instance::Bound, + types::{any::PyAnyMethods, string::PyStringMethods, PyString}, + FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject, }; /// Converts a Rust `str` to a Python object. @@ -119,15 +121,15 @@ impl<'source> FromPyObject<'source> for &'source str { #[cfg(feature = "experimental-inspect")] fn type_input() -> TypeInfo { - ::type_input() + ::type_input() } } /// Allows extracting strings from Python objects. /// Accepts Python `str` and `unicode` objects. impl FromPyObject<'_> for String { - fn extract(obj: &PyAny) -> PyResult { - obj.downcast::()?.to_str().map(ToOwned::to_owned) + fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult { + obj.downcast::()?.to_cow().map(Cow::into_owned) } #[cfg(feature = "experimental-inspect")] @@ -137,8 +139,8 @@ impl FromPyObject<'_> for String { } impl FromPyObject<'_> for char { - fn extract(obj: &PyAny) -> PyResult { - let s = obj.downcast::()?.to_str()?; + fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult { + let s = obj.downcast::()?.to_cow()?; let mut iter = s.chars(); if let (Some(ch), None) = (iter.next(), iter.next()) { Ok(ch) @@ -158,7 +160,7 @@ impl FromPyObject<'_> for char { #[cfg(test)] mod tests { use crate::Python; - use crate::{FromPyObject, IntoPy, PyObject, ToPyObject}; + use crate::{IntoPy, PyObject, ToPyObject}; use std::borrow::Cow; #[test] @@ -198,7 +200,7 @@ mod tests { let s = "Hello Python"; let py_string = s.to_object(py); - let s2: &str = FromPyObject::extract(py_string.as_ref(py)).unwrap(); + let s2: &str = py_string.as_ref(py).extract().unwrap(); assert_eq!(s, s2); }) } @@ -208,7 +210,7 @@ mod tests { Python::with_gil(|py| { let ch = '😃'; let py_string = ch.to_object(py); - let ch2: char = FromPyObject::extract(py_string.as_ref(py)).unwrap(); + let ch2: char = py_string.as_ref(py).extract().unwrap(); assert_eq!(ch, ch2); }) } @@ -218,7 +220,7 @@ mod tests { Python::with_gil(|py| { let s = "Hello Python"; let py_string = s.to_object(py); - let err: crate::PyResult = FromPyObject::extract(py_string.as_ref(py)); + let err: crate::PyResult = py_string.as_ref(py).extract(); assert!(err .unwrap_err() .to_string() diff --git a/src/conversions/std/time.rs b/src/conversions/std/time.rs index 71cdfa23..bdf938c0 100755 --- a/src/conversions/std/time.rs +++ b/src/conversions/std/time.rs @@ -1,21 +1,24 @@ use crate::exceptions::{PyOverflowError, PyValueError}; use crate::sync::GILOnceCell; +use crate::types::any::PyAnyMethods; #[cfg(Py_LIMITED_API)] use crate::types::PyType; #[cfg(not(Py_LIMITED_API))] use crate::types::{timezone_utc, PyDateTime, PyDelta, PyDeltaAccess}; #[cfg(Py_LIMITED_API)] use crate::Py; -use crate::{intern, FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject}; +use crate::{ + intern, Bound, FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, +}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; const SECONDS_PER_DAY: u64 = 24 * 60 * 60; impl FromPyObject<'_> for Duration { - fn extract(obj: &PyAny) -> PyResult { + fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult { #[cfg(not(Py_LIMITED_API))] let (days, seconds, microseconds) = { - let delta: &PyDelta = obj.downcast()?; + let delta = obj.downcast::()?; ( delta.get_days(), delta.get_seconds(), @@ -93,7 +96,7 @@ impl IntoPy for Duration { // TODO: it might be nice to investigate using timestamps anyway, at least when the datetime is a safe range. impl FromPyObject<'_> for SystemTime { - fn extract(obj: &PyAny) -> PyResult { + fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult { let duration_since_unix_epoch: Duration = obj .call_method1(intern!(obj.py(), "__sub__"), (unix_epoch_py(obj.py()),))? .extract()?; diff --git a/src/coroutine.rs b/src/coroutine.rs index 415bbc88..c4b5ddf3 100644 --- a/src/coroutine.rs +++ b/src/coroutine.rs @@ -118,7 +118,7 @@ impl Coroutine { } // if waker has been waken during future polling, this is roughly equivalent to // `await asyncio.sleep(0)`, so just yield `None`. - Ok(py.None().into()) + Ok(py.None().into_py(py)) } } diff --git a/src/types/float.rs b/src/types/float.rs index 4b4dc93d..fb4ca9f4 100644 --- a/src/types/float.rs +++ b/src/types/float.rs @@ -98,7 +98,7 @@ impl IntoPy for f64 { impl<'source> FromPyObject<'source> for f64 { // PyFloat_AsDouble returns -1.0 upon failure #![allow(clippy::float_cmp)] - fn extract(obj: &'source PyAny) -> PyResult { + fn extract_bound(obj: &Bound<'source, PyAny>) -> PyResult { // On non-limited API, .value() uses PyFloat_AS_DOUBLE which // allows us to have an optimized fast path for the case when // we have exactly a `float` object (it's not worth going through @@ -143,7 +143,7 @@ impl IntoPy for f32 { } impl<'source> FromPyObject<'source> for f32 { - fn extract(obj: &'source PyAny) -> PyResult { + fn extract_bound(obj: &Bound<'source, PyAny>) -> PyResult { Ok(obj.extract::()? as f32) } diff --git a/src/types/mod.rs b/src/types/mod.rs index 5f88d57c..f802348f 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -224,8 +224,8 @@ macro_rules! pyobject_native_type_extract { ($name:ty $(;$generics:ident)*) => { impl<'py, $($generics,)*> $crate::FromPyObject<'py> for &'py $name { #[inline] - fn extract(obj: &'py $crate::PyAny) -> $crate::PyResult { - obj.downcast().map_err(::std::convert::Into::into) + fn extract_bound(obj: &$crate::Bound<'py, $crate::PyAny>) -> $crate::PyResult { + ::std::clone::Clone::clone(obj).into_gil_ref().downcast().map_err(::std::convert::Into::into) } } } diff --git a/src/types/module.rs b/src/types/module.rs index 7edf1642..8824dfcf 100644 --- a/src/types/module.rs +++ b/src/types/module.rs @@ -5,7 +5,7 @@ use crate::pyclass::PyClass; use crate::types::{ any::PyAnyMethods, list::PyListMethods, PyAny, PyCFunction, PyDict, PyList, PyString, }; -use crate::{exceptions, ffi, Bound, IntoPy, Py, PyNativeType, PyObject, Python}; +use crate::{exceptions, ffi, Bound, FromPyObject, IntoPy, Py, PyNativeType, PyObject, Python}; use std::ffi::CString; use std::str; @@ -146,7 +146,7 @@ impl PyModule { return Err(PyErr::fetch(py)); } - <&PyModule as crate::FromPyObject>::extract(py.from_owned_ptr_or_err(mptr)?) + <&PyModule as FromPyObject>::extract(py.from_owned_ptr_or_err(mptr)?) } } diff --git a/src/types/sequence.rs b/src/types/sequence.rs index 64e8f316..28a6fd48 100644 --- a/src/types/sequence.rs +++ b/src/types/sequence.rs @@ -1,4 +1,4 @@ -use crate::err::{self, PyDowncastError, PyErr, PyResult}; +use crate::err::{self, DowncastError, PyDowncastError, PyErr, PyResult}; use crate::exceptions::PyTypeError; use crate::ffi_ptr_ext::FfiPtrExt; #[cfg(feature = "experimental-inspect")] @@ -11,6 +11,8 @@ use crate::type_object::PyTypeInfo; use crate::types::{PyAny, PyList, PyString, PyTuple, PyType}; use crate::{ffi, FromPyObject, Py, PyNativeType, PyTypeCheck, Python, ToPyObject}; +use super::any::PyAnyMethods; + /// Represents a reference to a Python object supporting the sequence protocol. #[repr(transparent)] pub struct PySequence(PyAny); @@ -481,7 +483,7 @@ impl<'a, T> FromPyObject<'a> for Vec where T: FromPyObject<'a>, { - fn extract(obj: &'a PyAny) -> PyResult { + fn extract_bound(obj: &Bound<'a, PyAny>) -> PyResult { if obj.is_instance_of::() { return Err(PyTypeError::new_err("Can't extract `str` to `Vec`")); } @@ -494,17 +496,17 @@ where } } -fn extract_sequence<'s, T>(obj: &'s PyAny) -> PyResult> +fn extract_sequence<'s, T>(obj: &Bound<'s, PyAny>) -> PyResult> where T: FromPyObject<'s>, { // Types that pass `PySequence_Check` usually implement enough of the sequence protocol // to support this function and if not, we will only fail extraction safely. - let seq: &PySequence = unsafe { + let seq = unsafe { if ffi::PySequence_Check(obj.as_ptr()) != 0 { - obj.downcast_unchecked() + obj.downcast_unchecked::() } else { - return Err(PyDowncastError::new(obj, "Sequence").into()); + return Err(DowncastError::new(obj, "Sequence").into()); } }; @@ -602,7 +604,6 @@ mod tests { let v = "London Calling"; let ob = v.to_object(py); - assert!(ob.extract::>(py).is_err()); assert!(ob.extract::>(py).is_err()); assert!(ob.extract::>(py).is_err()); }); diff --git a/src/types/tuple.rs b/src/types/tuple.rs index 38f5f7e9..26bd698c 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -629,7 +629,7 @@ impl IntoPy> for Bound<'_, PyTuple> { } #[cold] -fn wrong_tuple_length(t: &PyTuple, expected_length: usize) -> PyErr { +fn wrong_tuple_length(t: &Bound<'_, PyTuple>, expected_length: usize) -> PyErr { let msg = format!( "expected tuple of length {}, but got tuple of length {}", expected_length, @@ -667,7 +667,7 @@ fn type_output() -> TypeInfo { } impl<'s, $($T: FromPyObject<'s>),+> FromPyObject<'s> for ($($T,)+) { - fn extract(obj: &'s PyAny) -> PyResult + fn extract_bound(obj: &Bound<'s, PyAny>) -> PyResult { let t = obj.downcast::()?; if t.len() == $length { From 0d4df9c19dee6cb934f8b0003a0c3bd5bd970a88 Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Sun, 4 Feb 2024 14:12:35 +0000 Subject: [PATCH 2/2] adjust `FromPyObject` implementations to always use `'py` lifetime --- pyo3-macros-backend/src/frompyobject.rs | 4 +-- src/buffer.rs | 2 +- src/conversion.rs | 34 ++++++++++++------------- src/conversions/chrono.rs | 2 +- src/conversions/either.rs | 8 +++--- src/conversions/hashbrown.rs | 14 +++++----- src/conversions/indexmap.rs | 8 +++--- src/conversions/num_bigint.rs | 8 +++--- src/conversions/smallvec.rs | 10 ++++---- src/conversions/std/array.rs | 10 ++++---- src/conversions/std/map.rs | 16 ++++++------ src/conversions/std/num.rs | 2 +- src/conversions/std/set.rs | 12 ++++----- src/conversions/std/slice.rs | 4 +-- src/conversions/std/string.rs | 4 +-- src/instance.rs | 4 +-- src/types/any.rs | 4 +-- src/types/bytes.rs | 4 +-- src/types/float.rs | 8 +++--- src/types/sequence.rs | 10 ++++---- src/types/tuple.rs | 4 +-- 21 files changed, 86 insertions(+), 86 deletions(-) diff --git a/pyo3-macros-backend/src/frompyobject.rs b/pyo3-macros-backend/src/frompyobject.rs index 2b527dc8..f4774d88 100644 --- a/pyo3-macros-backend/src/frompyobject.rs +++ b/pyo3-macros-backend/src/frompyobject.rs @@ -568,8 +568,8 @@ pub fn build_derive_from_pyobject(tokens: &DeriveInput) -> Result { let lt_param = if let Some(lt) = verify_and_get_lifetime(generics)? { lt.clone() } else { - trait_generics.params.push(parse_quote!('source)); - parse_quote!('source) + trait_generics.params.push(parse_quote!('py)); + parse_quote!('py) }; let mut where_clause: syn::WhereClause = parse_quote!(where); for param in generics.type_params() { diff --git a/src/buffer.rs b/src/buffer.rs index 40bf1a1e..d18f05e2 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -182,7 +182,7 @@ pub unsafe trait Element: Copy { fn is_compatible_format(format: &CStr) -> bool; } -impl<'source, T: Element> FromPyObject<'source> for PyBuffer { +impl<'py, T: Element> FromPyObject<'py> for PyBuffer { fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult> { Self::get(obj.as_gil_ref()) } diff --git a/src/conversion.rs b/src/conversion.rs index 3af038af..d9536aa9 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -209,7 +209,7 @@ pub trait IntoPy: Sized { /// depend on the lifetime of the `obj` or the `prepared` variable. /// /// For example, when extracting `&str` from a Python byte string, the resulting string slice will -/// point to the existing string data (lifetime: `'source`). +/// point to the existing string data (lifetime: `'py`). /// On the other hand, when extracting `&str` from a Python Unicode string, the preparation step /// will convert the string to UTF-8, and the resulting string slice will have lifetime `'prepared`. /// Since which case applies depends on the runtime type of the Python object, @@ -219,12 +219,12 @@ pub trait IntoPy: Sized { /// has two methods `extract` and `extract_bound` which are defaulted to call each other. To avoid /// infinite recursion, implementors must implement at least one of these methods. The recommendation /// is to implement `extract_bound` and leave `extract` as the default implementation. -pub trait FromPyObject<'source>: Sized { +pub trait FromPyObject<'py>: Sized { /// Extracts `Self` from the source GIL Ref `obj`. /// /// Implementors are encouraged to implement `extract_bound` and leave this method as the /// default implementation, which will forward calls to `extract_bound`. - fn extract(ob: &'source PyAny) -> PyResult { + fn extract(ob: &'py PyAny) -> PyResult { Self::extract_bound(&ob.as_borrowed()) } @@ -232,7 +232,7 @@ pub trait FromPyObject<'source>: Sized { /// /// Implementors are encouraged to implement this method and leave `extract` defaulted, as /// this will be most compatible with PyO3's future API. - fn extract_bound(ob: &Bound<'source, PyAny>) -> PyResult { + fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { Self::extract(ob.clone().into_gil_ref()) } @@ -308,56 +308,56 @@ impl> IntoPy for Cell { } } -impl<'a, T: FromPyObject<'a>> FromPyObject<'a> for Cell { - fn extract(ob: &'a PyAny) -> PyResult { +impl<'py, T: FromPyObject<'py>> FromPyObject<'py> for Cell { + fn extract(ob: &'py PyAny) -> PyResult { T::extract(ob).map(Cell::new) } } -impl<'a, T> FromPyObject<'a> for &'a PyCell +impl<'py, T> FromPyObject<'py> for &'py PyCell where T: PyClass, { - fn extract(obj: &'a PyAny) -> PyResult { + fn extract(obj: &'py PyAny) -> PyResult { obj.downcast().map_err(Into::into) } } -impl<'a, T> FromPyObject<'a> for T +impl FromPyObject<'_> for T where T: PyClass + Clone, { - fn extract(obj: &'a PyAny) -> PyResult { + fn extract(obj: &PyAny) -> PyResult { let cell: &PyCell = obj.downcast()?; Ok(unsafe { cell.try_borrow_unguarded()?.clone() }) } } -impl<'a, T> FromPyObject<'a> for PyRef<'a, T> +impl<'py, T> FromPyObject<'py> for PyRef<'py, T> where T: PyClass, { - fn extract(obj: &'a PyAny) -> PyResult { + fn extract(obj: &'py PyAny) -> PyResult { let cell: &PyCell = obj.downcast()?; cell.try_borrow().map_err(Into::into) } } -impl<'a, T> FromPyObject<'a> for PyRefMut<'a, T> +impl<'py, T> FromPyObject<'py> for PyRefMut<'py, T> where T: PyClass, { - fn extract(obj: &'a PyAny) -> PyResult { + fn extract(obj: &'py PyAny) -> PyResult { let cell: &PyCell = obj.downcast()?; cell.try_borrow_mut().map_err(Into::into) } } -impl<'a, T> FromPyObject<'a> for Option +impl<'py, T> FromPyObject<'py> for Option where - T: FromPyObject<'a>, + T: FromPyObject<'py>, { - fn extract(obj: &'a PyAny) -> PyResult { + fn extract(obj: &'py PyAny) -> PyResult { if obj.as_ptr() == unsafe { ffi::Py_None() } { Ok(None) } else { diff --git a/src/conversions/chrono.rs b/src/conversions/chrono.rs index 4a00d8a3..6e529918 100644 --- a/src/conversions/chrono.rs +++ b/src/conversions/chrono.rs @@ -275,7 +275,7 @@ impl IntoPy for DateTime { } } -impl FromPyObject<'a>> FromPyObject<'_> for DateTime { +impl FromPyObject<'py>> FromPyObject<'_> for DateTime { fn extract_bound(dt: &Bound<'_, PyAny>) -> PyResult> { #[cfg(not(Py_LIMITED_API))] let dt = dt.downcast::()?; diff --git a/src/conversions/either.rs b/src/conversions/either.rs index 897369e5..c763cdf9 100644 --- a/src/conversions/either.rs +++ b/src/conversions/either.rs @@ -82,13 +82,13 @@ where } #[cfg_attr(docsrs, doc(cfg(feature = "either")))] -impl<'source, L, R> FromPyObject<'source> for Either +impl<'py, L, R> FromPyObject<'py> for Either where - L: FromPyObject<'source>, - R: FromPyObject<'source>, + L: FromPyObject<'py>, + R: FromPyObject<'py>, { #[inline] - fn extract_bound(obj: &Bound<'source, PyAny>) -> PyResult { + fn extract_bound(obj: &Bound<'py, PyAny>) -> PyResult { if let Ok(l) = obj.extract::() { Ok(Either::Left(l)) } else if let Ok(r) = obj.extract::() { diff --git a/src/conversions/hashbrown.rs b/src/conversions/hashbrown.rs index f8260037..d2cbe4ad 100644 --- a/src/conversions/hashbrown.rs +++ b/src/conversions/hashbrown.rs @@ -51,13 +51,13 @@ where } } -impl<'source, K, V, S> FromPyObject<'source> for hashbrown::HashMap +impl<'py, K, V, S> FromPyObject<'py> for hashbrown::HashMap where - K: FromPyObject<'source> + cmp::Eq + hash::Hash, - V: FromPyObject<'source>, + K: FromPyObject<'py> + cmp::Eq + hash::Hash, + V: FromPyObject<'py>, S: hash::BuildHasher + Default, { - fn extract_bound(ob: &Bound<'source, PyAny>) -> Result { + fn extract_bound(ob: &Bound<'py, PyAny>) -> Result { let dict = ob.downcast::()?; let mut ret = hashbrown::HashMap::with_capacity_and_hasher(dict.len(), S::default()); for (k, v) in dict.iter() { @@ -90,12 +90,12 @@ where } } -impl<'source, K, S> FromPyObject<'source> for hashbrown::HashSet +impl<'py, K, S> FromPyObject<'py> for hashbrown::HashSet where - K: FromPyObject<'source> + cmp::Eq + hash::Hash, + K: FromPyObject<'py> + cmp::Eq + hash::Hash, S: hash::BuildHasher + Default, { - fn extract_bound(ob: &Bound<'source, PyAny>) -> PyResult { + fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { match ob.downcast::() { Ok(set) => set.iter().map(|any| any.extract()).collect(), Err(err) => { diff --git a/src/conversions/indexmap.rs b/src/conversions/indexmap.rs index 1bd638da..53f7f936 100644 --- a/src/conversions/indexmap.rs +++ b/src/conversions/indexmap.rs @@ -118,13 +118,13 @@ where } } -impl<'source, K, V, S> FromPyObject<'source> for indexmap::IndexMap +impl<'py, K, V, S> FromPyObject<'py> for indexmap::IndexMap where - K: FromPyObject<'source> + cmp::Eq + hash::Hash, - V: FromPyObject<'source>, + K: FromPyObject<'py> + cmp::Eq + hash::Hash, + V: FromPyObject<'py>, S: hash::BuildHasher + Default, { - fn extract_bound(ob: &Bound<'source, PyAny>) -> Result { + fn extract_bound(ob: &Bound<'py, PyAny>) -> Result { let dict = ob.downcast::()?; let mut ret = indexmap::IndexMap::with_capacity_and_hasher(dict.len(), S::default()); for (k, v) in dict.iter() { diff --git a/src/conversions/num_bigint.rs b/src/conversions/num_bigint.rs index 41845814..1d536623 100644 --- a/src/conversions/num_bigint.rs +++ b/src/conversions/num_bigint.rs @@ -111,8 +111,8 @@ bigint_conversion!(BigUint, 0, BigUint::to_bytes_le); bigint_conversion!(BigInt, 1, BigInt::to_signed_bytes_le); #[cfg_attr(docsrs, doc(cfg(feature = "num-bigint")))] -impl<'source> FromPyObject<'source> for BigInt { - fn extract_bound(ob: &Bound<'source, PyAny>) -> PyResult { +impl<'py> FromPyObject<'py> for BigInt { + fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { let py = ob.py(); // fast path - checking for subclass of `int` just checks a bit in the type object let num_owned: Py; @@ -159,8 +159,8 @@ impl<'source> FromPyObject<'source> for BigInt { } #[cfg_attr(docsrs, doc(cfg(feature = "num-bigint")))] -impl<'source> FromPyObject<'source> for BigUint { - fn extract_bound(ob: &Bound<'source, PyAny>) -> PyResult { +impl<'py> FromPyObject<'py> for BigUint { + fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { let py = ob.py(); // fast path - checking for subclass of `int` just checks a bit in the type object let num_owned: Py; diff --git a/src/conversions/smallvec.rs b/src/conversions/smallvec.rs index d9ed8419..ade64a51 100644 --- a/src/conversions/smallvec.rs +++ b/src/conversions/smallvec.rs @@ -54,12 +54,12 @@ where } } -impl<'a, A> FromPyObject<'a> for SmallVec +impl<'py, A> FromPyObject<'py> for SmallVec where A: Array, - A::Item: FromPyObject<'a>, + A::Item: FromPyObject<'py>, { - fn extract_bound(obj: &Bound<'a, PyAny>) -> PyResult { + fn extract_bound(obj: &Bound<'py, PyAny>) -> PyResult { if obj.is_instance_of::() { return Err(PyTypeError::new_err("Can't extract `str` to `SmallVec`")); } @@ -72,10 +72,10 @@ where } } -fn extract_sequence<'s, A>(obj: &Bound<'s, PyAny>) -> PyResult> +fn extract_sequence<'py, A>(obj: &Bound<'py, PyAny>) -> PyResult> where A: Array, - A::Item: FromPyObject<'s>, + A::Item: FromPyObject<'py>, { // Types that pass `PySequence_Check` usually implement enough of the sequence protocol // to support this function and if not, we will only fail extraction safely. diff --git a/src/conversions/std/array.rs b/src/conversions/std/array.rs index e5e1744e..0ea16713 100644 --- a/src/conversions/std/array.rs +++ b/src/conversions/std/array.rs @@ -45,18 +45,18 @@ where } } -impl<'a, T, const N: usize> FromPyObject<'a> for [T; N] +impl<'py, T, const N: usize> FromPyObject<'py> for [T; N] where - T: FromPyObject<'a>, + T: FromPyObject<'py>, { - fn extract_bound(obj: &Bound<'a, PyAny>) -> PyResult { + fn extract_bound(obj: &Bound<'py, PyAny>) -> PyResult { create_array_from_obj(obj) } } -fn create_array_from_obj<'s, T, const N: usize>(obj: &Bound<'s, PyAny>) -> PyResult<[T; N]> +fn create_array_from_obj<'py, T, const N: usize>(obj: &Bound<'py, PyAny>) -> PyResult<[T; N]> where - T: FromPyObject<'s>, + T: FromPyObject<'py>, { // Types that pass `PySequence_Check` usually implement enough of the sequence protocol // to support this function and if not, we will only fail extraction safely. diff --git a/src/conversions/std/map.rs b/src/conversions/std/map.rs index 1b47c870..1c3f669e 100644 --- a/src/conversions/std/map.rs +++ b/src/conversions/std/map.rs @@ -67,13 +67,13 @@ where } } -impl<'source, K, V, S> FromPyObject<'source> for collections::HashMap +impl<'py, K, V, S> FromPyObject<'py> for collections::HashMap where - K: FromPyObject<'source> + cmp::Eq + hash::Hash, - V: FromPyObject<'source>, + K: FromPyObject<'py> + cmp::Eq + hash::Hash, + V: FromPyObject<'py>, S: hash::BuildHasher + Default, { - fn extract_bound(ob: &Bound<'source, PyAny>) -> Result { + fn extract_bound(ob: &Bound<'py, PyAny>) -> Result { let dict = ob.downcast::()?; let mut ret = collections::HashMap::with_capacity_and_hasher(dict.len(), S::default()); for (k, v) in dict.iter() { @@ -88,12 +88,12 @@ where } } -impl<'source, K, V> FromPyObject<'source> for collections::BTreeMap +impl<'py, K, V> FromPyObject<'py> for collections::BTreeMap where - K: FromPyObject<'source> + cmp::Ord, - V: FromPyObject<'source>, + K: FromPyObject<'py> + cmp::Ord, + V: FromPyObject<'py>, { - fn extract_bound(ob: &Bound<'source, PyAny>) -> Result { + fn extract_bound(ob: &Bound<'py, PyAny>) -> Result { let dict = ob.downcast::()?; let mut ret = collections::BTreeMap::new(); for (k, v) in dict.iter() { diff --git a/src/conversions/std/num.rs b/src/conversions/std/num.rs index 1ced6cbb..82f63016 100644 --- a/src/conversions/std/num.rs +++ b/src/conversions/std/num.rs @@ -127,7 +127,7 @@ macro_rules! int_fits_c_long { } } - impl<'source> FromPyObject<'source> for $rust_type { + impl<'py> FromPyObject<'py> for $rust_type { fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult { let val: c_long = extract_int!(obj, -1, ffi::PyLong_AsLong)?; <$rust_type>::try_from(val) diff --git a/src/conversions/std/set.rs b/src/conversions/std/set.rs index 7d1b91c5..c955801a 100644 --- a/src/conversions/std/set.rs +++ b/src/conversions/std/set.rs @@ -51,12 +51,12 @@ where } } -impl<'source, K, S> FromPyObject<'source> for collections::HashSet +impl<'py, K, S> FromPyObject<'py> for collections::HashSet where - K: FromPyObject<'source> + cmp::Eq + hash::Hash, + K: FromPyObject<'py> + cmp::Eq + hash::Hash, S: hash::BuildHasher + Default, { - fn extract_bound(ob: &Bound<'source, PyAny>) -> PyResult { + fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { match ob.downcast::() { Ok(set) => set.iter().map(|any| any.extract()).collect(), Err(err) => { @@ -91,11 +91,11 @@ where } } -impl<'source, K> FromPyObject<'source> for collections::BTreeSet +impl<'py, K> FromPyObject<'py> for collections::BTreeSet where - K: FromPyObject<'source> + cmp::Ord, + K: FromPyObject<'py> + cmp::Ord, { - fn extract_bound(ob: &Bound<'source, PyAny>) -> PyResult { + fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { match ob.downcast::() { Ok(set) => set.iter().map(|any| any.extract()).collect(), Err(err) => { diff --git a/src/conversions/std/slice.rs b/src/conversions/std/slice.rs index f77cd661..62809327 100644 --- a/src/conversions/std/slice.rs +++ b/src/conversions/std/slice.rs @@ -13,8 +13,8 @@ impl<'a> IntoPy for &'a [u8] { } } -impl<'a> FromPyObject<'a> for &'a [u8] { - fn extract(obj: &'a PyAny) -> PyResult { +impl<'py> FromPyObject<'py> for &'py [u8] { + fn extract(obj: &'py PyAny) -> PyResult { Ok(obj.downcast::()?.as_bytes()) } diff --git a/src/conversions/std/string.rs b/src/conversions/std/string.rs index 2ac08855..ac29d804 100644 --- a/src/conversions/std/string.rs +++ b/src/conversions/std/string.rs @@ -114,8 +114,8 @@ impl<'a> IntoPy for &'a String { /// Allows extracting strings from Python objects. /// Accepts Python `str` and `unicode` objects. -impl<'source> FromPyObject<'source> for &'source str { - fn extract(ob: &'source PyAny) -> PyResult { +impl<'py> FromPyObject<'py> for &'py str { + fn extract(ob: &'py PyAny) -> PyResult { ob.downcast::()?.to_str() } diff --git a/src/instance.rs b/src/instance.rs index 793d0e32..92fc0185 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -996,9 +996,9 @@ impl Py { /// Extracts some type from the Python object. /// /// This is a wrapper function around `FromPyObject::extract()`. - pub fn extract<'p, D>(&'p self, py: Python<'p>) -> PyResult + pub fn extract<'py, D>(&'py self, py: Python<'py>) -> PyResult where - D: FromPyObject<'p>, + D: FromPyObject<'py>, { FromPyObject::extract(unsafe { py.from_borrowed_ptr(self.as_ptr()) }) } diff --git a/src/types/any.rs b/src/types/any.rs index 61c3c672..d79a9227 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -801,9 +801,9 @@ impl PyAny { /// /// This is a wrapper function around [`FromPyObject::extract()`]. #[inline] - pub fn extract<'a, D>(&'a self) -> PyResult + pub fn extract<'py, D>(&'py self) -> PyResult where - D: FromPyObject<'a>, + D: FromPyObject<'py>, { FromPyObject::extract(self) } diff --git a/src/types/bytes.rs b/src/types/bytes.rs index 296925dc..e0631602 100644 --- a/src/types/bytes.rs +++ b/src/types/bytes.rs @@ -203,8 +203,8 @@ impl> Index for Bound<'_, PyBytes> { /// If the source object is a `bytes` object, the `Cow` will be borrowed and /// pointing into the source object, and no copying or heap allocations will happen. /// If it is a `bytearray`, its contents will be copied to an owned `Cow`. -impl<'source> FromPyObject<'source> for Cow<'source, [u8]> { - fn extract(ob: &'source PyAny) -> PyResult { +impl<'py> FromPyObject<'py> for Cow<'py, [u8]> { + fn extract(ob: &'py PyAny) -> PyResult { if let Ok(bytes) = ob.downcast::() { return Ok(Cow::Borrowed(bytes.as_bytes())); } diff --git a/src/types/float.rs b/src/types/float.rs index fb4ca9f4..766c597b 100644 --- a/src/types/float.rs +++ b/src/types/float.rs @@ -95,10 +95,10 @@ impl IntoPy for f64 { } } -impl<'source> FromPyObject<'source> for f64 { +impl<'py> FromPyObject<'py> for f64 { // PyFloat_AsDouble returns -1.0 upon failure #![allow(clippy::float_cmp)] - fn extract_bound(obj: &Bound<'source, PyAny>) -> PyResult { + fn extract_bound(obj: &Bound<'py, PyAny>) -> PyResult { // On non-limited API, .value() uses PyFloat_AS_DOUBLE which // allows us to have an optimized fast path for the case when // we have exactly a `float` object (it's not worth going through @@ -142,8 +142,8 @@ impl IntoPy for f32 { } } -impl<'source> FromPyObject<'source> for f32 { - fn extract_bound(obj: &Bound<'source, PyAny>) -> PyResult { +impl<'py> FromPyObject<'py> for f32 { + fn extract_bound(obj: &Bound<'py, PyAny>) -> PyResult { Ok(obj.extract::()? as f32) } diff --git a/src/types/sequence.rs b/src/types/sequence.rs index 28a6fd48..19f6846b 100644 --- a/src/types/sequence.rs +++ b/src/types/sequence.rs @@ -479,11 +479,11 @@ fn sequence_slice(seq: &PySequence, start: usize, end: usize) -> &PySequence { index_impls!(PySequence, "sequence", sequence_len, sequence_slice); -impl<'a, T> FromPyObject<'a> for Vec +impl<'py, T> FromPyObject<'py> for Vec where - T: FromPyObject<'a>, + T: FromPyObject<'py>, { - fn extract_bound(obj: &Bound<'a, PyAny>) -> PyResult { + fn extract_bound(obj: &Bound<'py, PyAny>) -> PyResult { if obj.is_instance_of::() { return Err(PyTypeError::new_err("Can't extract `str` to `Vec`")); } @@ -496,9 +496,9 @@ where } } -fn extract_sequence<'s, T>(obj: &Bound<'s, PyAny>) -> PyResult> +fn extract_sequence<'py, T>(obj: &Bound<'py, PyAny>) -> PyResult> where - T: FromPyObject<'s>, + T: FromPyObject<'py>, { // Types that pass `PySequence_Check` usually implement enough of the sequence protocol // to support this function and if not, we will only fail extraction safely. diff --git a/src/types/tuple.rs b/src/types/tuple.rs index 26bd698c..a8737c25 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -666,8 +666,8 @@ fn type_output() -> TypeInfo { } } - impl<'s, $($T: FromPyObject<'s>),+> FromPyObject<'s> for ($($T,)+) { - fn extract_bound(obj: &Bound<'s, PyAny>) -> PyResult + impl<'py, $($T: FromPyObject<'py>),+> FromPyObject<'py> for ($($T,)+) { + fn extract_bound(obj: &Bound<'py, PyAny>) -> PyResult { let t = obj.downcast::()?; if t.len() == $length {