python/mypy

"object" not callable (another thorny `partial` issue)

rknLA opened this issue · 6 comments

rknLA commented

I suspect that this will be closed in favor of #1484, but it seemed that creating a separate issue would be more convenient for tidiness.

I have some code which is yielding a mypy error:

error: "object" not callable

The code looks similar to this (with the line of the error denoted by <---):

from functools import partial
from another_module import another_mutator

TAnyDict = Dict[str, Any]

def mutator1(bar: TAnyDict, baz: TAnyDict) -> TAnyDict:
    # ...
    return bar

def mutator2(bar: TAnyDict, baz: TAnyDict) -> TAnyDict:
    # ...
    return bar

# ... etc, more mutator functions

some_local_var = 'foo'
some_functions = [  # type: List[Callable[[TAnyDict, TAnyDict], TAnyDict]] 
    mutator1,
    mutator2,
    partial(another_mutator, some_local_var),
    mutator3,
    mutator4
]

for d in some_other_dicts:
    res = {}
    for func in some_functions:
        res = func(res, some_dict)  # <--- this is the line that causes the error
    do_something_with(res)

It was only after fully writing out an Issue for this that I realized that the core issue was related to lack of partial support, rather than an issue with my Callable declaration, or a different bug in mypy.

Obviously this will become a moot point when partial is properly supported, but in the meantime, I would have expected the mypy error to occur on the partial(...) line within the list, rather than within the for loop.

The latest mypy version complains about the example (the type annotation for some_functions is on the wrong line):

t.py:17: error: misplaced type annotation

If the annotation is left out, I can reproduce the issue -- the inferred type of some_functions will be List[object]. This is because the join of the result of partial(...) and a callable is object.

The recommended workaround is to use lambda or define a function using def instead of using partial when the latter doesn't work correctly.

The fix to #797 may also fix this issue.

rknLA commented

Looks like a typo snuck in there? #2786 looks like it addresses #2778

Whoops. Thanks for noticing!

@gvanrossum I believe mypy indeed should special-case functools.partial, in a way that will make binding of self (including the treatment of selftype) "fall out" of the implementation.

I think this should be closed in favour of #1484 (especially taking into account that there is partial support of partial due to protocols landed, so that the only way now is to write a plugin, see #1484).