pylint
pylint copied to clipboard
no-member false positive related to an import confusion
Steps to reproduce
I have the following file structure:
mymodule/
__init__.py
foobar.py
In __init__.py I have:
from .foobar import *
And in foobar.py I have:
__all__ = ('FooBar',)
class FooBar:
pass
foobar = FooBar()
Current behavior
The issue is that because pylint ignores __all__ when I have code like:
from mymodule import foobar
foobar.FooBar()
I get the following error:
E1101: Instance of 'FooBar' has no 'FooBar' member (no-member)
The issue is that foobar variable shadows foobar module in the view of pylint.
Expected behavior
There should be no error. I think that in the case of static __all__ variables, pylint should respect them.
pylint --version output
pylint 2.0.1
astroid 2.0.2
Python 3.6.3 (default, Oct 3 2017, 21:45:48)
[GCC 7.2.0]
HI @mitar
Thanks for creating an issue. It's true that pylint does not consider __all__ any longer, this is for a couple of years now. The reason we decided against it was that people tended to modify __all__ dynamically, which in turn resulted in false positives in pylint, because it wasn't able to infer all the potential mutations brought to __all__.
With that being said, in general it's not necessarily a problem, since pylint is still able to find the members in a module or library, just that it finds everything and not what you added to __all__.
And with that being said, I can't reproduce your problem locally using pylint==2.1.1. I added a reference to a non-existent Foo just to test it out, and it emitted the error as you can see below, but not one for FooBar:
a.py:1:0: C0111: Missing module docstring (missing-docstring)
a.py:4:0: E1101: Module 'mymodule.foobar' has no 'Foo' member (no-member)
I made reproduction here: https://github.com/mitar/pylint-issue-2392
Running pylint mymodule I get:
************* Module mymodule
mymodule/__init__.py:1:0: C0111: Missing module docstring (missing-docstring)
mymodule/__init__.py:1:0: W0401: Wildcard import foobar (wildcard-import)
************* Module mymodule.foobar
mymodule/foobar.py:1:0: C0111: Missing module docstring (missing-docstring)
mymodule/foobar.py:4:0: C0111: Missing class docstring (missing-docstring)
mymodule/foobar.py:4:0: R0903: Too few public methods (0/2) (too-few-public-methods)
mymodule/foobar.py:7:0: C0103: Constant name "foobar" doesn't conform to UPPER_CASE naming style (invalid-name)
************* Module mymodule.test
mymodule/test.py:1:0: C0111: Missing module docstring (missing-docstring)
mymodule/test.py:3:0: E1101: Instance of 'FooBar' has no 'FooBar' member (no-member)
--------------------------------------------------------------------
Your code has been rated at -7.14/10 (previous run: -7.14/10, +0.00)
See the last message.
Gotcha, I see what you mean now. The problem is that somehow pylint imports the foobar assignment from the file, not the module itself.
Yes, because when it is importing all symbols and not just those from __all__ it shadows the module foobar with the variable of the same name.
@mitar pylint stopped considering __all__ for a couple of years now, but the reason of this bug is somewhat different than handling or not handling __all__. Updated the title so it doesn't mention __all__ any longer as that results in confusion.