diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 266611d0fc7..ff6069d74f2 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -22,8 +22,7 @@ are always available. They are listed here in alphabetical order. The function is invoked by the :keyword:`import` statement. It mainly exists so that you can replace it with another function that has a compatible interface, in order to change the semantics of the :keyword:`import` - statement. For examples of why and how you would do this, see the standard - library module :mod:`ihooks`. See also the built-in module :mod:`imp`, which + statement. See also the built-in module :mod:`imp`, which defines some useful operations out of which you can build your own :func:`__import__` function. diff --git a/Doc/library/undoc.rst b/Doc/library/undoc.rst index 78098b094da..62157d44f50 100644 --- a/Doc/library/undoc.rst +++ b/Doc/library/undoc.rst @@ -14,15 +14,6 @@ Fredrik Lundh; the specific contents of this chapter have been substantially revised. -Miscellaneous useful utilities -============================== - -Some of these are very old and/or not very robust; marked with "hmm." - -:mod:`ihooks` - --- Import hook support (for :mod:`rexec`; may become obsolete). - - Platform specific modules ========================= diff --git a/Lib/ihooks.py b/Lib/ihooks.py deleted file mode 100644 index 433f51341a8..00000000000 --- a/Lib/ihooks.py +++ /dev/null @@ -1,514 +0,0 @@ -"""Import hook support. - -Consistent use of this module will make it possible to change the -different mechanisms involved in loading modules independently. - -While the built-in module imp exports interfaces to the built-in -module searching and loading algorithm, and it is possible to replace -the built-in function __import__ in order to change the semantics of -the import statement, until now it has been difficult to combine the -effect of different __import__ hacks, like loading modules from URLs -by rimport.py. - -This module defines three new concepts: - -1) A "file system hooks" class provides an interface to a filesystem. - -One hooks class is defined (Hooks), which uses the interface provided -by standard modules os and os.path. It should be used as the base -class for other hooks classes. - -2) A "module loader" class provides an interface to search for a -module in a search path and to load it. It defines a method which -searches for a module in a single directory; by overriding this method -one can redefine the details of the search. If the directory is None, -built-in and frozen modules are searched instead. - -Two module loader class are defined, both implementing the search -strategy used by the built-in __import__ function: ModuleLoader uses -the imp module's find_module interface, while HookableModuleLoader -uses a file system hooks class to interact with the file system. Both -use the imp module's load_* interfaces to actually load the module. - -3) A "module importer" class provides an interface to import a -module, as well as interfaces to reload and unload a module. It also -provides interfaces to install and uninstall itself instead of the -default __import__ and reload (and unload) functions. - -One module importer class is defined (ModuleImporter), which uses a -module loader instance passed in (by default HookableModuleLoader is -instantiated). - -The classes defined here should be used as base classes for extended -functionality along those lines. - -If a module importer class supports dotted names, its import_module() -must return a different value depending on whether it is called on -behalf of a "from ... import ..." statement or not. (This is caused -by the way the __import__ hook is used by the Python interpreter.) -""" - - -import builtins -import imp -import os -import sys - -__all__ = ["BasicModuleLoader","Hooks","ModuleLoader","FancyModuleLoader", - "BasicModuleImporter","ModuleImporter","install","uninstall"] - -VERBOSE = 0 - - -from imp import C_EXTENSION, PY_SOURCE, PY_COMPILED -from imp import C_BUILTIN, PY_FROZEN, PKG_DIRECTORY -BUILTIN_MODULE = C_BUILTIN -FROZEN_MODULE = PY_FROZEN - - -class _Verbose: - - def __init__(self, verbose = VERBOSE): - self.verbose = verbose - - def get_verbose(self): - return self.verbose - - def set_verbose(self, verbose): - self.verbose = verbose - - # XXX The following is an experimental interface - - def note(self, *args): - if self.verbose: - self.message(*args) - - def message(self, format, *args): - if args: - print(format%args) - else: - print(format) - - -class BasicModuleLoader(_Verbose): - - """Basic module loader. - - This provides the same functionality as built-in import. It - doesn't deal with checking sys.modules -- all it provides is - find_module() and a load_module(), as well as find_module_in_dir() - which searches just one directory, and can be overridden by a - derived class to change the module search algorithm when the basic - dependency on sys.path is unchanged. - - The interface is a little more convenient than imp's: - find_module(name, [path]) returns None or 'stuff', and - load_module(name, stuff) loads the module. - - """ - - def find_module(self, name, path = None): - if path is None: - path = [None] + self.default_path() - for dir in path: - stuff = self.find_module_in_dir(name, dir) - if stuff: return stuff - return None - - def default_path(self): - return sys.path - - def find_module_in_dir(self, name, dir): - if dir is None: - return self.find_builtin_module(name) - else: - try: - return imp.find_module(name, [dir]) - except ImportError: - return None - - def find_builtin_module(self, name): - # XXX frozen packages? - if imp.is_builtin(name): - return None, '', ('', '', BUILTIN_MODULE) - if imp.is_frozen(name): - return None, '', ('', '', FROZEN_MODULE) - return None - - def load_module(self, name, stuff): - file, filename, info = stuff - try: - return imp.load_module(name, file, filename, info) - finally: - if file: file.close() - - -class Hooks(_Verbose): - - """Hooks into the filesystem and interpreter. - - By deriving a subclass you can redefine your filesystem interface, - e.g. to merge it with the URL space. - - This base class behaves just like the native filesystem. - - """ - - # imp interface - def get_suffixes(self): return imp.get_suffixes() - def new_module(self, name): return imp.new_module(name) - def is_builtin(self, name): return imp.is_builtin(name) - def init_builtin(self, name): return imp.init_builtin(name) - def is_frozen(self, name): return imp.is_frozen(name) - def init_frozen(self, name): return imp.init_frozen(name) - def get_frozen_object(self, name): return imp.get_frozen_object(name) - def load_source(self, name, filename, file=None): - return imp.load_source(name, filename, file) - def load_compiled(self, name, filename, file=None): - return imp.load_compiled(name, filename, file) - def load_dynamic(self, name, filename, file=None): - return imp.load_dynamic(name, filename, file) - def load_package(self, name, filename, file=None): - return imp.load_module(name, file, filename, ("", "", PKG_DIRECTORY)) - - def add_module(self, name): - d = self.modules_dict() - if name in d: return d[name] - d[name] = m = self.new_module(name) - return m - - # sys interface - def modules_dict(self): return sys.modules - def default_path(self): return sys.path - - def path_split(self, x): return os.path.split(x) - def path_join(self, x, y): return os.path.join(x, y) - def path_isabs(self, x): return os.path.isabs(x) - # etc. - - def path_exists(self, x): return os.path.exists(x) - def path_isdir(self, x): return os.path.isdir(x) - def path_isfile(self, x): return os.path.isfile(x) - def path_islink(self, x): return os.path.islink(x) - # etc. - - def openfile(self, *x): return open(*x) - openfile_error = IOError - def listdir(self, x): return os.listdir(x) - listdir_error = os.error - # etc. - - -class ModuleLoader(BasicModuleLoader): - - """Default module loader; uses file system hooks. - - By defining suitable hooks, you might be able to load modules from - other sources than the file system, e.g. from compressed or - encrypted files, tar files or (if you're brave!) URLs. - - """ - - def __init__(self, hooks = None, verbose = VERBOSE): - BasicModuleLoader.__init__(self, verbose) - self.hooks = hooks or Hooks(verbose) - - def default_path(self): - return self.hooks.default_path() - - def modules_dict(self): - return self.hooks.modules_dict() - - def get_hooks(self): - return self.hooks - - def set_hooks(self, hooks): - self.hooks = hooks - - def find_builtin_module(self, name): - # XXX frozen packages? - if self.hooks.is_builtin(name): - return None, '', ('', '', BUILTIN_MODULE) - if self.hooks.is_frozen(name): - return None, '', ('', '', FROZEN_MODULE) - return None - - def find_module_in_dir(self, name, dir, allow_packages=1): - if dir is None: - return self.find_builtin_module(name) - if allow_packages: - fullname = self.hooks.path_join(dir, name) - if self.hooks.path_isdir(fullname): - stuff = self.find_module_in_dir("__init__", fullname, 0) - if stuff: - file = stuff[0] - if file: file.close() - return None, fullname, ('', '', PKG_DIRECTORY) - for info in self.hooks.get_suffixes(): - suff, mode, type = info - fullname = self.hooks.path_join(dir, name+suff) - try: - fp = self.hooks.openfile(fullname, mode) - return fp, fullname, info - except self.hooks.openfile_error: - pass - return None - - def load_module(self, name, stuff): - file, filename, info = stuff - (suff, mode, type) = info - try: - if type == BUILTIN_MODULE: - return self.hooks.init_builtin(name) - if type == FROZEN_MODULE: - return self.hooks.init_frozen(name) - if type == C_EXTENSION: - m = self.hooks.load_dynamic(name, filename, file) - elif type == PY_SOURCE: - m = self.hooks.load_source(name, filename, file) - elif type == PY_COMPILED: - m = self.hooks.load_compiled(name, filename, file) - elif type == PKG_DIRECTORY: - m = self.hooks.load_package(name, filename, file) - else: - raise ImportError("Unrecognized module type (%r) for %s" - % (type, name)) - finally: - if file: file.close() - m.__file__ = filename - return m - - -class FancyModuleLoader(ModuleLoader): - - """Fancy module loader -- parses and execs the code itself.""" - - def load_module(self, name, stuff): - file, filename, (suff, mode, type) = stuff - realfilename = filename - path = None - - if type == PKG_DIRECTORY: - initstuff = self.find_module_in_dir("__init__", filename, 0) - if not initstuff: - raise ImportError("No __init__ module in package %s" % name) - initfile, initfilename, initinfo = initstuff - initsuff, initmode, inittype = initinfo - if inittype not in (PY_COMPILED, PY_SOURCE): - if initfile: initfile.close() - raise ImportError("Bad type (%r) for __init__ module" - " in package %s" % (inittype, name)) - path = [filename] - file = initfile - realfilename = initfilename - type = inittype - - if type == FROZEN_MODULE: - code = self.hooks.get_frozen_object(name) - elif type == PY_COMPILED: - import marshal - file.seek(8) - code = marshal.load(file) - elif type == PY_SOURCE: - data = file.read() - code = compile(data, realfilename, 'exec') - else: - return ModuleLoader.load_module(self, name, stuff) - - m = self.hooks.add_module(name) - if path: - m.__path__ = path - m.__file__ = filename - try: - exec(code, m.__dict__) - except: - d = self.hooks.modules_dict() - if name in d: - del d[name] - raise - return m - - -class BasicModuleImporter(_Verbose): - - """Basic module importer; uses module loader. - - This provides basic import facilities but no package imports. - - """ - - def __init__(self, loader = None, verbose = VERBOSE): - _Verbose.__init__(self, verbose) - self.loader = loader or ModuleLoader(None, verbose) - self.modules = self.loader.modules_dict() - - def get_loader(self): - return self.loader - - def set_loader(self, loader): - self.loader = loader - - def get_hooks(self): - return self.loader.get_hooks() - - def set_hooks(self, hooks): - return self.loader.set_hooks(hooks) - - def import_module(self, name, globals={}, locals={}, fromlist=[]): - name = str(name) - if name in self.modules: - return self.modules[name] # Fast path - stuff = self.loader.find_module(name) - if not stuff: - raise ImportError("No module named %s" % name) - return self.loader.load_module(name, stuff) - - def reload(self, module, path = None): - name = str(module.__name__) - stuff = self.loader.find_module(name, path) - if not stuff: - raise ImportError("Module %s not found for reload" % name) - return self.loader.load_module(name, stuff) - - def unload(self, module): - del self.modules[str(module.__name__)] - # XXX Should this try to clear the module's namespace? - - def install(self): - self.save_import_module = builtins.__import__ - if not hasattr(builtins, 'unload'): - builtins.unload = None - self.save_unload = builtins.unload - builtins.__import__ = self.import_module - builtins.unload = self.unload - - def uninstall(self): - builtins.__import__ = self.save_import_module - builtins.unload = self.save_unload - if not builtins.unload: - del builtins.unload - - -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) - q, tail = self.find_head_package(parent, str(name)) - m = self.load_tail(q, tail) - if not fromlist: - return q - if hasattr(m, "__path__"): - self.ensure_fromlist(m, fromlist) - return m - - def determine_parent(self, globals): - if not globals or not "__name__" in globals: - 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 - - def find_head_package(self, parent, name): - if '.' in name: - i = name.find('.') - head = name[:i] - tail = name[i+1:] - else: - head = name - tail = "" - if parent: - qname = "%s.%s" % (parent.__name__, head) - else: - qname = head - q = self.import_it(head, qname, parent) - if q: return q, tail - if parent: - qname = head - parent = None - q = self.import_it(head, qname, parent) - if q: return q, tail - raise ImportError("No module named " + qname) - - def load_tail(self, q, tail): - m = q - while tail: - i = tail.find('.') - if i < 0: i = len(tail) - head, tail = tail[:i], tail[i+1:] - mname = "%s.%s" % (m.__name__, head) - m = self.import_it(head, mname, m) - if not m: - raise ImportError("No module named " + mname) - return m - - def ensure_fromlist(self, m, fromlist, recursive=0): - for sub in fromlist: - if sub == "*": - if not recursive: - try: - all = m.__all__ - except AttributeError: - pass - else: - self.ensure_fromlist(m, all, 1) - continue - if sub != "*" and not hasattr(m, sub): - subname = "%s.%s" % (m.__name__, sub) - submod = self.import_it(sub, subname, m) - if not submod: - raise ImportError("No module named " + subname) - - def import_it(self, partname, fqname, parent, force_load=0): - if not partname: - raise ValueError("Empty module name") - if not force_load: - try: - return self.modules[fqname] - except KeyError: - pass - try: - path = parent and parent.__path__ - except AttributeError: - return None - partname = str(partname) - stuff = self.loader.find_module(partname, path) - if not stuff: - return None - fqname = str(fqname) - m = self.loader.load_module(fqname, stuff) - if parent: - setattr(parent, partname, m) - return m - - def reload(self, module): - name = str(module.__name__) - if '.' not in name: - return self.import_it(name, name, None, force_load=1) - i = name.rfind('.') - pname = name[:i] - parent = self.modules[pname] - return self.import_it(name[i+1:], name, parent, force_load=1) - - -default_importer = None -current_importer = None - -def install(importer = None): - global current_importer - current_importer = importer or default_importer or ModuleImporter() - current_importer.install() - -def uninstall(): - global current_importer - current_importer.uninstall() diff --git a/Lib/test/test_sundry.py b/Lib/test/test_sundry.py index db7ed4e553a..ca6b23d2143 100644 --- a/Lib/test/test_sundry.py +++ b/Lib/test/test_sundry.py @@ -49,7 +49,6 @@ class TestUntestedModules(unittest.TestCase): import formatter import getpass import htmlentitydefs - import ihooks import imghdr import keyword import linecache diff --git a/Misc/NEWS b/Misc/NEWS index e2c165cfcc0..c4d66e046e0 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -21,6 +21,8 @@ Extension Modules Library ------- +- The ihooks module has been removed. + - The fpformat module has been removed. - The dircache module has been removed.