Brett's PEP 3122 prompted me to finally PEP'ify my proposed solution for the current incompatibility between PEP 328 (absolute imports) and PEP 338 (executing modules as scripts). The only user visible change (other than bug 1510172 going away) would be the presence of a new module level attribute in the main module. Regards, Nick. PEP: 366 Title: Main module explicit relative imports Version: $Revision: 55046 $ Last-Modified: $Date: 2007-05-01 21:13:47 +1000 (Tue, 01 May 2007) $ Author: Nick Coghlan <ncoghlan@gmail.com> Status: Final Type: Standards Track Content-Type: text/x-rst Created: 1-May-2007 Python-Version: 2.6 Post-History: 1-May-2007 Abstract ======== This PEP proposes a backwards compatible mechanism that permits the use of explicit relative imports from executable modules within packages. Such imports currently fail due to an awkward interaction between PEP 328 and PEP 338 - this behaviour is the subject of at least one open SF bug report (#1510172)[1]. With the proposed mechanism, relative imports will work automatically if the module is executed using the ``-m`` switch. A small amount of boilerplate will be needed in the module itself to allow the relative imports to work when the file is executed by name. Import Statements and the Main Module ===================================== (This section is taken from the final revision of PEP 338) The release of 2.5b1 showed a surprising (although obvious in retrospect) interaction between PEP 338 and PEP 328 - explicit relative imports don't work from a main module. This is due to the fact that relative imports rely on ``__name__`` to determine the current module's position in the package hierarchy. In a main module, the value of ``__name__`` is always ``'__main__'``, so explicit relative imports will always fail (as they only work for a module inside a package). Investigation into why implicit relative imports *appear* to work when a main module is executed directly but fail when executed using ``-m`` showed that such imports are actually always treated as absolute imports. Because of the way direct execution works, the package containing the executed module is added to sys.path, so its sibling modules are actually imported as top level modules. This can easily lead to multiple copies of the sibling modules in the application if implicit relative imports are used in modules that may be directly executed (e.g. test modules or utility scripts). For the 2.5 release, the recommendation is to always use absolute imports in any module that is intended to be used as a main module. The ``-m`` switch already provides a benefit here, as it inserts the current directory into ``sys.path``, instead of the directory contain the main module. This means that it is possible to run a module from inside a package using ``-m`` so long as the current directory contains the top level directory for the package. Absolute imports will work correctly even if the package isn't installed anywhere else on sys.path. If the module is executed directly and uses absolute imports to retrieve its sibling modules, then the top level package directory needs to be installed somewhere on sys.path (since the current directory won't be added automatically). Here's an example file layout:: devel/ pkg/ __init__.py moduleA.py moduleB.py test/ __init__.py test_A.py test_B.py So long as the current directory is ``devel``, or ``devel`` is already on ``sys.path`` and the test modules use absolute imports (such as ``import pkg.moduleA`` to retrieve the module under test, PEP 338 allows the tests to be run as:: python -m pkg.test.test_A python -m pkg.test.test_B Rationale for Change ==================== In rejecting PEP 3122 (which proposed a higher impact solution to this problem), Guido has indicated that he still isn't particularly keen on the idea of executing modules inside packages as scripts [2]. Despite these misgivings he has previously approved the addition of the ``-m`` switch in Python 2.4, and the ``runpy`` module based enhancements described in PEP 338 for Python 2.5. The philosophy that motivated those previous additions (i.e. access to utility or testing scripts without needing to worry about name clashes in either the OS executable namespace or the top level Python namespace) is also the motivation behind fixing what I see as a bug in the current implementation. This PEP is intended to provide a solution which permits explicit relative imports from main modules, without incurring any significant costs during interpreter startup or normal module import. Proposed Solution ================= The heart of the proposed solution is a new module attribute ``__package_name__``. This attribute will be defined only in the main module (i.e. modules where ``__name__ == "__main__"``). For a directly executed main module, this attribute will be set to the empty string. For a module executed using ``runpy.run_module()`` with the ``run_name`` parameter set to ``"__main__"``, the attribute will be set to ``mod_name.rpartition('.')[0]`` (i.e., everything up to but not including the last period). In the import machinery there is an error handling path which deals with the case where an explicit relative reference attempts to go higher than the top level in the package hierarchy. This error path would be changed to fall back on the ``__package_name__`` attribute for explicit relative imports when the importing module is called ``"__main__"``. With this change, explicit relative imports will work automatically from a script executed with the ``-m`` switch. To allow direct execution of the module, the following boilerplate would be needed at the top of the script:: if __name__ == "__main__" and not __package_name__: __package_name__ = "<expected_pkg_name>" Note that this boilerplate has the same disadvantage as the use of absolute imports of sibling modules - if the script is moved to a different package or subpackage, the boilerplate will need to be updated manually. With this feature in place, the test scripts in the package above would be able to change their import lines to something along the lines of ``import ..moduleA``. The scripts could then be executed unmodified even if the name of the package was changed. (Rev 47142 in SVN implemented an early variant of this proposal which stored the main module's real module name in the '__module_name__' attribute. It was reverted due to the fact that 2.5 was already in beta by that time.) Alternative Proposals ===================== PEP 3122 proposed addressing this problem by changing the way the main module is identified. That's a huge compatibility cost to incur to fix something that is a pretty minor bug in the overall scheme of things. The advantage of the proposal in this PEP is that its only impact on normal code is the tiny amount of time needed at startup to set the extra attribute in the main module. The changes to the import machinery are all in an existing error handling path, so normal imports don't incur any performance penalty at all. References ========== .. [1] Absolute/relative import not working? (http://www.python.org/sf/1510172) .. [2] Guido's rejection of PEP 3122 (http://mail.python.org/pipermail/python-3000/2007-April/006793.html) Copyright ========= This document has been placed in the public domain. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia --------------------------------------------------------------- http://www.boredomandlaziness.org
participants (1)
-
Nick Coghlan