Skip to content

E0602 (undefined-variable) - False positive #3298

@arquolo

Description

@arquolo

Given:

> pylint --version
pylint 2.6.0
astroid 2.4.2
Python 3.8.5 (default, Sep  3 2020, 21:29:08) [MSC v.1916 64 bit (AMD64)]

> tree .
.
├──bug
│  ├── __init__.py
│  └── module.py
└──run_bug.py

with bug/__init__.py:

from .module import *

__all__ = module.__all__

and bug/module.py:

__all__ = ['func']

def func() -> None:
    print('works')

and run_bug.py:

from bug import func

func()

code works:

> python -c "import bug ; bug.func()"
works

and this also works:

> python run_bug.py
works

and bug is here:

> pylint bug run_bug --disable=C
************* Module bug
bug\__init__.py:3:10: E1101: Class 'module' has no '__all__' member (no-member)
bug\__init__.py:3:10: E0602: Undefined variable 'module' (undefined-variable)

Problem is that when * is imported from bug.module, module becomes imported to bug, but PyLint thinks that it doesn't.
All I wanted is to delegate filling of __all__ to submodules, like in asyncio.
Explanation is here.

Activity

jamesbraza

jamesbraza commented on Nov 6, 2020

@jamesbraza

I believe I'm hitting this same bug. Seems like the problem lies with some combination of:

  • __all__ in one file
  • Local folder + wildcard importing in another file

Minimal Repro

other_file:

__all__ = ["name"]

name = "foo"

main_file:

from .other_file import *

_ = name

This results in the following error message:

main_file.py: E0602: Undefined variable 'name' (undefined-variable)

Output of pylint --version:

pylint 2.6.0
astroid 2.4.2
Python 3.8.6 (default, Oct 27 2020, 11:18:42)
[Clang 12.0.0 (clang-1200.0.32.27)]
hippo91

hippo91 commented on Nov 19, 2020

@hippo91
Contributor

@jamesbraza i'm trying to reproduce your case but i end up with ImportError: attempted relative import with no known parent package when running python3 main.py. The file structure is:

tree . 
.
├── main_file.py
└── other_file.py

0 directories, 2 files
jamesbraza

jamesbraza commented on Nov 19, 2020

@jamesbraza

Hi @hippo91 sorry it looks like I was invoking my minimal repro differently. The error you're getting lies in the concepts from this stack overflow question: Relative imports in Python 3.

There are multiple options at invocations for directly with python3, including:

  • Removing the . from from .other_file import * in main_file.py and use python3 main_file.py
  • Adding a parent directory undef_var_bug and change import to include parent folder
undef_var_bug
├── main_file.py
└── other_file.py

Update import in from undef_var_bug.other_file import *, and invoke via python3 -m undef_var_bug.main_file.

Let me know if neither of those work for you.

hippo91

hippo91 commented on Nov 26, 2020

@hippo91
Contributor

@jamesbraza , i tested with the first solution. So i have the following code structure:

tree bug_pylint_3298
bug_pylint_3298
├── main_file.py
└── other_file

with:

cat bug_pylint_3298/main_file.py
from other_file import *

_ = name

and

cat bug_pylint_3298/other_file.py
__all__ = ["name"]

name = "foo"

Then linting is ok:

pylint bug_pylint_3298
************* Module bug_pylint_3298.main_file
bug_pylint_3298/main_file.py:1:0: C0114: Missing module docstring (missing-module-docstring)
bug_pylint_3298/main_file.py:1:0: W0401: Wildcard import other_file (wildcard-import)
************* Module bug_pylint_3298.other_file
bug_pylint_3298/other_file.py:1:0: C0114: Missing module docstring (missing-module-docstring)
bug_pylint_3298/other_file.py:3:0: C0103: Constant name "name" doesn't conform to UPPER_CASE naming style (invalid-name)
pylint --version
pylint 2.6.1-dev1
astroid 2.5.0
Python 3.7.9 (default, Nov 26 2020, 08:29:18) 
[GCC 8.3.0]

The false positive undefined-variable message emission doesn't occur. Do you agree?

arquolo

arquolo commented on Nov 26, 2020

@arquolo
Author

@hippo91
No, undefined-variable message does occur, you invoke it wrong. I have updated issue

changed the title [-]E0602 False positives[/-] [+]E1101 False positive[/+] on Nov 26, 2020
jamesbraza

jamesbraza commented on Nov 27, 2020

@jamesbraza

@hippo91 so I copied what you'd set up, and I figured out the problem, I don't believe your code actually runs. I know because when I ran it via python -m bug_pylint_3298.main_file, the result was: ModuleNotFoundError: No module named 'other_file'

Your main_file.py begins with from other_file:

from other_file import *

However, it should be:

from bug_pylint_3298.other_file import *

And now the module executes as intended. And then when you invoke pylint, the bug surfaces:

(venv) ➜  bananas_dir pylint bug_pylint_3298
************* Module bug_pylint_3298.main_file
bug_pylint_3298/main_file.py:1:0: C0114: Missing module docstring (missing-module-docstring)
bug_pylint_3298/main_file.py:1:0: E0401: Unable to import 'bug_pylint_3298.other_file' (import-error)
bug_pylint_3298/main_file.py:1:0: W0401: Wildcard import bug_pylint_3298.other_file (wildcard-import)
bug_pylint_3298/main_file.py:3:4: E0602: Undefined variable 'name' (undefined-variable)
************* Module bug_pylint_3298.other_file
bug_pylint_3298/other_file.py:1:0: C0114: Missing module docstring (missing-module-docstring)
bug_pylint_3298/other_file.py:3:0: C0103: Constant name "name" doesn't conform to UPPER_CASE naming style (invalid-name)

To fix it in this case, one can add an __init__.py to the bug_pylint_3298 directory, and it seems the error disappears.

(venv) ➜  bananas_dir pylint bug_pylint_3298
************* Module bug_pylint_3298.main_file
bug_pylint_3298/main_file.py:1:0: C0114: Missing module docstring (missing-module-docstring)
bug_pylint_3298/main_file.py:1:0: W0401: Wildcard import bug_pylint_3298.other_file (wildcard-import)
************* Module bug_pylint_3298.other_file
bug_pylint_3298/other_file.py:1:0: C0114: Missing module docstring (missing-module-docstring)
bug_pylint_3298/other_file.py:3:0: C0103: Constant name "name" doesn't conform to UPPER_CASE naming style (invalid-name)

Seems like pylint:

  1. Fails to realize the code actually runs
  2. Then reports import-error
  3. Finally reports undefined-variable, since it can't seem to parse the wildcard import (hence the preceding import-error)
jamesbraza

jamesbraza commented on Nov 27, 2020

@jamesbraza

However, @arquolo seems to have changed the issue to be from E0602 (undefined-variable) to E1101 (no-member) w.r.t. module.__all__, which now makes my contributions here being sort of off-topic.

@arquolo I think your problem may be in the fact that python -c is different from just invoking pylint.

Invoking via python -c runs the input as if it's a __main__, which is why this works. However, if you were to try and invoke in a plain way, you can see Python can't actually run:

(venv) ➜  bananas_dir tree bug
bug
├── __init__.py
└── module.py

(venv) ➜  bananas_dir python -m bug
/path/to/bin/python: No module named bug.__main__; 'bug' is a package and cannot be directly executed

This may be why pylint can't properly parse the wildcard import... somewhere behind the scenes the real problem may be that the module can't be run. Just my guess, but I am not sure.

changed the title [-]E1101 False positive[/-] [+]E0602 False positive[/+] on Nov 27, 2020
arquolo

arquolo commented on Nov 27, 2020

@arquolo
Author

@jamesbraza
I have updated issue, and yet it's still E0602 (it was 2 am here, I misread the log).
It doesn't depend whether module is imported in python -c, or in a plain way in python script, it still works.
I'm not trying to run a package, but import it.
Problem is not with star import, but with star import from subpackage, what imports subpackage too, and Pylint fails with last.

changed the title [-]E0602 False positive[/-] [+]E0602 (undefined-variable) - False positive[/+] on Nov 27, 2020
hippo91

hippo91 commented on Nov 28, 2020

@hippo91
Contributor

@arquolo and @jamesbraza thanks for your remarks. I'm now able to reproduce the bug.
Here is attached a reproducer. I can confirm that adding an empty __init__.py file makes the bug disappear. That's why this issue may be linked to #3944.
bug_pylint_3298.tar.gz

NeilGirdhar

NeilGirdhar commented on Aug 31, 2021

@NeilGirdhar

I've been running into the same problem. It is as simple as

from .x import y
del x  # undefined-error!

in any file inside a package. Pylint just needs to do what Python does, which is to add an implicit import x.

stdedos

stdedos commented on Sep 19, 2023

@stdedos
Contributor

Is this similar to

src/matplotlib-stubs/__init__.pyi:37:17: E0602: Undefined variable 'PathLike' (undefined-variable)

and https://github.com/hoel-bagard/matplotlib-stubs/blob/f24bcb7808881bf5a1dd7271ce50b0ad0fb0051f/src/matplotlib-stubs/__init__.pyi#L36-L38 ?

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @stdedos@PCManticore@NeilGirdhar@Pierre-Sassoulas@jamesbraza

        Issue actions

          E0602 (undefined-variable) - False positive · Issue #3298 · pylint-dev/pylint