Index: Python/import.c =================================================================== --- Python/import.c (revision 47159) +++ Python/import.c (working copy) @@ -2072,7 +2072,10 @@ { static PyObject *namestr = NULL; static PyObject *pathstr = NULL; - PyObject *modname, *modpath, *modules, *parent; + static PyObject *overridestr = NULL; + char *namestart = NULL; + Py_ssize_t namelen = 0; + PyObject *modname, *modpath, *override, *modules, *parent; if (globals == NULL || !PyDict_Check(globals) || !level) return Py_None; @@ -2087,41 +2090,55 @@ if (pathstr == NULL) return NULL; } + if (overridestr == NULL) { + overridestr = PyString_InternFromString("__module_name__"); + if (overridestr == NULL) + return NULL; + } *buf = '\0'; *p_buflen = 0; modname = PyDict_GetItem(globals, namestr); if (modname == NULL || !PyString_Check(modname)) return Py_None; + namestart = PyString_AS_STRING(modname); + namelen = PyString_GET_SIZE(modname); + if ((namestart[0] == '_') && (strcmp(namestart, "__main__") == 0)) { + /* Check for __module_name__ override in main module */ + override = PyDict_GetItem(globals, overridestr); + if (override != NULL && override != modname && \ + PyString_Check(override)) { + namestart = PyString_AS_STRING(override); + namelen = PyString_GET_SIZE(override); + } + } modpath = PyDict_GetItem(globals, pathstr); if (modpath != NULL) { - Py_ssize_t len = PyString_GET_SIZE(modname); - if (len > MAXPATHLEN) { + if (namelen > MAXPATHLEN) { PyErr_SetString(PyExc_ValueError, "Module name too long"); return NULL; } - strcpy(buf, PyString_AS_STRING(modname)); + strcpy(buf, namestart); } else { - char *start = PyString_AS_STRING(modname); - char *lastdot = strrchr(start, '.'); + char *lastdot = strrchr(namestart, '.'); size_t len; if (lastdot == NULL && level > 0) { PyErr_SetString(PyExc_ValueError, - "Relative importpath too deep"); + "Relative import path too deep"); return NULL; } if (lastdot == NULL) return Py_None; - len = lastdot - start; + len = lastdot - namestart; if (len >= MAXPATHLEN) { PyErr_SetString(PyExc_ValueError, "Module name too long"); return NULL; } - strncpy(buf, start, len); + strncpy(buf, namestart, len); buf[len] = '\0'; } @@ -2129,7 +2146,7 @@ char *dot = strrchr(buf, '.'); if (dot == NULL) { PyErr_SetString(PyExc_ValueError, - "Relative importpath too deep"); + "Relative import path too deep"); return NULL; } *dot = '\0'; @@ -2144,7 +2161,7 @@ return parent; /* We expect, but can't guarantee, if parent != None, that: - parent.__name__ == buf - - parent.__dict__ is globals + - parent.__dict__ is globals <-- Do we really expect this? If this is violated... Who cares? */ } Index: Doc/tut/tut.tex =================================================================== --- Doc/tut/tut.tex (revision 47159) +++ Doc/tut/tut.tex (working copy) @@ -2936,6 +2936,24 @@ in the \module{Sound.Effects} package, it can use \code{from Sound.Effects import echo}. +Starting with Python 2.5, in addition to the implicit relative imports +described above, you can write explicit relative imports with the +\code{from module import name} form of import statement. These explicit +relative imports use leading dots to indicate the current and parent +packages involved in the relative import. From the \module{surround} +module for example, you might do + +\begin{verbatim} +from . import echo +from .. import Formats +from ..Filters import equalizer +\end{verbatim} + +Note that explicit relative imports are based on the name of the current +module. In order for them to work from a main module, it must be +executed using the \code{-m} switch and the module name, rather than by +executing the source file directly. + \subsection{Packages in Multiple Directories} Packages support one more special attribute, \member{__path__}. This Index: Lib/test/test_runpy.py =================================================================== --- Lib/test/test_runpy.py (revision 47159) +++ Lib/test/test_runpy.py (working copy) @@ -126,7 +126,7 @@ try: del sys.modules[entry] except KeyError, ex: - if verbose: print ex # Persist with cleaning up + if verbose: print 'Missing key:', ex # Persist with cleaning up if verbose: print " Removed sys.modules entries" del sys.path[0] if verbose: print " Removed sys.path entry" @@ -135,32 +135,34 @@ try: os.remove(os.path.join(root, name)) except OSError, ex: - if verbose: print ex # Persist with cleaning up + if verbose: print 'Failed remove:', ex # Persist with cleaning up for name in dirs: fullname = os.path.join(root, name) try: os.rmdir(fullname) except OSError, ex: - if verbose: print ex # Persist with cleaning up + if verbose: print 'Failed rmdir:', ex # Persist with cleaning up try: os.rmdir(top) if verbose: print " Removed package tree" except OSError, ex: if verbose: print ex # Persist with cleaning up - def _check_module(self, depth): + def _check_module(self, source, depth, run_func, check_func=None): pkg_dir, mod_fname, mod_name = ( - self._make_pkg("x=1\n", depth)) + self._make_pkg(source, depth)) try: if verbose: print "Running from source:", mod_name - d1 = run_module(mod_name) # Read from source - self.failUnless(d1["x"] == 1) + d1 = run_func(mod_name) + if check_func is not None: + self.failUnless(check_func(d1)) del d1 # Ensure __loader__ entry doesn't keep file open __import__(mod_name) os.remove(mod_fname) if verbose: print "Running from compiled:", mod_name - d2 = run_module(mod_name) # Read from bytecode - self.failUnless(d2["x"] == 1) + d2 = run_func(mod_name) + if check_func is not None: + self.failUnless(check_func(d2)) del d2 # Ensure __loader__ entry doesn't keep file open finally: self._del_pkg(pkg_dir, depth, mod_name) @@ -169,9 +171,20 @@ def test_run_module(self): for depth in range(4): if verbose: print "Testing package depth:", depth - self._check_module(depth) + def check_func(d): + return d["x"] == 1 + self._check_module("x=1\n", depth, run_module, check_func) + def test_run_module_main(self): + for depth in range(1, 4): + if verbose: print "Testing package depth:", depth + source = "from . import __init__\n" + def run_func(mod_name): + return run_module(mod_name, + run_name='__main__', alter_sys=True) + self._check_module(source, depth, run_func) + def test_main(): run_unittest(RunModuleCodeTest) run_unittest(RunModuleTest)