This PEP proposes a backwards compatible mechanism that permitsthe use of explicit relative imports from executable modules withinpackages. Such imports currently fail due to an awkward interactionbetweenPEP 328 andPEP 338.
By adding a new module level attribute, this PEP allows relative importsto work automatically if the module is executed using the-m switch.A small amount of boilerplate in the module itself will allow the relativeimports to work when the file is executed by name.
Guido accepted the PEP in November 2007[5].
The major proposed change is the introduction of a new module levelattribute,__package__. When it is present, relative imports willbe based on this attribute rather than the module__name__attribute.
As with the current__name__ attribute, setting__package__ willbe the responsibility of thePEP 302 loader used to import a module.Loaders which useimp.new_module() to create the module object willhave the new attribute set automatically toNone. When the importsystem encounters an explicit relative import in a module without__package__ set (or with it set toNone), it will calculate andstore the correct value (__name__.rpartition('.')[0] for normalmodules and__name__ for package initialisation modules). If__package__ has already been set then the import system will useit in preference to recalculating the package name from the__name__ and__path__ attributes.
Therunpy module will explicitly set the new attribute, basing it offthe name used to locate the module to be executed rather than the nameused to set the module’s__name__ attribute. This will allow relativeimports to work correctly from main modules executed with the-mswitch.
When the main module is specified by its filename, then the__package__ attribute will be set toNone. To allowrelative imports when the module is executed directly, boilerplatesimilar to the following would be needed before the first relativeimport statement:
if__name__=="__main__"and__package__isNone:__package__="expected.package.name"
Note that this boilerplate is sufficient only if the top level packageis already accessible viasys.path. Additional code that manipulatessys.path would be needed in order for direct execution to workwithout the top level package already being importable.
This approach also has the same disadvantage as the use of absoluteimports of sibling modules - if the script is moved to a differentpackage or subpackage, the boilerplate will need to be updatedmanually. It has the advantage that this change need only be madeonce per file, regardless of the number of relative imports.
Note that setting__package__ to the empty string explicitly ispermitted, and has the effect of disabling all relative imports fromthat module (since the import machinery will consider it to be atop level module in that case). This means that tools likerunpydo not need to provide special case handling for top level moduleswhen setting__package__.
The current inability to use explicit relative imports from the mainmodule is the subject of at least one open SF bug report (#1510172)[1],and has most likely been a factor in at least a few queries oncomp.lang.python (such as Alan Isaac’s question in[2]).
This PEP is intended to provide a solution which permits explicitrelative imports from main modules, without incurring any significantcosts during interpreter startup or normal module import.
The section inPEP 338 on relative imports and the main module providesfurther details and background on this problem.
Rev 47142 in SVN implemented an early variant of this proposalwhich stored the main module’s real module name in the__module_name__ attribute. It was reverted due to the factthat 2.5 was already in beta by that time.
Patch 1487[4] is the proposed implementation for this PEP.
PEP 3122 proposed addressing this problem by changing the waythe main module is identified. That’s a significant compatibility costto incur to fix something that is a pretty minor bug in the overallscheme of things, and the PEP was rejected[3].
The advantage of the proposal in this PEP is that its only impact onnormal code is the small amount of time needed to set the extraattribute when importing a module. Relative imports themselves shouldbe sped up fractionally, as the package name is cached in the moduleglobals, rather than having to be worked out again for each relativeimport.
This document has been placed in the public domain.
Source:https://github.com/python/peps/blob/main/peps/pep-0366.rst
Last modified:2025-02-01 08:59:27 GMT