PyXR

c:\python24\lib \ ihooks.py



0001 """Import hook support.
0002 
0003 Consistent use of this module will make it possible to change the
0004 different mechanisms involved in loading modules independently.
0005 
0006 While the built-in module imp exports interfaces to the built-in
0007 module searching and loading algorithm, and it is possible to replace
0008 the built-in function __import__ in order to change the semantics of
0009 the import statement, until now it has been difficult to combine the
0010 effect of different __import__ hacks, like loading modules from URLs
0011 by rimport.py, or restricted execution by rexec.py.
0012 
0013 This module defines three new concepts:
0014 
0015 1) A "file system hooks" class provides an interface to a filesystem.
0016 
0017 One hooks class is defined (Hooks), which uses the interface provided
0018 by standard modules os and os.path.  It should be used as the base
0019 class for other hooks classes.
0020 
0021 2) A "module loader" class provides an interface to search for a
0022 module in a search path and to load it.  It defines a method which
0023 searches for a module in a single directory; by overriding this method
0024 one can redefine the details of the search.  If the directory is None,
0025 built-in and frozen modules are searched instead.
0026 
0027 Two module loader class are defined, both implementing the search
0028 strategy used by the built-in __import__ function: ModuleLoader uses
0029 the imp module's find_module interface, while HookableModuleLoader
0030 uses a file system hooks class to interact with the file system.  Both
0031 use the imp module's load_* interfaces to actually load the module.
0032 
0033 3) A "module importer" class provides an interface to import a
0034 module, as well as interfaces to reload and unload a module.  It also
0035 provides interfaces to install and uninstall itself instead of the
0036 default __import__ and reload (and unload) functions.
0037 
0038 One module importer class is defined (ModuleImporter), which uses a
0039 module loader instance passed in (by default HookableModuleLoader is
0040 instantiated).
0041 
0042 The classes defined here should be used as base classes for extended
0043 functionality along those lines.
0044 
0045 If a module importer class supports dotted names, its import_module()
0046 must return a different value depending on whether it is called on
0047 behalf of a "from ... import ..." statement or not.  (This is caused
0048 by the way the __import__ hook is used by the Python interpreter.)  It
0049 would also do wise to install a different version of reload().
0050 
0051 """
0052 
0053 
0054 import __builtin__
0055 import imp
0056 import os
0057 import sys
0058 
0059 __all__ = ["BasicModuleLoader","Hooks","ModuleLoader","FancyModuleLoader",
0060            "BasicModuleImporter","ModuleImporter","install","uninstall"]
0061 
0062 VERBOSE = 0
0063 
0064 
0065 from imp import C_EXTENSION, PY_SOURCE, PY_COMPILED
0066 from imp import C_BUILTIN, PY_FROZEN, PKG_DIRECTORY
0067 BUILTIN_MODULE = C_BUILTIN
0068 FROZEN_MODULE = PY_FROZEN
0069 
0070 
0071 class _Verbose:
0072 
0073     def __init__(self, verbose = VERBOSE):
0074         self.verbose = verbose
0075 
0076     def get_verbose(self):
0077         return self.verbose
0078 
0079     def set_verbose(self, verbose):
0080         self.verbose = verbose
0081 
0082     # XXX The following is an experimental interface
0083 
0084     def note(self, *args):
0085         if self.verbose:
0086             self.message(*args)
0087 
0088     def message(self, format, *args):
0089         if args:
0090             print format%args
0091         else:
0092             print format
0093 
0094 
0095 class BasicModuleLoader(_Verbose):
0096 
0097     """Basic module loader.
0098 
0099     This provides the same functionality as built-in import.  It
0100     doesn't deal with checking sys.modules -- all it provides is
0101     find_module() and a load_module(), as well as find_module_in_dir()
0102     which searches just one directory, and can be overridden by a
0103     derived class to change the module search algorithm when the basic
0104     dependency on sys.path is unchanged.
0105 
0106     The interface is a little more convenient than imp's:
0107     find_module(name, [path]) returns None or 'stuff', and
0108     load_module(name, stuff) loads the module.
0109 
0110     """
0111 
0112     def find_module(self, name, path = None):
0113         if path is None:
0114             path = [None] + self.default_path()
0115         for dir in path:
0116             stuff = self.find_module_in_dir(name, dir)
0117             if stuff: return stuff
0118         return None
0119 
0120     def default_path(self):
0121         return sys.path
0122 
0123     def find_module_in_dir(self, name, dir):
0124         if dir is None:
0125             return self.find_builtin_module(name)
0126         else:
0127             try:
0128                 return imp.find_module(name, [dir])
0129             except ImportError:
0130                 return None
0131 
0132     def find_builtin_module(self, name):
0133         # XXX frozen packages?
0134         if imp.is_builtin(name):
0135             return None, '', ('', '', BUILTIN_MODULE)
0136         if imp.is_frozen(name):
0137             return None, '', ('', '', FROZEN_MODULE)
0138         return None
0139 
0140     def load_module(self, name, stuff):
0141         file, filename, info = stuff
0142         try:
0143             return imp.load_module(name, file, filename, info)
0144         finally:
0145             if file: file.close()
0146 
0147 
0148 class Hooks(_Verbose):
0149 
0150     """Hooks into the filesystem and interpreter.
0151 
0152     By deriving a subclass you can redefine your filesystem interface,
0153     e.g. to merge it with the URL space.
0154 
0155     This base class behaves just like the native filesystem.
0156 
0157     """
0158 
0159     # imp interface
0160     def get_suffixes(self): return imp.get_suffixes()
0161     def new_module(self, name): return imp.new_module(name)
0162     def is_builtin(self, name): return imp.is_builtin(name)
0163     def init_builtin(self, name): return imp.init_builtin(name)
0164     def is_frozen(self, name): return imp.is_frozen(name)
0165     def init_frozen(self, name): return imp.init_frozen(name)
0166     def get_frozen_object(self, name): return imp.get_frozen_object(name)
0167     def load_source(self, name, filename, file=None):
0168         return imp.load_source(name, filename, file)
0169     def load_compiled(self, name, filename, file=None):
0170         return imp.load_compiled(name, filename, file)
0171     def load_dynamic(self, name, filename, file=None):
0172         return imp.load_dynamic(name, filename, file)
0173     def load_package(self, name, filename, file=None):
0174         return imp.load_module(name, file, filename, ("", "", PKG_DIRECTORY))
0175 
0176     def add_module(self, name):
0177         d = self.modules_dict()
0178         if name in d: return d[name]
0179         d[name] = m = self.new_module(name)
0180         return m
0181 
0182     # sys interface
0183     def modules_dict(self): return sys.modules
0184     def default_path(self): return sys.path
0185 
0186     def path_split(self, x): return os.path.split(x)
0187     def path_join(self, x, y): return os.path.join(x, y)
0188     def path_isabs(self, x): return os.path.isabs(x)
0189     # etc.
0190 
0191     def path_exists(self, x): return os.path.exists(x)
0192     def path_isdir(self, x): return os.path.isdir(x)
0193     def path_isfile(self, x): return os.path.isfile(x)
0194     def path_islink(self, x): return os.path.islink(x)
0195     # etc.
0196 
0197     def openfile(self, *x): return open(*x)
0198     openfile_error = IOError
0199     def listdir(self, x): return os.listdir(x)
0200     listdir_error = os.error
0201     # etc.
0202 
0203 
0204 class ModuleLoader(BasicModuleLoader):
0205 
0206     """Default module loader; uses file system hooks.
0207 
0208     By defining suitable hooks, you might be able to load modules from
0209     other sources than the file system, e.g. from compressed or
0210     encrypted files, tar files or (if you're brave!) URLs.
0211 
0212     """
0213 
0214     def __init__(self, hooks = None, verbose = VERBOSE):
0215         BasicModuleLoader.__init__(self, verbose)
0216         self.hooks = hooks or Hooks(verbose)
0217 
0218     def default_path(self):
0219         return self.hooks.default_path()
0220 
0221     def modules_dict(self):
0222         return self.hooks.modules_dict()
0223 
0224     def get_hooks(self):
0225         return self.hooks
0226 
0227     def set_hooks(self, hooks):
0228         self.hooks = hooks
0229 
0230     def find_builtin_module(self, name):
0231         # XXX frozen packages?
0232         if self.hooks.is_builtin(name):
0233             return None, '', ('', '', BUILTIN_MODULE)
0234         if self.hooks.is_frozen(name):
0235             return None, '', ('', '', FROZEN_MODULE)
0236         return None
0237 
0238     def find_module_in_dir(self, name, dir, allow_packages=1):
0239         if dir is None:
0240             return self.find_builtin_module(name)
0241         if allow_packages:
0242             fullname = self.hooks.path_join(dir, name)
0243             if self.hooks.path_isdir(fullname):
0244                 stuff = self.find_module_in_dir("__init__", fullname, 0)
0245                 if stuff:
0246                     file = stuff[0]
0247                     if file: file.close()
0248                     return None, fullname, ('', '', PKG_DIRECTORY)
0249         for info in self.hooks.get_suffixes():
0250             suff, mode, type = info
0251             fullname = self.hooks.path_join(dir, name+suff)
0252             try:
0253                 fp = self.hooks.openfile(fullname, mode)
0254                 return fp, fullname, info
0255             except self.hooks.openfile_error:
0256                 pass
0257         return None
0258 
0259     def load_module(self, name, stuff):
0260         file, filename, info = stuff
0261         (suff, mode, type) = info
0262         try:
0263             if type == BUILTIN_MODULE:
0264                 return self.hooks.init_builtin(name)
0265             if type == FROZEN_MODULE:
0266                 return self.hooks.init_frozen(name)
0267             if type == C_EXTENSION:
0268                 m = self.hooks.load_dynamic(name, filename, file)
0269             elif type == PY_SOURCE:
0270                 m = self.hooks.load_source(name, filename, file)
0271             elif type == PY_COMPILED:
0272                 m = self.hooks.load_compiled(name, filename, file)
0273             elif type == PKG_DIRECTORY:
0274                 m = self.hooks.load_package(name, filename, file)
0275             else:
0276                 raise ImportError, "Unrecognized module type (%r) for %s" % \
0277                       (type, name)
0278         finally:
0279             if file: file.close()
0280         m.__file__ = filename
0281         return m
0282 
0283 
0284 class FancyModuleLoader(ModuleLoader):
0285 
0286     """Fancy module loader -- parses and execs the code itself."""
0287 
0288     def load_module(self, name, stuff):
0289         file, filename, (suff, mode, type) = stuff
0290         realfilename = filename
0291         path = None
0292 
0293         if type == PKG_DIRECTORY:
0294             initstuff = self.find_module_in_dir("__init__", filename, 0)
0295             if not initstuff:
0296                 raise ImportError, "No __init__ module in package %s" % name
0297             initfile, initfilename, initinfo = initstuff
0298             initsuff, initmode, inittype = initinfo
0299             if inittype not in (PY_COMPILED, PY_SOURCE):
0300                 if initfile: initfile.close()
0301                 raise ImportError, \
0302                     "Bad type (%r) for __init__ module in package %s" % (
0303                     inittype, name)
0304             path = [filename]
0305             file = initfile
0306             realfilename = initfilename
0307             type = inittype
0308 
0309         if type == FROZEN_MODULE:
0310             code = self.hooks.get_frozen_object(name)
0311         elif type == PY_COMPILED:
0312             import marshal
0313             file.seek(8)
0314             code = marshal.load(file)
0315         elif type == PY_SOURCE:
0316             data = file.read()
0317             code = compile(data, realfilename, 'exec')
0318         else:
0319             return ModuleLoader.load_module(self, name, stuff)
0320 
0321         m = self.hooks.add_module(name)
0322         if path:
0323             m.__path__ = path
0324         m.__file__ = filename
0325         try:
0326             exec code in m.__dict__
0327         except:
0328             d = self.hooks.modules_dict()
0329             if name in d:
0330                 del d[name]
0331             raise
0332         return m
0333 
0334 
0335 class BasicModuleImporter(_Verbose):
0336 
0337     """Basic module importer; uses module loader.
0338 
0339     This provides basic import facilities but no package imports.
0340 
0341     """
0342 
0343     def __init__(self, loader = None, verbose = VERBOSE):
0344         _Verbose.__init__(self, verbose)
0345         self.loader = loader or ModuleLoader(None, verbose)
0346         self.modules = self.loader.modules_dict()
0347 
0348     def get_loader(self):
0349         return self.loader
0350 
0351     def set_loader(self, loader):
0352         self.loader = loader
0353 
0354     def get_hooks(self):
0355         return self.loader.get_hooks()
0356 
0357     def set_hooks(self, hooks):
0358         return self.loader.set_hooks(hooks)
0359 
0360     def import_module(self, name, globals={}, locals={}, fromlist=[]):
0361         name = str(name)
0362         if name in self.modules:
0363             return self.modules[name] # Fast path
0364         stuff = self.loader.find_module(name)
0365         if not stuff:
0366             raise ImportError, "No module named %s" % name
0367         return self.loader.load_module(name, stuff)
0368 
0369     def reload(self, module, path = None):
0370         name = str(module.__name__)
0371         stuff = self.loader.find_module(name, path)
0372         if not stuff:
0373             raise ImportError, "Module %s not found for reload" % name
0374         return self.loader.load_module(name, stuff)
0375 
0376     def unload(self, module):
0377         del self.modules[str(module.__name__)]
0378         # XXX Should this try to clear the module's namespace?
0379 
0380     def install(self):
0381         self.save_import_module = __builtin__.__import__
0382         self.save_reload = __builtin__.reload
0383         if not hasattr(__builtin__, 'unload'):
0384             __builtin__.unload = None
0385         self.save_unload = __builtin__.unload
0386         __builtin__.__import__ = self.import_module
0387         __builtin__.reload = self.reload
0388         __builtin__.unload = self.unload
0389 
0390     def uninstall(self):
0391         __builtin__.__import__ = self.save_import_module
0392         __builtin__.reload = self.save_reload
0393         __builtin__.unload = self.save_unload
0394         if not __builtin__.unload:
0395             del __builtin__.unload
0396 
0397 
0398 class ModuleImporter(BasicModuleImporter):
0399 
0400     """A module importer that supports packages."""
0401 
0402     def import_module(self, name, globals=None, locals=None, fromlist=None):
0403         parent = self.determine_parent(globals)
0404         q, tail = self.find_head_package(parent, str(name))
0405         m = self.load_tail(q, tail)
0406         if not fromlist:
0407             return q
0408         if hasattr(m, "__path__"):
0409             self.ensure_fromlist(m, fromlist)
0410         return m
0411 
0412     def determine_parent(self, globals):
0413         if not globals or not "__name__" in globals:
0414             return None
0415         pname = globals['__name__']
0416         if "__path__" in globals:
0417             parent = self.modules[pname]
0418             assert globals is parent.__dict__
0419             return parent
0420         if '.' in pname:
0421             i = pname.rfind('.')
0422             pname = pname[:i]
0423             parent = self.modules[pname]
0424             assert parent.__name__ == pname
0425             return parent
0426         return None
0427 
0428     def find_head_package(self, parent, name):
0429         if '.' in name:
0430             i = name.find('.')
0431             head = name[:i]
0432             tail = name[i+1:]
0433         else:
0434             head = name
0435             tail = ""
0436         if parent:
0437             qname = "%s.%s" % (parent.__name__, head)
0438         else:
0439             qname = head
0440         q = self.import_it(head, qname, parent)
0441         if q: return q, tail
0442         if parent:
0443             qname = head
0444             parent = None
0445             q = self.import_it(head, qname, parent)
0446             if q: return q, tail
0447         raise ImportError, "No module named " + qname
0448 
0449     def load_tail(self, q, tail):
0450         m = q
0451         while tail:
0452             i = tail.find('.')
0453             if i < 0: i = len(tail)
0454             head, tail = tail[:i], tail[i+1:]
0455             mname = "%s.%s" % (m.__name__, head)
0456             m = self.import_it(head, mname, m)
0457             if not m:
0458                 raise ImportError, "No module named " + mname
0459         return m
0460 
0461     def ensure_fromlist(self, m, fromlist, recursive=0):
0462         for sub in fromlist:
0463             if sub == "*":
0464                 if not recursive:
0465                     try:
0466                         all = m.__all__
0467                     except AttributeError:
0468                         pass
0469                     else:
0470                         self.ensure_fromlist(m, all, 1)
0471                 continue
0472             if sub != "*" and not hasattr(m, sub):
0473                 subname = "%s.%s" % (m.__name__, sub)
0474                 submod = self.import_it(sub, subname, m)
0475                 if not submod:
0476                     raise ImportError, "No module named " + subname
0477 
0478     def import_it(self, partname, fqname, parent, force_load=0):
0479         if not partname:
0480             raise ValueError, "Empty module name"
0481         if not force_load:
0482             try:
0483                 return self.modules[fqname]
0484             except KeyError:
0485                 pass
0486         try:
0487             path = parent and parent.__path__
0488         except AttributeError:
0489             return None
0490         partname = str(partname)
0491         stuff = self.loader.find_module(partname, path)
0492         if not stuff:
0493             return None
0494         fqname = str(fqname)
0495         m = self.loader.load_module(fqname, stuff)
0496         if parent:
0497             setattr(parent, partname, m)
0498         return m
0499 
0500     def reload(self, module):
0501         name = str(module.__name__)
0502         if '.' not in name:
0503             return self.import_it(name, name, None, force_load=1)
0504         i = name.rfind('.')
0505         pname = name[:i]
0506         parent = self.modules[pname]
0507         return self.import_it(name[i+1:], name, parent, force_load=1)
0508 
0509 
0510 default_importer = None
0511 current_importer = None
0512 
0513 def install(importer = None):
0514     global current_importer
0515     current_importer = importer or default_importer or ModuleImporter()
0516     current_importer.install()
0517 
0518 def uninstall():
0519     global current_importer
0520     current_importer.uninstall()
0521 

Generated by PyXR 0.9.4
SourceForge.net Logo