Open juntyr opened 2 weeks ago
What is the performance impact of converting all source errors into rust compared to a plain PyErr?
What is the performance impact of converting all source errors into rust compared to a plain PyErr?
At the moment, this conversion scales linearly with the length of the causal chain. std::error::Error::source
returns a reference lifetime-bound to the original error, but PyErr::cause
returns an unbound PyErr
. Therefore, we need to materialize the full chain into a second chain on the Rust side (broadly speaking, struct PyErrChain { err: PyErr, source: Option<Box<PyErrChain>> }
). Since PyErr
can modify its cause through a clone, this materialization is also just a snapshot.
An alternative design I could think of is one that would provide a zero-cost wrapper around PyErr
and push all cost to when source
is called. Every error down the source chain would still point to the original top-level PyErr
but use type-system-level-only layers of wrapping to denote the chain depth. However, this would mean that when you have a reference to the 3rd cause in the chain and call it's source method, it would have to traverse all the way from the top-level back down to the 4th cause layer. Furthermore, this approach might need to panic if the causal chain has been modified in Python since wrapping it in Python.
Since I personally prefer the snapshot approach, I went with that one for the initial implementation.
I'd be delighted to hear if you have some ideas for how the API and its cost could be improved :)
I've recently been down a rabbit hole to improve error reporting across Python and Rust with preserved causality chains and just published the first version of my new https://github.com/juntyr/pyo3-error crate.
Most importantly, the crate provides conversions from
std::error::Error::source
causal chains topyo3::PyErr::cause
chains and a wrapper forPyErr
to interpret itspyo3::PyErr::cause
chain as astd::error::Error::source
chain.I hope that this crate might be useful to the broader PyO3 community (and I am sure someone will have ideas for how to make its API a lot more convenient :) )