Star import reveals internal names when __all__ omits or misspells entries
0 reputation · 07 Nov 2022, 22:51 UTC
0 reputation · 07 Nov 2022, 22:51 UTC
When a module defines __all__ but includes a name that is not actually defined in its namespace, the star import (from module import *) succeeds at definition time and only raises an AttributeError when a consumer attempts the import.
This delayed failure makes it difficult to catch typos during development or static analysis, and it leaves the public API contract ambiguous for tooling that relies on __all__ to determine exported symbols.
The language reference does not require validation of __all__ entries at module definition, leaving the behavior as an unresolved design point.
What mechanisms could enforce early validation of __all__ entries? Should linters flag undefined or misspelled names in __all__? Is there a way to make the import statement raise an error at module load time when __all__ contains unknown identifiers?
33275 reputation · 08 Nov 2022, 05:45 UTC
CPython does not validate ``__all__`` when a module is loaded. If ``__all__`` lists a name that does not exist in the module namespace, the module imports successfully. The failure is deferred until a consumer runs ``from module import *`` and the import system resolves each listed name against the module namespace; an undefined entry then raises ``AttributeError``. There is no built-in import statement option that raises at module load time solely because ``__all__`` contains an unknown identifier.
Confirmed: when a module defines ``__all__``, star import binds only the listed names, resolving each at consumer import time.
Confirmed: the language reference does not require the interpreter to audit ``__all__`` entries against defined names before finishing module execution.
Likely explanation: the delayed ``AttributeError`` occurs because name resolution is lazy relative to module definition. The typo exists in the module's public contract, but nothing forces the interpreter to check that contract at load time.
for _name in __all__:
if _name not in globals():
raise ImportError(f"__all__ contains undefined name: {_name!r}")
# testmod.py
__all__ = ["foo", "mis_spelled"]
def foo():
return 1
for _name in __all__:
if _name not in globals():
raise ImportError(f"__all__ contains undefined name: {_name!r}")
python3 -c "from testmod import *"
Expected result: ``ImportError: __all__ contains undefined name: 'mis_spelled'`` at import time.
One missing detail changes the recommendation: do you control the module's source code, or are you consuming third-party modules? If you do not control the source, self-validation is not practical; rely on linting, CI checks, or a project-wide import hook instead.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.