From patchwork Sat Sep 7 01:48:02 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: demandimport: honor absolute_import (issue4029) From: "Jason R. Coombs" X-Patchwork-Id: 2399 Message-Id: <6e4a42dd60124b0bbe770f63743390e5@BLUPR06MB003.namprd06.prod.outlook.com> To: "mercurial-devel@selenic.com" Date: Sat, 7 Sep 2013 01:48:02 +0000 # HG changeset patch # User Jason R. Coombs # Date 1378518380 14400 # Fri Sep 06 21:46:20 2013 -0400 # Node ID 6b00771ea6ce22dc3dda8b6da063d3112bfcbce8 # Parent 1d07bf106c2ad1c7ef5e257e754ca8d858bd04b0 demandimport: honor absolute_import (issue4029) diff -r 1d07bf106c2a -r 6b00771ea6ce mercurial/demandimport.py --- a/mercurial/demandimport.py Wed Sep 04 18:42:55 2013 -0700 +++ b/mercurial/demandimport.py Fri Sep 06 21:46:20 2013 -0400 @@ -25,6 +25,7 @@ ''' import __builtin__ +import __future__ _origimport = __import__ nothing = object() @@ -55,7 +56,7 @@ def _load(self): if not self._module: head, globals, locals, after = self._data - mod = _origimport(head, globals, locals) + mod = _origimport(head, globals, locals, [], self._level()) # load submodules def subload(mod, p): h, t = p, None @@ -74,6 +75,18 @@ locals[head] = mod object.__setattr__(self, "_module", mod) + def _level(self): + """ + Determine the 'level' parameter to the __import__ function, based on + self._data. + """ + head, globals, locals, after = self._data + abs_import = globals.get('absolute_import', None) + if isinstance(abs_import, __future__._Feature): + # absolute_import was indicated, so disallow relative imports + return 0 + return -1 + def __repr__(self): if self._module: return "" % self._data[0] @@ -81,7 +94,7 @@ def __call__(self, *args, **kwargs): raise TypeError("%s object is not callable" % repr(self)) def __getattribute__(self, attr): - if attr in ('_data', '_extend', '_load', '_module'): + if attr in ('_data', '_extend', '_load', '_module', '_level'): return object.__getattribute__(self, attr) self._load() return getattr(self._module, attr) diff -r 1d07bf106c2a -r 6b00771ea6ce tests/test-demandimport-absolute.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-demandimport-absolute.py Fri Sep 06 21:46:20 2013 -0400 @@ -0,0 +1,46 @@ +"test demand import when absolute_import is indicated" + +import os +import sys +import shutil +import textwrap +import unittest + +import silenttestrunner + +from mercurial import demandimport + +class TestAbsoluteImport(unittest.TestCase): + + def setUp(self): + os.mkdir('pkg') + f = open('pkg/mod.py', 'w') + f.write(textwrap.dedent(""" + from __future__ import absolute_import + import os + """).lstrip()) + f.close() + f = open('pkg/__init__.py', 'w') + f.close() + f = open('pkg/os.py', 'w') + f.write('''val = "this is not the module you're looking for"\n''') + f.close() + demandimport.enable() + + def tearDown(self): + shutil.rmtree('pkg') + demandimport.disable() + + def test_absolute_import(self): + if sys.version_info < (2,5): + print("Test only viable on Python 2.5 or later") + return + import pkg.mod + # trigger the loading of the module + pkg.mod.__name__ + assert pkg.mod.os.__name__ == 'os' + assert 'devnull' in dir(pkg.mod.os) + assert 'val' not in dir(pkg.mod.os) + +if __name__ == '__main__': + silenttestrunner.main(__name__)