make literally any import from any submodule a re-export unless renamed

This commit is contained in:
Aria Desires 2025-11-11 14:53:15 -05:00
parent e4374f14ed
commit 15b69517fb
3 changed files with 10 additions and 13 deletions

View File

@ -265,12 +265,10 @@ Similarly, for an `__init__.pyi` (stub) file, importing a non-exported name shou
but the inference would be `Unknown`. but the inference would be `Unknown`.
```py ```py
# error: 15 "Module `a` has no member `Foo`"
# error: 20 "Module `a` has no member `c`"
from a import Foo, c, foo from a import Foo, c, foo
reveal_type(Foo) # revealed: Unknown reveal_type(Foo) # revealed: <class 'Foo'>
reveal_type(c) # revealed: Unknown reveal_type(c) # revealed: <module 'a.b.c'>
reveal_type(foo) # revealed: <module 'a.foo'> reveal_type(foo) # revealed: <module 'a.foo'>
``` ```

View File

@ -25,7 +25,7 @@ This file currently covers the following details:
wild. Equivalent imports like `from whatever.thispackage import a` also introduce a re-export wild. Equivalent imports like `from whatever.thispackage import a` also introduce a re-export
(this has essentially zero ecosystem impact, we just felt it was more consistent). The only way (this has essentially zero ecosystem impact, we just felt it was more consistent). The only way
to opt out of this is to rename the import to something else (`from . import a as b`). to opt out of this is to rename the import to something else (`from . import a as b`).
`from .a import b` and equivalent does *not* introduce a re-export. `from .a import b` and equivalent also introduces a re-export, yes this is chaos.
Note: almost all tests in here have a stub and non-stub version, because we're interested in both Note: almost all tests in here have a stub and non-stub version, because we're interested in both
defining symbols *at all* and re-exporting them. defining symbols *at all* and re-exporting them.
@ -247,10 +247,8 @@ reveal_type(mypackage.submodule) # revealed: Unknown
reveal_type(mypackage.submodule.nested) # revealed: Unknown reveal_type(mypackage.submodule.nested) # revealed: Unknown
# error: "has no member `submodule`" # error: "has no member `submodule`"
reveal_type(mypackage.submodule.nested.X) # revealed: Unknown reveal_type(mypackage.submodule.nested.X) # revealed: Unknown
# error: "has no member `nested`" reveal_type(mypackage.nested) # revealed: <module 'mypackage.submodule.nested'>
reveal_type(mypackage.nested) # revealed: Unknown reveal_type(mypackage.nested.X) # revealed: int
# error: "has no member `nested`"
reveal_type(mypackage.nested.X) # revealed: Unknown
``` ```
### In Non-Stub ### In Non-Stub
@ -325,10 +323,8 @@ reveal_type(mypackage.submodule) # revealed: Unknown
reveal_type(mypackage.submodule.nested) # revealed: Unknown reveal_type(mypackage.submodule.nested) # revealed: Unknown
# error: "has no member `submodule`" # error: "has no member `submodule`"
reveal_type(mypackage.submodule.nested.X) # revealed: Unknown reveal_type(mypackage.submodule.nested.X) # revealed: Unknown
# error: "has no member `nested`" reveal_type(mypackage.nested) # revealed: <module 'mypackage.submodule.nested'>
reveal_type(mypackage.nested) # revealed: Unknown reveal_type(mypackage.nested.X) # revealed: int
# error: "has no member `nested`"
reveal_type(mypackage.nested.X) # revealed: Unknown
``` ```
### In Non-Stub ### In Non-Stub

View File

@ -1484,6 +1484,9 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
&& !self.seen_submodule_imports.contains(direct_submodule) && !self.seen_submodule_imports.contains(direct_submodule)
&& self.current_scope().is_global() && self.current_scope().is_global()
{ {
// Record that this is equivalent to `from .a import ...`
is_self_import = true;
self.seen_submodule_imports self.seen_submodule_imports
.insert(direct_submodule.to_owned()); .insert(direct_submodule.to_owned());