Skip to content

Commit cea21f9

Browse files
Add more c-api error functions (#7915)
* Add more c-api error functions * Return NULL when no cause is set
1 parent 62b081b commit cea21f9

3 files changed

Lines changed: 74 additions & 2 deletions

File tree

crates/capi/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub mod pyerrors;
1717
pub mod pylifecycle;
1818
pub mod pystate;
1919
pub mod refcount;
20+
pub mod traceback;
2021
pub mod tupleobject;
2122
pub mod unicodeobject;
2223
mod util;

crates/capi/src/pyerrors.rs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use crate::PyObject;
2-
use crate::pystate::with_vm;
1+
use crate::object::define_py_check;
2+
use crate::{PyObject, pystate::with_vm};
33
use core::convert::Infallible;
44
use core::ffi::{CStr, c_char, c_int};
55
use core::ptr::NonNull;
@@ -96,6 +96,8 @@ define_exception_statics! {
9696
PyExc_EncodingWarning => encoding_warning,
9797
}
9898

99+
define_py_check!(fn PyExceptionInstance_Check, exceptions.base_exception_type);
100+
99101
#[unsafe(no_mangle)]
100102
pub extern "C" fn PyErr_Occurred() -> *mut PyObject {
101103
with_vm(|vm| {
@@ -191,6 +193,15 @@ pub unsafe extern "C" fn PyErr_WriteUnraisable(obj: *mut PyObject) {
191193
})
192194
}
193195

196+
#[unsafe(no_mangle)]
197+
pub unsafe extern "C" fn PyExceptionClass_Check(obj: *mut PyObject) -> c_int {
198+
with_vm(|vm| unsafe {
199+
obj.as_ref()
200+
.and_then(|obj| obj.downcast_ref::<PyType>())
201+
.is_some_and(|ty| ty.is_subtype(vm.ctx.exceptions.base_exception_type))
202+
})
203+
}
204+
194205
#[unsafe(no_mangle)]
195206
pub unsafe extern "C" fn PyErr_NewException(
196207
name: *const c_char,
@@ -252,6 +263,42 @@ pub unsafe extern "C" fn PyErr_GivenExceptionMatches(
252263
})
253264
}
254265

266+
#[unsafe(no_mangle)]
267+
pub unsafe extern "C" fn PyException_GetTraceback(exc: *mut PyObject) -> *mut PyObject {
268+
with_vm(|vm| {
269+
let exc = unsafe { &*exc }.try_downcast_ref::<PyBaseException>(vm)?;
270+
let tb = exc
271+
.__traceback__()
272+
.map(|tb| tb.into_object().into_raw().as_ptr())
273+
.unwrap_or_default();
274+
Ok(tb)
275+
})
276+
}
277+
278+
#[unsafe(no_mangle)]
279+
pub unsafe extern "C" fn PyException_GetCause(exc: *mut PyObject) -> *mut PyObject {
280+
with_vm(|vm| {
281+
let exc = unsafe { &*exc }.try_downcast_ref::<PyBaseException>(vm)?;
282+
let cause = exc
283+
.__cause__()
284+
.map(|cause| cause.into_object().into_raw().as_ptr())
285+
.unwrap_or_default();
286+
Ok(cause)
287+
})
288+
}
289+
290+
#[unsafe(no_mangle)]
291+
pub unsafe extern "C" fn PyException_GetContext(exc: *mut PyObject) -> *mut PyObject {
292+
with_vm(|vm| {
293+
let exc = unsafe { &*exc }.try_downcast_ref::<PyBaseException>(vm)?;
294+
let context = exc
295+
.__context__()
296+
.map(|context| context.into_object().into_raw().as_ptr())
297+
.unwrap_or_default();
298+
Ok(context)
299+
})
300+
}
301+
255302
#[cfg(test)]
256303
mod tests {
257304
use pyo3::exceptions::PyTypeError;

crates/capi/src/traceback.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use crate::PyObject;
2+
use crate::object::define_py_check;
3+
use crate::pystate::with_vm;
4+
use core::ffi::c_int;
5+
use rustpython_vm::function::{FuncArgs, KwArgs};
6+
7+
define_py_check!(exact fn PyTraceBack_Check, types.traceback_type);
8+
9+
#[unsafe(no_mangle)]
10+
pub unsafe extern "C" fn PyTraceBack_Print(tb: *mut PyObject, file: *mut PyObject) -> c_int {
11+
with_vm(|vm| {
12+
let tb = unsafe { &*tb };
13+
let file = unsafe { &*file };
14+
let tb_module = vm.import("traceback", 0)?;
15+
let print_tb = tb_module.get_attr("print_tb", vm)?;
16+
17+
let kwargs: KwArgs = [("file".to_string(), file.to_owned())]
18+
.into_iter()
19+
.collect();
20+
print_tb.call(FuncArgs::new(vec![tb.to_owned()], kwargs), vm)?;
21+
22+
Ok(())
23+
})
24+
}

0 commit comments

Comments
 (0)