mercurial/demandimport.py
changeset 26457 7e81305092a0
parent 26456 86fc4a2863ff
child 26830 65387a30430e
equal deleted inserted replaced
26456:86fc4a2863ff 26457:7e81305092a0
    71             after = [rest]
    71             after = [rest]
    72         else:
    72         else:
    73             head = name
    73             head = name
    74             after = []
    74             after = []
    75         object.__setattr__(self, "_data",
    75         object.__setattr__(self, "_data",
    76                            (head, globals, locals, after, level))
    76                            (head, globals, locals, after, level, set()))
    77         object.__setattr__(self, "_module", None)
    77         object.__setattr__(self, "_module", None)
    78     def _extend(self, name):
    78     def _extend(self, name):
    79         """add to the list of submodules to load"""
    79         """add to the list of submodules to load"""
    80         self._data[3].append(name)
    80         self._data[3].append(name)
       
    81 
       
    82     def _addref(self, name):
       
    83         """Record that the named module ``name`` imports this module.
       
    84 
       
    85         References to this proxy class having the name of this module will be
       
    86         replaced at module load time. We assume the symbol inside the importing
       
    87         module is identical to the "head" name of this module. We don't
       
    88         actually know if "as X" syntax is being used to change the symbol name
       
    89         because this information isn't exposed to __import__.
       
    90         """
       
    91         self._data[5].add(name)
       
    92 
    81     def _load(self):
    93     def _load(self):
    82         if not self._module:
    94         if not self._module:
    83             head, globals, locals, after, level = self._data
    95             head, globals, locals, after, level, modrefs = self._data
    84             mod = _hgextimport(_import, head, globals, locals, None, level)
    96             mod = _hgextimport(_import, head, globals, locals, None, level)
    85             # load submodules
    97             # load submodules
    86             def subload(mod, p):
    98             def subload(mod, p):
    87                 h, t = p, None
    99                 h, t = p, None
    88                 if '.' in p:
   100                 if '.' in p:
    93                     subload(getattr(mod, h), t)
   105                     subload(getattr(mod, h), t)
    94 
   106 
    95             for x in after:
   107             for x in after:
    96                 subload(mod, x)
   108                 subload(mod, x)
    97 
   109 
    98             # are we in the locals dictionary still?
   110             # Replace references to this proxy instance with the actual module.
    99             if locals and locals.get(head) == self:
   111             if locals and locals.get(head) == self:
   100                 locals[head] = mod
   112                 locals[head] = mod
       
   113 
       
   114             for modname in modrefs:
       
   115                 modref = sys.modules.get(modname, None)
       
   116                 if modref and getattr(modref, head, None) == self:
       
   117                     setattr(modref, head, mod)
       
   118 
   101             object.__setattr__(self, "_module", mod)
   119             object.__setattr__(self, "_module", mod)
   102 
   120 
   103     def __repr__(self):
   121     def __repr__(self):
   104         if self._module:
   122         if self._module:
   105             return "<proxied module '%s'>" % self._data[0]
   123             return "<proxied module '%s'>" % self._data[0]
   106         return "<unloaded module '%s'>" % self._data[0]
   124         return "<unloaded module '%s'>" % self._data[0]
   107     def __call__(self, *args, **kwargs):
   125     def __call__(self, *args, **kwargs):
   108         raise TypeError("%s object is not callable" % repr(self))
   126         raise TypeError("%s object is not callable" % repr(self))
   109     def __getattribute__(self, attr):
   127     def __getattribute__(self, attr):
   110         if attr in ('_data', '_extend', '_load', '_module'):
   128         if attr in ('_data', '_extend', '_load', '_module', '_addref'):
   111             return object.__getattribute__(self, attr)
   129             return object.__getattribute__(self, attr)
   112         self._load()
   130         self._load()
   113         return getattr(self._module, attr)
   131         return getattr(self._module, attr)
   114     def __setattr__(self, attr, val):
   132     def __setattr__(self, attr, val):
   115         self._load()
   133         self._load()
   141         # level == -1: relative and absolute attempted (Python 2 only).
   159         # level == -1: relative and absolute attempted (Python 2 only).
   142         # level >= 0: absolute only (Python 2 w/ absolute_import and Python 3).
   160         # level >= 0: absolute only (Python 2 w/ absolute_import and Python 3).
   143         # The modern Mercurial convention is to use absolute_import everywhere,
   161         # The modern Mercurial convention is to use absolute_import everywhere,
   144         # so modern Mercurial code will have level >= 0.
   162         # so modern Mercurial code will have level >= 0.
   145 
   163 
       
   164         # The name of the module the import statement is located in.
       
   165         globalname = globals.get('__name__')
       
   166 
   146         def processfromitem(mod, attr, **kwargs):
   167         def processfromitem(mod, attr, **kwargs):
   147             """Process an imported symbol in the import statement.
   168             """Process an imported symbol in the import statement.
   148 
   169 
   149             If the symbol doesn't exist in the parent module, it must be a
   170             If the symbol doesn't exist in the parent module, it must be a
   150             module. We set missing modules up as _demandmod instances.
   171             module. We set missing modules up as _demandmod instances.
   151             """
   172             """
   152             symbol = getattr(mod, attr, nothing)
   173             symbol = getattr(mod, attr, nothing)
   153             if symbol is nothing:
   174             if symbol is nothing:
   154                 symbol = _demandmod(attr, mod.__dict__, locals, **kwargs)
   175                 symbol = _demandmod(attr, mod.__dict__, locals, **kwargs)
   155                 setattr(mod, attr, symbol)
   176                 setattr(mod, attr, symbol)
       
   177 
       
   178             # Record the importing module references this symbol so we can
       
   179             # replace the symbol with the actual module instance at load
       
   180             # time.
       
   181             if globalname and isinstance(symbol, _demandmod):
       
   182                 symbol._addref(globalname)
   156 
   183 
   157         if level >= 0:
   184         if level >= 0:
   158             # Mercurial's enforced import style does not use
   185             # Mercurial's enforced import style does not use
   159             # "from a import b,c,d" or "from .a import b,c,d" syntax. In
   186             # "from a import b,c,d" or "from .a import b,c,d" syntax. In
   160             # addition, this appears to be giving errors with some modules
   187             # addition, this appears to be giving errors with some modules