blob: ebd96e1c8a2dd0c6eeeeed30a365ec723f0cf644 [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
Brandt Bucher9d7b2c02019-04-07 01:00:41 -0700221syntax_error_test = [
222 "a.module",
223 ["a", "a.module", "b"],
224 ["b.module"], [],
225 """\
226a/__init__.py
227a/module.py
228 import b.module
229b/__init__.py
230b/module.py
231 ? # SyntaxError: invalid syntax
232"""]
233
234
235same_name_as_bad_test = [
236 "a.module",
237 ["a", "a.module", "b", "b.c"],
238 ["c"], [],
239 """\
240a/__init__.py
241a/module.py
242 import c
243 from b import c
244b/__init__.py
245b/c.py
246"""]
247
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200248
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000249def open_file(path):
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000250 dirname = os.path.dirname(path)
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200251 try:
252 os.makedirs(dirname)
253 except OSError as e:
254 if e.errno != errno.EEXIST:
255 raise
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000256 return open(path, "w")
257
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200258
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000259def create_package(source):
260 ofi = None
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000261 try:
262 for line in source.splitlines():
263 if line.startswith(" ") or line.startswith("\t"):
264 ofi.write(line.strip() + "\n")
265 else:
266 if ofi:
267 ofi.close()
268 ofi = open_file(os.path.join(TEST_DIR, line.strip()))
269 finally:
270 if ofi:
271 ofi.close()
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000272
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200273
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000274class ModuleFinderTest(unittest.TestCase):
Berker Peksag0a0d1da2014-07-07 14:58:12 +0300275 def _do_test(self, info, report=False, debug=0, replace_paths=[]):
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000276 import_this, modules, missing, maybe_missing, source = info
277 create_package(source)
278 try:
Berker Peksag0a0d1da2014-07-07 14:58:12 +0300279 mf = modulefinder.ModuleFinder(path=TEST_PATH, debug=debug,
280 replace_paths=replace_paths)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000281 mf.import_hook(import_this)
282 if report:
283 mf.report()
284## # This wouldn't work in general when executed several times:
285## opath = sys.path[:]
286## sys.path = TEST_PATH
287## try:
288## __import__(import_this)
289## except:
290## import traceback; traceback.print_exc()
291## sys.path = opath
292## return
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200293 modules = sorted(set(modules))
294 found = sorted(mf.modules)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000295 # check if we found what we expected, not more, not less
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200296 self.assertEqual(found, modules)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000297
298 # check for missing and maybe missing modules
299 bad, maybe = mf.any_missing_maybe()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000300 self.assertEqual(bad, missing)
301 self.assertEqual(maybe, maybe_missing)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000302 finally:
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200303 shutil.rmtree(TEST_DIR)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000304
305 def test_package(self):
306 self._do_test(package_test)
307
308 def test_maybe(self):
309 self._do_test(maybe_test)
310
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200311 def test_maybe_new(self):
312 self._do_test(maybe_test_new)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000313
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200314 def test_absolute_imports(self):
315 self._do_test(absolute_import_test)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000316
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200317 def test_relative_imports(self):
318 self._do_test(relative_import_test)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000319
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200320 def test_relative_imports_2(self):
321 self._do_test(relative_import_test_2)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000322
Éric Araujo1e3a68d2011-07-28 23:35:29 +0200323 def test_relative_imports_3(self):
324 self._do_test(relative_import_test_3)
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000325
Brett Cannon73b969e2012-12-22 19:34:21 -0500326 def test_relative_imports_4(self):
327 self._do_test(relative_import_test_4)
328
Brandt Bucher9d7b2c02019-04-07 01:00:41 -0700329 def test_syntax_error(self):
330 self._do_test(syntax_error_test)
331
332 def test_same_name_as_bad(self):
333 self._do_test(same_name_as_bad_test)
334
Brett Cannon298bb962014-02-28 10:44:45 -0500335 def test_bytecode(self):
336 base_path = os.path.join(TEST_DIR, 'a')
337 source_path = base_path + importlib.machinery.SOURCE_SUFFIXES[0]
338 bytecode_path = base_path + importlib.machinery.BYTECODE_SUFFIXES[0]
339 with open_file(source_path) as file:
340 file.write('testing_modulefinder = True\n')
341 py_compile.compile(source_path, cfile=bytecode_path)
342 os.remove(source_path)
343 self._do_test(bytecode_test)
344
Berker Peksag0a0d1da2014-07-07 14:58:12 +0300345 def test_replace_paths(self):
346 old_path = os.path.join(TEST_DIR, 'a', 'module.py')
347 new_path = os.path.join(TEST_DIR, 'a', 'spam.py')
348 with support.captured_stdout() as output:
349 self._do_test(maybe_test, debug=2,
350 replace_paths=[(old_path, new_path)])
351 output = output.getvalue()
Berker Peksaga90afbc2014-07-07 21:29:50 +0300352 expected = "co_filename %r changed to %r" % (old_path, new_path)
Berker Peksag0a0d1da2014-07-07 14:58:12 +0300353 self.assertIn(expected, output)
Benjamin Petersonc0747cf2008-11-03 20:31:38 +0000354
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300355 def test_extended_opargs(self):
356 extended_opargs_test = [
357 "a",
358 ["a", "b"],
359 [], [],
360 """\
361a.py
362 %r
363 import b
364b.py
365""" % list(range(2**16))] # 2**16 constants
366 self._do_test(extended_opargs_test)
367
Guido van Rossumfc2a0a82006-10-27 23:06:01 +0000368
369if __name__ == "__main__":
370 unittest.main()