|
| 1 | +""" |
| 2 | +Credit: https://github.com/django/django/blob/4.0.4/tests/utils_tests/test_module_loading.py |
| 3 | +
|
| 4 | +From April 25th, 2021. Changes: |
| 5 | +
|
| 6 | +- pytest compatibility, use monkeypatch.syspath_prepend |
| 7 | +- Removed django-specific material |
| 8 | +""" # noqa: E501 |
| 9 | +import os |
| 10 | +import sys |
| 11 | +import unittest |
| 12 | +from importlib import import_module |
| 13 | + |
| 14 | +import pytest |
| 15 | + |
| 16 | +from libvcs.utils.module_loading import import_string, module_has_submodule |
| 17 | + |
| 18 | +PY310 = sys.version_info >= (3, 10) |
| 19 | + |
| 20 | + |
| 21 | +class DefaultLoader(unittest.TestCase): |
| 22 | + def test_loader(self): |
| 23 | + "Normal module existence can be tested" |
| 24 | + test_module = import_module("tests.utils.test_module") |
| 25 | + test_no_submodule = import_module("tests.utils.test_no_submodule") |
| 26 | + |
| 27 | + # An importable child |
| 28 | + self.assertTrue(module_has_submodule(test_module, "good_module")) |
| 29 | + mod = import_module("tests.utils.test_module.good_module") |
| 30 | + self.assertEqual(mod.content, "Good Module") |
| 31 | + |
| 32 | + # A child that exists, but will generate an import error if loaded |
| 33 | + self.assertTrue(module_has_submodule(test_module, "bad_module")) |
| 34 | + with self.assertRaises(ImportError): |
| 35 | + import_module("tests.utils.test_module.bad_module") |
| 36 | + |
| 37 | + # A child that doesn't exist |
| 38 | + self.assertFalse(module_has_submodule(test_module, "no_such_module")) |
| 39 | + with self.assertRaises(ImportError): |
| 40 | + import_module("tests.utils.test_module.no_such_module") |
| 41 | + |
| 42 | + # A child that doesn't exist, but is the name of a package on the path |
| 43 | + self.assertFalse(module_has_submodule(test_module, "django")) |
| 44 | + with self.assertRaises(ImportError): |
| 45 | + import_module("tests.utils.test_module.django") |
| 46 | + |
| 47 | + # Don't be confused by caching of import misses |
| 48 | + import types # NOQA: causes attempted import of tests.utils.types |
| 49 | + |
| 50 | + self.assertFalse(module_has_submodule(sys.modules["tests.utils"], "types")) |
| 51 | + |
| 52 | + # A module which doesn't have a __path__ (so no submodules) |
| 53 | + self.assertFalse(module_has_submodule(test_no_submodule, "anything")) |
| 54 | + with self.assertRaises(ImportError): |
| 55 | + import_module("tests.utils.test_no_submodule.anything") |
| 56 | + |
| 57 | + def test_has_sumbodule_with_dotted_path(self): |
| 58 | + """Nested module existence can be tested.""" |
| 59 | + test_module = import_module("tests.utils.test_module") |
| 60 | + # A grandchild that exists. |
| 61 | + self.assertIs( |
| 62 | + module_has_submodule(test_module, "child_module.grandchild_module"), True |
| 63 | + ) |
| 64 | + # A grandchild that doesn't exist. |
| 65 | + self.assertIs( |
| 66 | + module_has_submodule(test_module, "child_module.no_such_module"), False |
| 67 | + ) |
| 68 | + # A grandchild whose parent doesn't exist. |
| 69 | + self.assertIs( |
| 70 | + module_has_submodule(test_module, "no_such_module.grandchild_module"), False |
| 71 | + ) |
| 72 | + # A grandchild whose parent is not a package. |
| 73 | + self.assertIs( |
| 74 | + module_has_submodule(test_module, "good_module.no_such_module"), False |
| 75 | + ) |
| 76 | + |
| 77 | + |
| 78 | +class EggLoader: |
| 79 | + def setUp(self): |
| 80 | + self.egg_dir = "%s/eggs" % os.path.dirname(__file__) |
| 81 | + |
| 82 | + def tearDown(self): |
| 83 | + sys.path_importer_cache.clear() |
| 84 | + |
| 85 | + sys.modules.pop("egg_module.sub1.sub2.bad_module", None) |
| 86 | + sys.modules.pop("egg_module.sub1.sub2.good_module", None) |
| 87 | + sys.modules.pop("egg_module.sub1.sub2", None) |
| 88 | + sys.modules.pop("egg_module.sub1", None) |
| 89 | + sys.modules.pop("egg_module.bad_module", None) |
| 90 | + sys.modules.pop("egg_module.good_module", None) |
| 91 | + sys.modules.pop("egg_module", None) |
| 92 | + |
| 93 | + def test_shallow_loader(self, monkeypatch: pytest.MonkeyPatch): |
| 94 | + "Module existence can be tested inside eggs" |
| 95 | + egg_name = "%s/test_egg.egg" % self.egg_dir |
| 96 | + monkeypatch.syspath_prepend(egg_name) |
| 97 | + egg_module = import_module("egg_module") |
| 98 | + |
| 99 | + # An importable child |
| 100 | + self.assertTrue(module_has_submodule(egg_module, "good_module")) |
| 101 | + mod = import_module("egg_module.good_module") |
| 102 | + self.assertEqual(mod.content, "Good Module") |
| 103 | + |
| 104 | + # A child that exists, but will generate an import error if loaded |
| 105 | + self.assertTrue(module_has_submodule(egg_module, "bad_module")) |
| 106 | + with self.assertRaises(ImportError): |
| 107 | + import_module("egg_module.bad_module") |
| 108 | + |
| 109 | + # A child that doesn't exist |
| 110 | + self.assertFalse(module_has_submodule(egg_module, "no_such_module")) |
| 111 | + with self.assertRaises(ImportError): |
| 112 | + import_module("egg_module.no_such_module") |
| 113 | + |
| 114 | + def test_deep_loader(self, monkeypatch: pytest.MonkeyPatch): |
| 115 | + "Modules deep inside an egg can still be tested for existence" |
| 116 | + egg_name = "%s/test_egg.egg" % self.egg_dir |
| 117 | + monkeypatch.syspath_prepend(egg_name) |
| 118 | + egg_module = import_module("egg_module.sub1.sub2") |
| 119 | + |
| 120 | + # An importable child |
| 121 | + self.assertTrue(module_has_submodule(egg_module, "good_module")) |
| 122 | + mod = import_module("egg_module.sub1.sub2.good_module") |
| 123 | + self.assertEqual(mod.content, "Deep Good Module") |
| 124 | + |
| 125 | + # A child that exists, but will generate an import error if loaded |
| 126 | + self.assertTrue(module_has_submodule(egg_module, "bad_module")) |
| 127 | + with self.assertRaises(ImportError): |
| 128 | + import_module("egg_module.sub1.sub2.bad_module") |
| 129 | + |
| 130 | + # A child that doesn't exist |
| 131 | + self.assertFalse(module_has_submodule(egg_module, "no_such_module")) |
| 132 | + with self.assertRaises(ImportError): |
| 133 | + import_module("egg_module.sub1.sub2.no_such_module") |
| 134 | + |
| 135 | + |
| 136 | +class ModuleImportTests: |
| 137 | + def test_import_string(self): |
| 138 | + cls = import_string("libvcs.utils.module_loading.import_string") |
| 139 | + self.assertEqual(cls, import_string) |
| 140 | + |
| 141 | + # Test exceptions raised |
| 142 | + with self.assertRaises(ImportError): |
| 143 | + import_string("no_dots_in_path&quo
5F77
t;) |
| 144 | + msg = 'Module "tests.utils" does not define a "unexistent" attribute' |
| 145 | + with self.assertRaisesMessage(ImportError, msg): |
| 146 | + import_string("tests.utils.unexistent") |
0 commit comments