In Flask, @app.errorhandler() is used to create a decorator that will decorate a user function that takes one argument, a type of exception. We've tried the following to type annotate this decorator, but have been unsuccessful in getting useful type checking out.
from __future__ import annotations
import typing as t
# ErrorBound = t.TypeVar("ErrorBound", bound=t.Type[Exception])
# HandlerCallable = t.Callable[[ErrorBound], None]
HandlerCallable = t.Callable[[Exception], None]
HandlerDecorator = t.TypeVar("HandlerDecorator", bound=HandlerCallable)
def handler(code: t.Type[Exception]) -> t.Callable[[HandlerDecorator], HandlerDecorator]:
def wrapper(f: HandlerDecorator) -> HandlerDecorator:
return f
return wrapper
# This is the basic use case. It should pass.
@handler(ValueError)
def one(e: ValueError) -> None:
pass
# This should pass. It's not required to match the decorator
# argument to the decorated parameter, although that would b a nice bonus.
@handler(ValueError)
def two(e: Exception) -> None:
pass
# This should also pass. It is possible to stack the decorator,
# and the user should be able to annotate that their function
# takes a union of Exceptions.
@handler(ValueError)
@handler(TypeError)
def three(e: ValueError | TypeError) -> None:
pass
# This should fail, str is not a type of exception.
@handler(ValueError)
@handler(TypeError)
def four(e: str) -> None:
pass
With the uncommented types at the top, only the two function passes. Mypy requires that the argument type is exactly Exception.
If the TypeVar and alternate HandlerCallable are uncommented, all four functions pass, but the four function should fail. I've come to understand that this is not the correct way to use TypeVar because it's treated as Any. However, I can't think of another way to express "the argument of this function can be any exception type".
In Flask,
@app.errorhandler()is used to create a decorator that will decorate a user function that takes one argument, a type of exception. We've tried the following to type annotate this decorator, but have been unsuccessful in getting useful type checking out.With the uncommented types at the top, only the
twofunction passes. Mypy requires that the argument type is exactlyException.If the
TypeVarand alternateHandlerCallableare uncommented, all four functions pass, but thefourfunction should fail. I've come to understand that this is not the correct way to useTypeVarbecause it's treated asAny. However, I can't think of another way to express "the argument of this function can be any exception type".