Package pyamf :: Package util :: Module imports |
[hide private]
[frames] | no frames]

# Source Code for Module pyamf.util.imports

      1  # Copyright (c) 2007-2009 The PyAMF Project.
      2  # See LICENSE.txt for details.
      3
      4  """
      5  Tools for doing dynamic imports.
      6
      7  @since: 0.3
      8  """
      9
     10  import sys
     11
     12
     13  __all__ = ['when_imported']
     14
     15  #: A list of callables to be executed when the module is imported.
     16  post_load_hooks = {}
     17  #: List of modules that have already been loaded.
     18  loaded_modules = []
     19
     20
     21 -class ModuleFinder(object):
     22      """
     23      This is a special module finder object that executes a collection of
     24      callables when a specific module has been imported. An instance of this
     25      is placed in C{sys.meta_path}, which is consulted before C{sys.modules} -
     26      allowing us to provide this functionality.
     27
     28      @see: L{when_imported}
     29      @since: 0.5
     30      """
     31
     32 -    def find_module(self, name, path):
     33          """
     34          Called when an import is made. If there are hooks waiting for this
     35          module to be imported then we stop the normal import process and
     36          manually load the module.
     37
     38          @param name: The name of the module being imported.
     39          @param path The root path of the module (if a package). We ignore this.
     40          @return: If we want to hook this module, we return a C{loader}
     41              interface (which is this instance again). If not we return C{None}
     42              to allow the standard import process to continue.
     43          """
     44          if name in loaded_modules or name not in post_load_hooks:
     45              return None
     46
     47          return self
     48
     49 -    def load_module(self, name):
     50          """
     51          If we get this far, then there are hooks waiting to be called on
     52          import of this module. We manually load the module and then run the
     53          hooks.
     54
     55          @param name: The name of the module to import.
     56          """
     57          loaded_modules.append(name)
     58          parent, child = split_module(name)
     59
     60          __import__(name, {}, {}, [])
     61
     62          mod = sys.modules[name]
     63
     64          run_hooks(name, mod)
     65
     66          return mod
     67
     68
     69 -def run_hooks(name, module):
     70      """
     71      Run all hooks for a module.
     72      Load an unactivated "lazy" module object.
     73      """
     74      try:
     75          for hook in post_load_hooks[name]:
     76              hook(module)
     77      finally:
     78          del post_load_hooks[name]
     79
     80
     81 -def split_module(name):
     82      """
     83      Splits a module name into its parent and child parts.
     84
     85      >>> split_module('foo.bar.baz')
     86      'foo.bar', 'baz'
     87      >>> split_module('foo')
     88      None, 'foo'
     89      """
     90      try:
     91          splitpos = name.rindex('.') + 1
     92
     93          return name[:splitpos - 1], name[splitpos:]
     94      except ValueError:
     95          return None, name
     96
     97
     98 -def when_imported(name, hook):
     99      """
    100      Call C{hook(module)} when module named C{name} is first used.
    101
    102      'hook' must accept one argument: the module object named by 'name', which
    103      must be a fully qualified (i.e. absolute) module name.  The hook should
    104      not raise any exceptions, or it will prevent later hooks from running.
    105
    106      If the module has already been imported normally, 'hook(module)' is
    107      called immediately, and the module object is returned from this function.
    108      If the module has not been imported, then the hook is called when the
    109      module is first imported.
    110      """
    111      if name in loaded_modules or name in sys.modules:
    112          hook(sys.modules[name])
    113
    114          return
    115
    116      if name not in post_load_hooks:
    117          post_load_hooks[name] = []
    118
    119      post_load_hooks[name].append(hook)
    120
    121
    122  # this is required for reloading this module
    123  for obj in sys.meta_path:
    124      if obj.__class__ is ModuleFinder:
    125          break
    126  else:
    127      sys.meta_path.insert(0, ModuleFinder())
    128