Pylint: False-positive E1102 (not-callable) with list of functions

Created on 23 May 2017  路  5Comments  路  Source: PyCQA/pylint

Steps to reproduce

Run pylint on this code

cfg = [
        {'v': [0, 1], 'f': None},
        {'v': [1, 2], 'f': sum}
    ]

if __name__ == '__main__':
    for c in cfg:
        if c['f'] is not None:
            c['f'](c['v'])

Current behavior

Error on the last line:
test.py:9: [E1102(not-callable), ] c['f'] is not callable

Only the first item of the list is test to figure out if it is callable or not. If cfg is changed to

cfg = [
        {'v': [1, 2], 'f': sum},
        {'v': [0, 1], 'f': None}
    ]

then there is no error.

Expected behavior

No error

pylint --version output

pylint 1.7.1,
astroid 1.5.2
Python 2.7.12 (default, Nov 19 2016, 06:48:10)
[GCC 5.4.0 20160609]

topic-control-flow

Most helpful comment

Even with the if callable(f) test it still produces the same error. My use case with instance attributes:

# -*- coding: utf-8 -*
"""
Demo for false positive pylint E1102 error
"""


class Foo:
    """
    A class whose instance have a possibly callable
    attributes `func` and `func2`
    """

    def __init__(self):
        self.func = None
        self.func2 = None

    def run_func(self):
        """
        This function is ok if we define the `self.func`
        at least in one of the instances (see the main below)
        """
        if self.func and callable(self.func):
            return self.func()

    def run_func2(self):
        """
        This function will give us a E1102
        even when no its calls found!
        """
        if self.func2 and callable(self.func2):
            return self.func2()  # <-- E1102: 31,19: self.func2 is not callable (not-callable)


def main():
    """Entry point"""

    foo_obj = Foo()
    foo_obj.func = lambda: 42
    print(foo_obj.run_func())

    # even when the `func is None` on another instance
    # this code is still ok because of previous `func` assignment
    foo_obj2 = Foo()
    print(foo_obj2.run_func())


if __name__ == '__main__':
    main()

All 5 comments

Another similar use case.

class Test:

    # Override in child class
    _func = None

    def test(self):
        if self._func is not None:
            return self._func()

pylint could avoid this kind of false positives thanks to the is not None test but what if we know for sure that self._func has been replaced and we don't test?

Even with the if callable(f) test it still produces the same error. My use case with instance attributes:

# -*- coding: utf-8 -*
"""
Demo for false positive pylint E1102 error
"""


class Foo:
    """
    A class whose instance have a possibly callable
    attributes `func` and `func2`
    """

    def __init__(self):
        self.func = None
        self.func2 = None

    def run_func(self):
        """
        This function is ok if we define the `self.func`
        at least in one of the instances (see the main below)
        """
        if self.func and callable(self.func):
            return self.func()

    def run_func2(self):
        """
        This function will give us a E1102
        even when no its calls found!
        """
        if self.func2 and callable(self.func2):
            return self.func2()  # <-- E1102: 31,19: self.func2 is not callable (not-callable)


def main():
    """Entry point"""

    foo_obj = Foo()
    foo_obj.func = lambda: 42
    print(foo_obj.run_func())

    # even when the `func is None` on another instance
    # this code is still ok because of previous `func` assignment
    foo_obj2 = Foo()
    print(foo_obj2.run_func())


if __name__ == '__main__':
    main()

just adding my example here, for my future reference

import inspect
import typing


class Task:
    my_a: typing.Union[None, typing.Type["Task"]] = None

    def __init__(self,) -> None:
        if self.my_a is not None:
            assert inspect.isclass(self.my_a)
            assert issubclass(self.my_a, Task)
            assert callable(self.my_a)
            self.a = self.my_a()
            self.a.hello()

    def hello(self):
        print("hello")


class A(Task):
    my_a = Task

a: Task = A()
python cool.py
    hello

mypy --show-column-numbers -p cli -p cool # passes OK

pylint --enable=E --disable=W,R,C cool.py`
    cool.py:13:21: E1102: self.my_a is not callable (not-callable)

I am seeing this problem with pylint 2.4.4 on

lol = getattr('abc', 'nonexistent_attribute', None)
lolol = 3 if lol is None else lol()

.

Seeing this with astroid 2.5, Python 3.0, pylint 2.7.1, on code using progress module not substantially different from test code, though test code passes.

https://github.com/verigak/progress/

Was this page helpful?
0 / 5 - 0 ratings