Show More
@@ -188,15 +188,23 b' def _demandimport(name, globals=None, lo' | |||||
188 | if globalname and isinstance(symbol, _demandmod): |
|
188 | if globalname and isinstance(symbol, _demandmod): | |
189 | symbol._addref(globalname) |
|
189 | symbol._addref(globalname) | |
190 |
|
190 | |||
|
191 | def chainmodules(rootmod, modname): | |||
|
192 | # recurse down the module chain, and return the leaf module | |||
|
193 | mod = rootmod | |||
|
194 | for comp in modname.split('.')[1:]: | |||
|
195 | if getattr(mod, comp, nothing) is nothing: | |||
|
196 | setattr(mod, comp, | |||
|
197 | _demandmod(comp, mod.__dict__, mod.__dict__)) | |||
|
198 | mod = getattr(mod, comp) | |||
|
199 | return mod | |||
|
200 | ||||
191 | if level >= 0: |
|
201 | if level >= 0: | |
192 | # The "from a import b,c,d" or "from .a import b,c,d" |
|
|||
193 | # syntax gives errors with some modules for unknown |
|
|||
194 | # reasons. Work around the problem. |
|
|||
195 | if name: |
|
202 | if name: | |
196 | return _hgextimport(_origimport, name, globals, locals, |
|
203 | # "from a import b" or "from .a import b" style | |
197 | fromlist, level) |
|
204 | rootmod = _hgextimport(_origimport, name, globals, locals, | |
198 |
|
205 | level=level) | ||
199 | if _pypy: |
|
206 | mod = chainmodules(rootmod, name) | |
|
207 | elif _pypy: | |||
200 | # PyPy's __import__ throws an exception if invoked |
|
208 | # PyPy's __import__ throws an exception if invoked | |
201 | # with an empty name and no fromlist. Recreate the |
|
209 | # with an empty name and no fromlist. Recreate the | |
202 | # desired behaviour by hand. |
|
210 | # desired behaviour by hand. | |
@@ -220,12 +228,7 b' def _demandimport(name, globals=None, lo' | |||||
220 | # But, we still need to support lazy loading of standard library and 3rd |
|
228 | # But, we still need to support lazy loading of standard library and 3rd | |
221 | # party modules. So handle level == -1. |
|
229 | # party modules. So handle level == -1. | |
222 | mod = _hgextimport(_origimport, name, globals, locals) |
|
230 | mod = _hgextimport(_origimport, name, globals, locals) | |
223 | # recurse down the module chain |
|
231 | mod = chainmodules(mod, name) | |
224 | for comp in name.split('.')[1:]: |
|
|||
225 | if getattr(mod, comp, nothing) is nothing: |
|
|||
226 | setattr(mod, comp, |
|
|||
227 | _demandmod(comp, mod.__dict__, mod.__dict__)) |
|
|||
228 | mod = getattr(mod, comp) |
|
|||
229 |
|
232 | |||
230 | for x in fromlist: |
|
233 | for x in fromlist: | |
231 | processfromitem(mod, x) |
|
234 | processfromitem(mod, x) |
@@ -249,6 +249,191 b' Check absolute/relative import of extens' | |||||
249 | $TESTTMP/a (glob) |
|
249 | $TESTTMP/a (glob) | |
250 | #endif |
|
250 | #endif | |
251 |
|
251 | |||
|
252 | #if absimport | |||
|
253 | ||||
|
254 | Examine whether module loading is delayed until actual refering, even | |||
|
255 | though module is imported with "absolute_import" feature. | |||
|
256 | ||||
|
257 | Files below in each packages are used for descirbed purpose: | |||
|
258 | ||||
|
259 | - "called": examine whether "from MODULE import ATTR" works correctly | |||
|
260 | - "unused": examine whether loading is delayed correctly | |||
|
261 | - "used": examine whether "from PACKAGE import MODULE" works correctly | |||
|
262 | ||||
|
263 | Package hierarchy is needed to examine whether demand importing works | |||
|
264 | as expected for "from SUB.PACK.AGE import MODULE". | |||
|
265 | ||||
|
266 | Setup "external library" to be imported with "absolute_import" | |||
|
267 | feature. | |||
|
268 | ||||
|
269 | $ mkdir -p $TESTTMP/extlibroot/lsub1/lsub2 | |||
|
270 | $ touch $TESTTMP/extlibroot/__init__.py | |||
|
271 | $ touch $TESTTMP/extlibroot/lsub1/__init__.py | |||
|
272 | $ touch $TESTTMP/extlibroot/lsub1/lsub2/__init__.py | |||
|
273 | ||||
|
274 | $ cat > $TESTTMP/extlibroot/lsub1/lsub2/called.py <<EOF | |||
|
275 | > def func(): | |||
|
276 | > return "this is extlibroot.lsub1.lsub2.called.func()" | |||
|
277 | > EOF | |||
|
278 | $ cat > $TESTTMP/extlibroot/lsub1/lsub2/unused.py <<EOF | |||
|
279 | > raise Exception("extlibroot.lsub1.lsub2.unused is loaded unintentionally") | |||
|
280 | > EOF | |||
|
281 | $ cat > $TESTTMP/extlibroot/lsub1/lsub2/used.py <<EOF | |||
|
282 | > detail = "this is extlibroot.lsub1.lsub2.used" | |||
|
283 | > EOF | |||
|
284 | ||||
|
285 | Setup sub-package of "external library", which causes instantiation of | |||
|
286 | demandmod in "recurse down the module chain" code path. Relative | |||
|
287 | importing with "absolute_import" feature isn't tested, because "level | |||
|
288 | >=1 " doesn't cause instantiation of demandmod. | |||
|
289 | ||||
|
290 | $ mkdir -p $TESTTMP/extlibroot/recursedown/abs | |||
|
291 | $ cat > $TESTTMP/extlibroot/recursedown/abs/used.py <<EOF | |||
|
292 | > detail = "this is extlibroot.recursedown.abs.used" | |||
|
293 | > EOF | |||
|
294 | $ cat > $TESTTMP/extlibroot/recursedown/abs/__init__.py <<EOF | |||
|
295 | > from __future__ import absolute_import | |||
|
296 | > from extlibroot.recursedown.abs.used import detail | |||
|
297 | > EOF | |||
|
298 | ||||
|
299 | $ mkdir -p $TESTTMP/extlibroot/recursedown/legacy | |||
|
300 | $ cat > $TESTTMP/extlibroot/recursedown/legacy/used.py <<EOF | |||
|
301 | > detail = "this is extlibroot.recursedown.legacy.used" | |||
|
302 | > EOF | |||
|
303 | $ cat > $TESTTMP/extlibroot/recursedown/legacy/__init__.py <<EOF | |||
|
304 | > # legacy style (level == -1) import | |||
|
305 | > from extlibroot.recursedown.legacy.used import detail | |||
|
306 | > EOF | |||
|
307 | ||||
|
308 | $ cat > $TESTTMP/extlibroot/recursedown/__init__.py <<EOF | |||
|
309 | > from __future__ import absolute_import | |||
|
310 | > from extlibroot.recursedown.abs import detail as absdetail | |||
|
311 | > from .legacy import detail as legacydetail | |||
|
312 | > EOF | |||
|
313 | ||||
|
314 | Setup extension local modules to be imported with "absolute_import" | |||
|
315 | feature. | |||
|
316 | ||||
|
317 | $ mkdir -p $TESTTMP/absextroot/xsub1/xsub2 | |||
|
318 | $ touch $TESTTMP/absextroot/xsub1/__init__.py | |||
|
319 | $ touch $TESTTMP/absextroot/xsub1/xsub2/__init__.py | |||
|
320 | ||||
|
321 | $ cat > $TESTTMP/absextroot/xsub1/xsub2/called.py <<EOF | |||
|
322 | > def func(): | |||
|
323 | > return "this is absextroot.xsub1.xsub2.called.func()" | |||
|
324 | > EOF | |||
|
325 | $ cat > $TESTTMP/absextroot/xsub1/xsub2/unused.py <<EOF | |||
|
326 | > raise Exception("absextroot.xsub1.xsub2.unused is loaded unintentionally") | |||
|
327 | > EOF | |||
|
328 | $ cat > $TESTTMP/absextroot/xsub1/xsub2/used.py <<EOF | |||
|
329 | > detail = "this is absextroot.xsub1.xsub2.used" | |||
|
330 | > EOF | |||
|
331 | ||||
|
332 | Setup extension local modules to examine whether demand importing | |||
|
333 | works as expected in "level > 1" case. | |||
|
334 | ||||
|
335 | $ cat > $TESTTMP/absextroot/relimportee.py <<EOF | |||
|
336 | > detail = "this is absextroot.relimportee" | |||
|
337 | > EOF | |||
|
338 | $ cat > $TESTTMP/absextroot/xsub1/xsub2/relimporter.py <<EOF | |||
|
339 | > from __future__ import absolute_import | |||
|
340 | > from ... import relimportee | |||
|
341 | > detail = "this relimporter imports %r" % (relimportee.detail) | |||
|
342 | > EOF | |||
|
343 | ||||
|
344 | Setup modules, which actually import extension local modules at | |||
|
345 | runtime. | |||
|
346 | ||||
|
347 | $ cat > $TESTTMP/absextroot/absolute.py << EOF | |||
|
348 | > from __future__ import absolute_import | |||
|
349 | > | |||
|
350 | > # import extension local modules absolutely (level = 0) | |||
|
351 | > from absextroot.xsub1.xsub2 import used, unused | |||
|
352 | > from absextroot.xsub1.xsub2.called import func | |||
|
353 | > | |||
|
354 | > def getresult(): | |||
|
355 | > result = [] | |||
|
356 | > result.append(used.detail) | |||
|
357 | > result.append(func()) | |||
|
358 | > return result | |||
|
359 | > EOF | |||
|
360 | ||||
|
361 | $ cat > $TESTTMP/absextroot/relative.py << EOF | |||
|
362 | > from __future__ import absolute_import | |||
|
363 | > | |||
|
364 | > # import extension local modules relatively (level == 1) | |||
|
365 | > from .xsub1.xsub2 import used, unused | |||
|
366 | > from .xsub1.xsub2.called import func | |||
|
367 | > | |||
|
368 | > # import a module, which implies "importing with level > 1" | |||
|
369 | > from .xsub1.xsub2 import relimporter | |||
|
370 | > | |||
|
371 | > def getresult(): | |||
|
372 | > result = [] | |||
|
373 | > result.append(used.detail) | |||
|
374 | > result.append(func()) | |||
|
375 | > result.append(relimporter.detail) | |||
|
376 | > return result | |||
|
377 | > EOF | |||
|
378 | ||||
|
379 | Setup main procedure of extension. | |||
|
380 | ||||
|
381 | $ cat > $TESTTMP/absextroot/__init__.py <<EOF | |||
|
382 | > from __future__ import absolute_import | |||
|
383 | > from mercurial import cmdutil | |||
|
384 | > cmdtable = {} | |||
|
385 | > command = cmdutil.command(cmdtable) | |||
|
386 | > | |||
|
387 | > # "absolute" and "relative" shouldn't be imported before actual | |||
|
388 | > # command execution, because (1) they import same modules, and (2) | |||
|
389 | > # preceding import (= instantiate "demandmod" object instead of | |||
|
390 | > # real "module" object) might hide problem of succeeding import. | |||
|
391 | > | |||
|
392 | > @command('showabsolute', [], norepo=True) | |||
|
393 | > def showabsolute(ui, *args, **opts): | |||
|
394 | > from absextroot import absolute | |||
|
395 | > ui.write('ABS: %s\n' % '\nABS: '.join(absolute.getresult())) | |||
|
396 | > | |||
|
397 | > @command('showrelative', [], norepo=True) | |||
|
398 | > def showrelative(ui, *args, **opts): | |||
|
399 | > from . import relative | |||
|
400 | > ui.write('REL: %s\n' % '\nREL: '.join(relative.getresult())) | |||
|
401 | > | |||
|
402 | > # import modules from external library | |||
|
403 | > from extlibroot.lsub1.lsub2 import used as lused, unused as lunused | |||
|
404 | > from extlibroot.lsub1.lsub2.called import func as lfunc | |||
|
405 | > from extlibroot.recursedown import absdetail, legacydetail | |||
|
406 | > | |||
|
407 | > def uisetup(ui): | |||
|
408 | > result = [] | |||
|
409 | > result.append(lused.detail) | |||
|
410 | > result.append(lfunc()) | |||
|
411 | > result.append(absdetail) | |||
|
412 | > result.append(legacydetail) | |||
|
413 | > ui.write('LIB: %s\n' % '\nLIB: '.join(result)) | |||
|
414 | > EOF | |||
|
415 | ||||
|
416 | Examine module importing. | |||
|
417 | ||||
|
418 | $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showabsolute) | |||
|
419 | LIB: this is extlibroot.lsub1.lsub2.used | |||
|
420 | LIB: this is extlibroot.lsub1.lsub2.called.func() | |||
|
421 | LIB: this is extlibroot.recursedown.abs.used | |||
|
422 | LIB: this is extlibroot.recursedown.legacy.used | |||
|
423 | ABS: this is absextroot.xsub1.xsub2.used | |||
|
424 | ABS: this is absextroot.xsub1.xsub2.called.func() | |||
|
425 | ||||
|
426 | $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showrelative) | |||
|
427 | LIB: this is extlibroot.lsub1.lsub2.used | |||
|
428 | LIB: this is extlibroot.lsub1.lsub2.called.func() | |||
|
429 | LIB: this is extlibroot.recursedown.abs.used | |||
|
430 | LIB: this is extlibroot.recursedown.legacy.used | |||
|
431 | REL: this is absextroot.xsub1.xsub2.used | |||
|
432 | REL: this is absextroot.xsub1.xsub2.called.func() | |||
|
433 | REL: this relimporter imports 'this is absextroot.relimportee' | |||
|
434 | ||||
|
435 | #endif | |||
|
436 | ||||
252 | $ cd .. |
|
437 | $ cd .. | |
253 |
|
438 | |||
254 | hide outer repo |
|
439 | hide outer repo |
General Comments 0
You need to be logged in to leave comments.
Login now