-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Closed
Labels
bugmypy got something wrongmypy got something wrong
Description
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:
passWith 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".
Metadata
Metadata
Assignees
Labels
bugmypy got something wrongmypy got something wrong