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

False positive used-before-assignment when assignment can be an import #3127

Closed
mthuurne opened this issue Sep 24, 2019 · 7 comments
Closed
Assignees
Milestone

Comments

@mthuurne
Copy link
Contributor

Steps to reproduce

Run pylint on the following code:

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from collections import Counter
else:
    Counter = object

def tick(c: Counter, name: str) -> None:
    c[name] += 1

While this example is rather pointless, I use similar constructs a lot when I have to import a name only for the purpose of type checking. It helps avoid import cycles between modules.

Current behavior

pylint reports on the def tick line:

E0601: Using variable 'Counter' before assignment (used-before-assignment)

Expected behavior

No errors are reported, since Counter is guaranteed to be defined.

pylint --version output

pylint 2.4.0
astroid 2.3.0
Python 3.7.2 (default, Feb 26 2019, 13:02:33)
[GCC 7.3.1 20180323 [gcc-7-branch revision 258812]]

@mthuurne
Copy link
Contributor Author

That's quick. Thanks!

@mthuurne
Copy link
Contributor Author

It seems the fix in 2.4.1 fixes the case where one type is imported inside a type guard, but when multiple types are imported, there is still an error reported for every type except the first.

For this test case:

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from collections import Counter
    from collections import OrderedDict
else:
    Counter = object
    OrderedDict = object

def tick(c: Counter, deltas: OrderedDict) -> None:
    for name, delta in deltas.items():
        c[name] += delta

pylint reports:

E0601: Using variable 'OrderedDict' before assignment (used-before-assignment)

@Deimos
Copy link

Deimos commented Dec 17, 2019

I'm still seeing this false positive on a similar case. For me, it's a workaround because mypy doesn't deal with SQLAlchemy's hybrid_property decorator correctly, so I do this:

if TYPE_CHECKING:
    from builtins import property as hybrid_property
else:
    from sqlalchemy.ext.hybrid import hybrid_property

This makes it so that mypy treats @hybrid_property as @property and understands the getter/setter methods. However, it's causing a used-before-assignment error in pylint 2.4.4.

@snejus
Copy link

snejus commented May 31, 2020

Same issue here, pylint 2.5.2:

from typing import TYPE_CHECKING, Type

if TYPE_CHECKING:
    from django.db.models import Model

def run(sender: Type[Model]):

@mthuurne
Copy link
Contributor Author

Same issue here, pylint 2.5.2:

from typing import TYPE_CHECKING, Type

if TYPE_CHECKING:
    from django.db.models import Model

def run(sender: Type[Model]):

I think in that example pylint is correct to report an error, since that will lead to a runtime error when executed and Model is undefined when the def statement runs.

@snejus
Copy link

snejus commented Jun 1, 2020

You are entirely correct - sorry for making waves :)

@wieczorek1990
Copy link

Use:

from __future__ import annotations

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants