A better way to handle exception?
Hi there,
Thank you so much for this gem. I have been using Effect.ts in Typescript, and I think what you did here is very close to Effect.ts.
There is one thing I am trying to do, but due to the lack of skill, I haven't managed to yet.
Do you think it is possible to create a handle function such that as we specify a handler function, it should return an effect without the handled exception?
It should look something like this, but I think type subtraction/exclusion is not possible in Python yet.
def handle(
effect: Effect[Dep1, Exception1 | Exception2, T1],
error_tag: Exception1,
handler: Callable[[Exception1], Effect[Dep2, Exception3, T2]]
) -> Effect[Dep1 | Dep2, Exception2 | Exception3, T1 | T2]:
...
Hi there! Sorry about the delay in response, I have been out making adventures with other projects 😅
I think type subtraction/exclusion is not possible in Python yet.
Correct, sadly I don't think there is anyway to type what you want. For specific errors you can of course do:
from stateless import catch, throw, Try
def some_effect() -> Try[RuntimeError | IOError | ZeroDivisionError, str]:
...
def handle_some_errors() -> Try[RuntimeError | ZeroDivisionError, str]:
result = yield from catch(some_effect)()
match result:
case str(result):
return result
case IOError():
return "default value on io error"
case e:
# this abomination is to make the type checker
# shut up about this code path missing a return
return (yield from throw(e))
If you come up with a good pattern for this, please do share! 😄
Hi again. It only took me 9 months, but I think I may have come up with a solution to this problem 😄
It seems a function with this signature:
def catch_just(
*e: Type[E2],
) -> Callable[[Callable[P, Effect[A, E2 | E, R]]], Callable[P, Effect[A, E, R | E2]]]:
...
Is possible, and produces the expected types both with mypy and pyright. I haven't tested any other type checkers.
For example:
from stateless import Runtime, Success, Try, catch_just, throws
@throws(ValueError, ZeroDivisionError)
def f() -> Success[str]:
raise ZeroDivisionError()
def use_f() -> Try[ValueError, str]:
maybe_s = yield from catch_just(ZeroDivisionError)(f)()
reveal_type(maybe_s) # revealed type is: ZeroDivisionError | str
match maybe_s:
case ZeroDivisionError():
return "default value"
case s:
return s
I just released an implementation of this for version 0.5.3. Check out the readme of the latest release for details.