diff --git a/django/utils/module_loading.py b/django/utils/module_loading.py index 32ca69a9fd..4b76f6cbdd 100644 --- a/django/utils/module_loading.py +++ b/django/utils/module_loading.py @@ -12,7 +12,7 @@ def module_has_submodule(package, module_name): except KeyError: pass for finder in sys.meta_path: - if finder.find_module(name): + if finder.find_module(name, package): return True for entry in package.__path__: # No __path__, then not a package. try: diff --git a/tests/regressiontests/utils/module_loading.py b/tests/regressiontests/utils/module_loading.py index 24c0b0753f..2e9d167fe9 100644 --- a/tests/regressiontests/utils/module_loading.py +++ b/tests/regressiontests/utils/module_loading.py @@ -1,5 +1,6 @@ import os import sys +import imp from zipimport import zipimporter from django.utils import unittest @@ -8,6 +9,12 @@ from django.utils.module_loading import module_has_submodule class DefaultLoader(unittest.TestCase): + def setUp(self): + sys.meta_path.insert(0, ProxyFinder()) + + def tearDown(self): + sys.meta_path.pop(0) + def test_loader(self): "Normal module existence can be tested" test_module = import_module('regressiontests.utils.test_module') @@ -25,6 +32,10 @@ class DefaultLoader(unittest.TestCase): self.assertFalse(module_has_submodule(test_module, 'no_such_module')) self.assertRaises(ImportError, import_module, 'regressiontests.utils.test_module.no_such_module') + # A child that doesn't exist, but is the name of a package on the path + self.assertFalse(module_has_submodule(test_module, 'django')) + self.assertRaises(ImportError, import_module, 'regressiontests.utils.test_module.django') + # Don't be confused by caching of import misses import types # causes attempted import of regressiontests.utils.types self.assertFalse(module_has_submodule(sys.modules['regressiontests.utils'], 'types')) @@ -84,6 +95,25 @@ class EggLoader(unittest.TestCase): self.assertFalse(module_has_submodule(egg_module, 'no_such_module')) self.assertRaises(ImportError, import_module, 'egg_module.sub1.sub2.no_such_module') +class ProxyFinder(object): + def __init__(self): + self._cache = {} + + def find_module(self, fullname, path=None): + tail = fullname.rsplit('.', 1)[-1] + try: + self._cache[fullname] = imp.find_module(tail, path) + except ImportError: + return None + else: + return self # this is a loader as well + + def load_module(self, fullname): + if fullname in sys.modules: + return sys.modules[fullname] + fd, fn, info = self._cache[fullname] + return imp.load_module(fullname, fd, fn, info) + class TestFinder(object): def __init__(self, *args, **kwargs): self.importer = zipimporter(*args, **kwargs)