Why does mypy give errors, indirectly calling a function through the variable with collections.abc.Callable? and How can I solve the errors?

mypy doesn’t give any errors, directly calling a function as shown below:

def func(x: int, y: int = 5) -> int:
    return x+y

print(func(3))        # No error
print(func(2, 4))     # No error
print(func(x=3))      # No error
print(func(x=2, y=4)) # No error

But mypy gives the errors, indirectly calling a function through the variable with collections.abc.Callable as shown below:

from collections.abc import Callable


def func(x: int, y: int = 5) -> int:
    return x+y

v: Callable[[int, int], int] = func # Here

print(v(3))        # error: Too few arguments  
print(v(x=3))      # error: Unexpected keyword argument "x"  
print(v(x=2, y=4)) # error: Unexpected keyword argument "x"  
                   # error: Unexpected keyword argument "y"
                   
print(v(2, 4)) # No error

Now, why does mypy give the errors, indirectly calling a function through the variable with collections.abc.Callable? and How can I solve the errors?

The reason is that Callable[[int, int], int] denotes a callable object (like a function) that can be called with 2 integers as positional arguments and that returns an integer. Therefore, print(v(2, 4)) works.

In order to represent other signatures, you can use typing.Protocol:

class MyType(typing.Protocol):
    @staticmethod
    def __call__(x: int, y: int = ...) -> int: ...

Then you should be able to write

v: MyType = func
print(v(3))
...

However, you cannot write

def func(x: int, z: int = 5) -> int:
    return x+z

v: MyType = func

because MyType represents a callable that can be called with 1 or 2 parameters, where the first parameter could be either provided as positional parameter or as parameter with name x and the second parameter could be either provided as positional parameter or as parameter with name y or omitted.

1 Like

Mypy errors occur because collections.abc.Callable expects exactly two arguments and ignores defaults or keywords. Using typing.Callable with a matching signature fixes the issue.

The docstring for typing.Callable says

Deprecated alias to collections.abc.Callable.
[...]
There is no syntax to indicate optional or keyword arguments;
such function types are rarely used as callback types.

So, please elaborate: How can one do this with typing.Callable?

2 Likes

To fix the Mypy errors, use typing.Callable instead of collections.abc.Callable and specify the full function signature including argument types and the return type. For example, Callable[[int, str], bool] defines a function taking an int and a str and returning a bool. If the signature is complex or unknown, you can use Callable[..., bool] to allow any arguments with a bool return type. This ensures Mypy correctly recognizes the types and avoids errors related to the strict argument rules of collections.abc.Callable.

typing.Callable and collections.abc.Callable are the same thing. They do not work differently in any way, whatshowever, and type-checkers used to say the same. Now that typing.Callable and other ABC’s in typing are deprecated, it will give even more errors.

To be honest, this response sound like you did not use typing before, haven’t read the docs, or just didn’t use it for a long time. It is (and was!) clearly stated, that typing.Callable is an alias or the collections.abc counterpart, and that it is deprecated too, as @tstefan clearly stated. Doing what you suggested would just add more errors, whilst the first reply on this topic already gave a working solution.

Please try and check what you post before you post it, especially when trying to answer the questions of others.

Also, to be fair, the phrasing of your reply sounds like it was AI generated, which is discouraged. If someone could just Google a solution, they would most likely not ask here. They would have already Googled it, and asked AI too. They are here, because they expect people with experience to help them.

1 Like