Show More
@@ -73,14 +73,26 b' class _demandmod(object):' | |||||
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): | |
@@ -95,9 +107,15 b' class _demandmod(object):' | |||||
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): | |
@@ -107,7 +125,7 b' class _demandmod(object):' | |||||
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) | |
@@ -143,6 +161,9 b' def _demandimport(name, globals=None, lo' | |||||
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 | |||
@@ -154,6 +175,12 b' def _demandimport(name, globals=None, lo' | |||||
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) | |
156 |
|
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) | |||
|
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 |
General Comments 0
You need to be logged in to leave comments.
Login now