use crate::instance::Bound;
use crate::panic::PanicException;
use crate::type_object::PyTypeInfo;
use crate::types::any::PyAnyMethods;
use crate::types::{string::PyStringMethods, typeobject::PyTypeMethods, PyTraceback, PyType};
use crate::{
exceptions::{self, PyBaseException},
ffi,
};
use crate::{Borrowed, BoundObject, Py, PyAny, PyObject, Python};
#[allow(deprecated)]
use crate::{IntoPy, ToPyObject};
use std::borrow::Cow;
use std::ffi::{CStr, CString};
mod err_state;
mod impls;
use crate::conversion::IntoPyObject;
use err_state::{PyErrState, PyErrStateLazyFnOutput, PyErrStateNormalized};
use std::convert::Infallible;
pub struct PyErr {
state: PyErrState,
}
#[cfg(feature = "nightly")]
unsafe impl crate::marker::Ungil for PyErr {}
pub type PyResult<T> = Result<T, PyErr>;
#[derive(Debug)]
pub struct DowncastError<'a, 'py> {
from: Borrowed<'a, 'py, PyAny>,
to: Cow<'static, str>,
}
impl<'a, 'py> DowncastError<'a, 'py> {
pub fn new(from: &'a Bound<'py, PyAny>, to: impl Into<Cow<'static, str>>) -> Self {
DowncastError {
from: from.as_borrowed(),
to: to.into(),
}
}
pub(crate) fn new_from_borrowed(
from: Borrowed<'a, 'py, PyAny>,
to: impl Into<Cow<'static, str>>,
) -> Self {
DowncastError {
from,
to: to.into(),
}
}
}
#[derive(Debug)]
pub struct DowncastIntoError<'py> {
from: Bound<'py, PyAny>,
to: Cow<'static, str>,
}
impl<'py> DowncastIntoError<'py> {
pub fn new(from: Bound<'py, PyAny>, to: impl Into<Cow<'static, str>>) -> Self {
DowncastIntoError {
from,
to: to.into(),
}
}
pub fn into_inner(self) -> Bound<'py, PyAny> {
self.from
}
}
pub trait PyErrArguments: Send + Sync {
fn arguments(self, py: Python<'_>) -> PyObject;
}
impl<T> PyErrArguments for T
where
T: for<'py> IntoPyObject<'py> + Send + Sync,
{
fn arguments(self, py: Python<'_>) -> PyObject {
match self.into_pyobject(py) {
Ok(obj) => obj.into_any().unbind(),
Err(e) => panic!("Converting PyErr arguments failed: {}", e.into()),
}
}
}
impl PyErr {
#[inline]
pub fn new<T, A>(args: A) -> PyErr
where
T: PyTypeInfo,
A: PyErrArguments + Send + Sync + 'static,
{
PyErr::from_state(PyErrState::lazy(Box::new(move |py| {
PyErrStateLazyFnOutput {
ptype: T::type_object(py).into(),
pvalue: args.arguments(py),
}
})))
}
pub fn from_type<A>(ty: Bound<'_, PyType>, args: A) -> PyErr
where
A: PyErrArguments + Send + Sync + 'static,
{
PyErr::from_state(PyErrState::lazy_arguments(ty.unbind().into_any(), args))
}
#[deprecated(since = "0.23.0", note = "renamed to `PyErr::from_type`")]
#[inline]
pub fn from_type_bound<A>(ty: Bound<'_, PyType>, args: A) -> PyErr
where
A: PyErrArguments + Send + Sync + 'static,
{
Self::from_type(ty, args)
}
pub fn from_value(obj: Bound<'_, PyAny>) -> PyErr {
let state = match obj.downcast_into::<PyBaseException>() {
Ok(obj) => PyErrState::normalized(PyErrStateNormalized::new(obj)),
Err(err) => {
let obj = err.into_inner();
let py = obj.py();
PyErrState::lazy_arguments(obj.unbind(), py.None())
}
};
PyErr::from_state(state)
}
#[deprecated(since = "0.23.0", note = "renamed to `PyErr::from_value`")]
#[inline]
pub fn from_value_bound(obj: Bound<'_, PyAny>) -> PyErr {
Self::from_value(obj)
}
pub fn get_type<'py>(&self, py: Python<'py>) -> Bound<'py, PyType> {
self.normalized(py).ptype(py)
}
#[deprecated(since = "0.23.0", note = "renamed to `PyErr::get_type`")]
#[inline]
pub fn get_type_bound<'py>(&self, py: Python<'py>) -> Bound<'py, PyType> {
self.get_type(py)
}
pub fn value<'py>(&self, py: Python<'py>) -> &Bound<'py, PyBaseException> {
self.normalized(py).pvalue.bind(py)
}
#[deprecated(since = "0.23.0", note = "renamed to `PyErr::value`")]
#[inline]
pub fn value_bound<'py>(&self, py: Python<'py>) -> &Bound<'py, PyBaseException> {
self.value(py)
}
pub fn into_value(self, py: Python<'_>) -> Py<PyBaseException> {
let normalized = self.normalized(py);
let exc = normalized.pvalue.clone_ref(py);
if let Some(tb) = normalized.ptraceback(py) {
unsafe {
ffi::PyException_SetTraceback(exc.as_ptr(), tb.as_ptr());
}
}
exc
}
pub fn traceback<'py>(&self, py: Python<'py>) -> Option<Bound<'py, PyTraceback>> {
self.normalized(py).ptraceback(py)
}
#[deprecated(since = "0.23.0", note = "renamed to `PyErr::traceback`")]
#[inline]
pub fn traceback_bound<'py>(&self, py: Python<'py>) -> Option<Bound<'py, PyTraceback>> {
self.traceback(py)
}
#[inline]
pub fn occurred(_: Python<'_>) -> bool {
unsafe { !ffi::PyErr_Occurred().is_null() }
}
pub fn take(py: Python<'_>) -> Option<PyErr> {
let state = PyErrStateNormalized::take(py)?;
let pvalue = state.pvalue.bind(py);
if pvalue.get_type().as_ptr() == PanicException::type_object_raw(py).cast() {
let msg: String = pvalue
.str()
.map(|py_str| py_str.to_string_lossy().into())
.unwrap_or_else(|_| String::from("Unwrapped panic from Python code"));
Self::print_panic_and_unwind(py, PyErrState::normalized(state), msg)
}
Some(PyErr::from_state(PyErrState::normalized(state)))
}
fn print_panic_and_unwind(py: Python<'_>, state: PyErrState, msg: String) -> ! {
eprintln!("--- PyO3 is resuming a panic after fetching a PanicException from Python. ---");
eprintln!("Python stack trace below:");
state.restore(py);
unsafe {
ffi::PyErr_PrintEx(0);
}
std::panic::resume_unwind(Box::new(msg))
}
#[cfg_attr(debug_assertions, track_caller)]
#[inline]
pub fn fetch(py: Python<'_>) -> PyErr {
const FAILED_TO_FETCH: &str = "attempted to fetch exception but none was set";
match PyErr::take(py) {
Some(err) => err,
#[cfg(debug_assertions)]
None => panic!("{}", FAILED_TO_FETCH),
#[cfg(not(debug_assertions))]
None => exceptions::PySystemError::new_err(FAILED_TO_FETCH),
}
}
pub fn new_type<'py>(
py: Python<'py>,
name: &CStr,
doc: Option<&CStr>,
base: Option<&Bound<'py, PyType>>,
dict: Option<PyObject>,
) -> PyResult<Py<PyType>> {
let base: *mut ffi::PyObject = match base {
None => std::ptr::null_mut(),
Some(obj) => obj.as_ptr(),
};
let dict: *mut ffi::PyObject = match dict {
None => std::ptr::null_mut(),
Some(obj) => obj.as_ptr(),
};
let doc_ptr = match doc.as_ref() {
Some(c) => c.as_ptr(),
None => std::ptr::null(),
};
let ptr = unsafe { ffi::PyErr_NewExceptionWithDoc(name.as_ptr(), doc_ptr, base, dict) };
unsafe { Py::from_owned_ptr_or_err(py, ptr) }
}
#[deprecated(since = "0.23.0", note = "renamed to `PyErr::new_type`")]
#[inline]
pub fn new_type_bound<'py>(
py: Python<'py>,
name: &str,
doc: Option<&str>,
base: Option<&Bound<'py, PyType>>,
dict: Option<PyObject>,
) -> PyResult<Py<PyType>> {
let null_terminated_name =
CString::new(name).expect("Failed to initialize nul terminated exception name");
let null_terminated_doc =
doc.map(|d| CString::new(d).expect("Failed to initialize nul terminated docstring"));
Self::new_type(
py,
&null_terminated_name,
null_terminated_doc.as_deref(),
base,
dict,
)
}
pub fn display(&self, py: Python<'_>) {
#[cfg(Py_3_12)]
unsafe {
ffi::PyErr_DisplayException(self.value(py).as_ptr())
}
#[cfg(not(Py_3_12))]
unsafe {
let traceback = self.traceback(py);
let type_bound = self.get_type(py);
ffi::PyErr_Display(
type_bound.as_ptr(),
self.value(py).as_ptr(),
traceback
.as_ref()
.map_or(std::ptr::null_mut(), |traceback| traceback.as_ptr()),
)
}
}
pub fn print(&self, py: Python<'_>) {
self.clone_ref(py).restore(py);
unsafe { ffi::PyErr_PrintEx(0) }
}
pub fn print_and_set_sys_last_vars(&self, py: Python<'_>) {
self.clone_ref(py).restore(py);
unsafe { ffi::PyErr_PrintEx(1) }
}
pub fn matches<'py, T>(&self, py: Python<'py>, exc: T) -> Result<bool, T::Error>
where
T: IntoPyObject<'py>,
{
Ok(self.is_instance(py, &exc.into_pyobject(py)?.into_any().as_borrowed()))
}
#[inline]
pub fn is_instance(&self, py: Python<'_>, ty: &Bound<'_, PyAny>) -> bool {
let type_bound = self.get_type(py);
(unsafe { ffi::PyErr_GivenExceptionMatches(type_bound.as_ptr(), ty.as_ptr()) }) != 0
}
#[deprecated(since = "0.23.0", note = "renamed to `PyErr::is_instance`")]
#[inline]
pub fn is_instance_bound(&self, py: Python<'_>, ty: &Bound<'_, PyAny>) -> bool {
self.is_instance(py, ty)
}
#[inline]
pub fn is_instance_of<T>(&self, py: Python<'_>) -> bool
where
T: PyTypeInfo,
{
self.is_instance(py, &T::type_object(py))
}
#[inline]
pub fn restore(self, py: Python<'_>) {
self.state.restore(py)
}
#[inline]
pub fn write_unraisable(self, py: Python<'_>, obj: Option<&Bound<'_, PyAny>>) {
self.restore(py);
unsafe { ffi::PyErr_WriteUnraisable(obj.map_or(std::ptr::null_mut(), Bound::as_ptr)) }
}
#[deprecated(since = "0.23.0", note = "renamed to `PyErr::write_unraisable`")]
#[inline]
pub fn write_unraisable_bound(self, py: Python<'_>, obj: Option<&Bound<'_, PyAny>>) {
self.write_unraisable(py, obj)
}
pub fn warn<'py>(
py: Python<'py>,
category: &Bound<'py, PyAny>,
message: &CStr,
stacklevel: i32,
) -> PyResult<()> {
error_on_minusone(py, unsafe {
ffi::PyErr_WarnEx(
category.as_ptr(),
message.as_ptr(),
stacklevel as ffi::Py_ssize_t,
)
})
}
#[deprecated(since = "0.23.0", note = "renamed to `PyErr::warn`")]
#[inline]
pub fn warn_bound<'py>(
py: Python<'py>,
category: &Bound<'py, PyAny>,
message: &str,
stacklevel: i32,
) -> PyResult<()> {
let message = CString::new(message)?;
Self::warn(py, category, &message, stacklevel)
}
pub fn warn_explicit<'py>(
py: Python<'py>,
category: &Bound<'py, PyAny>,
message: &CStr,
filename: &CStr,
lineno: i32,
module: Option<&CStr>,
registry: Option<&Bound<'py, PyAny>>,
) -> PyResult<()> {
let module_ptr = match module {
None => std::ptr::null_mut(),
Some(s) => s.as_ptr(),
};
let registry: *mut ffi::PyObject = match registry {
None => std::ptr::null_mut(),
Some(obj) => obj.as_ptr(),
};
error_on_minusone(py, unsafe {
ffi::PyErr_WarnExplicit(
category.as_ptr(),
message.as_ptr(),
filename.as_ptr(),
lineno,
module_ptr,
registry,
)
})
}
#[deprecated(since = "0.23.0", note = "renamed to `PyErr::warn`")]
#[inline]
pub fn warn_explicit_bound<'py>(
py: Python<'py>,
category: &Bound<'py, PyAny>,
message: &str,
filename: &str,
lineno: i32,
module: Option<&str>,
registry: Option<&Bound<'py, PyAny>>,
) -> PyResult<()> {
let message = CString::new(message)?;
let filename = CString::new(filename)?;
let module = module.map(CString::new).transpose()?;
Self::warn_explicit(
py,
category,
&message,
&filename,
lineno,
module.as_deref(),
registry,
)
}
#[inline]
pub fn clone_ref(&self, py: Python<'_>) -> PyErr {
PyErr::from_state(PyErrState::normalized(self.normalized(py).clone_ref(py)))
}
pub fn cause(&self, py: Python<'_>) -> Option<PyErr> {
use crate::ffi_ptr_ext::FfiPtrExt;
let obj =
unsafe { ffi::PyException_GetCause(self.value(py).as_ptr()).assume_owned_or_opt(py) };
#[cfg(GraalPy)]
if let Some(cause) = &obj {
if cause.is_none() {
return None;
}
}
obj.map(Self::from_value)
}
pub fn set_cause(&self, py: Python<'_>, cause: Option<Self>) {
let value = self.value(py);
let cause = cause.map(|err| err.into_value(py));
unsafe {
ffi::PyException_SetCause(
value.as_ptr(),
cause.map_or(std::ptr::null_mut(), Py::into_ptr),
);
}
}
#[inline]
fn from_state(state: PyErrState) -> PyErr {
PyErr { state }
}
#[inline]
fn normalized(&self, py: Python<'_>) -> &PyErrStateNormalized {
self.state.as_normalized(py)
}
}
impl std::fmt::Debug for PyErr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
Python::with_gil(|py| {
f.debug_struct("PyErr")
.field("type", &self.get_type(py))
.field("value", self.value(py))
.field("traceback", &self.traceback(py))
.finish()
})
}
}
impl std::fmt::Display for PyErr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Python::with_gil(|py| {
let value = self.value(py);
let type_name = value.get_type().qualname().map_err(|_| std::fmt::Error)?;
write!(f, "{}", type_name)?;
if let Ok(s) = value.str() {
write!(f, ": {}", &s.to_string_lossy())
} else {
write!(f, ": <exception str() failed>")
}
})
}
}
impl std::error::Error for PyErr {}
#[allow(deprecated)]
impl IntoPy<PyObject> for PyErr {
#[inline]
fn into_py(self, py: Python<'_>) -> PyObject {
self.into_pyobject(py).unwrap().into_any().unbind()
}
}
#[allow(deprecated)]
impl ToPyObject for PyErr {
#[inline]
fn to_object(&self, py: Python<'_>) -> PyObject {
self.into_pyobject(py).unwrap().into_any().unbind()
}
}
#[allow(deprecated)]
impl IntoPy<PyObject> for &PyErr {
#[inline]
fn into_py(self, py: Python<'_>) -> PyObject {
self.into_pyobject(py).unwrap().into_any().unbind()
}
}
impl<'py> IntoPyObject<'py> for PyErr {
type Target = PyBaseException;
type Output = Bound<'py, Self::Target>;
type Error = Infallible;
#[inline]
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
Ok(self.into_value(py).into_bound(py))
}
}
impl<'py> IntoPyObject<'py> for &PyErr {
type Target = PyBaseException;
type Output = Bound<'py, Self::Target>;
type Error = Infallible;
#[inline]
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
self.clone_ref(py).into_pyobject(py)
}
}
struct PyDowncastErrorArguments {
from: Py<PyType>,
to: Cow<'static, str>,
}
impl PyErrArguments for PyDowncastErrorArguments {
fn arguments(self, py: Python<'_>) -> PyObject {
const FAILED_TO_EXTRACT: Cow<'_, str> = Cow::Borrowed("<failed to extract type name>");
let from = self.from.bind(py).qualname();
let from = match &from {
Ok(qn) => qn.to_cow().unwrap_or(FAILED_TO_EXTRACT),
Err(_) => FAILED_TO_EXTRACT,
};
format!("'{}' object cannot be converted to '{}'", from, self.to)
.into_pyobject(py)
.unwrap()
.into_any()
.unbind()
}
}
pub trait ToPyErr {}
impl<'py, T> std::convert::From<Bound<'py, T>> for PyErr
where
T: ToPyErr,
{
#[inline]
fn from(err: Bound<'py, T>) -> PyErr {
PyErr::from_value(err.into_any())
}
}
impl std::convert::From<DowncastError<'_, '_>> for PyErr {
fn from(err: DowncastError<'_, '_>) -> PyErr {
let args = PyDowncastErrorArguments {
from: err.from.get_type().into(),
to: err.to,
};
exceptions::PyTypeError::new_err(args)
}
}
impl std::error::Error for DowncastError<'_, '_> {}
impl std::fmt::Display for DowncastError<'_, '_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
display_downcast_error(f, &self.from, &self.to)
}
}
impl std::convert::From<DowncastIntoError<'_>> for PyErr {
fn from(err: DowncastIntoError<'_>) -> PyErr {
let args = PyDowncastErrorArguments {
from: err.from.get_type().into(),
to: err.to,
};
exceptions::PyTypeError::new_err(args)
}
}
impl std::error::Error for DowncastIntoError<'_> {}
impl std::fmt::Display for DowncastIntoError<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
display_downcast_error(f, &self.from, &self.to)
}
}
fn display_downcast_error(
f: &mut std::fmt::Formatter<'_>,
from: &Bound<'_, PyAny>,
to: &str,
) -> std::fmt::Result {
write!(
f,
"'{}' object cannot be converted to '{}'",
from.get_type().qualname().map_err(|_| std::fmt::Error)?,
to
)
}
#[track_caller]
pub fn panic_after_error(_py: Python<'_>) -> ! {
unsafe {
ffi::PyErr_Print();
}
panic!("Python API call failed");
}
#[inline]
pub(crate) fn error_on_minusone<T: SignedInteger>(py: Python<'_>, result: T) -> PyResult<()> {
if result != T::MINUS_ONE {
Ok(())
} else {
Err(PyErr::fetch(py))
}
}
pub(crate) trait SignedInteger: Eq {
const MINUS_ONE: Self;
}
macro_rules! impl_signed_integer {
($t:ty) => {
impl SignedInteger for $t {
const MINUS_ONE: Self = -1;
}
};
}
impl_signed_integer!(i8);
impl_signed_integer!(i16);
impl_signed_integer!(i32);
impl_signed_integer!(i64);
impl_signed_integer!(i128);
impl_signed_integer!(isize);
#[cfg(test)]
mod tests {
use super::PyErrState;
use crate::exceptions::{self, PyTypeError, PyValueError};
use crate::{ffi, PyErr, PyTypeInfo, Python};
#[test]
fn no_error() {
assert!(Python::with_gil(PyErr::take).is_none());
}
#[test]
fn set_valueerror() {
Python::with_gil(|py| {
let err: PyErr = exceptions::PyValueError::new_err("some exception message");
assert!(err.is_instance_of::<exceptions::PyValueError>(py));
err.restore(py);
assert!(PyErr::occurred(py));
let err = PyErr::fetch(py);
assert!(err.is_instance_of::<exceptions::PyValueError>(py));
assert_eq!(err.to_string(), "ValueError: some exception message");
})
}
#[test]
fn invalid_error_type() {
Python::with_gil(|py| {
let err: PyErr = PyErr::new::<crate::types::PyString, _>(());
assert!(err.is_instance_of::<exceptions::PyTypeError>(py));
err.restore(py);
let err = PyErr::fetch(py);
assert!(err.is_instance_of::<exceptions::PyTypeError>(py));
assert_eq!(
err.to_string(),
"TypeError: exceptions must derive from BaseException"
);
})
}
#[test]
fn set_typeerror() {
Python::with_gil(|py| {
let err: PyErr = exceptions::PyTypeError::new_err(());
err.restore(py);
assert!(PyErr::occurred(py));
drop(PyErr::fetch(py));
});
}
#[test]
#[should_panic(expected = "new panic")]
fn fetching_panic_exception_resumes_unwind() {
use crate::panic::PanicException;
Python::with_gil(|py| {
let err: PyErr = PanicException::new_err("new panic");
err.restore(py);
assert!(PyErr::occurred(py));
let _ = PyErr::fetch(py);
});
}
#[test]
#[should_panic(expected = "new panic")]
#[cfg(not(Py_3_12))]
fn fetching_normalized_panic_exception_resumes_unwind() {
use crate::panic::PanicException;
Python::with_gil(|py| {
let err: PyErr = PanicException::new_err("new panic");
let _ = err.normalized(py);
err.restore(py);
assert!(PyErr::occurred(py));
let _ = PyErr::fetch(py);
});
}
#[test]
fn err_debug() {
Python::with_gil(|py| {
let err = py
.run(ffi::c_str!("raise Exception('banana')"), None, None)
.expect_err("raising should have given us an error");
let debug_str = format!("{:?}", err);
assert!(debug_str.starts_with("PyErr { "));
assert!(debug_str.ends_with(" }"));
let mut fields = debug_str["PyErr { ".len()..debug_str.len() - 2].split(", ");
assert_eq!(fields.next().unwrap(), "type: <class 'Exception'>");
assert_eq!(fields.next().unwrap(), "value: Exception('banana')");
let traceback = fields.next().unwrap();
assert!(traceback.starts_with("traceback: Some(<traceback object at 0x"));
assert!(traceback.ends_with(">)"));
assert!(fields.next().is_none());
});
}
#[test]
fn err_display() {
Python::with_gil(|py| {
let err = py
.run(ffi::c_str!("raise Exception('banana')"), None, None)
.expect_err("raising should have given us an error");
assert_eq!(err.to_string(), "Exception: banana");
});
}
#[test]
fn test_pyerr_send_sync() {
fn is_send<T: Send>() {}
fn is_sync<T: Sync>() {}
is_send::<PyErr>();
is_sync::<PyErr>();
is_send::<PyErrState>();
is_sync::<PyErrState>();
}
#[test]
fn test_pyerr_matches() {
Python::with_gil(|py| {
let err = PyErr::new::<PyValueError, _>("foo");
assert!(err.matches(py, PyValueError::type_object(py)).unwrap());
assert!(err
.matches(
py,
(PyValueError::type_object(py), PyTypeError::type_object(py))
)
.unwrap());
assert!(!err.matches(py, PyTypeError::type_object(py)).unwrap());
let err: PyErr = PyErr::from_type(crate::types::PyString::type_object(py), "foo");
assert!(err.matches(py, PyTypeError::type_object(py)).unwrap());
})
}
#[test]
fn test_pyerr_cause() {
Python::with_gil(|py| {
let err = py
.run(ffi::c_str!("raise Exception('banana')"), None, None)
.expect_err("raising should have given us an error");
assert!(err.cause(py).is_none());
let err = py
.run(
ffi::c_str!("raise Exception('banana') from Exception('apple')"),
None,
None,
)
.expect_err("raising should have given us an error");
let cause = err
.cause(py)
.expect("raising from should have given us a cause");
assert_eq!(cause.to_string(), "Exception: apple");
err.set_cause(py, None);
assert!(err.cause(py).is_none());
let new_cause = exceptions::PyValueError::new_err("orange");
err.set_cause(py, Some(new_cause));
let cause = err
.cause(py)
.expect("set_cause should have given us a cause");
assert_eq!(cause.to_string(), "ValueError: orange");
});
}
#[test]
fn warnings() {
use crate::types::any::PyAnyMethods;
Python::with_gil(|py| {
let cls = py.get_type::<exceptions::PyUserWarning>();
let warnings = py.import("warnings").unwrap();
warnings.call_method0("resetwarnings").unwrap();
#[cfg(not(Py_GIL_DISABLED))]
assert_warnings!(
py,
{ PyErr::warn(py, &cls, ffi::c_str!("I am warning you"), 0).unwrap() },
[(exceptions::PyUserWarning, "I am warning you")]
);
warnings
.call_method1("simplefilter", ("error", &cls))
.unwrap();
PyErr::warn(py, &cls, ffi::c_str!("I am warning you"), 0).unwrap_err();
warnings.call_method0("resetwarnings").unwrap();
warnings
.call_method1("filterwarnings", ("error", "", &cls, "pyo3test"))
.unwrap();
#[cfg(not(Py_GIL_DISABLED))]
assert_warnings!(
py,
{ PyErr::warn(py, &cls, ffi::c_str!("I am warning you"), 0).unwrap() },
[(exceptions::PyUserWarning, "I am warning you")]
);
let err = PyErr::warn_explicit(
py,
&cls,
ffi::c_str!("I am warning you"),
ffi::c_str!("pyo3test.py"),
427,
None,
None,
)
.unwrap_err();
assert!(err
.value(py)
.getattr("args")
.unwrap()
.get_item(0)
.unwrap()
.eq("I am warning you")
.unwrap());
warnings.call_method0("resetwarnings").unwrap();
});
}
}