diff --git a/Lib/ihooks.py b/Lib/ihooks.py index 86b0f65b63f..8761dac7cd0 100644 --- a/Lib/ihooks.py +++ b/Lib/ihooks.py @@ -49,7 +49,7 @@ by the way the __import__ hook is used by the Python interpreter.) It would also do wise to install a different version of reload(). """ -from warnings import warnpy3k +from warnings import warnpy3k, warn warnpy3k("the ihooks module has been removed in Python 3.0", stacklevel=2) del warnpy3k @@ -401,8 +401,9 @@ class ModuleImporter(BasicModuleImporter): """A module importer that supports packages.""" - def import_module(self, name, globals=None, locals=None, fromlist=None): - parent = self.determine_parent(globals) + def import_module(self, name, globals=None, locals=None, fromlist=None, + level=-1): + parent = self.determine_parent(globals, level) q, tail = self.find_head_package(parent, str(name)) m = self.load_tail(q, tail) if not fromlist: @@ -411,21 +412,50 @@ class ModuleImporter(BasicModuleImporter): self.ensure_fromlist(m, fromlist) return m - def determine_parent(self, globals): - if not globals or not "__name__" in globals: + def determine_parent(self, globals, level=-1): + if not globals or not level: return None - pname = globals['__name__'] - if "__path__" in globals: - parent = self.modules[pname] - assert globals is parent.__dict__ - return parent - if '.' in pname: - i = pname.rfind('.') - pname = pname[:i] - parent = self.modules[pname] - assert parent.__name__ == pname - return parent - return None + pkgname = globals.get('__package__') + if pkgname is not None: + if not pkgname and level > 0: + raise ValueError, 'Attempted relative import in non-package' + else: + # __package__ not set, figure it out and set it + modname = globals.get('__name__') + if modname is None: + return None + if "__path__" in globals: + # __path__ is set so modname is already the package name + pkgname = modname + else: + # normal module, work out package name if any + if '.' not in modname: + if level > 0: + raise ValueError, ('Attempted relative import in ' + 'non-package') + globals['__package__'] = None + return None + pkgname = modname.rpartition('.')[0] + globals['__package__'] = pkgname + if level > 0: + dot = len(pkgname) + for x in range(level, 1, -1): + try: + dot = pkgname.rindex('.', 0, dot) + except ValueError: + raise ValueError('attempted relative import beyond ' + 'top-level package') + pkgname = pkgname[:dot] + try: + return sys.modules[pkgname] + except KeyError: + if level < 1: + warn("Parent module '%s' not found while handling " + "absolute import" % pkgname, RuntimeWarning, 1) + return None + else: + raise SystemError, ("Parent module '%s' not loaded, cannot " + "perform relative import" % pkgname) def find_head_package(self, parent, name): if '.' in name: @@ -446,7 +476,7 @@ class ModuleImporter(BasicModuleImporter): parent = None q = self.import_it(head, qname, parent) if q: return q, tail - raise ImportError, "No module named " + qname + raise ImportError, "No module named '%s'" % qname def load_tail(self, q, tail): m = q @@ -457,7 +487,7 @@ class ModuleImporter(BasicModuleImporter): mname = "%s.%s" % (m.__name__, head) m = self.import_it(head, mname, m) if not m: - raise ImportError, "No module named " + mname + raise ImportError, "No module named '%s'" % mname return m def ensure_fromlist(self, m, fromlist, recursive=0): @@ -475,11 +505,13 @@ class ModuleImporter(BasicModuleImporter): subname = "%s.%s" % (m.__name__, sub) submod = self.import_it(sub, subname, m) if not submod: - raise ImportError, "No module named " + subname + raise ImportError, "No module named '%s'" % subname def import_it(self, partname, fqname, parent, force_load=0): if not partname: - raise ValueError, "Empty module name" + # completely empty module name should only happen in + # 'from . import' or __import__("") + return parent if not force_load: try: return self.modules[fqname] diff --git a/Misc/NEWS b/Misc/NEWS index 5c5acd7a8a6..cd6c9308b5f 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -405,6 +405,8 @@ Core and Builtins Library ------- +- Add support to the `ihooks` module for relative imports. + - Issue #6894: Fixed the issue urllib2 doesn't respect "no_proxy" environment - Issue #7086: Added TCP support to SysLogHandler, and tidied up some