# HG changeset patch # User FUJIWARA Katsunori # Date 2016-08-06 13:24:33 # Node ID 14f077f7519afb623dbfad37b411b2356f325fb3 # Parent 919a4b7f531d38531c7b3e455b3e2acb13867f87 demandimport: import sub-module relatively as expected (issue5208) Before this patch, importing sub-module might (1) fail or (2) success but import incorrect module, because demandimport tries to import sub-module with level=-1 (on Python 2.x) or level=0 (on Python 3.x), which is default value of "level" argument at construction of "_demandmod" proxy object. (1) on Python 3.x, importing sub-module always fails to import existing sub-module (2) both on Python 2.x and 3.x, importing sub-module might import same name module on root level unintentionally On Python 2.x, existing sub-module is prior to this unexpected module. Therefore, this problem hasn't appeared. To import sub-module relatively as expected, this patch specifies "1" as import level explicitly at construction of "_demandmod" proxy object for sub-module. diff --git a/mercurial/demandimport.py b/mercurial/demandimport.py --- a/mercurial/demandimport.py +++ b/mercurial/demandimport.py @@ -117,7 +117,8 @@ class _demandmod(object): if '.' in p: h, t = p.split('.', 1) if getattr(mod, h, nothing) is nothing: - setattr(mod, h, _demandmod(p, mod.__dict__, mod.__dict__)) + setattr(mod, h, _demandmod(p, mod.__dict__, mod.__dict__, + level=1)) elif t: subload(getattr(mod, h), t) @@ -210,8 +211,8 @@ def _demandimport(name, globals=None, lo mod = rootmod for comp in modname.split('.')[1:]: if getattr(mod, comp, nothing) is nothing: - setattr(mod, comp, - _demandmod(comp, mod.__dict__, mod.__dict__)) + setattr(mod, comp, _demandmod(comp, mod.__dict__, + mod.__dict__, level=1)) mod = getattr(mod, comp) return mod diff --git a/tests/test-extension.t b/tests/test-extension.t --- a/tests/test-extension.t +++ b/tests/test-extension.t @@ -432,6 +432,36 @@ Examine module importing. REL: this is absextroot.xsub1.xsub2.called.func() REL: this relimporter imports 'this is absextroot.relimportee' +Examine whether sub-module is imported relatively as expected. + +See also issue5208 for detail about example case on Python 3.x. + + $ f -q $TESTTMP/extlibroot/lsub1/lsub2/notexist.py + $TESTTMP/extlibroot/lsub1/lsub2/notexist.py: file not found + + $ cat > $TESTTMP/notexist.py < text = 'notexist.py at root is loaded unintentionally\n' + > EOF + + $ cat > $TESTTMP/checkrelativity.py < from mercurial import cmdutil + > cmdtable = {} + > command = cmdutil.command(cmdtable) + > + > # demand import avoids failure of importing notexist here + > import extlibroot.lsub1.lsub2.notexist + > + > @command('checkrelativity', [], norepo=True) + > def checkrelativity(ui, *args, **opts): + > try: + > ui.write(extlibroot.lsub1.lsub2.notexist.text) + > return 1 # unintentional success + > except ImportError: + > pass # intentional failure + > EOF + + $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.checkrelativity=$TESTTMP/checkrelativity.py checkrelativity) + #endif $ cd ..