You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Statically declare the exceptions E that a function f can raise, which will be statically checked by comparing E with the exceptions F that can be raised by the functions called inside f minus the exceptions C caught by f: E = F - C.
fromtypingimportCallable, NoReturn, ParamSpec, TypeVar, Protocol, cast# ==============================================================================# tooling# ==============================================================================defassert_never(value: NoReturn) ->NoReturn:
# This also works at runtime as wellassertFalse, f"This code should never be reached, got: {value}"P=ParamSpec("P")
R=TypeVar("R", covariant=True)
E=TypeVar("E", bound=tuple)
classRaisingFunc(Protocol[P, R, E]):
errors: Edef__call__(self, *args: P.args, **kwargs: P.kwargs) ->R:
...
defraises(errors: E) ->Callable[[Callable[P, R]], RaisingFunc[P, R, E]]:
defdecorator(func: Callable[P, R]) ->RaisingFunc[P, R, E]:
func=cast(RaisingFunc[P, R, E], func)
func.errors=errorsreturnfuncreturndecorator# ==============================================================================# demo code# ==============================================================================classSomeError(Exception):
...
classAnotherError(Exception):
...
@raises((ValueError, SomeError, AnotherError))deffoo(i: int):
ifi==0:
raiseValueError("Must not be zero")
elifi==1:
raiseSomeError("Must not be one")
elifi==2:
raiseAnotherError("Must not be two")
print("that's ok")
@raises((ValueError, AnotherError))defbar(i: int):
try:
foo(i)
exceptfoo.errorsase:
ifisinstance(e, SomeError):
print("ignore some error")
else:
raisetry:
bar(0)
exceptbar.errorsase:
ifisinstance(e, ValueError):
print("value error")
elifisinstance(e, AnotherError):
print("some error")
else:
# Here mypy checks for exhaustivenessassert_never(e)
raise
Requires Mypy plugin, or new feature
classSomeError(Exception):
...
classAnotherError(Exception):
...
@raises((ValueError, SomeError, AnotherError))deffoo(i: int):
ifi==0:
raiseValueError("Must not be zero")
elifi==1:
raiseSomeError("Must not be one")
elifi==2:
raiseAnotherError("Must not be two")
print("that's ok")
# mypy checks that @raises arguments are correct, as mypy deduces# from the source code that (ValueError, SomeError, AnotherError)# can be raised.@raises((ValueError, AnotherError))defbar(i: int):
try:
foo(i)
exceptfoo.errorsase:
ifisinstance(e, SomeError):
print("ignore some error")
else:
raise# mypy checks that @raises arguments are correct, as mypy deduces# from the source code that (ValueError, AnotherError) can be# raised, because mypy see that foo(i) can raise# (ValueError, SomeError, AnotherError), but SomeError is catchedtry:
bar(0)
exceptValueError:
print("value error")
exceptAnotherError:
print("some error")
# Here mypy checks for exhaustiveness, as it knows that bar(i) can raise# ValueError or AnotherError
Edge cases
I didn't think to much for now to edge cases or counter examples that do not work.
The text was updated successfully, but these errors were encountered:
Personally I'd like to see the discussion include some learnings from other languages. For example, Java had checked exceptions pretty much from the start. Interesting to see how that fared for them. I know other languages were not quick to adopt those. But this is all probably a topic for python/typing.
Duplicate of e.g. #7326 (and agreed that python/typing is now the better repo to discuss). In general, I think checked exceptions aren't particularly viable in Python
Feature
More support on exception static checking.
Pitch
Statically declare the exceptions E that a function f can raise, which will be statically checked by comparing E with the exceptions F that can be raised by the functions called inside f minus the exceptions C caught by f: E = F - C.
Also discussed in typing-sig mailing list.
Example
Working with Python 3.11
Requires Mypy plugin, or new feature
Edge cases
I didn't think to much for now to edge cases or counter examples that do not work.
The text was updated successfully, but these errors were encountered: