Go Rusty with exception handling in Python
Redowan Delowar
February 2, 2022
While grokking Black formatter's codebase, I came across this [Rust-influenced error
handling model] that offers an interesting way of handling exceptions in Python. Exception
handling in Python usually follows the EAFP paradigm where it's easier to ask for
forgiveness than permission.
However, Rust has this [recoverable error] handling workflow that leverages generic Enums. I
wanted to explore how Black emulates that in Python. This is how it works:
In the above snippet, two generic types Ok and Err represent the return type and the
error types of a callable respectively. These two generics were then combined into one
Result generic type. You'd use the Result generic to handle exceptions as follows:
This will print:
If you run Mypy on the snippet, it'll succeed as well.
You can also apply constraints on the return or exception types as follows:
Running the script will give you this:
In this case, Mypy will catch the type inconsistency before runtime.
Breadcrumbs
Black extensively uses this [rusty pattern] in the transformation part of the codebase. This
showed me another way of thinking about handling recoverable exceptions while ensuring type
safety in a Python codebase.
However, I wouldn't go about and mindlessly refactor any exception handling logic that I
come across to follow this pattern. You might find it useful if you need to handle
exceptions in a recoverable fashion and need additional type safety around the logic.
Further reading
- [Beginner's guide to error handling in Rust]
[rust-influenced error handling model]:
https://github.com/psf/black/blob/main/src/black/rusty.py
[recoverable error]:
https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html
[rusty pattern]:
https://github.com/psf/black/blob/6417c99bfdbdc057e4a10aeff9967a751f4f85e9/src/black/trans.py#L61
[beginner's guide to error handling in rust]:
https://www.sheshbabu.com/posts/rust-error-handling/
Discussion in the ATmosphere