diff --git a/mercurial/demandimport.py b/mercurial/demandimport.py --- a/mercurial/demandimport.py +++ b/mercurial/demandimport.py @@ -191,11 +191,16 @@ def _demandimport(name, globals=None, lo def processfromitem(mod, attr): """Process an imported symbol in the import statement. - If the symbol doesn't exist in the parent module, it must be a - module. We set missing modules up as _demandmod instances. + If the symbol doesn't exist in the parent module, and if the + parent module is a package, it must be a module. We set missing + modules up as _demandmod instances. """ symbol = getattr(mod, attr, nothing) + nonpkg = getattr(mod, '__path__', nothing) is nothing if symbol is nothing: + if nonpkg: + # do not try relative import, which would raise ValueError + raise ImportError('cannot import name %s' % attr) mn = '%s.%s' % (mod.__name__, attr) if mn in ignore: importfunc = _origimport diff --git a/tests/test-demandimport.py b/tests/test-demandimport.py --- a/tests/test-demandimport.py +++ b/tests/test-demandimport.py @@ -63,6 +63,15 @@ print("re =", f(re)) print("re.stderr =", f(re.stderr)) print("re =", f(re)) +import contextlib +print("contextlib =", f(contextlib)) +try: + from contextlib import unknownattr + print('no demandmod should be created for attribute of non-package ' + 'module:\ncontextlib.unknownattr =', f(unknownattr)) +except ImportError as inst: + print('contextlib.unknownattr = ImportError: %s' % inst) + demandimport.disable() os.environ['HGDEMANDIMPORT'] = 'disable' # this enable call should not actually enable demandimport! diff --git a/tests/test-demandimport.py.out b/tests/test-demandimport.py.out --- a/tests/test-demandimport.py.out +++ b/tests/test-demandimport.py.out @@ -16,4 +16,6 @@ fred = re = re.stderr = ', mode 'w' at 0x?> re = +contextlib = +contextlib.unknownattr = ImportError: cannot import name unknownattr node =