summaryrefslogtreecommitdiff
path: root/Lib/importlib/test/import_/test_caching.py
blob: 48dc64311af0aff943881cf6927effdef4d99fa7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
"""Test that sys.modules is used properly by import."""
from .. import util
from . import util as import_util
import sys
from types import MethodType
import unittest


class UseCache(unittest.TestCase):

    """When it comes to sys.modules, import prefers it over anything else.

    Once a name has been resolved, sys.modules is checked to see if it contains
    the module desired. If so, then it is returned [use cache]. If it is not
    found, then the proper steps are taken to perform the import, but
    sys.modules is still used to return the imported module (e.g., not what a
    loader returns) [from cache on return]. This also applies to imports of
    things contained within a package and thus get assigned as an attribute
    [from cache to attribute] or pulled in thanks to a fromlist import
    [from cache for fromlist]. But if sys.modules contains None then
    ImportError is raised [None in cache].

    """
    def test_using_cache(self):
        # [use cache]
        module_to_use = "some module found!"
        with util.uncache(module_to_use):
            sys.modules['some_module'] = module_to_use
            module = import_util.import_('some_module')
            self.assertEqual(id(module_to_use), id(module))

    def test_None_in_cache(self):
        #[None in cache]
        name = 'using_None'
        with util.uncache(name):
            sys.modules[name] = None
            with self.assertRaises(ImportError):
                import_util.import_(name)

    def create_mock(self, *names, return_=None):
        mock = util.mock_modules(*names)
        original_load = mock.load_module
        def load_module(self, fullname):
            original_load(fullname)
            return return_
        mock.load_module = MethodType(load_module, mock)
        return mock

    # __import__ inconsistent between loaders and built-in import when it comes
    #   to when to use the module in sys.modules and when not to.
    @import_util.importlib_only
    def test_using_cache_after_loader(self):
        # [from cache on return]
        with self.create_mock('module') as mock:
            with util.import_state(meta_path=[mock]):
                module = import_util.import_('module')
                self.assertEqual(id(module), id(sys.modules['module']))

    # See test_using_cache_after_loader() for reasoning.
    @import_util.importlib_only
    def test_using_cache_for_assigning_to_attribute(self):
        # [from cache to attribute]
        with self.create_mock('pkg.__init__', 'pkg.module') as importer:
            with util.import_state(meta_path=[importer]):
                module = import_util.import_('pkg.module')
                self.assertTrue(hasattr(module, 'module'))
                self.assertTrue(id(module.module), id(sys.modules['pkg.module']))

    # See test_using_cache_after_loader() for reasoning.
    @import_util.importlib_only
    def test_using_cache_for_fromlist(self):
        # [from cache for fromlist]
        with self.create_mock('pkg.__init__', 'pkg.module') as importer:
            with util.import_state(meta_path=[importer]):
                module = import_util.import_('pkg', fromlist=['module'])
                self.assertTrue(hasattr(module, 'module'))
                self.assertEqual(id(module.module),
                                 id(sys.modules['pkg.module']))


def test_main():
    from test.support import run_unittest
    run_unittest(UseCache)

if __name__ == '__main__':
    test_main()