Better handling of `anyhow::Error` and `eyre::Report`
Both anyhow::Error and eyre::Report are for dynamic error handling, I think it's feasible to make some improvements:
- Unwrap inner error, if it's containing a
PyErr(However extra information should be combined to?) - Extract the error chain into an exception chain (since both libraries have
Error::chain/Report::chain)
I'm willing to contribute :)
I think it would be best to propose concrete separate PR for these changes to discuss them based on a concrete implementation instead of in the abstract.
As far as I understand anyhow already prints its error in a similar manner to how nested exceptions are printed. What difference would this make and what things would it let you do that you cannot do right now?
As far as I understand anyhow already prints its error in a similar manner to how nested exceptions are printed. What difference would this make and what things would it let you do that you cannot do right now?
When using anyhow::Result as function return type, RuntimeError is always raised when an error occurred. I have some Python callbacks to call within the Rust function, whose exceptions will also be converted to RuntimeError (PyErr -> anyhow::Error -> PyErr)
I'm not entirely sure what you want - do you want to be able to return a anyhow::Error to python, have it converted to a RuntimeError and then be able to get the original error back? If so that'll be hard because right now we just convert it to a string and create a RuntimeError with that.
I'm not entirely sure what you want - do you want to be able to return a anyhow::Error to python, have it converted to a RuntimeError and then be able to get the original error back? If so that'll be hard because right now we just convert it to a string and create a RuntimeError with that.
I prefer letting the original error bubble up, other errors get converted to RuntimeError. (Error::downcast(PyErr))
I don't understand you at all. Can you maybe give an example?
If you have an instance of anyhow::Error that was created from a PyErr via impl From<E> for anyhow::Error where E: std::error::Error, then instead of our current approach
impl From<anyhow::Error> for PyErr {
fn from(err: anyhow::Error) -> Self {
PyRuntimeError::new_err(format!("{:?}", err))
}
}
do something like
impl From<anyhow::Error> for PyErr {
fn from(err: anyhow::Error) -> Self {
if let Ok(err) = err.downcast::<Self>() {
return err;
}
PyRuntimeError::new_err(format!("{:?}", err))
}
}
impl From<anyhow::Error> for PyErr {
fn from(error: anyhow::Error) -> Self {
match error.downcast::<Self>() {
Ok(py_err) => py_err,
Err(error) => PyRuntimeError::new_err(format!("{:?}", error))
}
}
}
impl From<eyre::Report> for PyErr {
fn from(error: Report) -> Self {
match error.downcast::<Self>() {
Ok(py_err) => py_err,
Err(report) => PyRuntimeError::new_err(format!("{:?}", report))
}
}
}
This one should do the work.
However I think it's too naive:
anyhow::Error&eyre::Reportboth support "error chain", which should be presented in the result exception.anyhow::Errorhas an additionalcontext, which I'm thinking about how to present that. (BaseException.__notes__seems relevant, however it's added in Python 3.11.)
However I think it's too naive:
Probably, but getting those into the main branch would be an improvement already. Why not open a PR?