implement `PyErr::write_unraisable_bound`

This commit is contained in:
David Hewitt 2023-12-24 14:49:43 +00:00
parent 7d245842d4
commit 877e34ac86
9 changed files with 32 additions and 15 deletions

View File

@ -42,6 +42,7 @@
//! } //! }
//! ``` //! ```
use crate::exceptions::{PyTypeError, PyUserWarning, PyValueError}; use crate::exceptions::{PyTypeError, PyUserWarning, PyValueError};
use crate::instance::Bound;
#[cfg(Py_LIMITED_API)] #[cfg(Py_LIMITED_API)]
use crate::sync::GILOnceCell; use crate::sync::GILOnceCell;
#[cfg(not(Py_LIMITED_API))] #[cfg(not(Py_LIMITED_API))]
@ -465,7 +466,7 @@ fn warn_truncated_leap_second(obj: &PyAny) {
"ignored leap-second, `datetime` does not support leap-seconds", "ignored leap-second, `datetime` does not support leap-seconds",
0, 0,
) { ) {
e.write_unraisable(py, Some(obj)) e.write_unraisable_bound(py, Some(Bound::borrowed_from_gil_ref(&obj)))
}; };
} }

View File

@ -535,6 +535,16 @@ impl PyErr {
.restore(py) .restore(py)
} }
/// Deprecated form of `PyErr::write_unraisable_bound`.
#[deprecated(
since = "0.21.0",
note = "`PyErr::write_unraisable` will be replaced by `PyErr::write_unraisable_bound` in a future PyO3 version"
)]
#[inline]
pub fn write_unraisable(self, py: Python<'_>, obj: Option<&PyAny>) {
self.write_unraisable_bound(py, obj.as_ref().map(Bound::borrowed_from_gil_ref))
}
/// Reports the error as unraisable. /// Reports the error as unraisable.
/// ///
/// This calls `sys.unraisablehook()` using the current exception and obj argument. /// This calls `sys.unraisablehook()` using the current exception and obj argument.
@ -557,16 +567,16 @@ impl PyErr {
/// # fn main() -> PyResult<()> { /// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| { /// Python::with_gil(|py| {
/// match failing_function() { /// match failing_function() {
/// Err(pyerr) => pyerr.write_unraisable(py, None), /// Err(pyerr) => pyerr.write_unraisable_bound(py, None),
/// Ok(..) => { /* do something here */ } /// Ok(..) => { /* do something here */ }
/// } /// }
/// Ok(()) /// Ok(())
/// }) /// })
/// # } /// # }
#[inline] #[inline]
pub fn write_unraisable(self, py: Python<'_>, obj: Option<&PyAny>) { pub fn write_unraisable_bound(self, py: Python<'_>, obj: Option<&Bound<'_, PyAny>>) {
self.restore(py); self.restore(py);
unsafe { ffi::PyErr_WriteUnraisable(obj.map_or(std::ptr::null_mut(), |x| x.as_ptr())) } unsafe { ffi::PyErr_WriteUnraisable(obj.map_or(std::ptr::null_mut(), Bound::as_ptr)) }
} }
/// Issues a warning message. /// Issues a warning message.

View File

@ -1067,7 +1067,7 @@ impl ThreadCheckerImpl {
"{} is unsendable, but is being dropped on another thread", "{} is unsendable, but is being dropped on another thread",
type_name type_name
)) ))
.write_unraisable(py, None); .write_unraisable_bound(py, None);
return false; return false;
} }

View File

@ -10,8 +10,8 @@ use std::{
}; };
use crate::{ use crate::{
callback::PyCallbackOutput, ffi, impl_::panic::PanicTrap, methods::IPowModulo, callback::PyCallbackOutput, ffi, ffi_ptr_ext::FfiPtrExt, impl_::panic::PanicTrap,
panic::PanicException, types::PyModule, GILPool, Py, PyResult, Python, methods::IPowModulo, panic::PanicException, types::PyModule, GILPool, Py, PyResult, Python,
}; };
#[inline] #[inline]
@ -224,7 +224,7 @@ where
if let Err(py_err) = panic::catch_unwind(move || body(py)) if let Err(py_err) = panic::catch_unwind(move || body(py))
.unwrap_or_else(|payload| Err(PanicException::from_panic_payload(payload))) .unwrap_or_else(|payload| Err(PanicException::from_panic_payload(payload)))
{ {
py_err.write_unraisable(py, py.from_borrowed_ptr_or_opt(ctx)); py_err.write_unraisable_bound(py, ctx.assume_borrowed_or_opt(py).as_deref());
} }
trap.disarm(); trap.disarm();
} }

View File

@ -3,6 +3,7 @@ use crate::pycell::{PyBorrowError, PyBorrowMutError, PyCell};
use crate::pyclass::boolean_struct::{False, True}; use crate::pyclass::boolean_struct::{False, True};
use crate::type_object::HasPyGilRef; use crate::type_object::HasPyGilRef;
use crate::types::any::PyAnyMethods; use crate::types::any::PyAnyMethods;
use crate::types::string::PyStringMethods;
use crate::types::{PyDict, PyString, PyTuple}; use crate::types::{PyDict, PyString, PyTuple};
use crate::{ use crate::{
ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyClass, PyClassInitializer, PyRef, PyRefMut, ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyClass, PyClassInitializer, PyRef, PyRefMut,
@ -97,10 +98,8 @@ fn python_format(
f: &mut std::fmt::Formatter<'_>, f: &mut std::fmt::Formatter<'_>,
) -> Result<(), std::fmt::Error> { ) -> Result<(), std::fmt::Error> {
match format_result { match format_result {
Result::Ok(s) => return f.write_str(&s.as_gil_ref().to_string_lossy()), Result::Ok(s) => return f.write_str(&s.to_string_lossy()),
Result::Err(err) => { Result::Err(err) => err.write_unraisable_bound(any.py(), Some(any)),
err.write_unraisable(any.py(), std::option::Option::Some(any.as_gil_ref()))
}
} }
match any.get_type().name() { match any.get_type().name() {

View File

@ -257,7 +257,10 @@ impl PyTypeCheck for PyMapping {
|| get_mapping_abc(object.py()) || get_mapping_abc(object.py())
.and_then(|abc| object.is_instance(abc)) .and_then(|abc| object.is_instance(abc))
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
err.write_unraisable(object.py(), Some(object)); err.write_unraisable_bound(
object.py(),
Some(Bound::borrowed_from_gil_ref(&object)),
);
false false
}) })
} }

View File

@ -107,7 +107,7 @@ macro_rules! pyobject_native_type_base(
{ {
match self.str() { match self.str() {
::std::result::Result::Ok(s) => return f.write_str(&s.to_string_lossy()), ::std::result::Result::Ok(s) => return f.write_str(&s.to_string_lossy()),
::std::result::Result::Err(err) => err.write_unraisable(self.py(), ::std::option::Option::Some(self)), ::std::result::Result::Err(err) => err.write_unraisable_bound(self.py(), ::std::option::Option::Some($crate::Bound::borrowed_from_gil_ref(&self))),
} }
match self.get_type().name() { match self.get_type().name() {

View File

@ -541,7 +541,10 @@ impl PyTypeCheck for PySequence {
|| get_sequence_abc(object.py()) || get_sequence_abc(object.py())
.and_then(|abc| object.is_instance(abc)) .and_then(|abc| object.is_instance(abc))
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
err.write_unraisable(object.py(), Some(object)); err.write_unraisable_bound(
object.py(),
Some(Bound::borrowed_from_gil_ref(&object)),
);
false false
}) })
} }

View File

@ -100,6 +100,7 @@ fn test_exception_nosegfault() {
#[test] #[test]
#[cfg(Py_3_8)] #[cfg(Py_3_8)]
#[allow(deprecated)]
fn test_write_unraisable() { fn test_write_unraisable() {
use common::UnraisableCapture; use common::UnraisableCapture;
use pyo3::{exceptions::PyRuntimeError, ffi}; use pyo3::{exceptions::PyRuntimeError, ffi};