Search code examples
pythonpython-decoratorstype-hintingmypy

mypy call-arg error where default argument is set


I have code that looks like the following:

from typing import Callable


def decorate(func: Callable[[str], None]) -> Callable[[str], None]:
    return func


@decorate
def do_something(some_str: str = 'Hello world') -> None:
    print(some_str)


if __name__ == '__main__':
    do_something()

When running mypy, it reports the following error for the last line:

error: Too few arguments for "do_something" [call-arg]

How can I fix this error (without changing the return type of decorate to Callable[..., None])?


Solution

  • Use a TypeVar to indicate that the input and return type are equivalent and defined by the Callable received. Since Callable types include the entire signature, this lets the type checker infer positional/optional/keyword arguments as well.

    from typing import Callable, TypeVar
    
    # A type variable that can represent any Callable type
    C = TypeVar("C", bound=Callable)
    
    # The input Callable type defines the output Callable type as well
    def decorate(func: C) -> C:
        return func
    

    If decorate can only work with callables that may take a string, adjust the bound accordingly.

    # A type variable that can represent any Callable type that takes a string
    C = TypeVar("C", bound=Callable[[str], None])
    

    Notably, a callable taking a str or using a default still satisfies Callable[[str], None] since it can be called with a str argument.