blob: 8e4986835d3be7d40057daf989b85e43817c1fac [file] [log] [blame]
Brett Cannonf254a752009-01-30 00:22:35 +00001from .. import abc
Brett Cannon4ee2cda2009-02-01 03:08:31 +00002from . import util as source_util
Brett Cannonfd074152012-04-14 14:10:13 -04003
Brett Cannoncb66eb02012-05-11 12:58:42 -04004from importlib import machinery
Barry Warsaw28a691b2010-04-17 00:19:56 +00005import errno
Brett Cannon938d44d2012-04-22 19:58:33 -04006import imp
Brett Cannonfd074152012-04-14 14:10:13 -04007import os
Brett Cannon23cbd8a2009-01-18 00:24:28 +00008import py_compile
Brett Cannona9976b32013-01-11 15:40:12 -05009import stat
10import sys
11import tempfile
Brett Cannonfd074152012-04-14 14:10:13 -040012from test.support import make_legacy_pyc
Brett Cannon23cbd8a2009-01-18 00:24:28 +000013import unittest
14import warnings
15
16
Brett Cannonf254a752009-01-30 00:22:35 +000017class FinderTests(abc.FinderTests):
Brett Cannon23cbd8a2009-01-18 00:24:28 +000018
19 """For a top-level module, it should just be found directly in the
20 directory being searched. This is true for a directory with source
21 [top-level source], bytecode [top-level bc], or both [top-level both].
22 There is also the possibility that it is a package [top-level package], in
23 which case there will be a directory with the module name and an
24 __init__.py file. If there is a directory without an __init__.py an
25 ImportWarning is returned [empty dir].
26
27 For sub-modules and sub-packages, the same happens as above but only use
28 the tail end of the name [sub module] [sub package] [sub empty].
29
30 When there is a conflict between a package and module having the same name
31 in the same directory, the package wins out [package over module]. This is
32 so that imports of modules within the package can occur rather than trigger
33 an import error.
34
35 When there is a package and module with the same name, always pick the
36 package over the module [package over module]. This is so that imports from
37 the package have the possibility of succeeding.
38
39 """
40
Nick Coghlan48fec052012-08-20 13:18:15 +100041 def get_finder(self, root):
Brett Cannoncb66eb02012-05-11 12:58:42 -040042 loader_details = [(machinery.SourceFileLoader,
Brett Cannonac9f2f32012-08-10 13:47:54 -040043 machinery.SOURCE_SUFFIXES),
Brett Cannoncb66eb02012-05-11 12:58:42 -040044 (machinery.SourcelessFileLoader,
Brett Cannonac9f2f32012-08-10 13:47:54 -040045 machinery.BYTECODE_SUFFIXES)]
Nick Coghlan48fec052012-08-20 13:18:15 +100046 return machinery.FileFinder(root, *loader_details)
47
48 def import_(self, root, module):
49 return self.get_finder(root).find_module(module)
Brett Cannon23cbd8a2009-01-18 00:24:28 +000050
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}
Brett Cannon4ee2cda2009-02-01 03:08:31 +000061 with source_util.create_modules(*create) as mapping:
Brett Cannon23cbd8a2009-01-18 00:24:28 +000062 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])
Barry Warsaw28a691b2010-04-17 00:19:56 +000068 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
Brett Cannon23cbd8a2009-01-18 00:24:28 +000076 loader = self.import_(mapping['.root'], test)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000077 self.assertTrue(hasattr(loader, 'load_module'))
Brett Cannon23cbd8a2009-01-18 00:24:28 +000078 return loader
79
80 def test_module(self):
81 # [top-level source]
82 self.run_test('top_level')
83 # [top-level bc]
Barry Warsaw28a691b2010-04-17 00:19:56 +000084 self.run_test('top_level', compile_={'top_level'},
85 unlink={'top_level'})
Brett Cannon23cbd8a2009-01-18 00:24:28 +000086 # [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):
Brett Cannon4ee2cda2009-02-01 03:08:31 +0000101 with source_util.create_modules('pkg.__init__', 'pkg.sub') as mapping:
Brett Cannon23cbd8a2009-01-18 00:24:28 +0000102 pkg_dir = os.path.dirname(mapping['pkg.__init__'])
103 loader = self.import_(pkg_dir, 'pkg.sub')
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000104 self.assertTrue(hasattr(loader, 'load_module'))
Brett Cannon23cbd8a2009-01-18 00:24:28 +0000105
106 # [sub package]
107 def test_package_in_package(self):
Brett Cannon4ee2cda2009-02-01 03:08:31 +0000108 context = source_util.create_modules('pkg.__init__', 'pkg.sub.__init__')
Brett Cannon23cbd8a2009-01-18 00:24:28 +0000109 with context as mapping:
110 pkg_dir = os.path.dirname(mapping['pkg.__init__'])
111 loader = self.import_(pkg_dir, 'pkg.sub')
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000112 self.assertTrue(hasattr(loader, 'load_module'))
Brett Cannon23cbd8a2009-01-18 00:24:28 +0000113
Brett Cannon23cbd8a2009-01-18 00:24:28 +0000114 # [package over modules]
115 def test_package_over_module(self):
Brett Cannon23cbd8a2009-01-18 00:24:28 +0000116 name = '_temp'
117 loader = self.run_test(name, {'{0}.__init__'.format(name), name})
Eric V. Smithe51a3692012-06-24 19:13:55 -0400118 self.assertIn('__init__', loader.get_filename(name))
Brett Cannon23cbd8a2009-01-18 00:24:28 +0000119
Brett Cannon23cbd8a2009-01-18 00:24:28 +0000120 def test_failure(self):
Brett Cannon4ee2cda2009-02-01 03:08:31 +0000121 with source_util.create_modules('blah') as mapping:
Brett Cannon23cbd8a2009-01-18 00:24:28 +0000122 nothing = self.import_(mapping['.root'], 'sdfsadsadf')
Eric V. Smithb1095152012-06-28 06:15:01 -0400123 self.assertIsNone(nothing)
Brett Cannon23cbd8a2009-01-18 00:24:28 +0000124
Brett Cannond71bed32010-07-03 22:18:47 +0000125 def test_empty_string_for_dir(self):
126 # The empty string from sys.path means to search in the cwd.
Brett Cannoncb66eb02012-05-11 12:58:42 -0400127 finder = machinery.FileFinder('', (machinery.SourceFileLoader,
Brett Cannonac9f2f32012-08-10 13:47:54 -0400128 machinery.SOURCE_SUFFIXES))
Brett Cannond71bed32010-07-03 22:18:47 +0000129 with open('mod.py', 'w') as file:
130 file.write("# test file for importlib")
131 try:
132 loader = finder.find_module('mod')
133 self.assertTrue(hasattr(loader, 'load_module'))
134 finally:
135 os.unlink('mod.py')
136
Brett Cannonb46a1792012-02-27 18:15:42 -0500137 def test_invalidate_caches(self):
138 # invalidate_caches() should reset the mtime.
Brett Cannoncb66eb02012-05-11 12:58:42 -0400139 finder = machinery.FileFinder('', (machinery.SourceFileLoader,
Brett Cannonac9f2f32012-08-10 13:47:54 -0400140 machinery.SOURCE_SUFFIXES))
Brett Cannonb46a1792012-02-27 18:15:42 -0500141 finder._path_mtime = 42
142 finder.invalidate_caches()
143 self.assertEqual(finder._path_mtime, -1)
144
Nick Coghlan48fec052012-08-20 13:18:15 +1000145 # Regression test for http://bugs.python.org/issue14846
146 def test_dir_removal_handling(self):
147 mod = 'mod'
148 with source_util.create_modules(mod) as mapping:
149 finder = self.get_finder(mapping['.root'])
150 self.assertIsNotNone(finder.find_module(mod))
151 self.assertIsNone(finder.find_module(mod))
Brett Cannon23cbd8a2009-01-18 00:24:28 +0000152
Brett Cannona9976b32013-01-11 15:40:12 -0500153 @unittest.skipUnless(sys.platform != 'win32',
154 'os.chmod() does not support the needed arguments under Windows')
155 def test_no_read_directory(self):
156 # Issue #16730
157 tempdir = tempfile.TemporaryDirectory()
158 original_mode = os.stat(tempdir.name).st_mode
159 def cleanup(tempdir):
160 """Cleanup function for the temporary directory.
161
162 Since we muck with the permissions, we want to set them back to
163 their original values to make sure the directory can be properly
164 cleaned up.
165
166 """
167 os.chmod(tempdir.name, original_mode)
168 # If this is not explicitly called then the __del__ method is used,
169 # but since already mucking around might as well explicitly clean
170 # up.
171 tempdir.__exit__(None, None, None)
172 self.addCleanup(cleanup, tempdir)
173 os.chmod(tempdir.name, stat.S_IWUSR | stat.S_IXUSR)
174 finder = self.get_finder(tempdir.name)
175 self.assertEqual((None, []), finder.find_loader('doesnotexist'))
176
177 def test_ignore_file(self):
178 # If a directory got changed to a file from underneath us, then don't
179 # worry about looking for submodules.
180 with tempfile.NamedTemporaryFile() as file_obj:
181 finder = self.get_finder(file_obj.name)
182 self.assertEqual((None, []), finder.find_loader('doesnotexist'))
183
184
Brett Cannon23cbd8a2009-01-18 00:24:28 +0000185def test_main():
186 from test.support import run_unittest
187 run_unittest(FinderTests)
188
189
190if __name__ == '__main__':
191 test_main()