1 import __future__
2 import os
3 import unittest
4 import distutils.dir_util
5 import tempfile
6 
7 from test import test_support
8 
9 try: set
10 except NameError: from sets import Set as set
11 
12 import modulefinder
13 
14 # Note: To test modulefinder with Python 2.2, sets.py and
15 # modulefinder.py must be available - they are not in the standard
16 # library.
17 
18 TEST_DIR = tempfile.mkdtemp()
19 TEST_PATH = [TEST_DIR, os.path.dirname(__future__.__file__)]
20 
21 # Each test description is a list of 5 items:
22 #
23 # 1. a module name that will be imported by modulefinder
24 # 2. a list of module names that modulefinder is required to find
25 # 3. a list of module names that modulefinder should complain
26 #    about because they are not found
27 # 4. a list of module names that modulefinder should complain
28 #    about because they MAY be not found
29 # 5. a string specifying packages to create; the format is obvious imo.
30 #
31 # Each package will be created in TEST_DIR, and TEST_DIR will be
32 # removed after the tests again.
33 # Modulefinder searches in a path that contains TEST_DIR, plus
34 # the standard Lib directory.
35 
36 maybe_test = [
37     "a.module",
38     ["a", "a.module", "sys",
39      "b"],
40     ["c"], ["b.something"],
41     """\
42 a/__init__.py
43 a/module.py
44                                 from b import something
45                                 from c import something
46 b/__init__.py
47                                 from sys import *
48 """]
49 
50 maybe_test_new = [
51     "a.module",
52     ["a", "a.module", "sys",
53      "b", "__future__"],
54     ["c"], ["b.something"],
55     """\
56 a/__init__.py
57 a/module.py
58                                 from b import something
59                                 from c import something
60 b/__init__.py
61                                 from __future__ import absolute_import
62                                 from sys import *
63 """]
64 
65 package_test = [
66     "a.module",
67     ["a", "a.b", "a.c", "a.module", "mymodule", "sys"],
68     ["blahblah"], [],
69     """\
70 mymodule.py
71 a/__init__.py
72                                 import blahblah
73                                 from a import b
74                                 import c
75 a/module.py
76                                 import sys
77                                 from a import b as x
78                                 from a.c import sillyname
79 a/b.py
80 a/c.py
81                                 from a.module import x
82                                 import mymodule as sillyname
83                                 from sys import version_info
84 """]
85 
86 absolute_import_test = [
87     "a.module",
88     ["a", "a.module",
89      "b", "b.x", "b.y", "b.z",
90      "__future__", "sys", "exceptions"],
91     ["blahblah"], [],
92     """\
93 mymodule.py
94 a/__init__.py
95 a/module.py
96                                 from __future__ import absolute_import
97                                 import sys # sys
98                                 import blahblah # fails
99                                 import exceptions # exceptions
100                                 import b.x # b.x
101                                 from b import y # b.y
102                                 from b.z import * # b.z.*
103 a/exceptions.py
104 a/sys.py
105                                 import mymodule
106 a/b/__init__.py
107 a/b/x.py
108 a/b/y.py
109 a/b/z.py
110 b/__init__.py
111                                 import z
112 b/unused.py
113 b/x.py
114 b/y.py
115 b/z.py
116 """]
117 
118 relative_import_test = [
119     "a.module",
120     ["__future__",
121      "a", "a.module",
122      "a.b", "a.b.y", "a.b.z",
123      "a.b.c", "a.b.c.moduleC",
124      "a.b.c.d", "a.b.c.e",
125      "a.b.x",
126      "exceptions"],
127     [], [],
128     """\
129 mymodule.py
130 a/__init__.py
131                                 from .b import y, z # a.b.y, a.b.z
132 a/module.py
133                                 from __future__ import absolute_import # __future__
134                                 import exceptions # exceptions
135 a/exceptions.py
136 a/sys.py
137 a/b/__init__.py
138                                 from ..b import x # a.b.x
139                                 #from a.b.c import moduleC
140                                 from .c import moduleC # a.b.moduleC
141 a/b/x.py
142 a/b/y.py
143 a/b/z.py
144 a/b/g.py
145 a/b/c/__init__.py
146                                 from ..c import e # a.b.c.e
147 a/b/c/moduleC.py
148                                 from ..c import d # a.b.c.d
149 a/b/c/d.py
150 a/b/c/e.py
151 a/b/c/x.py
152 """]
153 
154 relative_import_test_2 = [
155     "a.module",
156     ["a", "a.module",
157      "a.sys",
158      "a.b", "a.b.y", "a.b.z",
159      "a.b.c", "a.b.c.d",
160      "a.b.c.e",
161      "a.b.c.moduleC",
162      "a.b.c.f",
163      "a.b.x",
164      "a.another"],
165     [], [],
166     """\
167 mymodule.py
168 a/__init__.py
169                                 from . import sys # a.sys
170 a/another.py
171 a/module.py
172                                 from .b import y, z # a.b.y, a.b.z
173 a/exceptions.py
174 a/sys.py
175 a/b/__init__.py
176                                 from .c import moduleC # a.b.c.moduleC
177                                 from .c import d # a.b.c.d
178 a/b/x.py
179 a/b/y.py
180 a/b/z.py
181 a/b/c/__init__.py
182                                 from . import e # a.b.c.e
183 a/b/c/moduleC.py
184                                 #
185                                 from . import f   # a.b.c.f
186                                 from .. import x  # a.b.x
187                                 from ... import another # a.another
188 a/b/c/d.py
189 a/b/c/e.py
190 a/b/c/f.py
191 """]
192 
193 relative_import_test_3 = [
194     "a.module",
195     ["a", "a.module"],
196     ["a.bar"],
197     [],
198     """\
199 a/__init__.py
200                                 def foo(): pass
201 a/module.py
202                                 from . import foo
203                                 from . import bar
204 """]
205 
206 def open_file(path):
207     ##print "#", os.path.abspath(path)
208     dirname = os.path.dirname(path)
209     distutils.dir_util.mkpath(dirname)
210     return open(path, "w")
211 
212 def create_package(source):
213     ofi = None
214     try:
215         for line in source.splitlines():
216             if line.startswith(" ") or line.startswith("\t"):
217                 ofi.write(line.strip() + "\n")
218             else:
219                 if ofi:
220                     ofi.close()
221                 ofi = open_file(os.path.join(TEST_DIR, line.strip()))
222     finally:
223         if ofi:
224             ofi.close()
225 
226 class ModuleFinderTest(unittest.TestCase):
227     def _do_test(self, info, report=False):
228         import_this, modules, missing, maybe_missing, source = info
229         create_package(source)
230         try:
231             mf = modulefinder.ModuleFinder(path=TEST_PATH)
232             mf.import_hook(import_this)
233             if report:
234                 mf.report()
235 ##                # This wouldn't work in general when executed several times:
236 ##                opath = sys.path[:]
237 ##                sys.path = TEST_PATH
238 ##                try:
239 ##                    __import__(import_this)
240 ##                except:
241 ##                    import traceback; traceback.print_exc()
242 ##                sys.path = opath
243 ##                return
244             modules = set(modules)
245             found = set(mf.modules.keys())
246             more = list(found - modules)
247             less = list(modules - found)
248             # check if we found what we expected, not more, not less
249             self.assertEqual((more, less), ([], []))
250 
251             # check for missing and maybe missing modules
252             bad, maybe = mf.any_missing_maybe()
253             self.assertEqual(bad, missing)
254             self.assertEqual(maybe, maybe_missing)
255         finally:
256             distutils.dir_util.remove_tree(TEST_DIR)
257 
258     def test_package(self):
259         self._do_test(package_test)
260 
261     def test_maybe(self):
262         self._do_test(maybe_test)
263 
264     if getattr(__future__, "absolute_import", None):
265 
266         def test_maybe_new(self):
267             self._do_test(maybe_test_new)
268 
269         def test_absolute_imports(self):
270             self._do_test(absolute_import_test)
271 
272         def test_relative_imports(self):
273             self._do_test(relative_import_test)
274 
275         def test_relative_imports_2(self):
276             self._do_test(relative_import_test_2)
277 
278         def test_relative_imports_3(self):
279             self._do_test(relative_import_test_3)
280 
281     def test_extended_opargs(self):
282         extended_opargs_test = [
283             "a",
284             ["a", "b"],
285             [], [],
286             """\
287 a.py
288                                 %r
289                                 import b
290 b.py
291 """ % range(2**16)]  # 2**16 constants
292         self._do_test(extended_opargs_test)
293 
294 def test_main():
295     distutils.log.set_threshold(distutils.log.WARN)
296     test_support.run_unittest(ModuleFinderTest)
297 
298 if __name__ == "__main__":
299     unittest.main()
300