eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/mercurial/demandimport.py
changeset 69 c6bca38c1cbf
equal deleted inserted replaced
68:5ff1fc726848 69:c6bca38c1cbf
       
     1 # demandimport.py - global demand-loading of modules for Mercurial
       
     2 #
       
     3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
       
     4 #
       
     5 # This software may be used and distributed according to the terms of the
       
     6 # GNU General Public License version 2 or any later version.
       
     7 
       
     8 '''
       
     9 demandimport - automatic demandloading of modules
       
    10 
       
    11 To enable this module, do:
       
    12 
       
    13   import demandimport; demandimport.enable()
       
    14 
       
    15 Imports of the following forms will be demand-loaded:
       
    16 
       
    17   import a, b.c
       
    18   import a.b as c
       
    19   from a import b,c # a will be loaded immediately
       
    20 
       
    21 These imports will not be delayed:
       
    22 
       
    23   from a import *
       
    24   b = __import__(a)
       
    25 '''
       
    26 
       
    27 import __builtin__
       
    28 _origimport = __import__
       
    29 
       
    30 class _demandmod(object):
       
    31     """module demand-loader and proxy"""
       
    32     def __init__(self, name, globals, locals):
       
    33         if '.' in name:
       
    34             head, rest = name.split('.', 1)
       
    35             after = [rest]
       
    36         else:
       
    37             head = name
       
    38             after = []
       
    39         object.__setattr__(self, "_data", (head, globals, locals, after))
       
    40         object.__setattr__(self, "_module", None)
       
    41     def _extend(self, name):
       
    42         """add to the list of submodules to load"""
       
    43         self._data[3].append(name)
       
    44     def _load(self):
       
    45         if not self._module:
       
    46             head, globals, locals, after = self._data
       
    47             mod = _origimport(head, globals, locals)
       
    48             # load submodules
       
    49             def subload(mod, p):
       
    50                 h, t = p, None
       
    51                 if '.' in p:
       
    52                     h, t = p.split('.', 1)
       
    53                 if not hasattr(mod, h):
       
    54                     setattr(mod, h, _demandmod(p, mod.__dict__, mod.__dict__))
       
    55                 elif t:
       
    56                     subload(getattr(mod, h), t)
       
    57 
       
    58             for x in after:
       
    59                 subload(mod, x)
       
    60 
       
    61             # are we in the locals dictionary still?
       
    62             if locals and locals.get(head) == self:
       
    63                 locals[head] = mod
       
    64             object.__setattr__(self, "_module", mod)
       
    65 
       
    66     def __repr__(self):
       
    67         if self._module:
       
    68             return "<proxied module '%s'>" % self._data[0]
       
    69         return "<unloaded module '%s'>" % self._data[0]
       
    70     def __call__(self, *args, **kwargs):
       
    71         raise TypeError("%s object is not callable" % repr(self))
       
    72     def __getattribute__(self, attr):
       
    73         if attr in ('_data', '_extend', '_load', '_module'):
       
    74             return object.__getattribute__(self, attr)
       
    75         self._load()
       
    76         return getattr(self._module, attr)
       
    77     def __setattr__(self, attr, val):
       
    78         self._load()
       
    79         setattr(self._module, attr, val)
       
    80 
       
    81 def _demandimport(name, globals=None, locals=None, fromlist=None, level=None):
       
    82     if not locals or name in ignore or fromlist == ('*',):
       
    83         # these cases we can't really delay
       
    84         if level is None:
       
    85             return _origimport(name, globals, locals, fromlist)
       
    86         else:
       
    87             return _origimport(name, globals, locals, fromlist, level)
       
    88     elif not fromlist:
       
    89         # import a [as b]
       
    90         if '.' in name: # a.b
       
    91             base, rest = name.split('.', 1)
       
    92             # email.__init__ loading email.mime
       
    93             if globals and globals.get('__name__', None) == base:
       
    94                 return _origimport(name, globals, locals, fromlist)
       
    95             # if a is already demand-loaded, add b to its submodule list
       
    96             if base in locals:
       
    97                 if isinstance(locals[base], _demandmod):
       
    98                     locals[base]._extend(rest)
       
    99                 return locals[base]
       
   100         return _demandmod(name, globals, locals)
       
   101     else:
       
   102         if level is not None:
       
   103             # from . import b,c,d or from .a import b,c,d
       
   104             return _origimport(name, globals, locals, fromlist, level)
       
   105         # from a import b,c,d
       
   106         mod = _origimport(name, globals, locals)
       
   107         # recurse down the module chain
       
   108         for comp in name.split('.')[1:]:
       
   109             if not hasattr(mod, comp):
       
   110                 setattr(mod, comp, _demandmod(comp, mod.__dict__, mod.__dict__))
       
   111             mod = getattr(mod, comp)
       
   112         for x in fromlist:
       
   113             # set requested submodules for demand load
       
   114             if not(hasattr(mod, x)):
       
   115                 setattr(mod, x, _demandmod(x, mod.__dict__, locals))
       
   116         return mod
       
   117 
       
   118 ignore = [
       
   119     '_hashlib',
       
   120     '_xmlplus',
       
   121     'fcntl',
       
   122     'win32com.gen_py',
       
   123     '_winreg', # 2.7 mimetypes needs immediate ImportError
       
   124     'pythoncom',
       
   125     # imported by tarfile, not available under Windows
       
   126     'pwd',
       
   127     'grp',
       
   128     # imported by profile, itself imported by hotshot.stats,
       
   129     # not available under Windows
       
   130     'resource',
       
   131     # this trips up many extension authors
       
   132     'gtk',
       
   133     # setuptools' pkg_resources.py expects "from __main__ import x" to
       
   134     # raise ImportError if x not defined
       
   135     '__main__',
       
   136     '_ssl', # conditional imports in the stdlib, issue1964
       
   137     ]
       
   138 
       
   139 def enable():
       
   140     "enable global demand-loading of modules"
       
   141     __builtin__.__import__ = _demandimport
       
   142 
       
   143 def disable():
       
   144     "disable global demand-loading of modules"
       
   145     __builtin__.__import__ = _origimport
       
   146