an importable child a child that exists but will generate an import error if loaded a child that doesn t exist a child that doesn t exist but is the name of a package on the path don t be confused by caching of import misses a module which doesn t have a path so no submodules nested module existence can be tested testmodule importmoduleutilstests testmodule a grandchild that exists self assertis modulehassubmoduletestmodule childmodule grandchildmodule true a grandchild that doesn t exist self assertis modulehassubmoduletestmodule childmodule nosuchmodule false a grandchild whose parent doesn t exist self assertis modulehassubmoduletestmodule nosuchmodule grandchildmodule false a grandchild whose parent is not a package self assertis modulehassubmoduletestmodule goodmodule nosuchmodule false class eggloaderunittest testcase def setupself self eggdir seggs os path dirnamefile def teardownself sys pathimportercache clear sys modules popeggmodule sub1 sub2 badmodule none sys modules popeggmodule sub1 sub2 goodmodule none sys modules popeggmodule sub1 sub2 none sys modules popeggmodule sub1 none sys modules popeggmodule badmodule none sys modules popeggmodule goodmodule none sys modules popeggmodule none def testshallowloaderself module existence can be tested inside eggs eggname stestegg egg self eggdir with extendsyspatheggname eggmodule importmoduleeggmodule an importable child self asserttruemodulehassubmoduleeggmodule goodmodule mod importmoduleeggmodule goodmodule self assertequalmod content good module a child that exists but will generate an import error if loaded self asserttruemodulehassubmoduleeggmodule badmodule with self assertraisesimporterror importmoduleeggmodule badmodule a child that doesn t exist self assertfalsemodulehassubmoduleeggmodule nosuchmodule with self assertraisesimporterror importmoduleeggmodule nosuchmodule def testdeeploaderself modules deep inside an egg can still be tested for existence eggname stestegg egg self eggdir with extendsyspatheggname eggmodule importmoduleeggmodule sub1 sub2 an importable child self asserttruemodulehassubmoduleeggmodule goodmodule mod importmoduleeggmodule sub1 sub2 goodmodule self assertequalmod content deep good module a child that exists but will generate an import error if loaded self asserttruemodulehassubmoduleeggmodule badmodule with self assertraisesimporterror importmoduleeggmodule sub1 sub2 badmodule a child that doesn t exist self assertfalsemodulehassubmoduleeggmodule nosuchmodule with self assertraisesimporterror importmoduleeggmodule sub1 sub2 nosuchmodule class moduleimporttestssimpletestcase def testimportstringself cls importstringdjango utils moduleloading importstring self assertequalcls importstring test exceptions raised with self assertraisesimporterror importstringnodotsinpath msg module utilstests does not define a unexistent attribute with self assertraisesmessageimporterror msg importstringutilstests unexistent modifysettingsinstalledappsappend utilstests testmodule class autodiscovermodulestestcasesimpletestcase def teardownself sys pathimportercache clear sys modules poputilstests testmodule anotherbadmodule none sys modules poputilstests testmodule anothergoodmodule none sys modules poputilstests testmodule badmodule none sys modules poputilstests testmodule goodmodule none sys modules poputilstests testmodule none def testautodiscovermodulesfoundself autodiscovermodulesgoodmodule def testautodiscovermodulesnotfoundself autodiscovermodulesmissingmodule def testautodiscovermodulesfoundbutbadmoduleself with self assertraisesmessage importerror no module named apackagenamethatdoesnotexist autodiscovermodulesbadmodule def testautodiscovermodulesseveralonebadmoduleself with self assertraisesmessage importerror no module named apackagenamethatdoesnotexist autodiscovermodulesgoodmodule badmodule def testautodiscovermodulesseveralfoundself autodiscovermodulesgoodmodule anothergoodmodule def testautodiscovermodulesseveralfoundwithregistryself from testmodule import site autodiscovermodulesgoodmodule anothergoodmodule registertosite self assertequalsite registry lorem ipsum def testvalidateregistrykeepsintactself from testmodule import site with self assertraisesmessageexception some random exception autodiscovermodulesanotherbadmodule registertosite self assertequalsite registry def testvalidateregistryresetsaftererroneousmoduleself from testmodule import site with self assertraisesmessageexception some random exception autodiscovermodules anothergoodmodule anotherbadmodule registertosite self assertequalsite registry lorem ipsum def testvalidateregistryresetsaftermissingmoduleself from testmodule import site autodiscovermodules doesnotexist anothergoodmodule doesnotexist2 registertosite self assertequalsite registry lorem ipsum class testfinder def initself args kwargs self importer zipimporterargs kwargs def findspecself path targetnone return self importer findspecpath target class customloadereggloader def setupself super setup sys pathhooks insert0 testfinder sys pathimportercache clear def teardownself super teardown sys pathhooks pop0 an importable child a child that exists but will generate an import error if loaded a child that doesn t exist a child that doesn t exist but is the name of a package on the path don t be confused by caching of import misses noqa causes attempted import of utils_tests types a module which doesn t have a __path__ so no submodules nested module existence can be tested a grandchild that exists a grandchild that doesn t exist a grandchild whose parent doesn t exist a grandchild whose parent is not a package an importable child a child that exists but will generate an import error if loaded a child that doesn t exist an importable child a child that exists but will generate an import error if loaded a child that doesn t exist test exceptions raised the custom loader test is exactly the same as the eggloader but it uses a custom defined loader class although the eggloader combines both functions into one class this isn t required
import os
import sys
import unittest
from importlib import import_module
from zipimport import zipimporter

from django.test import SimpleTestCase, modify_settings
from django.test.utils import extend_sys_path
from django.utils.module_loading import (
    autodiscover_modules,
    import_string,
    module_has_submodule,
)


class DefaultLoader(unittest.TestCase):
    def test_loader(self):
        "Normal module existence can be tested"
        test_module = import_module("utils_tests.test_module")
        test_no_submodule = import_module("utils_tests.test_no_submodule")

        
        self.assertTrue(module_has_submodule(test_module, "good_module"))
        mod = import_module("utils_tests.test_module.good_module")
        self.assertEqual(mod.content, "Good Module")

        
        self.assertTrue(module_has_submodule(test_module, "bad_module"))
        with self.assertRaises(ImportError):
            import_module("utils_tests.test_module.bad_module")

        
        self.assertFalse(module_has_submodule(test_module, "no_such_module"))
        with self.assertRaises(ImportError):
            import_module("utils_tests.test_module.no_such_module")

        
        self.assertFalse(module_has_submodule(test_module, "django"))
        with self.assertRaises(ImportError):
            import_module("utils_tests.test_module.django")

        
        import types  

        self.assertFalse(module_has_submodule(sys.modules["utils_tests"], "types"))

        
        self.assertFalse(module_has_submodule(test_no_submodule, "anything"))
        with self.assertRaises(ImportError):
            import_module("utils_tests.test_no_submodule.anything")

    def test_has_sumbodule_with_dotted_path(self):
        
        test_module = import_module("utils_tests.test_module")
        
        self.assertIs(
            module_has_submodule(test_module, "child_module.grandchild_module"), True
        )
        
        self.assertIs(
            module_has_submodule(test_module, "child_module.no_such_module"), False
        )
        
        self.assertIs(
            module_has_submodule(test_module, "no_such_module.grandchild_module"), False
        )
        
        self.assertIs(
            module_has_submodule(test_module, "good_module.no_such_module"), False
        )


class EggLoader(unittest.TestCase):
    def setUp(self):
        self.egg_dir = "%s/eggs" % os.path.dirname(__file__)

    def tearDown(self):
        sys.path_importer_cache.clear()

        sys.modules.pop("egg_module.sub1.sub2.bad_module", None)
        sys.modules.pop("egg_module.sub1.sub2.good_module", None)
        sys.modules.pop("egg_module.sub1.sub2", None)
        sys.modules.pop("egg_module.sub1", None)
        sys.modules.pop("egg_module.bad_module", None)
        sys.modules.pop("egg_module.good_module", None)
        sys.modules.pop("egg_module", None)

    def test_shallow_loader(self):
        "Module existence can be tested inside eggs"
        egg_name = "%s/test_egg.egg" % self.egg_dir
        with extend_sys_path(egg_name):
            egg_module = import_module("egg_module")

            
            self.assertTrue(module_has_submodule(egg_module, "good_module"))
            mod = import_module("egg_module.good_module")
            self.assertEqual(mod.content, "Good Module")

            
            self.assertTrue(module_has_submodule(egg_module, "bad_module"))
            with self.assertRaises(ImportError):
                import_module("egg_module.bad_module")

            
            self.assertFalse(module_has_submodule(egg_module, "no_such_module"))
            with self.assertRaises(ImportError):
                import_module("egg_module.no_such_module")

    def test_deep_loader(self):
        "Modules deep inside an egg can still be tested for existence"
        egg_name = "%s/test_egg.egg" % self.egg_dir
        with extend_sys_path(egg_name):
            egg_module = import_module("egg_module.sub1.sub2")

            
            self.assertTrue(module_has_submodule(egg_module, "good_module"))
            mod = import_module("egg_module.sub1.sub2.good_module")
            self.assertEqual(mod.content, "Deep Good Module")

            
            self.assertTrue(module_has_submodule(egg_module, "bad_module"))
            with self.assertRaises(ImportError):
                import_module("egg_module.sub1.sub2.bad_module")

            
            self.assertFalse(module_has_submodule(egg_module, "no_such_module"))
            with self.assertRaises(ImportError):
                import_module("egg_module.sub1.sub2.no_such_module")


class ModuleImportTests(SimpleTestCase):
    def test_import_string(self):
        cls = import_string("django.utils.module_loading.import_string")
        self.assertEqual(cls, import_string)

        
        with self.assertRaises(ImportError):
            import_string("no_dots_in_path")
        msg = 'Module "utils_tests" does not define a "unexistent" attribute'
        with self.assertRaisesMessage(ImportError, msg):
            import_string("utils_tests.unexistent")


@modify_settings(INSTALLED_APPS={"append": "utils_tests.test_module"})
class AutodiscoverModulesTestCase(SimpleTestCase):
    def tearDown(self):
        sys.path_importer_cache.clear()

        sys.modules.pop("utils_tests.test_module.another_bad_module", None)
        sys.modules.pop("utils_tests.test_module.another_good_module", None)
        sys.modules.pop("utils_tests.test_module.bad_module", None)
        sys.modules.pop("utils_tests.test_module.good_module", None)
        sys.modules.pop("utils_tests.test_module", None)

    def test_autodiscover_modules_found(self):
        autodiscover_modules("good_module")

    def test_autodiscover_modules_not_found(self):
        autodiscover_modules("missing_module")

    def test_autodiscover_modules_found_but_bad_module(self):
        with self.assertRaisesMessage(
            ImportError, "No module named 'a_package_name_that_does_not_exist'"
        ):
            autodiscover_modules("bad_module")

    def test_autodiscover_modules_several_one_bad_module(self):
        with self.assertRaisesMessage(
            ImportError, "No module named 'a_package_name_that_does_not_exist'"
        ):
            autodiscover_modules("good_module", "bad_module")

    def test_autodiscover_modules_several_found(self):
        autodiscover_modules("good_module", "another_good_module")

    def test_autodiscover_modules_several_found_with_registry(self):
        from .test_module import site

        autodiscover_modules("good_module", "another_good_module", register_to=site)
        self.assertEqual(site._registry, {"lorem": "ipsum"})

    def test_validate_registry_keeps_intact(self):
        from .test_module import site

        with self.assertRaisesMessage(Exception, "Some random exception."):
            autodiscover_modules("another_bad_module", register_to=site)
        self.assertEqual(site._registry, {})

    def test_validate_registry_resets_after_erroneous_module(self):
        from .test_module import site

        with self.assertRaisesMessage(Exception, "Some random exception."):
            autodiscover_modules(
                "another_good_module", "another_bad_module", register_to=site
            )
        self.assertEqual(site._registry, {"lorem": "ipsum"})

    def test_validate_registry_resets_after_missing_module(self):
        from .test_module import site

        autodiscover_modules(
            "does_not_exist", "another_good_module", "does_not_exist2", register_to=site
        )
        self.assertEqual(site._registry, {"lorem": "ipsum"})


class TestFinder:
    def __init__(self, *args, **kwargs):
        self.importer = zipimporter(*args, **kwargs)

    def find_spec(self, path, target=None):
        return self.importer.find_spec(path, target)


class CustomLoader(EggLoader):
    

    def setUp(self):
        super().setUp()
        sys.path_hooks.insert(0, TestFinder)
        sys.path_importer_cache.clear()

    def tearDown(self):
        super().tearDown()
        sys.path_hooks.pop(0)