Deriving BaseException
for custom error enums
#4165
-
Hi there, My library is used both in Rust and in Python, so many functions return, e.g., However, in Python, the only way to catch an error from my library is with a generic try/except, e.g.: try:
Epoch("2024-05-32 00:00:00")
except Exception as e: # Bare
print(e) This works, but idiomatic Python recommends that a specific exception be caught instead of just Is there a way to derive Thanks |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 5 replies
-
I don't think that just implementing that function is sufficient. impl DurationError {
fn type_object_raw(py: Python<'_>) -> *mut PyTypeObject {
static TYPE_OBJECT: GILOnceCell<Py<PyType>> = GILOnceCell::new();
TYPE_OBJECT
.get_or_init(py, || {
PyErr::new_type_bound(
py,
"hifitime.DurationError",
Some("mydoc"),
Some(&py.get_type_bound::<DurationError>()),
None,
)
.expect("Failed to initialize new exception type.")
})
.as_ptr() as *mut PyTypeObject
}
}
#[pymethods]
impl Duration {
fn test_raise(&self) -> Result<(), DurationError> {
Err(DurationError::Overflow)
}
} >>> from hifitime import Duration, DurationError
>>> Duration.MIN().test_raise
<built-in method test_raise of hifitime.Duration object at 0x7f0dcd2fdda0>
>>> Duration.MIN().test_raise()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception: Overflow
>>> try:
... Duration.MIN().test_raise()
... except DurationError as e:
... print(e)
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
Exception: Overflow
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
TypeError: catching classes that do not inherit from BaseException is not allowed
>>> |
Beta Was this translation helpful? Give feedback.
-
I think you want to expose a custom exception type and use that while converting you library error into // your library error type
pub enum EpochError { ... }
// The exception type that gets exposed to Python
// alternativly the `create_exception!` macro should also work
#[pyclass]
#[pyo3(name = "EpochError", extends = PyBaseException)] // or PyException
pub struct PyEpochError {}
#[pymethods]
impl PyEpochError {
#[new]
#[pyo3(signature = (*_args, **_kwargs))]
fn new(_args: Bound<'_, PyTuple>, _kwargs: Option<Bound<'_, PyDict>>) -> Self {
Self {}
}
}
// convert you library error into a PyErr using the custom exception type
impl From<EpochError> for PyErr {
fn from(value: EpochError) -> Self {
// example: use the display impl as error msg
PyErr::new::<PyEpochError, _>(value.to_string())
}
} This should allow you to catch the specific exception from Python try:
some_function_that_raises_epoch_error()
except EpochError:
pass
|
Beta Was this translation helpful? Give feedback.
I think you want to expose a custom exception type and use that while converting you library error into
PyErr
. Perhaps you can do something like this: