Use the new bound API instead of .as_ref(py) (#3853)

* Use the new bound API instead of .as_ref(py)

* Move import into a nested scope

* Use to_cow instead of to_str for compatibility

`to_str` is not available before Python 3.10 on the limited api.

* Relax &self lifetimes

* Use Bound<'py, PyAny> in test Mapping signatures

* Use .as_bytes(py)

* Simplify ThrowCallback::throw signature

* Avoid .as_any call with Py api instead of Bound
This commit is contained in:
Lily Foote 2024-02-18 00:09:56 +00:00 committed by GitHub
parent 5f42c02e4f
commit 0dd568d397
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 71 additions and 62 deletions

View File

@ -87,7 +87,8 @@ mod test_ipaddr {
};
let pyobj = ip.into_py(py);
let repr = pyobj.as_ref(py).repr().unwrap().to_string_lossy();
let repr = pyobj.bind(py).repr().unwrap();
let repr = repr.to_string_lossy();
assert_eq!(repr, format!("{}('{}')", py_cls, ip));
let ip2: IpAddr = pyobj.extract(py).unwrap();

View File

@ -68,13 +68,11 @@ impl FromPyObject<'_> for OsString {
// Create an OsStr view into the raw bytes from Python
#[cfg(target_os = "wasi")]
let os_str: &OsStr = std::os::wasi::ffi::OsStrExt::from_bytes(
fs_encoded_bytes.as_ref(ob.py()).as_bytes(),
);
let os_str: &OsStr =
std::os::wasi::ffi::OsStrExt::from_bytes(fs_encoded_bytes.as_bytes(ob.py()));
#[cfg(not(target_os = "wasi"))]
let os_str: &OsStr = std::os::unix::ffi::OsStrExt::from_bytes(
fs_encoded_bytes.as_ref(ob.py()).as_bytes(),
);
let os_str: &OsStr =
std::os::unix::ffi::OsStrExt::from_bytes(fs_encoded_bytes.as_bytes(ob.py()));
Ok(os_str.to_os_string())
}

View File

@ -94,10 +94,10 @@ mod tests {
.unwrap_err();
let cow = Cow::<[u8]>::Borrowed(b"foobar").to_object(py);
assert!(cow.as_ref(py).is_instance_of::<PyBytes>());
assert!(cow.bind(py).is_instance_of::<PyBytes>());
let cow = Cow::<[u8]>::Owned(b"foobar".to_vec()).to_object(py);
assert!(cow.as_ref(py).is_instance_of::<PyBytes>());
assert!(cow.bind(py).is_instance_of::<PyBytes>());
});
}
}

View File

@ -159,6 +159,7 @@ impl FromPyObject<'_> for char {
#[cfg(test)]
mod tests {
use crate::types::any::PyAnyMethods;
use crate::Python;
use crate::{IntoPy, PyObject, ToPyObject};
use std::borrow::Cow;
@ -200,7 +201,7 @@ mod tests {
let s = "Hello Python";
let py_string = s.to_object(py);
let s2: &str = py_string.as_ref(py).extract().unwrap();
let s2: &str = py_string.bind(py).extract().unwrap();
assert_eq!(s, s2);
})
}
@ -210,7 +211,7 @@ mod tests {
Python::with_gil(|py| {
let ch = '😃';
let py_string = ch.to_object(py);
let ch2: char = py_string.as_ref(py).extract().unwrap();
let ch2: char = py_string.bind(py).extract().unwrap();
assert_eq!(ch, ch2);
})
}
@ -220,7 +221,7 @@ mod tests {
Python::with_gil(|py| {
let s = "Hello Python";
let py_string = s.to_object(py);
let err: crate::PyResult<char> = py_string.as_ref(py).extract();
let err: crate::PyResult<char> = py_string.bind(py).extract();
assert!(err
.unwrap_err()
.to_string()

View File

@ -14,8 +14,8 @@ use crate::{
coroutine::{cancel::ThrowCallback, waker::AsyncioWaker},
exceptions::{PyAttributeError, PyRuntimeError, PyStopIteration},
panic::PanicException,
types::{PyIterator, PyString},
IntoPy, Py, PyAny, PyErr, PyNativeType, PyObject, PyResult, Python,
types::{string::PyStringMethods, PyIterator, PyString},
IntoPy, Py, PyAny, PyErr, PyObject, PyResult, Python,
};
pub(crate) mod cancel;
@ -75,7 +75,7 @@ impl Coroutine {
};
// reraise thrown exception it
match (throw, &self.throw_callback) {
(Some(exc), Some(cb)) => cb.throw(exc.as_ref(py)),
(Some(exc), Some(cb)) => cb.throw(exc),
(Some(exc), None) => {
self.close();
return Err(PyErr::from_value_bound(exc.into_bound(py)));
@ -135,7 +135,7 @@ impl Coroutine {
#[getter]
fn __qualname__(&self, py: Python<'_>) -> PyResult<Py<PyString>> {
match (&self.name, &self.qualname_prefix) {
(Some(name), Some(prefix)) => Ok(format!("{}.{}", prefix, name.as_ref(py).to_str()?)
(Some(name), Some(prefix)) => Ok(format!("{}.{}", prefix, name.bind(py).to_cow()?)
.as_str()
.into_py(py)),
(Some(name), None) => Ok(name.clone_ref(py)),

View File

@ -1,4 +1,4 @@
use crate::{PyAny, PyObject};
use crate::{Py, PyAny, PyObject};
use parking_lot::Mutex;
use std::future::Future;
use std::pin::Pin;
@ -68,9 +68,9 @@ impl Future for Cancelled<'_> {
pub struct ThrowCallback(Arc<Mutex<Inner>>);
impl ThrowCallback {
pub(super) fn throw(&self, exc: &PyAny) {
pub(super) fn throw(&self, exc: Py<PyAny>) {
let mut inner = self.0.lock();
inner.exception = Some(exc.into());
inner.exception = Some(exc);
if let Some(waker) = inner.waker.take() {
waker.wake();
}

View File

@ -1,7 +1,7 @@
use crate::sync::GILOnceCell;
use crate::types::any::PyAnyMethods;
use crate::types::PyCFunction;
use crate::{intern, wrap_pyfunction, Py, PyAny, PyObject, PyResult, Python};
use crate::{intern, wrap_pyfunction, Bound, Py, PyAny, PyObject, PyResult, Python};
use pyo3_macros::pyfunction;
use std::sync::Arc;
use std::task::Wake;
@ -25,10 +25,13 @@ impl AsyncioWaker {
self.0.take();
}
pub(super) fn initialize_future<'a>(&'a self, py: Python<'a>) -> PyResult<Option<&'a PyAny>> {
pub(super) fn initialize_future<'py>(
&self,
py: Python<'py>,
) -> PyResult<Option<&Bound<'py, PyAny>>> {
let init = || LoopAndFuture::new(py).map(Some);
let loop_and_future = self.0.get_or_try_init(py, init)?.as_ref();
Ok(loop_and_future.map(|LoopAndFuture { future, .. }| future.as_ref(py)))
Ok(loop_and_future.map(|LoopAndFuture { future, .. }| future.bind(py)))
}
}
@ -74,7 +77,7 @@ impl LoopAndFuture {
let call_soon_threadsafe = self.event_loop.call_method1(
py,
intern!(py, "call_soon_threadsafe"),
(release_waiter, self.future.as_ref(py)),
(release_waiter, self.future.bind(py)),
);
if let Err(err) = call_soon_threadsafe {
// `call_soon_threadsafe` will raise if the event loop is closed;

View File

@ -2,6 +2,7 @@ use crate::instance::Bound;
use crate::panic::PanicException;
use crate::type_object::PyTypeInfo;
use crate::types::any::PyAnyMethods;
use crate::types::string::PyStringMethods;
use crate::types::{PyTraceback, PyType};
use crate::{
exceptions::{self, PyBaseException},
@ -403,7 +404,7 @@ impl PyErr {
if ptype.as_ptr() == PanicException::type_object_raw(py).cast() {
let msg = pvalue
.as_ref()
.and_then(|obj| obj.as_ref(py).str().ok())
.and_then(|obj| obj.bind(py).str().ok())
.map(|py_str| py_str.to_string_lossy().into())
.unwrap_or_else(|| String::from("Unwrapped panic from Python code"));
@ -425,7 +426,7 @@ impl PyErr {
#[cfg(Py_3_12)]
fn _take(py: Python<'_>) -> Option<PyErr> {
let state = PyErrStateNormalized::take(py)?;
let pvalue = state.pvalue.as_ref(py);
let pvalue = state.pvalue.bind(py);
if pvalue.get_type().as_ptr() == PanicException::type_object_raw(py).cast() {
let msg: String = pvalue
.str()
@ -905,7 +906,6 @@ impl std::fmt::Debug for PyErr {
impl std::fmt::Display for PyErr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use crate::types::string::PyStringMethods;
Python::with_gil(|py| {
let value = self.value_bound(py);
let type_name = value.get_type().qualname().map_err(|_| std::fmt::Error)?;

View File

@ -989,7 +989,7 @@ where
/// Panics if the value is currently mutably borrowed. For a non-panicking variant, use
/// [`try_borrow`](#method.try_borrow).
pub fn borrow<'py>(&'py self, py: Python<'py>) -> PyRef<'py, T> {
self.as_ref(py).borrow()
self.bind(py).borrow()
}
/// Mutably borrows the value `T`.
@ -1028,7 +1028,7 @@ where
where
T: PyClass<Frozen = False>,
{
self.as_ref(py).borrow_mut()
self.bind(py).borrow_mut()
}
/// Attempts to immutably borrow the value `T`, returning an error if the value is currently mutably borrowed.
@ -1042,7 +1042,7 @@ where
/// Equivalent to `self.as_ref(py).borrow_mut()` -
/// see [`PyCell::try_borrow`](crate::pycell::PyCell::try_borrow).
pub fn try_borrow<'py>(&'py self, py: Python<'py>) -> Result<PyRef<'py, T>, PyBorrowError> {
self.as_ref(py).try_borrow()
self.bind(py).try_borrow()
}
/// Attempts to mutably borrow the value `T`, returning an error if the value is currently borrowed.
@ -1060,7 +1060,7 @@ where
where
T: PyClass<Frozen = False>,
{
self.as_ref(py).try_borrow_mut()
self.bind(py).try_borrow_mut()
}
/// Provide an immutable borrow of the value `T` without acquiring the GIL.
@ -1667,7 +1667,7 @@ where
T::AsRefTarget: std::fmt::Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Python::with_gil(|py| std::fmt::Display::fmt(self.as_ref(py), f))
Python::with_gil(|py| std::fmt::Display::fmt(self.bind(py), f))
}
}

View File

@ -96,7 +96,7 @@
//!
//! // We borrow the guard and then dereference
//! // it to get a mutable reference to Number
//! let mut guard: PyRefMut<'_, Number> = n.as_ref(py).borrow_mut();
//! let mut guard: PyRefMut<'_, Number> = n.bind(py).borrow_mut();
//! let n_mutable: &mut Number = &mut *guard;
//!
//! n_mutable.increment();
@ -105,7 +105,7 @@
//! // `PyRefMut` before borrowing again.
//! drop(guard);
//!
//! let n_immutable: &Number = &n.as_ref(py).borrow();
//! let n_immutable: &Number = &n.bind(py).borrow();
//! assert_eq!(n_immutable.inner, 1);
//!
//! Ok(())

View File

@ -491,7 +491,7 @@ mod tests {
});
Python::with_gil(|py| {
let f = unsafe { cap.as_ref(py).reference::<fn(u32) -> u32>() };
let f = unsafe { cap.bind(py).reference::<fn(u32) -> u32>() };
assert_eq!(f(123), 123);
});
}
@ -555,7 +555,7 @@ mod tests {
});
Python::with_gil(|py| {
let ctx: &Vec<u8> = unsafe { cap.as_ref(py).reference() };
let ctx: &Vec<u8> = unsafe { cap.bind(py).reference() };
assert_eq!(ctx, &[1, 2, 3, 4]);
})
}
@ -574,7 +574,7 @@ mod tests {
});
Python::with_gil(|py| {
let ctx_ptr: *mut c_void = cap.as_ref(py).context().unwrap();
let ctx_ptr: *mut c_void = cap.bind(py).context().unwrap();
let ctx = unsafe { *Box::from_raw(ctx_ptr.cast::<&Vec<u8>>()) };
assert_eq!(ctx, &vec![1_u8, 2, 3, 4]);
})

View File

@ -235,7 +235,7 @@ fn test_unsendable<T: PyClass + 'static>() -> PyResult<()> {
// Accessing the value inside this thread should not panic
let caught_panic =
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| -> PyResult<_> {
assert_eq!(obj.as_ref(py).getattr("value")?.extract::<usize>()?, 5);
assert_eq!(obj.getattr(py, "value")?.extract::<usize>(py)?, 5);
Ok(())
}))
.is_err();

View File

@ -89,7 +89,7 @@ fn test_polymorphic_container_stores_sub_class() {
.unwrap()
.to_object(py);
p.as_ref(py)
p.bind(py)
.setattr(
"inner",
PyCell::new(
@ -116,7 +116,7 @@ fn test_polymorphic_container_does_not_accept_other_types() {
.unwrap()
.to_object(py);
let setattr = |value: PyObject| p.as_ref(py).setattr("inner", value);
let setattr = |value: PyObject| p.bind(py).setattr("inner", value);
assert!(setattr(1i32.into_py(py)).is_err());
assert!(setattr(py.None()).is_err());

View File

@ -22,8 +22,14 @@ fn test_cfg() {
Python::with_gil(|py| {
let cfg = CfgClass { b: 3 };
let py_cfg = Py::new(py, cfg).unwrap();
assert!(py_cfg.as_ref(py).getattr("a").is_err());
let b: u32 = py_cfg.as_ref(py).getattr("b").unwrap().extract().unwrap();
assert!(py_cfg.bind(py).as_any().getattr("a").is_err());
let b: u32 = py_cfg
.bind(py)
.as_any()
.getattr("b")
.unwrap()
.extract()
.unwrap();
assert_eq!(b, 3);
});
}

View File

@ -247,7 +247,7 @@ mod inheriting_native_type {
let item = &py.eval_bound("object()", None, None).unwrap();
assert_eq!(item.get_refcnt(), 1);
dict_sub.as_ref(py).set_item("foo", item).unwrap();
dict_sub.bind(py).as_any().set_item("foo", item).unwrap();
assert_eq!(item.get_refcnt(), 2);
drop(dict_sub);

View File

@ -123,7 +123,7 @@ fn mapping_is_not_sequence() {
PyMapping::register::<Mapping>(py).unwrap();
assert!(m.as_ref(py).downcast::<PyMapping>().is_ok());
assert!(m.as_ref(py).downcast::<PySequence>().is_err());
assert!(m.bind(py).as_any().downcast::<PyMapping>().is_ok());
assert!(m.bind(py).as_any().downcast::<PySequence>().is_err());
});
}

View File

@ -191,20 +191,20 @@ pub struct Mapping {
#[pymethods]
impl Mapping {
fn __len__(&self, py: Python<'_>) -> usize {
self.values.as_ref(py).len()
self.values.bind(py).len()
}
fn __getitem__<'a>(&'a self, key: &'a PyAny) -> PyResult<&'a PyAny> {
let any: &PyAny = self.values.as_ref(key.py()).as_ref();
fn __getitem__<'py>(&self, key: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
let any: &Bound<'py, PyAny> = self.values.bind(key.py());
any.get_item(key)
}
fn __setitem__(&self, key: &PyAny, value: &PyAny) -> PyResult<()> {
self.values.as_ref(key.py()).set_item(key, value)
fn __setitem__<'py>(&self, key: &Bound<'py, PyAny>, value: &Bound<'py, PyAny>) -> PyResult<()> {
self.values.bind(key.py()).set_item(key, value)
}
fn __delitem__(&self, key: &PyAny) -> PyResult<()> {
self.values.as_ref(key.py()).del_item(key)
fn __delitem__(&self, key: &Bound<'_, PyAny>) -> PyResult<()> {
self.values.bind(key.py()).del_item(key)
}
}
@ -221,7 +221,7 @@ fn mapping() {
)
.unwrap();
let mapping: &PyMapping = inst.as_ref(py).downcast().unwrap();
let mapping: &Bound<'_, PyMapping> = inst.bind(py).as_any().downcast().unwrap();
py_assert!(py, inst, "len(inst) == 0");
@ -323,7 +323,7 @@ fn sequence() {
let inst = Py::new(py, Sequence { values: vec![] }).unwrap();
let sequence: &PySequence = inst.as_ref(py).downcast().unwrap();
let sequence: &Bound<'_, PySequence> = inst.bind(py).as_any().downcast().unwrap();
py_assert!(py, inst, "len(inst) == 0");
@ -350,16 +350,16 @@ fn sequence() {
// indices.
assert!(sequence.len().is_err());
// however regular python len() works thanks to mp_len slot
assert_eq!(inst.as_ref(py).len().unwrap(), 0);
assert_eq!(inst.bind(py).as_any().len().unwrap(), 0);
py_run!(py, inst, "inst.append(0)");
sequence.set_item(0, 5).unwrap();
assert_eq!(inst.as_ref(py).len().unwrap(), 1);
assert_eq!(inst.bind(py).as_any().len().unwrap(), 1);
assert_eq!(sequence.get_item(0).unwrap().extract::<u8>().unwrap(), 5);
sequence.del_item(0).unwrap();
assert_eq!(inst.as_ref(py).len().unwrap(), 0);
assert_eq!(inst.bind(py).as_any().len().unwrap(), 0);
});
}
@ -658,10 +658,10 @@ impl OnceFuture {
fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {
slf
}
fn __next__<'py>(&'py mut self, py: Python<'py>) -> Option<&'py PyAny> {
fn __next__<'py>(&mut self, py: Python<'py>) -> Option<&Bound<'py, PyAny>> {
if !self.polled {
self.polled = true;
Some(self.future.as_ref(py))
Some(self.future.bind(py))
} else {
None
}

View File

@ -63,12 +63,12 @@ impl Iter {
}
fn __next__(mut slf: PyRefMut<'_, Self>) -> PyResult<Option<PyObject>> {
let bytes = slf.keys.as_ref(slf.py()).as_bytes();
let bytes = slf.keys.bind(slf.py()).as_bytes();
match bytes.get(slf.idx) {
Some(&b) => {
slf.idx += 1;
let py = slf.py();
let reader = slf.reader.as_ref(py);
let reader = slf.reader.bind(py);
let reader_ref = reader.try_borrow()?;
let res = reader_ref
.inner

View File

@ -276,7 +276,7 @@ fn test_generic_list_set() {
.items
.iter()
.zip(&[1u32, 2, 3])
.all(|(a, b)| a.as_ref(py).eq(&b.into_py(py)).unwrap()));
.all(|(a, b)| a.bind(py).eq(&b.into_py(py)).unwrap()));
});
}

View File

@ -31,7 +31,7 @@ fn mut_ref_arg() {
let inst2 = Py::new(py, MutRefArg { n: 0 }).unwrap();
py_run!(py, inst1 inst2, "inst1.set_other(inst2)");
let inst2 = inst2.as_ref(py).borrow();
let inst2 = inst2.bind(py).borrow();
assert_eq!(inst2.n, 100);
});
}