@CamilloMoschner and i have been talking a lot about a good api design for error handling. Ideally we make
- a pattern that can be shared across all front ends to handle all errors.
- a standard library of error handlers, while also allowing the user to easily write their own.
- stackable error handlers: “retry pickup in the same place, if that doesn’t work try the next 5 tipspots, if that doesn’t work send a slack message.”
Below are three main ideas. I will use lh.pick_up_tips
to demonstrate because it’s an easy example, but keep in mind we should generalize to all methods.
1. Context manger
PoC PR here: error handling: option 1 (PoC) by rickwierenga · Pull Request #507 · PyLabRobot/pylabrobot · GitHub
with lh.on_fail(ChannelizedError, try_next_tip_spot(iter(tip_rack["B1:H1"]))):
await lh.pick_up_tips(tip_rack["A1"])
- You can stack context managers.
- It’s nice that it’s possible to use he same error handler on multiple calls / across functions.
- However it’s also a downside. Camillo raised a good point that this is too dangerous: it’s not clear which error handler is active where. You can have things like:
with lh.on_fail(ChannelizedError, try_next_tip_spot(iter(tip_rack["B1:H1"]))):
deep_function()
The other two options are specific to each lh/frontend call. “It does mean more code for every command but it means it is very clear what error handling is applied to what command and how”
2. Separate functions that do error handling
Roughly the following:
await lhtip_pickup_handler(
tip_iterator=iter(tip_rack["B1:H1"]))
...
)
essentially new functions that incorporate error handling.
It’s nice that it’s very explicit what’s going on. The main downsides are adding error handling would completely change your code, and it’s not clear how you would stack error handlers. It can also cloud/make ambiguous the api of the front end.
3. A new parameter to existing functions
Similar to #2, but using the original method as opposed to having a new method wrapping the original, we pass the handler as an argument to the existing method
await lh.pick_up_tips(
tip_rack["A1"],
error_handler=try_next_tip_spot(iter(tip_rack["B1:H1"]))
)
what do you think?