python (3.12.0)
1 from test.test_importlib import abc, util
2
3 machinery = util.import_importlib('importlib.machinery')
4
5 import errno
6 import os
7 import py_compile
8 import stat
9 import sys
10 import tempfile
11 from test.support.import_helper import make_legacy_pyc
12 import unittest
13 import warnings
14
15
16 class ESC[4;38;5;81mFinderTests(ESC[4;38;5;149mabcESC[4;38;5;149m.ESC[4;38;5;149mFinderTests):
17
18 """For a top-level module, it should just be found directly in the
19 directory being searched. This is true for a directory with source
20 [top-level source], bytecode [top-level bc], or both [top-level both].
21 There is also the possibility that it is a package [top-level package], in
22 which case there will be a directory with the module name and an
23 __init__.py file. If there is a directory without an __init__.py an
24 ImportWarning is returned [empty dir].
25
26 For sub-modules and sub-packages, the same happens as above but only use
27 the tail end of the name [sub module] [sub package] [sub empty].
28
29 When there is a conflict between a package and module having the same name
30 in the same directory, the package wins out [package over module]. This is
31 so that imports of modules within the package can occur rather than trigger
32 an import error.
33
34 When there is a package and module with the same name, always pick the
35 package over the module [package over module]. This is so that imports from
36 the package have the possibility of succeeding.
37
38 """
39
40 def get_finder(self, root):
41 loader_details = [(self.machinery.SourceFileLoader,
42 self.machinery.SOURCE_SUFFIXES),
43 (self.machinery.SourcelessFileLoader,
44 self.machinery.BYTECODE_SUFFIXES)]
45 return self.machinery.FileFinder(root, *loader_details)
46
47 def import_(self, root, module):
48 finder = self.get_finder(root)
49 return self._find(finder, module, loader_only=True)
50
51 def run_test(self, test, create=None, *, compile_=None, unlink=None):
52 """Test the finding of 'test' with the creation of modules listed in
53 'create'.
54
55 Any names listed in 'compile_' are byte-compiled. Modules
56 listed in 'unlink' have their source files deleted.
57
58 """
59 if create is None:
60 create = {test}
61 with util.create_modules(*create) as mapping:
62 if compile_:
63 for name in compile_:
64 py_compile.compile(mapping[name])
65 if unlink:
66 for name in unlink:
67 os.unlink(mapping[name])
68 try:
69 make_legacy_pyc(mapping[name])
70 except OSError as error:
71 # Some tests do not set compile_=True so the source
72 # module will not get compiled and there will be no
73 # PEP 3147 pyc file to rename.
74 if error.errno != errno.ENOENT:
75 raise
76 loader = self.import_(mapping['.root'], test)
77 self.assertTrue(hasattr(loader, 'load_module'))
78 return loader
79
80 def test_module(self):
81 # [top-level source]
82 self.run_test('top_level')
83 # [top-level bc]
84 self.run_test('top_level', compile_={'top_level'},
85 unlink={'top_level'})
86 # [top-level both]
87 self.run_test('top_level', compile_={'top_level'})
88
89 # [top-level package]
90 def test_package(self):
91 # Source.
92 self.run_test('pkg', {'pkg.__init__'})
93 # Bytecode.
94 self.run_test('pkg', {'pkg.__init__'}, compile_={'pkg.__init__'},
95 unlink={'pkg.__init__'})
96 # Both.
97 self.run_test('pkg', {'pkg.__init__'}, compile_={'pkg.__init__'})
98
99 # [sub module]
100 def test_module_in_package(self):
101 with util.create_modules('pkg.__init__', 'pkg.sub') as mapping:
102 pkg_dir = os.path.dirname(mapping['pkg.__init__'])
103 loader = self.import_(pkg_dir, 'pkg.sub')
104 self.assertTrue(hasattr(loader, 'load_module'))
105
106 # [sub package]
107 def test_package_in_package(self):
108 context = util.create_modules('pkg.__init__', 'pkg.sub.__init__')
109 with context as mapping:
110 pkg_dir = os.path.dirname(mapping['pkg.__init__'])
111 loader = self.import_(pkg_dir, 'pkg.sub')
112 self.assertTrue(hasattr(loader, 'load_module'))
113
114 # [package over modules]
115 def test_package_over_module(self):
116 name = '_temp'
117 loader = self.run_test(name, {'{0}.__init__'.format(name), name})
118 self.assertIn('__init__', loader.get_filename(name))
119
120 def test_failure(self):
121 with util.create_modules('blah') as mapping:
122 nothing = self.import_(mapping['.root'], 'sdfsadsadf')
123 self.assertEqual(nothing, self.NOT_FOUND)
124
125 def test_empty_string_for_dir(self):
126 # The empty string from sys.path means to search in the cwd.
127 finder = self.machinery.FileFinder('', (self.machinery.SourceFileLoader,
128 self.machinery.SOURCE_SUFFIXES))
129 with open('mod.py', 'w', encoding='utf-8') as file:
130 file.write("# test file for importlib")
131 try:
132 loader = self._find(finder, 'mod', loader_only=True)
133 self.assertTrue(hasattr(loader, 'load_module'))
134 finally:
135 os.unlink('mod.py')
136
137 def test_invalidate_caches(self):
138 # invalidate_caches() should reset the mtime.
139 finder = self.machinery.FileFinder('', (self.machinery.SourceFileLoader,
140 self.machinery.SOURCE_SUFFIXES))
141 finder._path_mtime = 42
142 finder.invalidate_caches()
143 self.assertEqual(finder._path_mtime, -1)
144
145 # Regression test for http://bugs.python.org/issue14846
146 def test_dir_removal_handling(self):
147 mod = 'mod'
148 with util.create_modules(mod) as mapping:
149 finder = self.get_finder(mapping['.root'])
150 found = self._find(finder, 'mod', loader_only=True)
151 self.assertIsNotNone(found)
152 found = self._find(finder, 'mod', loader_only=True)
153 self.assertEqual(found, self.NOT_FOUND)
154
155 @unittest.skipUnless(sys.platform != 'win32',
156 'os.chmod() does not support the needed arguments under Windows')
157 def test_no_read_directory(self):
158 # Issue #16730
159 tempdir = tempfile.TemporaryDirectory()
160 self.enterContext(tempdir)
161 # Since we muck with the permissions, we want to set them back to
162 # their original values to make sure the directory can be properly
163 # cleaned up.
164 original_mode = os.stat(tempdir.name).st_mode
165 self.addCleanup(os.chmod, tempdir.name, original_mode)
166 os.chmod(tempdir.name, stat.S_IWUSR | stat.S_IXUSR)
167 finder = self.get_finder(tempdir.name)
168 found = self._find(finder, 'doesnotexist')
169 self.assertEqual(found, self.NOT_FOUND)
170
171 def test_ignore_file(self):
172 # If a directory got changed to a file from underneath us, then don't
173 # worry about looking for submodules.
174 with tempfile.NamedTemporaryFile() as file_obj:
175 finder = self.get_finder(file_obj.name)
176 found = self._find(finder, 'doesnotexist')
177 self.assertEqual(found, self.NOT_FOUND)
178
179
180 class ESC[4;38;5;81mFinderTestsPEP451(ESC[4;38;5;149mFinderTests):
181
182 NOT_FOUND = None
183
184 def _find(self, finder, name, loader_only=False):
185 spec = finder.find_spec(name)
186 return spec.loader if spec is not None else spec
187
188
189 (Frozen_FinderTestsPEP451,
190 Source_FinderTestsPEP451
191 ) = util.test_both(FinderTestsPEP451, machinery=machinery)
192
193
194 class ESC[4;38;5;81mFinderTestsPEP420(ESC[4;38;5;149mFinderTests):
195
196 NOT_FOUND = (None, [])
197
198 def _find(self, finder, name, loader_only=False):
199 spec = finder.find_spec(name)
200 if spec is None:
201 return self.NOT_FOUND
202 if loader_only:
203 return spec.loader
204 return spec.loader, spec.submodule_search_locations
205
206
207 (Frozen_FinderTestsPEP420,
208 Source_FinderTestsPEP420
209 ) = util.test_both(FinderTestsPEP420, machinery=machinery)
210
211
212 if __name__ == '__main__':
213 unittest.main()