Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

not-callable false positive in type narrowing #7412

Closed
mttbernardini opened this issue Sep 5, 2022 · 5 comments
Closed

not-callable false positive in type narrowing #7412

mttbernardini opened this issue Sep 5, 2022 · 5 comments
Labels
Control flow Requires control flow understanding False Positive 🦟 A message is emitted but nothing is wrong with the code Needs PR This issue is accepted, sufficiently specified and now needs an implementation

Comments

@mttbernardini
Copy link

Bug description

Pylint emits a false positive when calling func(), which shouldn't happen because of the type narrowing of the if.

from typing import Optional

class W():
    def __init__(self, f):
        self.f = f

    def __call__(self, *args, **kwargs):
        print("> Call")
        r = self.f(*args, **kwargs)
        print("< Ret")
        return r

func: Optional[W] = None

def test():
    if func is not None:
        func()

I noticed that if I add to the previous code the following snippet, the error disappears:

def init():
    global func
    func = W(lambda x: x-2)

Similarly, the error is not emitted if func is initialized directly in global scope.

However I think this kind of inference is wrong because the above code could be a module and func could be set from outside and the if is guarding that scenario 🤔

Configuration

No response

Command used

pylint --disable=C,R callable.py

Pylint output

************* Module callable
callable.py:17:8: E1102: func is not callable (not-callable)

Expected behavior

pylint shouldn't report E1102 in this case.

Pylint version

pylint 2.15.0
astroid 2.12.5
Python 3.8.2 (default, Jun  8 2021, 11:59:35) 
[Clang 12.0.5 (clang-1205.0.22.11)]

OS / Environment

MacOS 11.5.2

Additional dependencies

No response

@mttbernardini mttbernardini added the Needs triage 📥 Just created, needs acknowledgment, triage, and proper labelling label Sep 5, 2022
@Pierre-Sassoulas Pierre-Sassoulas added Control flow Requires control flow understanding False Positive 🦟 A message is emitted but nothing is wrong with the code Needs PR This issue is accepted, sufficiently specified and now needs an implementation and removed Needs triage 📥 Just created, needs acknowledgment, triage, and proper labelling labels Sep 5, 2022
@DanielNoord
Copy link
Collaborator

This is just something that pylint is not good at. We struggle with some control flow inference using if and we don't take type annotation into account currently. This could change in the future though.

@joelspadin
Copy link

I found a similar case which is likely the same root cause:

class Base:
    pass

class Version1(Base):
    pass

class Version2(Base):
    pase

def get_type(version: int) -> type[Base]:
    if version == 1:
        return Version1
    if version == 2:
        return Version2
    raise NotImplementedError()

version = 1
cls = get_type(version)
obj = cls() # not-callable

If I change get_type to

def get_type(version: int) -> type[Base]:
    if version == 1:
        return Version1
    if version == 2:
        return Version2
    raise NotImplementedError()
    return Version1

then it no longer gives the false positive not-callable but instead (correctly) gives a unreachable on the extra return I added.

@kojiromike

This comment was marked as off-topic.

@Pierre-Sassoulas

This comment was marked as off-topic.

@jacobtylerwalls
Copy link
Member

Fixed in pylint-dev/astroid#1189 (astroid 2.13)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Control flow Requires control flow understanding False Positive 🦟 A message is emitted but nothing is wrong with the code Needs PR This issue is accepted, sufficiently specified and now needs an implementation
Projects
None yet
Development

No branches or pull requests

6 participants