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

Module X has no attribute Y when using star imports #4930

Closed
nicktimko opened this issue Apr 18, 2018 · 17 comments
Closed

Module X has no attribute Y when using star imports #4930

nicktimko opened this issue Apr 18, 2018 · 17 comments
Labels
bug mypy got something wrong false-positive mypy gave an error on correct code priority-1-normal topic-import-cycles

Comments

@nicktimko
Copy link

nicktimko commented Apr 18, 2018

mypy seems to emit a spurious warning that it can't find an attribute of a module that should be imported via a star import and where another import refers to it.

Input

$ head mypackage/*

  • ==> mypackage/__init__.py <==
from mypackage.submod1 import *     # * -> HELLO and error goes away
from mypackage.submod2 import greet # comment out and error goes away
__all__ = ['HELLO', 'greet'] # does nothing
  • ==> mypackage/submod1.py <==
__all__ = ['HELLO']
HELLO = 'hello there'
  • ==> mypackage/submod2.py <==
from mypackage import HELLO
__all__ = ['greet']
def greet():
    print(HELLO)

Current Output

$ mypy mypackage
mypackage/submod2.py:1: error: Module 'mypackage' has no attribute 'HELLO'
$ python -c "import mypackage;mypackage.greet()" # Python has no problems
hello there
$ python --version; mypy --version
Python 3.6.4
mypy 0.590

(haven't checked with master, but I couldn't find any recently closed issues that seemed to talk about something like this)

Expected Output

No error from mypy.

As per the comments in the __init__.py, if some of the imports are tweaked, then mypy is happy. It doesn't seem to be sated by an __all__ to help the star import. I don't quite understand why not importing mypackage.submod2 causes the error to go away as well; it's not like there's a circular import between 1 and 2 where the names in the module aren't defined before it imports (i.e. if you moved the ...import greet line above the other, Python would choke)

@jacebrowning
Copy link

I can still reproduce this with mypy 0.600.

@JelleZijlstra JelleZijlstra self-assigned this May 14, 2018
@JelleZijlstra
Copy link
Member

I looked into this for a bit. Here is a test that reproduces the problem: JelleZijlstra@6b124e2. The problem goes away when one uses from b import HELLO instead of from b import *.

I think what's going on here is as follows:

  • semantic analyzer pass 1 adds names from import_from, but not import_alll (because at that point we don't know anything about other modules yet)
  • semantic analyzer pass 2 adds names from import_all, relying on what was added in pass 1. But if we're trying to import from a module that uses import_all, and pass 2 hasn't run on that module yet, we can't see the names from the import_all, and we get an error.

This could be fixable with an additional semanal pass or something like a callback in pass 1 that runs when the module we're import_alling from is processed, and adds names to the module that is using import_all.

@JelleZijlstra
Copy link
Member

My branch master...JelleZijlstra:circularstar has a fix for the original bug now, but it introduces various new bugs. I don't understand for now what's going on in some of those tests. I'll take another look at this later.

@JelleZijlstra
Copy link
Member

The reason why my code is buggy is that if there is a circular dependency involving import * (as in this test: cb20eaf), I end up adding an ImportedName in both modules, so mypy believes the name exists in either both files or neither file.

This doesn't seem easy to solve. Strictly speaking, mypy should follow the same sequence as Python does at import time: start with one file, then if there is an import, switch to the imported file, then return to the original file. But that would require a full rewrite of pass 1 of semantic analysis and probably a broader change in mypy's build pipeline.

Another solution could be to declare that mypy does not support import * in an import cycle and throw an error that makes this explicit.

@gvanrossum
Copy link
Member

gvanrossum commented May 15, 2018 via email

@sebastian-philipp
Copy link

not supporting import * is a bit unfortunate. 😞. I guess we can live with it. Needs proper documentation, though.

@gvanrossum
Copy link
Member

gvanrossum commented Mar 26, 2019 via email

@sebastian-philipp
Copy link

ok, the effect I'm seeing here is then caused by something else. thanks!

Click to expand
    #  cat <<EOF > ./mypy.ini
    [mypy]
    strict_optional = True
    no_implicit_optional = True
    ignore_missing_imports = True
    warn_incomplete_stub = True
    check_untyped_defs = True
    show_error_context = True
    EOF
    #  cat test_foo.py 
    from nose.tools import *
    def test_foo():
        eq_(1,1)
    #  nosetests test_foo.py 
    .
    ----------------------------------------------------------------------
    Ran 1 test in 0.000s
    OK
    #  mypy --config-file=mypy.ini test_foo.py
    test_foo.py: note: In function "test_foo":
    test_foo.py:3: error: Name 'eq_' is not defined

@JukkaL
Copy link
Collaborator

JukkaL commented Mar 26, 2019

This might be fixed by the new semantic analyzer (experimental version available on GitHub mypy master by using --new-semantic-analyzer). It generally improves the processing of imports within import cycles.

@chadrik
Copy link
Contributor

chadrik commented Apr 19, 2019

I have the same issue. I tried with 0.710+dev.f0491839adf2db2da74768b1d01f8e244e769f59 using --new-semantic-analyzer and it did not fix the problem.

@chadrik
Copy link
Contributor

chadrik commented Apr 19, 2019

If you do decide to drop support for import * in an import cycle, it would be great to at least inform the user about the source of the cycle. In my case it's not obvious, and it could be (???) caused by imports inside a TYPE_CHECKING block, which I can't remove without invalidating my annotations.

I would really rather mypy did not drop support for import * in a cycle.

@JukkaL
Copy link
Collaborator

JukkaL commented May 21, 2019

We are not planning to drop support for import * in import cycles, but there may be specific use cases that are too hard to support.

@JukkaL
Copy link
Collaborator

JukkaL commented Jul 3, 2019

I'm dropping the new-semantic-analyzer label since this doesn't seem specific to it.

@JukkaL JukkaL added bug mypy got something wrong false-positive mypy gave an error on correct code and removed semantic-analyzer Problems that happen during semantic analysis labels Jul 3, 2019
@nicktimko
Copy link
Author

nicktimko commented Jul 3, 2019

Would it be any easier to constrain support for import * in a cycle where the * imported module/package defines a (static) __all__?

@marmistrz
Copy link

marmistrz commented Jun 3, 2021

This happens while using pygame:

from pygame.locals import KEYUP

results in

test.py:1: error: Module 'pygame.locals' has no attribute 'KEYUP'

even though the constant is there. The type hint is also properly resolved by VS Code. The constant is explicitly re-exported using __all__.

@bczsalba
Copy link

bczsalba commented Aug 11, 2021

Any update on this? If anything, there really should be something to tell the user what the issue is, as I just spent 20 minutes trying to figure out the cause.

Though, best would be if from module import * would be supported, at least when __all__ is defined. For now you have to either manually import everything or manually re-type every field, even though the information is there.

Also, as a note: pylint seems completely fine with this behavior.

@ilevkivskyi
Copy link
Member

FWIW the original example passes cleanly on current master (both with and without __all__). So closing this for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong false-positive mypy gave an error on correct code priority-1-normal topic-import-cycles
Projects
None yet
Development

No branches or pull requests

10 participants