You can’t use Callable to say anything about additional arguments; they are not generic. Your only option is to say that your decorator takes a Callable and that a different Callable is returned.
In your case you can nail down the return type with a typevar:
RT = TypeVar('RT') # return type
def inject_user() -> Callable[[Callable[..., RT]], Callable[..., RT]]:
def decorator(func: Callable[..., RT]) -> Callable[..., RT]:
def wrapper(*args, **kwargs) -> RT:
# ...
Even then the resulting decorated foo() function has a typing signature of def (*Any, **Any) -> builtins.bool* when you use reveal_type().
Various proposals are currently being discussed to make Callable more flexible but those have not yet come to fruition. See
- Allow variadic generics
- Proposal: Generalize
Callableto be able to specify argument names and kinds - TypeVar to represent a Callable’s arguments
- Support function decorators excellently
for some examples. The last one in that list is an umbrella ticket that includes your specific usecase, the decorator that alters the callable signature:
Mess with the return type or with arguments
For an arbitrary function you can’t do this at all yet — there isn’t even a syntax. Here’s me making up some syntax for it.