diff --git a/crates/capi/src/lib.rs b/crates/capi/src/lib.rs index 35158e394de..7196ad23351 100644 --- a/crates/capi/src/lib.rs +++ b/crates/capi/src/lib.rs @@ -17,6 +17,7 @@ pub mod pyerrors; pub mod pylifecycle; pub mod pystate; pub mod refcount; +pub mod traceback; pub mod tupleobject; pub mod unicodeobject; mod util; diff --git a/crates/capi/src/pyerrors.rs b/crates/capi/src/pyerrors.rs index 4554757c66e..0052c1eac6d 100644 --- a/crates/capi/src/pyerrors.rs +++ b/crates/capi/src/pyerrors.rs @@ -1,5 +1,5 @@ -use crate::PyObject; -use crate::pystate::with_vm; +use crate::object::define_py_check; +use crate::{PyObject, pystate::with_vm}; use core::convert::Infallible; use core::ffi::{CStr, c_char, c_int}; use core::ptr::NonNull; @@ -96,6 +96,8 @@ define_exception_statics! { PyExc_EncodingWarning => encoding_warning, } +define_py_check!(fn PyExceptionInstance_Check, exceptions.base_exception_type); + #[unsafe(no_mangle)] pub extern "C" fn PyErr_Occurred() -> *mut PyObject { with_vm(|vm| { @@ -191,6 +193,15 @@ pub unsafe extern "C" fn PyErr_WriteUnraisable(obj: *mut PyObject) { }) } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyExceptionClass_Check(obj: *mut PyObject) -> c_int { + with_vm(|vm| unsafe { + obj.as_ref() + .and_then(|obj| obj.downcast_ref::()) + .is_some_and(|ty| ty.is_subtype(vm.ctx.exceptions.base_exception_type)) + }) +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn PyErr_NewException( name: *const c_char, @@ -252,6 +263,42 @@ pub unsafe extern "C" fn PyErr_GivenExceptionMatches( }) } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyException_GetTraceback(exc: *mut PyObject) -> *mut PyObject { + with_vm(|vm| { + let exc = unsafe { &*exc }.try_downcast_ref::(vm)?; + let tb = exc + .__traceback__() + .map(|tb| tb.into_object().into_raw().as_ptr()) + .unwrap_or_default(); + Ok(tb) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyException_GetCause(exc: *mut PyObject) -> *mut PyObject { + with_vm(|vm| { + let exc = unsafe { &*exc }.try_downcast_ref::(vm)?; + let cause = exc + .__cause__() + .map(|cause| cause.into_object().into_raw().as_ptr()) + .unwrap_or_default(); + Ok(cause) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyException_GetContext(exc: *mut PyObject) -> *mut PyObject { + with_vm(|vm| { + let exc = unsafe { &*exc }.try_downcast_ref::(vm)?; + let context = exc + .__context__() + .map(|context| context.into_object().into_raw().as_ptr()) + .unwrap_or_default(); + Ok(context) + }) +} + #[cfg(test)] mod tests { use pyo3::exceptions::PyTypeError; diff --git a/crates/capi/src/traceback.rs b/crates/capi/src/traceback.rs new file mode 100644 index 00000000000..5b264b1ddbc --- /dev/null +++ b/crates/capi/src/traceback.rs @@ -0,0 +1,24 @@ +use crate::PyObject; +use crate::object::define_py_check; +use crate::pystate::with_vm; +use core::ffi::c_int; +use rustpython_vm::function::{FuncArgs, KwArgs}; + +define_py_check!(exact fn PyTraceBack_Check, types.traceback_type); + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyTraceBack_Print(tb: *mut PyObject, file: *mut PyObject) -> c_int { + with_vm(|vm| { + let tb = unsafe { &*tb }; + let file = unsafe { &*file }; + let tb_module = vm.import("traceback", 0)?; + let print_tb = tb_module.get_attr("print_tb", vm)?; + + let kwargs: KwArgs = [("file".to_string(), file.to_owned())] + .into_iter() + .collect(); + print_tb.call(FuncArgs::new(vec![tb.to_owned()], kwargs), vm)?; + + Ok(()) + }) +}