blob: 4c49e9aeafcd91ee3661fdb1e28e4bcb338485f3 [file] [log] [blame]
Christian Heimes05e8be12008-02-23 18:30:17 +00001import os
Éric Araujo1e3a68d2011-07-28 23:35:29 +02002import errno
Brett Cannon298bb962014-02-28 10:44:45 -05003import importlib.machinery
4import py_compile
Éric Araujo1e3a68d2011-07-28 23:35:29 +02005import shutil
Guido van Rossumfc2a0a82006-10-27 23:06:01 +00006import unittest
Guido van Rossumfc2a0a82006-10-27 23:06:01 +00007import tempfile
8
Benjamin Petersonee8712c2008-05-20 21:35:26 +00009from test import support
Guido van Rossumfc2a0a82006-10-27 23:06:01 +000010
Guido van Rossumfc2a0a82006-10-27 23:06:01 +000011import modulefinder
12
Guido van Rossumfc2a0a82006-10-27 23:06:01 +000013TEST_DIR = tempfile.mkdtemp()
Éric Araujo1e3a68d2011-07-28 23:35:29 +020014TEST_PATH = [TEST_DIR, os.path.dirname(tempfile.__file__)]
Guido van Rossumfc2a0a82006-10-27 23:06:01 +000015
16# Each test description is a list of 5 items:
17#
18# 1. a module name that will be imported by modulefinder
19# 2. a list of module names that modulefinder is required to find
20# 3. a list of module names that modulefinder should complain
21# about because they are not found
22# 4. a list of module names that modulefinder should complain
23# about because they MAY be not found
24# 5. a string specifying packages to create; the format is obvious imo.
25#
26# Each package will be created in TEST_DIR, and TEST_DIR will be
27# removed after the tests again.
28# Modulefinder searches in a path that contains TEST_DIR, plus
29# the standard Lib directory.
30
31maybe_test = [
32 "a.module",
33 ["a", "a.module", "sys",
34 "b"],
35 ["c"], ["b.something"],
36 """\
37a/__init__.py
38a/module.py
39 from b import something
40 from c import something
41b/__init__.py
42 from sys import *
43"""]
44
45maybe_test_new = [
46 "a.module",
47 ["a", "a.module", "sys",
Thomas Wouters89f507f2006-12-13 04:49:30 +000048 "b", "__future__"],
Guido van Rossumfc2a0a82006-10-27 23:06:01 +000049 ["c"], ["b.something"],
50 """\
51a/__init__.py
52a/module.py
53 from b import something
54 from c import something
55b/__init__.py
Thomas Wouters89f507f2006-12-13 04:49:30 +000056 from __future__ import absolute_import
Guido van Rossumfc2a0a82006-10-27 23:06:01 +000057 from sys import *
58"""]
59
60package_test = [
61 "a.module",
62 ["a", "a.b", "a.c", "a.module", "mymodule", "sys"],
63 ["blahblah", "c"], [],
64 """\
65mymodule.py
66a/__init__.py
67 import blahblah
68 from a import b
69 import c
70a/module.py
71 import sys
72 from a import b as x
73 from a.c import sillyname
74a/b.py
75a/c.py
76 from a.module import x
77 import mymodule as sillyname
78 from sys import version_info
79"""]
80
81absolute_import_test = [
82 "a.module",
83 ["a", "a.module",
84 "b", "b.x", "b.y", "b.z",
Neal Norwitz2633c692007-02-26 22:22:47 +000085 "__future__", "sys", "gc"],
Guido van Rossumfc2a0a82006-10-27 23:06:01 +000086 ["blahblah", "z"], [],
87 """\
88mymodule.py
89a/__init__.py
90a/module.py
Thomas Wouters89f507f2006-12-13 04:49:30 +000091 from __future__ import absolute_import
Guido van Rossumfc2a0a82006-10-27 23:06:01 +000092 import sys # sys
93 import blahblah # fails
Neal Norwitz2633c692007-02-26 22:22:47 +000094 import gc # gc
Guido van Rossumfc2a0a82006-10-27 23:06:01 +000095 import b.x # b.x
96 from b import y # b.y
97 from b.z import * # b.z.*
Neal Norwitz2633c692007-02-26 22:22:47 +000098a/gc.py
Guido van Rossumfc2a0a82006-10-27 23:06:01 +000099a/sys.py
100 import mymodule
101a/b/__init__.py
102a/b/x.py
103a/b/y.py
104a/b/z.py
105b/__init__.py
106 import z
107b/unused.py
108b/x.py
109b/y.py
110b/z.py
111"""]
112
113relative_import_test = [
114 "a.module",
Thomas Wouters89f507f2006-12-13 04:49:30 +0000115 ["__future__",
116 "a", "a.module",
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000117 "a.b", "a.b.y", "a.b.z",
118 "a.b.c", "a.b.c.moduleC",
119 "a.b.c.d", "a.b.c.e",
120 "a.b.x",
Neal Norwitz2633c692007-02-26 22:22:47 +0000121 "gc"],
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000122 [], [],
123 """\
124mymodule.py
125a/__init__.py
126 from .b import y, z # a.b.y, a.b.z
127a/module.py
Thomas Wouters89f507f2006-12-13 04:49:30 +0000128 from __future__ import absolute_import # __future__
Neal Norwitz2633c692007-02-26 22:22:47 +0000129 import gc # gc
130a/gc.py
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000131a/sys.py
132a/b/__init__.py
133 from ..b import x # a.b.x
134 #from a.b.c import moduleC
135 from .c import moduleC # a.b.moduleC
136a/b/x.py
137a/b/y.py
138a/b/z.py
139a/b/g.py
140a/b/c/__init__.py
141 from ..c import e # a.b.c.e
142a/b/c/moduleC.py
143 from ..c import d # a.b.c.d
144a/b/c/d.py
145a/b/c/e.py
146a/b/c/x.py
147"""]
148
149relative_import_test_2 = [
150 "a.module",
151 ["a", "a.module",
152 "a.sys",
153 "a.b", "a.b.y", "a.b.z",
154 "a.b.c", "a.b.c.d",
155 "a.b.c.e",
156 "a.b.c.moduleC",
157 "a.b.c.f",
158 "a.b.x",
159 "a.another"],
160 [], [],
161 """\
162mymodule.py
163a/__init__.py
164 from . import sys # a.sys
165a/another.py
166a/module.py
167 from .b import y, z # a.b.y, a.b.z
Neal Norwitz2633c692007-02-26 22:22:47 +0000168a/gc.py
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000169a/sys.py
170a/b/__init__.py
171 from .c import moduleC # a.b.c.moduleC
172 from .c import d # a.b.c.d
173a/b/x.py
174a/b/y.py
175a/b/z.py
176a/b/c/__init__.py
177 from . import e # a.b.c.e
178a/b/c/moduleC.py
179 #
180 from . import f # a.b.c.f
181 from .. import x # a.b.x
182 from ... import another # a.another
183a/b/c/d.py
184a/b/c/e.py
185a/b/c/f.py
186"""]
187
Benjamin Petersonc0747cf2008-11-03 20:31:38 +0000188relative_import_test_3 = [
189 "a.module",
190 ["a", "a.module"],
191 ["a.bar"],
192 [],
193 """\
194a/__init__.py
195 def foo(): pass
196a/module.py
197 from . import foo
198 from . import bar
199"""]
200
Brett Cannon73b969e2012-12-22 19:34:21 -0500201relative_import_test_4 = [
202 "a.module",
203 ["a", "a.module"],
204 [],
205 [],
206 """\
207a/__init__.py
208 def foo(): pass
209a/module.py
210 from . import *
211"""]
212
Brett Cannon298bb962014-02-28 10:44:45 -0500213bytecode_test = [
214 "a",
215 ["a"],
216 [],
217 [],
218 ""
219]
220
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200221
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000222def open_file(path):
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000223 dirname = os.path.dirname(path)
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200224 try:
225 os.makedirs(dirname)
226 except OSError as e:
227 if e.errno != errno.EEXIST:
228 raise
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000229 return open(path, "w")
230
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200231
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000232def create_package(source):
233 ofi = None
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000234 try:
235 for line in source.splitlines():
236 if line.startswith(" ") or line.startswith("\t"):
237 ofi.write(line.strip() + "\n")
238 else:
239 if ofi:
240 ofi.close()
241 ofi = open_file(os.path.join(TEST_DIR, line.strip()))
242 finally:
243 if ofi:
244 ofi.close()
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000245
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200246
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000247class ModuleFinderTest(unittest.TestCase):
Berker Peksag0a0d1da2014-07-07 14:58:12 +0300248 def _do_test(self, info, report=False, debug=0, replace_paths=[]):
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000249 import_this, modules, missing, maybe_missing, source = info
250 create_package(source)
251 try:
Berker Peksag0a0d1da2014-07-07 14:58:12 +0300252 mf = modulefinder.ModuleFinder(path=TEST_PATH, debug=debug,
253 replace_paths=replace_paths)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000254 mf.import_hook(import_this)
255 if report:
256 mf.report()
257## # This wouldn't work in general when executed several times:
258## opath = sys.path[:]
259## sys.path = TEST_PATH
260## try:
261## __import__(import_this)
262## except:
263## import traceback; traceback.print_exc()
264## sys.path = opath
265## return
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200266 modules = sorted(set(modules))
267 found = sorted(mf.modules)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000268 # check if we found what we expected, not more, not less
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200269 self.assertEqual(found, modules)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000270
271 # check for missing and maybe missing modules
272 bad, maybe = mf.any_missing_maybe()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000273 self.assertEqual(bad, missing)
274 self.assertEqual(maybe, maybe_missing)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000275 finally:
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200276 shutil.rmtree(TEST_DIR)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000277
278 def test_package(self):
279 self._do_test(package_test)
280
281 def test_maybe(self):
282 self._do_test(maybe_test)
283
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200284 def test_maybe_new(self):
285 self._do_test(maybe_test_new)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000286
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200287 def test_absolute_imports(self):
288 self._do_test(absolute_import_test)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000289
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200290 def test_relative_imports(self):
291 self._do_test(relative_import_test)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000292
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200293 def test_relative_imports_2(self):
294 self._do_test(relative_import_test_2)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000295
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200296 def test_relative_imports_3(self):
297 self._do_test(relative_import_test_3)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000298
Brett Cannon73b969e2012-12-22 19:34:21 -0500299 def test_relative_imports_4(self):
300 self._do_test(relative_import_test_4)
301
Brett Cannon298bb962014-02-28 10:44:45 -0500302 def test_bytecode(self):
303 base_path = os.path.join(TEST_DIR, 'a')
304 source_path = base_path + importlib.machinery.SOURCE_SUFFIXES[0]
305 bytecode_path = base_path + importlib.machinery.BYTECODE_SUFFIXES[0]
306 with open_file(source_path) as file:
307 file.write('testing_modulefinder = True\n')
308 py_compile.compile(source_path, cfile=bytecode_path)
309 os.remove(source_path)
310 self._do_test(bytecode_test)
311
Berker Peksag0a0d1da2014-07-07 14:58:12 +0300312 def test_replace_paths(self):
313 old_path = os.path.join(TEST_DIR, 'a', 'module.py')
314 new_path = os.path.join(TEST_DIR, 'a', 'spam.py')
315 with support.captured_stdout() as output:
316 self._do_test(maybe_test, debug=2,
317 replace_paths=[(old_path, new_path)])
318 output = output.getvalue()
Berker Peksaga90afbc2014-07-07 21:29:50 +0300319 expected = "co_filename %r changed to %r" % (old_path, new_path)
Berker Peksag0a0d1da2014-07-07 14:58:12 +0300320 self.assertIn(expected, output)
Benjamin Petersonc0747cf2008-11-03 20:31:38 +0000321
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000322
323if __name__ == "__main__":
324 unittest.main()