2
0

test_module_loading.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. import os
  2. import sys
  3. import unittest
  4. from importlib import import_module
  5. from zipimport import zipimporter
  6. from django.test import SimpleTestCase, modify_settings
  7. from django.test.utils import extend_sys_path
  8. from django.utils.module_loading import (
  9. autodiscover_modules,
  10. import_string,
  11. module_has_submodule,
  12. )
  13. class DefaultLoader(unittest.TestCase):
  14. def test_loader(self):
  15. "Normal module existence can be tested"
  16. test_module = import_module("utils_tests.test_module")
  17. test_no_submodule = import_module("utils_tests.test_no_submodule")
  18. # An importable child
  19. self.assertTrue(module_has_submodule(test_module, "good_module"))
  20. mod = import_module("utils_tests.test_module.good_module")
  21. self.assertEqual(mod.content, "Good Module")
  22. # A child that exists, but will generate an import error if loaded
  23. self.assertTrue(module_has_submodule(test_module, "bad_module"))
  24. with self.assertRaises(ImportError):
  25. import_module("utils_tests.test_module.bad_module")
  26. # A child that doesn't exist
  27. self.assertFalse(module_has_submodule(test_module, "no_such_module"))
  28. with self.assertRaises(ImportError):
  29. import_module("utils_tests.test_module.no_such_module")
  30. # A child that doesn't exist, but is the name of a package on the path
  31. self.assertFalse(module_has_submodule(test_module, "django"))
  32. with self.assertRaises(ImportError):
  33. import_module("utils_tests.test_module.django")
  34. # Don't be confused by caching of import misses
  35. import types # NOQA: causes attempted import of utils_tests.types
  36. self.assertFalse(module_has_submodule(sys.modules["utils_tests"], "types"))
  37. # A module which doesn't have a __path__ (so no submodules)
  38. self.assertFalse(module_has_submodule(test_no_submodule, "anything"))
  39. with self.assertRaises(ImportError):
  40. import_module("utils_tests.test_no_submodule.anything")
  41. def test_has_sumbodule_with_dotted_path(self):
  42. """Nested module existence can be tested."""
  43. test_module = import_module("utils_tests.test_module")
  44. # A grandchild that exists.
  45. self.assertIs(
  46. module_has_submodule(test_module, "child_module.grandchild_module"), True
  47. )
  48. # A grandchild that doesn't exist.
  49. self.assertIs(
  50. module_has_submodule(test_module, "child_module.no_such_module"), False
  51. )
  52. # A grandchild whose parent doesn't exist.
  53. self.assertIs(
  54. module_has_submodule(test_module, "no_such_module.grandchild_module"), False
  55. )
  56. # A grandchild whose parent is not a package.
  57. self.assertIs(
  58. module_has_submodule(test_module, "good_module.no_such_module"), False
  59. )
  60. class EggLoader(unittest.TestCase):
  61. def setUp(self):
  62. self.egg_dir = "%s/eggs" % os.path.dirname(__file__)
  63. def tearDown(self):
  64. sys.path_importer_cache.clear()
  65. sys.modules.pop("egg_module.sub1.sub2.bad_module", None)
  66. sys.modules.pop("egg_module.sub1.sub2.good_module", None)
  67. sys.modules.pop("egg_module.sub1.sub2", None)
  68. sys.modules.pop("egg_module.sub1", None)
  69. sys.modules.pop("egg_module.bad_module", None)
  70. sys.modules.pop("egg_module.good_module", None)
  71. sys.modules.pop("egg_module", None)
  72. def test_shallow_loader(self):
  73. "Module existence can be tested inside eggs"
  74. egg_name = "%s/test_egg.egg" % self.egg_dir
  75. with extend_sys_path(egg_name):
  76. egg_module = import_module("egg_module")
  77. # An importable child
  78. self.assertTrue(module_has_submodule(egg_module, "good_module"))
  79. mod = import_module("egg_module.good_module")
  80. self.assertEqual(mod.content, "Good Module")
  81. # A child that exists, but will generate an import error if loaded
  82. self.assertTrue(module_has_submodule(egg_module, "bad_module"))
  83. with self.assertRaises(ImportError):
  84. import_module("egg_module.bad_module")
  85. # A child that doesn't exist
  86. self.assertFalse(module_has_submodule(egg_module, "no_such_module"))
  87. with self.assertRaises(ImportError):
  88. import_module("egg_module.no_such_module")
  89. def test_deep_loader(self):
  90. "Modules deep inside an egg can still be tested for existence"
  91. egg_name = "%s/test_egg.egg" % self.egg_dir
  92. with extend_sys_path(egg_name):
  93. egg_module = import_module("egg_module.sub1.sub2")
  94. # An importable child
  95. self.assertTrue(module_has_submodule(egg_module, "good_module"))
  96. mod = import_module("egg_module.sub1.sub2.good_module")
  97. self.assertEqual(mod.content, "Deep Good Module")
  98. # A child that exists, but will generate an import error if loaded
  99. self.assertTrue(module_has_submodule(egg_module, "bad_module"))
  100. with self.assertRaises(ImportError):
  101. import_module("egg_module.sub1.sub2.bad_module")
  102. # A child that doesn't exist
  103. self.assertFalse(module_has_submodule(egg_module, "no_such_module"))
  104. with self.assertRaises(ImportError):
  105. import_module("egg_module.sub1.sub2.no_such_module")
  106. class ModuleImportTests(SimpleTestCase):
  107. def test_import_string(self):
  108. cls = import_string("django.utils.module_loading.import_string")
  109. self.assertEqual(cls, import_string)
  110. # Test exceptions raised
  111. with self.assertRaises(ImportError):
  112. import_string("no_dots_in_path")
  113. msg = 'Module "utils_tests" does not define a "unexistent" attribute'
  114. with self.assertRaisesMessage(ImportError, msg):
  115. import_string("utils_tests.unexistent")
  116. @modify_settings(INSTALLED_APPS={"append": "utils_tests.test_module"})
  117. class AutodiscoverModulesTestCase(SimpleTestCase):
  118. def tearDown(self):
  119. sys.path_importer_cache.clear()
  120. sys.modules.pop("utils_tests.test_module.another_bad_module", None)
  121. sys.modules.pop("utils_tests.test_module.another_good_module", None)
  122. sys.modules.pop("utils_tests.test_module.bad_module", None)
  123. sys.modules.pop("utils_tests.test_module.good_module", None)
  124. sys.modules.pop("utils_tests.test_module", None)
  125. def test_autodiscover_modules_found(self):
  126. autodiscover_modules("good_module")
  127. def test_autodiscover_modules_not_found(self):
  128. autodiscover_modules("missing_module")
  129. def test_autodiscover_modules_found_but_bad_module(self):
  130. with self.assertRaisesMessage(
  131. ImportError, "No module named 'a_package_name_that_does_not_exist'"
  132. ):
  133. autodiscover_modules("bad_module")
  134. def test_autodiscover_modules_several_one_bad_module(self):
  135. with self.assertRaisesMessage(
  136. ImportError, "No module named 'a_package_name_that_does_not_exist'"
  137. ):
  138. autodiscover_modules("good_module", "bad_module")
  139. def test_autodiscover_modules_several_found(self):
  140. autodiscover_modules("good_module", "another_good_module")
  141. def test_autodiscover_modules_several_found_with_registry(self):
  142. from .test_module import site
  143. autodiscover_modules("good_module", "another_good_module", register_to=site)
  144. self.assertEqual(site._registry, {"lorem": "ipsum"})
  145. def test_validate_registry_keeps_intact(self):
  146. from .test_module import site
  147. with self.assertRaisesMessage(Exception, "Some random exception."):
  148. autodiscover_modules("another_bad_module", register_to=site)
  149. self.assertEqual(site._registry, {})
  150. def test_validate_registry_resets_after_erroneous_module(self):
  151. from .test_module import site
  152. with self.assertRaisesMessage(Exception, "Some random exception."):
  153. autodiscover_modules(
  154. "another_good_module", "another_bad_module", register_to=site
  155. )
  156. self.assertEqual(site._registry, {"lorem": "ipsum"})
  157. def test_validate_registry_resets_after_missing_module(self):
  158. from .test_module import site
  159. autodiscover_modules(
  160. "does_not_exist", "another_good_module", "does_not_exist2", register_to=site
  161. )
  162. self.assertEqual(site._registry, {"lorem": "ipsum"})
  163. class TestFinder:
  164. def __init__(self, *args, **kwargs):
  165. self.importer = zipimporter(*args, **kwargs)
  166. def find_spec(self, path, target=None):
  167. return self.importer.find_spec(path, target)
  168. class CustomLoader(EggLoader):
  169. """The Custom Loader test is exactly the same as the EggLoader, but
  170. it uses a custom defined Loader class. Although the EggLoader combines both
  171. functions into one class, this isn't required.
  172. """
  173. def setUp(self):
  174. super().setUp()
  175. sys.path_hooks.insert(0, TestFinder)
  176. sys.path_importer_cache.clear()
  177. def tearDown(self):
  178. super().tearDown()
  179. sys.path_hooks.pop(0)