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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
from ..support import (mock_modules, import_state, import_, mock_path_hook,
importlib_only, uncache)
from contextlib import nested
from imp import new_module
import sys
from types import MethodType
import unittest
class BaseTests(unittest.TestCase):
"""When sys.meta_path cannot find the desired module, sys.path is
consulted. For each entry on the sequence [order], sys.path_importer_cache
is checked to see if it contains a key for the entry [cache check]. If an
importer is found then it is consulted before trying the next entry in
sys.path [cache use]. The 'path' argument to find_module() is never used
when trying to find a module [path not used].
If an entry from sys.path is not in sys.path_importer_cache, sys.path_hooks
is called in turn [hooks order]. If a path hook cannot handle an entry,
ImportError is raised [hook failure]. Otherwise the resulting object is
cached in sys.path_importer_cache and then consulted [hook success]. If no
hook is found, None is set in sys.path_importer_cache and the default
importer is tried [no hook].
For use of __path__ in a package, the above is all true, just substitute
"sys.path" for "__path__".
"""
def order_test(self, to_import, entry, search_path, path=[]):
# [order]
log = []
class LogFindModule(mock_modules):
def find_module(self, fullname):
log.append(self)
return super().find_module(fullname)
assert len(search_path) == 2
misser = LogFindModule(search_path[0])
hitter = LogFindModule(to_import)
with nested(misser, hitter):
cache = dict(zip(search_path, (misser, hitter)))
with import_state(path=path, path_importer_cache=cache):
import_(to_import)
self.assertEquals(log[0], misser)
self.assertEquals(log[1], hitter)
@importlib_only # __import__ uses PyDict_GetItem(), bypassing log.
def cache_use_test(self, to_import, entry, path=[]):
# [cache check], [cache use]
log = []
class LoggingDict(dict):
def __getitem__(self, item):
log.append(item)
return super(LoggingDict, self).__getitem__(item)
with mock_modules(to_import) as importer:
cache = LoggingDict()
cache[entry] = importer
with import_state(path=[entry], path_importer_cache=cache):
module = import_(to_import, fromlist=['a'])
self.assert_(module is importer[to_import])
self.assertEquals(len(cache), 1)
self.assertEquals([entry], log)
def hooks_order_test(self, to_import, entry, path=[]):
# [hooks order], [hooks failure], [hook success]
log = []
def logging_hook(entry):
log.append(entry)
raise ImportError
with mock_modules(to_import) as importer:
hitter = mock_path_hook(entry, importer=importer)
path_hooks = [logging_hook, logging_hook, hitter]
with import_state(path_hooks=path_hooks, path=path):
import_(to_import)
self.assertEquals(sys.path_importer_cache[entry], importer)
self.assertEquals(len(log), 2)
# [no hook] XXX Worry about after deciding how to handle the default hook.
def path_argument_test(self, to_import):
# [path not used]
class BadImporter:
"""Class to help detect TypeError from calling find_module() with
an improper number of arguments."""
def find_module(name):
raise ImportError
try:
import_(to_import)
except ImportError:
pass
class PathTests(BaseTests):
"""Tests for sys.path."""
def test_order(self):
self.order_test('hit', 'second', ['first', 'second'],
['first', 'second'])
def test_cache_use(self):
entry = "found!"
self.cache_use_test('hit', entry, [entry])
def test_hooks_order(self):
entry = "found!"
self.hooks_order_test('hit', entry, [entry])
def test_path_argument(self):
name = 'total junk'
with uncache(name):
self.path_argument_test(name)
class __path__Tests(BaseTests):
"""Tests for __path__."""
def run_test(self, test, entry, path, *args):
with mock_modules('pkg.__init__') as importer:
importer['pkg'].__path__ = path
importer.load_module('pkg')
test('pkg.hit', entry, *args)
@importlib_only # XXX Unknown reason why this fails.
def test_order(self):
self.run_test(self.order_test, 'second', ('first', 'second'), ['first',
'second'])
def test_cache_use(self):
location = "I'm here!"
self.run_test(self.cache_use_test, location, [location])
def test_hooks_order(self):
location = "I'm here!"
self.run_test(self.hooks_order_test, location, [location])
def test_path_argument(self):
module = new_module('pkg')
module.__path__ = ['random __path__']
name = 'pkg.whatever'
sys.modules['pkg'] = module
with uncache('pkg', name):
self.path_argument_test(name)
def test_main():
from test.support import run_unittest
run_unittest(PathTests, __path__Tests)
if __name__ == '__main__':
test_main()
|