Merge pull request #3334 from davidhewitt/pyerr-display
add PyErr::display
This commit is contained in:
commit
8ce6c26c81
|
@ -0,0 +1 @@
|
|||
Add `PyErr::Display` for all Python versions, and FFI symbol `PyErr_DisplayException` for Python 3.12.
|
|
@ -15,6 +15,9 @@ extern "C" {
|
|||
pub fn PyErr_PrintEx(arg1: c_int);
|
||||
#[cfg_attr(PyPy, link_name = "PyPyErr_Display")]
|
||||
pub fn PyErr_Display(arg1: *mut PyObject, arg2: *mut PyObject, arg3: *mut PyObject);
|
||||
|
||||
#[cfg(Py_3_12)]
|
||||
pub fn PyErr_DisplayException(exc: *mut PyObject);
|
||||
}
|
||||
|
||||
// skipped PyOS_InputHook
|
||||
|
|
|
@ -431,13 +431,32 @@ impl PyErr {
|
|||
}
|
||||
|
||||
/// Prints a standard traceback to `sys.stderr`.
|
||||
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 {
|
||||
ffi::PyErr_Display(
|
||||
self.get_type(py).as_ptr(),
|
||||
self.value(py).as_ptr(),
|
||||
self.traceback(py)
|
||||
.map_or(std::ptr::null_mut(), PyTraceback::as_ptr),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls `sys.excepthook` and then prints a standard traceback to `sys.stderr`.
|
||||
pub fn print(&self, py: Python<'_>) {
|
||||
self.clone_ref(py).restore(py);
|
||||
unsafe { ffi::PyErr_PrintEx(0) }
|
||||
}
|
||||
|
||||
/// Prints a standard traceback to `sys.stderr`, and sets
|
||||
/// `sys.last_{type,value,traceback}` attributes to this exception's data.
|
||||
/// Calls `sys.excepthook` and then prints a standard traceback to `sys.stderr`.
|
||||
///
|
||||
/// Additionally sets `sys.last_{type,value,traceback,exc}` attributes to this exception.
|
||||
pub fn print_and_set_sys_last_vars(&self, py: Python<'_>) {
|
||||
self.clone_ref(py).restore(py);
|
||||
unsafe { ffi::PyErr_PrintEx(1) }
|
||||
|
|
|
@ -813,20 +813,20 @@ mod tests {
|
|||
let err: PyErr = gaierror::new_err(());
|
||||
let socket = py
|
||||
.import("socket")
|
||||
.map_err(|e| e.print(py))
|
||||
.map_err(|e| e.display(py))
|
||||
.expect("could not import socket");
|
||||
|
||||
let d = PyDict::new(py);
|
||||
d.set_item("socket", socket)
|
||||
.map_err(|e| e.print(py))
|
||||
.map_err(|e| e.display(py))
|
||||
.expect("could not setitem");
|
||||
|
||||
d.set_item("exc", err)
|
||||
.map_err(|e| e.print(py))
|
||||
.map_err(|e| e.display(py))
|
||||
.expect("could not setitem");
|
||||
|
||||
py.run("assert isinstance(exc, socket.gaierror)", None, Some(d))
|
||||
.map_err(|e| e.print(py))
|
||||
.map_err(|e| e.display(py))
|
||||
.expect("assertion failed");
|
||||
});
|
||||
}
|
||||
|
@ -837,15 +837,15 @@ mod tests {
|
|||
let err: PyErr = MessageError::new_err(());
|
||||
let email = py
|
||||
.import("email")
|
||||
.map_err(|e| e.print(py))
|
||||
.map_err(|e| e.display(py))
|
||||
.expect("could not import email");
|
||||
|
||||
let d = PyDict::new(py);
|
||||
d.set_item("email", email)
|
||||
.map_err(|e| e.print(py))
|
||||
.map_err(|e| e.display(py))
|
||||
.expect("could not setitem");
|
||||
d.set_item("exc", err)
|
||||
.map_err(|e| e.print(py))
|
||||
.map_err(|e| e.display(py))
|
||||
.expect("could not setitem");
|
||||
|
||||
py.run(
|
||||
|
@ -853,7 +853,7 @@ mod tests {
|
|||
None,
|
||||
Some(d),
|
||||
)
|
||||
.map_err(|e| e.print(py))
|
||||
.map_err(|e| e.display(py))
|
||||
.expect("assertion failed");
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1228,7 +1228,7 @@ a = A()
|
|||
Python::with_gil(|py| {
|
||||
let v = py
|
||||
.eval("...", None, None)
|
||||
.map_err(|e| e.print(py))
|
||||
.map_err(|e| e.display(py))
|
||||
.unwrap()
|
||||
.to_object(py);
|
||||
|
||||
|
|
|
@ -1041,7 +1041,7 @@ mod tests {
|
|||
// Make sure builtin names are accessible
|
||||
let v: i32 = py
|
||||
.eval("min(1, 2)", None, None)
|
||||
.map_err(|e| e.print(py))
|
||||
.map_err(|e| e.display(py))
|
||||
.unwrap()
|
||||
.extract()
|
||||
.unwrap();
|
||||
|
@ -1158,7 +1158,10 @@ mod tests {
|
|||
Python::with_gil(|py| {
|
||||
assert_eq!(py.Ellipsis().to_string(), "Ellipsis");
|
||||
|
||||
let v = py.eval("...", None, None).map_err(|e| e.print(py)).unwrap();
|
||||
let v = py
|
||||
.eval("...", None, None)
|
||||
.map_err(|e| e.display(py))
|
||||
.unwrap();
|
||||
|
||||
assert!(v.eq(py.Ellipsis()).unwrap());
|
||||
});
|
||||
|
|
|
@ -1402,7 +1402,10 @@ class SimpleClass:
|
|||
#[test]
|
||||
fn test_is_ellipsis() {
|
||||
Python::with_gil(|py| {
|
||||
let v = py.eval("...", None, None).map_err(|e| e.print(py)).unwrap();
|
||||
let v = py
|
||||
.eval("...", None, None)
|
||||
.map_err(|e| e.display(py))
|
||||
.unwrap();
|
||||
|
||||
assert!(v.is_ellipsis());
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ assert module_with_functions.foo() == 123
|
|||
None,
|
||||
None,
|
||||
)
|
||||
.map_err(|e| e.print(py))
|
||||
.map_err(|e| e.display(py))
|
||||
.unwrap();
|
||||
})
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ fn new_with_two_args() {
|
|||
let typeobj = py.get_type::<NewWithTwoArgs>();
|
||||
let wrp = typeobj
|
||||
.call((10, 20), None)
|
||||
.map_err(|e| e.print(py))
|
||||
.map_err(|e| e.display(py))
|
||||
.unwrap();
|
||||
let obj = wrp.downcast::<PyCell<NewWithTwoArgs>>().unwrap();
|
||||
let obj_ref = obj.borrow();
|
||||
|
@ -172,7 +172,7 @@ assert c.from_rust is False
|
|||
let globals = PyModule::import(py, "__main__").unwrap().dict();
|
||||
globals.set_item("SuperClass", super_cls).unwrap();
|
||||
py.run(source, Some(globals), None)
|
||||
.map_err(|e| e.print(py))
|
||||
.map_err(|e| e.display(py))
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ fn test_time_check() {
|
|||
fn test_datetime_check() {
|
||||
Python::with_gil(|py| {
|
||||
let (obj, sub_obj, sub_sub_obj) = _get_subclasses(py, "datetime", "2018, 1, 1, 13, 30, 15")
|
||||
.map_err(|e| e.print(py))
|
||||
.map_err(|e| e.display(py))
|
||||
.unwrap();
|
||||
unsafe { PyDateTime_IMPORT() }
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ fn subclass() {
|
|||
None,
|
||||
Some(d),
|
||||
)
|
||||
.map_err(|e| e.print(py))
|
||||
.map_err(|e| e.display(py))
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -689,7 +689,7 @@ asyncio.run(main())
|
|||
let globals = PyModule::import(py, "__main__").unwrap().dict();
|
||||
globals.set_item("Once", once).unwrap();
|
||||
py.run(source, Some(globals), None)
|
||||
.map_err(|e| e.print(py))
|
||||
.map_err(|e| e.display(py))
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
@ -746,7 +746,7 @@ asyncio.run(main())
|
|||
.set_item("AsyncIterator", py.get_type::<AsyncIterator>())
|
||||
.unwrap();
|
||||
py.run(source, Some(globals), None)
|
||||
.map_err(|e| e.print(py))
|
||||
.map_err(|e| e.display(py))
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
@ -815,7 +815,7 @@ assert c.counter.count == 1
|
|||
let globals = PyModule::import(py, "__main__").unwrap().dict();
|
||||
globals.set_item("Counter", counter).unwrap();
|
||||
py.run(source, Some(globals), None)
|
||||
.map_err(|e| e.print(py))
|
||||
.map_err(|e| e.display(py))
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue