experimental-inspect: re-export submodules in the parent module stubs - #6360
experimental-inspect: re-export submodules in the parent module stubs#6360jonasdedden wants to merge 2 commits into
experimental-inspect: re-export submodules in the parent module stubs#6360Conversation
davidhewitt
left a comment
There was a problem hiding this comment.
Thanks, something seems off here
| annotations as annotations, | ||
| awaitable as awaitable, | ||
| buf_and_str as buf_and_str, | ||
| comparisons as comparisons, | ||
| consts as consts, | ||
| datetime as datetime, | ||
| dict_iter as dict_iter, | ||
| enums as enums, | ||
| exception as exception, | ||
| misc as misc, | ||
| objstore as objstore, | ||
| othermod as othermod, | ||
| path as path, | ||
| pyclasses as pyclasses, | ||
| pyfunctions as pyfunctions, | ||
| sequence as sequence, | ||
| subclassing as subclassing, |
There was a problem hiding this comment.
Why are there identity renames here?
There was a problem hiding this comment.
Please note that this is one of the things already explained in the PR description:
The redundant as alias follows the typeshed convention for submodule re-exports, for example
os/__init__.pyiwritingfrom . import path as path. Current checkers such as mypy or pyright are lenient about this, but the spec sees it as required.
The import X as X way is to signal to type-checkers that an import is explicitly meant as a re-export (and not just a necessary import to make some internal functionality work). The typing spec defines it here: https://typing.python.org/en/latest/spec/distributing.html#import-conventions
The example described in the PR description is this one: https://github.com/python/typeshed/blob/f40e0da70e10e818692c3a771d5d5ac7010042f9/stdlib/os/__init__.pyi#L49
Note that there commonly are actually two ways of explicitly re-exporting symbols, either through import X as X or by including the re-export in the __all__ list. The latter shall only be used for re-exports if you do a from X import * import and have to select which symbols of X to re-export. __all__ is typically reserved for symbols defined in the same module.
FYI, there is actually a PEP that tries to clean up this mess by introducing an export keyword: https://peps.python.org/pep-0843/
What was wrong
add_module_stub_fileswrites each submodule to its own sibling.pyi, butmodule_stubsnever referenced those files from the parent__init__.pyi. At runtime#[pymodule_export] use child;callsadd, which is a setattr, so the submodule is an attribute of its parent. Stub and runtime disagreed and stubtest reportedpyo3_pytests.<name> is not present in stubfor all 17 submodules. The module-level__getattr__fromincompletedoes not suppress these.The fix
In
Imports::create, when the module is a package, emit onefrom . import a as a, b as bline with the names sorted.The redundant
asalias follows the typeshed convention for submodule re-exports, for exampleos/__init__.pyiwritingfrom . import path as path. Current checkers such asmypyorpyrightare lenient about this, but the spec sees it as required.Submodule names are also chained into the local-elements seed of
local_name_to_module_and_attribute, so an annotation import that wants the same local name gets aliased instead of silently shadowing the submodule binding..is correct rather than..because only packages emit this line, and a package's own stub is always the__init__.pyisitting beside its submodule.pyifiles.