pylint icon indicating copy to clipboard operation
pylint copied to clipboard

no-member false positive related to an import confusion

Open mitar opened this issue 7 years ago • 5 comments

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]

mitar avatar Aug 07 '18 19:08 mitar

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)

PCManticore avatar Aug 09 '18 05:08 PCManticore

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.

mitar avatar Aug 09 '18 06:08 mitar

Gotcha, I see what you mean now. The problem is that somehow pylint imports the foobar assignment from the file, not the module itself.

PCManticore avatar Aug 09 '18 06:08 PCManticore

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 avatar Aug 09 '18 06:08 mitar

@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.

PCManticore avatar Aug 15 '18 16:08 PCManticore