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

Names are re-exported from stubs #2927

Closed
ilevkivskyi opened this issue Mar 1, 2017 · 9 comments
Closed

Names are re-exported from stubs #2927

ilevkivskyi opened this issue Mar 1, 2017 · 9 comments
Assignees
Labels
bug mypy got something wrong topic-pep-484

Comments

@ilevkivskyi
Copy link
Member

This code passes silently, but obviously fails at runtime:

from collections import TypeVar
from weakref import Generic
from getopt import List

T = TypeVar('T')

class C(Generic[T], List[int]):
    ...
@gvanrossum
Copy link
Member

gvanrossum commented Mar 1, 2017 via email

@ilevkivskyi
Copy link
Member Author

Hm... I just tried this with other modules, and it looks like names from stubs are always exported further by stubs. Namely I have this:

ivan@X-333 ~/Devel $ cat tsta.py 
x = 1

ivan@X-333 ~/Devel $ cat tstb.pyi 
from tsta import x

y = 2

ivan@X-333 ~/Devel $ cat tstc.py 
from tstb import x

y: int = x

Then mypy tstc.py passes without errors.

@ilevkivskyi ilevkivskyi changed the title Special types re-exported from stubs Names are re-exported from stubs Mar 1, 2017
@ilevkivskyi
Copy link
Member Author

From what I read in semanal.py, the module_public attribute is used only by visit_import_all. And indeed, if I change the code in tstc.py to from tstb import *, then mypy correctly complains Name 'x' is not defined.

But I think names imported in stubs should be never implicitly re-exported (not only when used with import *). Is this right?

@gvanrossum
Copy link
Member

What if you rename tsta.py to tsta.pyi?

@ilevkivskyi
Copy link
Member Author

What if you rename tsta.py to tsta.pyi?

The behavior is the same as with .py: passes silently with import x and complains Name 'x' is not defined with import *.

I am almost sure now that the problem is module_public is used for two different purposes: for identifying real public symbols in the runtime sense of this word (i.e. not starting with an underscore or present in __all__), and for re-exporting names from stubs. Only the first purpose is fully reflected in semanal.py/visit_import_all currently. I think we need an additional flag (maybe stub_only?) for symbols that should not be imported by visit_import_from and visit_import.

@JukkaL
Copy link
Collaborator

JukkaL commented Mar 1, 2017

I'm pretty sure that @ilevkivskyi is right and only from x import * is special right now for importing things defined in stubs.

@JukkaL
Copy link
Collaborator

JukkaL commented Mar 1, 2017

The reason for the current behavior is that from x import * importing internal definitions used to break a lot of user code, so that was fixed. Importing an internal definition by name is a less serious issue and kind of similar how you can also import module internals at runtime, since they usually aren't protected in any way, so we haven't done anything about that yet. For stubs we can reliably(?) know which definitions are internal so we should be able to hide module internals more effectively. This could still break some user code, however.

@gvanrossum
Copy link
Member

gvanrossum commented Mar 1, 2017 via email

@ilevkivskyi
Copy link
Member Author

I've always believed that you had to write from X import Y as Y in a stub in order to explicitly export Y. That's also what PEP 484 says AFAICT. But you're right it seems to work only for import *.

OK, then I will make a PR that will ensure this behaviour also for from mod import name. Running tests on typeshed will show how strictly the PEP rule from X import Y as Y was followed.

@ilevkivskyi ilevkivskyi self-assigned this Mar 31, 2017
@ilevkivskyi ilevkivskyi added bug mypy got something wrong topic-pep-484 labels Jul 12, 2017
ilevkivskyi added a commit that referenced this issue Jul 31, 2017
Fixes #2927

PEP 484 specifies that only names imported as
``from mod import name as name`` should be re-exported.
However, mypy didn't follow this rule so that this code
passed without errors but obviously fails at runtime:

from collections import TypeVar
from weakref import Generic
from getopt import List

T = TypeVar('T')

class C(Generic[T], List[int]):
    ...

This PR makes all these errors.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-pep-484
Projects
None yet
Development

No branches or pull requests

3 participants