diff --git a/guide/src/python_from_rust.md b/guide/src/python_from_rust.md index 1ac1a7c2..0b412c87 100644 --- a/guide/src/python_from_rust.md +++ b/guide/src/python_from_rust.md @@ -479,7 +479,7 @@ class House(object): } Err(e) => { house - .call_method1("__exit__", (e.get_type_bound(py), e.value(py), e.traceback_bound(py))) + .call_method1("__exit__", (e.get_type_bound(py), e.value_bound(py), e.traceback_bound(py))) .unwrap(); } } diff --git a/src/conversions/anyhow.rs b/src/conversions/anyhow.rs index 453799c6..a490bd4c 100644 --- a/src/conversions/anyhow.rs +++ b/src/conversions/anyhow.rs @@ -149,7 +149,7 @@ mod test_anyhow { Python::with_gil(|py| { let locals = [("err", pyerr)].into_py_dict_bound(py); let pyerr = py.run_bound("raise err", None, Some(&locals)).unwrap_err(); - assert_eq!(pyerr.value(py).to_string(), expected_contents); + assert_eq!(pyerr.value_bound(py).to_string(), expected_contents); }) } @@ -166,7 +166,7 @@ mod test_anyhow { Python::with_gil(|py| { let locals = [("err", pyerr)].into_py_dict_bound(py); let pyerr = py.run_bound("raise err", None, Some(&locals)).unwrap_err(); - assert_eq!(pyerr.value(py).to_string(), expected_contents); + assert_eq!(pyerr.value_bound(py).to_string(), expected_contents); }) } diff --git a/src/conversions/chrono.rs b/src/conversions/chrono.rs index d67818e6..6737c16f 100644 --- a/src/conversions/chrono.rs +++ b/src/conversions/chrono.rs @@ -590,7 +590,7 @@ mod tests { assert!(result.is_err()); let res = result.err().unwrap(); // Also check the error message is what we expect - let msg = res.value(py).repr().unwrap().to_string(); + let msg = res.value_bound(py).repr().unwrap().to_string(); assert_eq!(msg, "TypeError(\"zoneinfo.ZoneInfo(key='Europe/London') is not a fixed offset timezone\")"); }); } @@ -605,7 +605,7 @@ mod tests { // Now test that converting a PyDateTime with tzinfo to a NaiveDateTime fails let res: PyResult = py_datetime.extract(); assert_eq!( - res.unwrap_err().value(py).repr().unwrap().to_string(), + res.unwrap_err().value_bound(py).repr().unwrap().to_string(), "TypeError('expected a datetime without tzinfo')" ); }); @@ -620,14 +620,14 @@ mod tests { // Now test that converting a PyDateTime with tzinfo to a NaiveDateTime fails let res: PyResult> = py_datetime.extract(); assert_eq!( - res.unwrap_err().value(py).repr().unwrap().to_string(), + res.unwrap_err().value_bound(py).repr().unwrap().to_string(), "TypeError('expected a datetime with non-None tzinfo')" ); // Now test that converting a PyDateTime with tzinfo to a NaiveDateTime fails let res: PyResult> = py_datetime.extract(); assert_eq!( - res.unwrap_err().value(py).repr().unwrap().to_string(), + res.unwrap_err().value_bound(py).repr().unwrap().to_string(), "TypeError('expected a datetime with non-None tzinfo')" ); }); diff --git a/src/conversions/eyre.rs b/src/conversions/eyre.rs index d25a10af..64ed4a03 100644 --- a/src/conversions/eyre.rs +++ b/src/conversions/eyre.rs @@ -154,7 +154,7 @@ mod tests { Python::with_gil(|py| { let locals = [("err", pyerr)].into_py_dict_bound(py); let pyerr = py.run_bound("raise err", None, Some(&locals)).unwrap_err(); - assert_eq!(pyerr.value(py).to_string(), expected_contents); + assert_eq!(pyerr.value_bound(py).to_string(), expected_contents); }) } @@ -171,7 +171,7 @@ mod tests { Python::with_gil(|py| { let locals = [("err", pyerr)].into_py_dict_bound(py); let pyerr = py.run_bound("raise err", None, Some(&locals)).unwrap_err(); - assert_eq!(pyerr.value(py).to_string(), expected_contents); + assert_eq!(pyerr.value_bound(py).to_string(), expected_contents); }) } diff --git a/src/coroutine.rs b/src/coroutine.rs index c4b5ddf3..3a0df983 100644 --- a/src/coroutine.rs +++ b/src/coroutine.rs @@ -78,7 +78,7 @@ impl Coroutine { (Some(exc), Some(cb)) => cb.throw(exc.as_ref(py)), (Some(exc), None) => { self.close(); - return Err(PyErr::from_value(exc.as_ref(py))); + return Err(PyErr::from_value_bound(exc.into_bound(py))); } (None, _) => {} } diff --git a/src/err/err_state.rs b/src/err/err_state.rs index 863b2763..eb03d8b9 100644 --- a/src/err/err_state.rs +++ b/src/err/err_state.rs @@ -101,19 +101,20 @@ where } impl PyErrState { - pub(crate) fn lazy(ptype: &PyAny, args: impl PyErrArguments + 'static) -> Self { - let ptype = ptype.into(); + pub(crate) fn lazy(ptype: Py, args: impl PyErrArguments + 'static) -> Self { PyErrState::Lazy(Box::new(move |py| PyErrStateLazyFnOutput { ptype, pvalue: args.arguments(py), })) } - pub(crate) fn normalized(pvalue: &PyBaseException) -> Self { + pub(crate) fn normalized(pvalue: Bound<'_, PyBaseException>) -> Self { + #[cfg(not(Py_3_12))] + use crate::types::any::PyAnyMethods; + Self::Normalized(PyErrStateNormalized { #[cfg(not(Py_3_12))] ptype: pvalue.get_type().into(), - pvalue: pvalue.into(), #[cfg(not(Py_3_12))] ptraceback: unsafe { Py::from_owned_ptr_or_opt( @@ -121,6 +122,7 @@ impl PyErrState { ffi::PyException_GetTraceback(pvalue.as_ptr()), ) }, + pvalue: pvalue.into(), }) } diff --git a/src/err/impls.rs b/src/err/impls.rs index f49ac3eb..f14a839b 100644 --- a/src/err/impls.rs +++ b/src/err/impls.rs @@ -124,6 +124,8 @@ mod tests { #[test] fn io_errors() { + use crate::types::any::PyAnyMethods; + let check_err = |kind, expected_ty| { Python::with_gil(|py| { let rust_err = io::Error::new(kind, "some error msg"); @@ -139,8 +141,8 @@ mod tests { let py_err_recovered_from_rust_err: PyErr = rust_err_from_py_err.into(); assert!(py_err_recovered_from_rust_err - .value(py) - .is(py_error_clone.value(py))); // It should be the same exception + .value_bound(py) + .is(py_error_clone.value_bound(py))); // It should be the same exception }) }; diff --git a/src/err/mod.rs b/src/err/mod.rs index b5e72a71..b5cd02c0 100644 --- a/src/err/mod.rs +++ b/src/err/mod.rs @@ -187,7 +187,19 @@ impl PyErr { where A: PyErrArguments + Send + Sync + 'static, { - PyErr::from_state(PyErrState::lazy(ty, args)) + PyErr::from_state(PyErrState::lazy(ty.into(), args)) + } + + /// Deprecated form of [`PyErr::from_value_bound`]. + #[cfg_attr( + not(feature = "gil-refs"), + deprecated( + since = "0.21.0", + note = "`PyErr::from_value` will be replaced by `PyErr::from_value_bound` in a future PyO3 version" + ) + )] + pub fn from_value(obj: &PyAny) -> PyErr { + PyErr::from_value_bound(obj.as_borrowed().to_owned()) } /// Creates a new PyErr. @@ -201,33 +213,38 @@ impl PyErr { /// # Examples /// ```rust /// use pyo3::prelude::*; + /// use pyo3::PyTypeInfo; /// use pyo3::exceptions::PyTypeError; - /// use pyo3::types::{PyType, PyString}; + /// use pyo3::types::PyString; /// /// Python::with_gil(|py| { /// // Case #1: Exception object - /// let err = PyErr::from_value(PyTypeError::new_err("some type error").value(py)); + /// let err = PyErr::from_value_bound(PyTypeError::new_err("some type error") + /// .value_bound(py).clone().into_any()); /// assert_eq!(err.to_string(), "TypeError: some type error"); /// /// // Case #2: Exception type - /// let err = PyErr::from_value(PyType::new::(py)); + /// let err = PyErr::from_value_bound(PyTypeError::type_object_bound(py).into_any()); /// assert_eq!(err.to_string(), "TypeError: "); /// /// // Case #3: Invalid exception value - /// let err = PyErr::from_value(PyString::new_bound(py, "foo").as_gil_ref()); + /// let err = PyErr::from_value_bound(PyString::new_bound(py, "foo").into_any()); /// assert_eq!( /// err.to_string(), /// "TypeError: exceptions must derive from BaseException" /// ); /// }); /// ``` - pub fn from_value(obj: &PyAny) -> PyErr { - let state = if let Ok(obj) = obj.downcast::() { - PyErrState::normalized(obj) - } else { - // Assume obj is Type[Exception]; let later normalization handle if this - // is not the case - PyErrState::lazy(obj, obj.py().None()) + pub fn from_value_bound(obj: Bound<'_, PyAny>) -> PyErr { + let state = match obj.downcast_into::() { + Ok(obj) => PyErrState::normalized(obj), + Err(err) => { + // Assume obj is Type[Exception]; let later normalization handle if this + // is not the case + let obj = err.into_inner(); + let py = obj.py(); + PyErrState::lazy(obj.into_py(py), py.None()) + } }; PyErr::from_state(state) @@ -260,6 +277,18 @@ impl PyErr { self.normalized(py).ptype(py) } + /// Deprecated form of [`PyErr::value_bound`]. + #[cfg_attr( + not(feature = "gil-refs"), + deprecated( + since = "0.21.0", + note = "`PyErr::value` will be replaced by `PyErr::value_bound` in a future PyO3 version" + ) + )] + pub fn value<'py>(&'py self, py: Python<'py>) -> &'py PyBaseException { + self.value_bound(py).as_gil_ref() + } + /// Returns the value of this exception. /// /// # Examples @@ -270,11 +299,11 @@ impl PyErr { /// Python::with_gil(|py| { /// let err: PyErr = PyTypeError::new_err(("some type error",)); /// assert!(err.is_instance_of::(py)); - /// assert_eq!(err.value(py).to_string(), "some type error"); + /// assert_eq!(err.value_bound(py).to_string(), "some type error"); /// }); /// ``` - pub fn value<'py>(&'py self, py: Python<'py>) -> &'py PyBaseException { - self.normalized(py).pvalue.as_ref(py) + pub fn value_bound<'py>(&self, py: Python<'py>) -> &Bound<'py, PyBaseException> { + self.normalized(py).pvalue.bind(py) } /// Consumes self to take ownership of the exception value contained in this error. @@ -527,7 +556,7 @@ impl PyErr { pub fn display(&self, py: Python<'_>) { #[cfg(Py_3_12)] unsafe { - ffi::PyErr_DisplayException(self.value(py).as_ptr()) + ffi::PyErr_DisplayException(self.value_bound(py).as_ptr()) } #[cfg(not(Py_3_12))] @@ -540,7 +569,7 @@ impl PyErr { let type_bound = self.get_type_bound(py); ffi::PyErr_Display( type_bound.as_ptr(), - self.value(py).as_ptr(), + self.value_bound(py).as_ptr(), traceback .as_ref() .map_or(std::ptr::null_mut(), |traceback| traceback.as_ptr()), @@ -785,7 +814,7 @@ impl PyErr { /// let err: PyErr = PyTypeError::new_err(("some type error",)); /// let err_clone = err.clone_ref(py); /// assert!(err.get_type_bound(py).is(&err_clone.get_type_bound(py))); - /// assert!(err.value(py).is(err_clone.value(py))); + /// assert!(err.value_bound(py).is(err_clone.value_bound(py))); /// match err.traceback_bound(py) { /// None => assert!(err_clone.traceback_bound(py).is_none()), /// Some(tb) => assert!(err_clone.traceback_bound(py).unwrap().is(&tb)), @@ -800,15 +829,14 @@ impl PyErr { /// Return the cause (either an exception instance, or None, set by `raise ... from ...`) /// associated with the exception, as accessible from Python through `__cause__`. pub fn cause(&self, py: Python<'_>) -> Option { - let value = self.value(py); - let obj = - unsafe { py.from_owned_ptr_or_opt::(ffi::PyException_GetCause(value.as_ptr())) }; - obj.map(Self::from_value) + use crate::ffi_ptr_ext::FfiPtrExt; + unsafe { ffi::PyException_GetCause(self.value_bound(py).as_ptr()).assume_owned_or_opt(py) } + .map(Self::from_value_bound) } /// Set the cause associated with the exception, pass `None` to clear it. pub fn set_cause(&self, py: Python<'_>, cause: Option) { - let value = self.value(py); + let value = self.value_bound(py); let cause = cause.map(|err| err.into_value(py)); unsafe { // PyException_SetCause _steals_ a reference to cause, so must use .into_ptr() @@ -868,7 +896,7 @@ impl std::fmt::Debug for PyErr { Python::with_gil(|py| { f.debug_struct("PyErr") .field("type", &self.get_type_bound(py)) - .field("value", self.value(py)) + .field("value", self.value_bound(py)) .field("traceback", &self.traceback_bound(py)) .finish() }) @@ -877,8 +905,9 @@ 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(py); + let value = self.value_bound(py); let type_name = value.get_type().qualname().map_err(|_| std::fmt::Error)?; write!(f, "{}", type_name)?; if let Ok(s) = value.str() { @@ -1043,7 +1072,6 @@ impl_signed_integer!(isize); mod tests { use super::PyErrState; use crate::exceptions::{self, PyTypeError, PyValueError}; - use crate::types::any::PyAnyMethods; use crate::{PyErr, PyNativeType, PyTypeInfo, Python}; #[test] @@ -1237,6 +1265,7 @@ mod tests { #[test] fn warnings() { + use crate::types::any::PyAnyMethods; // Note: although the warning filter is interpreter global, keeping the // GIL locked should prevent effects to be visible to other testing // threads. @@ -1284,7 +1313,7 @@ mod tests { ) .unwrap_err(); assert!(err - .value(py) + .value_bound(py) .getattr("args") .unwrap() .get_item(0) diff --git a/src/exceptions.rs b/src/exceptions.rs index bcbe91b9..e7b6407e 100644 --- a/src/exceptions.rs +++ b/src/exceptions.rs @@ -9,7 +9,7 @@ //! yourself to import Python classes that are ultimately derived from //! `BaseException`. -use crate::{ffi, PyResult, Python}; +use crate::{ffi, Bound, PyResult, Python}; use std::ffi::CStr; use std::ops; use std::os::raw::c_char; @@ -22,6 +22,7 @@ macro_rules! impl_exception_boilerplate { impl ::std::convert::From<&$name> for $crate::PyErr { #[inline] fn from(err: &$name) -> $crate::PyErr { + #[allow(deprecated)] $crate::PyErr::from_value(err) } } @@ -613,7 +614,14 @@ impl_windows_native_exception!( ); impl PyUnicodeDecodeError { - /// Creates a Python `UnicodeDecodeError`. + /// Deprecated form of [`PyUnicodeDecodeError::new_bound`]. + #[cfg_attr( + not(feature = "gil-refs"), + deprecated( + since = "0.21.0", + note = "`PyUnicodeDecodeError::new` will be replaced by `PyUnicodeDecodeError::new_bound` in a future PyO3 version" + ) + )] pub fn new<'p>( py: Python<'p>, encoding: &CStr, @@ -621,16 +629,47 @@ impl PyUnicodeDecodeError { range: ops::Range, reason: &CStr, ) -> PyResult<&'p PyUnicodeDecodeError> { + Ok(PyUnicodeDecodeError::new_bound(py, encoding, input, range, reason)?.into_gil_ref()) + } + + /// Creates a Python `UnicodeDecodeError`. + pub fn new_bound<'p>( + py: Python<'p>, + encoding: &CStr, + input: &[u8], + range: ops::Range, + reason: &CStr, + ) -> PyResult> { + use crate::ffi_ptr_ext::FfiPtrExt; + use crate::py_result_ext::PyResultExt; unsafe { - py.from_owned_ptr_or_err(ffi::PyUnicodeDecodeError_Create( + ffi::PyUnicodeDecodeError_Create( encoding.as_ptr(), input.as_ptr() as *const c_char, input.len() as ffi::Py_ssize_t, range.start as ffi::Py_ssize_t, range.end as ffi::Py_ssize_t, reason.as_ptr(), - )) + ) + .assume_owned_or_err(py) } + .downcast_into() + } + + /// Deprecated form of [`PyUnicodeDecodeError::new_utf8_bound`]. + #[cfg_attr( + not(feature = "gil-refs"), + deprecated( + since = "0.21.0", + note = "`PyUnicodeDecodeError::new_utf8` will be replaced by `PyUnicodeDecodeError::new_utf8_bound` in a future PyO3 version" + ) + )] + pub fn new_utf8<'p>( + py: Python<'p>, + input: &[u8], + err: std::str::Utf8Error, + ) -> PyResult<&'p PyUnicodeDecodeError> { + Ok(PyUnicodeDecodeError::new_utf8_bound(py, input, err)?.into_gil_ref()) } /// Creates a Python `UnicodeDecodeError` from a Rust UTF-8 decoding error. @@ -646,7 +685,7 @@ impl PyUnicodeDecodeError { /// Python::with_gil(|py| { /// let invalid_utf8 = b"fo\xd8o"; /// let err = std::str::from_utf8(invalid_utf8).expect_err("should be invalid utf8"); - /// let decode_err = PyUnicodeDecodeError::new_utf8(py, invalid_utf8, err)?; + /// let decode_err = PyUnicodeDecodeError::new_utf8_bound(py, invalid_utf8, err)?; /// assert_eq!( /// decode_err.to_string(), /// "'utf-8' codec can't decode byte 0xd8 in position 2: invalid utf-8" @@ -654,13 +693,13 @@ impl PyUnicodeDecodeError { /// Ok(()) /// }) /// # } - pub fn new_utf8<'p>( + pub fn new_utf8_bound<'p>( py: Python<'p>, input: &[u8], err: std::str::Utf8Error, - ) -> PyResult<&'p PyUnicodeDecodeError> { + ) -> PyResult> { let pos = err.valid_up_to(); - PyUnicodeDecodeError::new( + PyUnicodeDecodeError::new_bound( py, CStr::from_bytes_with_nul(b"utf-8\0").unwrap(), input, @@ -745,7 +784,7 @@ macro_rules! test_exception { assert!(err.is_instance_of::<$exc_ty>(py)); - let value: &$exc_ty = err.value(py).downcast().unwrap(); + let value: &$exc_ty = err.value_bound(py).clone().into_gil_ref().downcast().unwrap(); assert!(value.source().is_none()); err.set_cause(py, Some($crate::exceptions::PyValueError::new_err("a cause"))); @@ -1025,14 +1064,14 @@ mod tests { #[cfg_attr(invalid_from_utf8_lint, allow(invalid_from_utf8))] let err = std::str::from_utf8(invalid_utf8).expect_err("should be invalid utf8"); Python::with_gil(|py| { - let decode_err = PyUnicodeDecodeError::new_utf8(py, invalid_utf8, err).unwrap(); + let decode_err = PyUnicodeDecodeError::new_utf8_bound(py, invalid_utf8, err).unwrap(); assert_eq!( format!("{:?}", decode_err), "UnicodeDecodeError('utf-8', b'fo\\xd8o', 2, 3, 'invalid utf-8')" ); // Restoring should preserve the same error - let e: PyErr = decode_err.into(); + let e = PyErr::from_value_bound(decode_err.into_any()); e.restore(py); assert_eq!( @@ -1081,7 +1120,11 @@ mod tests { let invalid_utf8 = b"fo\xd8o"; #[cfg_attr(invalid_from_utf8_lint, allow(invalid_from_utf8))] let err = std::str::from_utf8(invalid_utf8).expect_err("should be invalid utf8"); - PyErr::from_value(PyUnicodeDecodeError::new_utf8(py, invalid_utf8, err).unwrap()) + PyErr::from_value_bound( + PyUnicodeDecodeError::new_utf8_bound(py, invalid_utf8, err) + .unwrap() + .into_any(), + ) }); test_exception!(PyUnicodeEncodeError, |py| py .eval_bound("chr(40960).encode('ascii')", None, None) diff --git a/src/impl_/extract_argument.rs b/src/impl_/extract_argument.rs index ff1c2436..d9487359 100644 --- a/src/impl_/extract_argument.rs +++ b/src/impl_/extract_argument.rs @@ -167,8 +167,11 @@ pub fn from_py_with_with_default<'a, 'py, T>( pub fn argument_extraction_error(py: Python<'_>, arg_name: &str, error: PyErr) -> PyErr { use crate::types::any::PyAnyMethods; if error.get_type_bound(py).is(py.get_type::()) { - let remapped_error = - PyTypeError::new_err(format!("argument '{}': {}", arg_name, error.value(py))); + let remapped_error = PyTypeError::new_err(format!( + "argument '{}': {}", + arg_name, + error.value_bound(py) + )); remapped_error.set_cause(py, error.cause(py)); remapped_error } else { diff --git a/src/tests/common.rs b/src/tests/common.rs index ed3972f1..5eec6094 100644 --- a/src/tests/common.rs +++ b/src/tests/common.rs @@ -73,8 +73,8 @@ mod inner { #[cfg(all(feature = "macros", Py_3_8))] #[pymethods(crate = "pyo3")] impl UnraisableCapture { - pub fn hook(&mut self, unraisable: &PyAny) { - let err = PyErr::from_value(unraisable.getattr("exc_value").unwrap()); + pub fn hook(&mut self, unraisable: Bound<'_, PyAny>) { + let err = PyErr::from_value_bound(unraisable.getattr("exc_value").unwrap()); let instance = unraisable.getattr("object").unwrap(); self.capture = Some((err, instance.into())); } diff --git a/src/types/string.rs b/src/types/string.rs index 2b263571..2e17f909 100644 --- a/src/types/string.rs +++ b/src/types/string.rs @@ -73,9 +73,9 @@ impl<'a> PyStringData<'a> { match self { Self::Ucs1(data) => match str::from_utf8(data) { Ok(s) => Ok(Cow::Borrowed(s)), - Err(e) => Err(crate::PyErr::from_value(PyUnicodeDecodeError::new_utf8( - py, data, e, - )?)), + Err(e) => Err(crate::PyErr::from_value_bound( + PyUnicodeDecodeError::new_utf8_bound(py, data, e)?.into_any(), + )), }, Self::Ucs2(data) => match String::from_utf16(data) { Ok(s) => Ok(Cow::Owned(s)), @@ -83,24 +83,30 @@ impl<'a> PyStringData<'a> { let mut message = e.to_string().as_bytes().to_vec(); message.push(0); - Err(crate::PyErr::from_value(PyUnicodeDecodeError::new( - py, - CStr::from_bytes_with_nul(b"utf-16\0").unwrap(), - self.as_bytes(), - 0..self.as_bytes().len(), - CStr::from_bytes_with_nul(&message).unwrap(), - )?)) + Err(crate::PyErr::from_value_bound( + PyUnicodeDecodeError::new_bound( + py, + CStr::from_bytes_with_nul(b"utf-16\0").unwrap(), + self.as_bytes(), + 0..self.as_bytes().len(), + CStr::from_bytes_with_nul(&message).unwrap(), + )? + .into_any(), + )) } }, Self::Ucs4(data) => match data.iter().map(|&c| std::char::from_u32(c)).collect() { Some(s) => Ok(Cow::Owned(s)), - None => Err(crate::PyErr::from_value(PyUnicodeDecodeError::new( - py, - CStr::from_bytes_with_nul(b"utf-32\0").unwrap(), - self.as_bytes(), - 0..self.as_bytes().len(), - CStr::from_bytes_with_nul(b"error converting utf-32\0").unwrap(), - )?)), + None => Err(crate::PyErr::from_value_bound( + PyUnicodeDecodeError::new_bound( + py, + CStr::from_bytes_with_nul(b"utf-32\0").unwrap(), + self.as_bytes(), + 0..self.as_bytes().len(), + CStr::from_bytes_with_nul(b"error converting utf-32\0").unwrap(), + )? + .into_any(), + )), }, } } diff --git a/src/types/traceback.rs b/src/types/traceback.rs index b97e2ed0..19f42d4b 100644 --- a/src/types/traceback.rs +++ b/src/types/traceback.rs @@ -150,9 +150,9 @@ except Exception as e: Some(&locals), ) .unwrap(); - let err = PyErr::from_value(locals.get_item("err").unwrap().unwrap().into_gil_ref()); - let traceback = err.value(py).getattr("__traceback__").unwrap(); - assert!(err.traceback_bound(py).unwrap().is(traceback)); + let err = PyErr::from_value_bound(locals.get_item("err").unwrap().unwrap()); + let traceback = err.value_bound(py).getattr("__traceback__").unwrap(); + assert!(err.traceback_bound(py).unwrap().is(&traceback)); }) } diff --git a/tests/test_coroutine.rs b/tests/test_coroutine.rs index 549d54aa..5954b979 100644 --- a/tests/test_coroutine.rs +++ b/tests/test_coroutine.rs @@ -137,7 +137,7 @@ fn cancelled_coroutine() { ) .unwrap_err(); assert_eq!( - err.value(gil).get_type().qualname().unwrap(), + err.value_bound(gil).get_type().qualname().unwrap(), "CancelledError" ); })