##// END OF EJS Templates
Updated iptest to skip inputhook*.py files for doctesting.
Brian Granger -
Show More
@@ -1,279 +1,286 b''
1 1 # -*- coding: utf-8 -*-
2 2 """IPython Test Suite Runner.
3 3
4 4 This module provides a main entry point to a user script to test IPython
5 5 itself from the command line. There are two ways of running this script:
6 6
7 7 1. With the syntax `iptest all`. This runs our entire test suite by
8 8 calling this script (with different arguments) or trial recursively. This
9 9 causes modules and package to be tested in different processes, using nose
10 10 or trial where appropriate.
11 11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
12 12 the script simply calls nose, but with special command line flags and
13 13 plugins loaded.
14 14
15 15 For now, this script requires that both nose and twisted are installed. This
16 16 will change in the future.
17 17 """
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Module imports
21 21 #-----------------------------------------------------------------------------
22 22
23 23 import os
24 24 import os.path as path
25 25 import sys
26 26 import subprocess
27 27 import time
28 28 import warnings
29 29
30 30 import nose.plugins.builtin
31 31 from nose.core import TestProgram
32 32
33 33 from IPython.utils.platutils import find_cmd
34 34 from IPython.testing.plugin.ipdoctest import IPythonDoctest
35 35
36 36 pjoin = path.join
37 37
38 38 #-----------------------------------------------------------------------------
39 39 # Logic for skipping doctests
40 40 #-----------------------------------------------------------------------------
41 41
42 42 def test_for(mod):
43 43 """Test to see if mod is importable."""
44 44 try:
45 45 __import__(mod)
46 46 except ImportError:
47 47 return False
48 48 else:
49 49 return True
50 50
51 51 have_curses = test_for('_curses')
52 52 have_wx = test_for('wx')
53 53 have_zi = test_for('zope.interface')
54 54 have_twisted = test_for('twisted')
55 55 have_foolscap = test_for('foolscap')
56 56 have_objc = test_for('objc')
57 57 have_pexpect = test_for('pexpect')
58 have_gtk = test_for('gtk')
59 have_gobject = test_for('gobject')
58 60
59 61
60 62 def make_exclude():
61 63
62 64 # For the IPythonDoctest plugin, we need to exclude certain patterns that cause
63 65 # testing problems. We should strive to minimize the number of skipped
64 66 # modules, since this means untested code. As the testing machinery
65 67 # solidifies, this list should eventually become empty.
66 68 EXCLUDE = [pjoin('IPython', 'external'),
67 69 pjoin('IPython', 'frontend', 'process', 'winprocess.py'),
68 70 pjoin('IPython_doctest_plugin'),
69 71 pjoin('IPython', 'extensions', 'ipy_'),
70 72 pjoin('IPython', 'extensions', 'clearcmd'),
71 73 pjoin('IPython', 'extensions', 'PhysicalQInteractive'),
72 74 pjoin('IPython', 'extensions', 'scitedirector'),
73 75 pjoin('IPython', 'extensions', 'numeric_formats'),
74 76 pjoin('IPython', 'testing', 'attic'),
75 77 pjoin('IPython', 'testing', 'tools'),
76 pjoin('IPython', 'testing', 'mkdoctests')
78 pjoin('IPython', 'testing', 'mkdoctests'),
79 pjoin('IPython', 'lib', 'inputhook')
77 80 ]
78 81
79 82 if not have_wx:
80 83 EXCLUDE.append(pjoin('IPython', 'extensions', 'igrid'))
81 84 EXCLUDE.append(pjoin('IPython', 'gui'))
82 85 EXCLUDE.append(pjoin('IPython', 'frontend', 'wx'))
86 EXCLUDE.append(pjoin('IPython', 'lib', 'inputhookwx'))
87
88 if not have_gtk or not have_gobject:
89 EXCLUDE.append(pjoin('IPython', 'lib', 'inputhookgtk'))
83 90
84 91 if not have_objc:
85 92 EXCLUDE.append(pjoin('IPython', 'frontend', 'cocoa'))
86 93
87 94 if not have_curses:
88 95 EXCLUDE.append(pjoin('IPython', 'extensions', 'ibrowse'))
89 96
90 97 if not sys.platform == 'win32':
91 98 EXCLUDE.append(pjoin('IPython', 'utils', 'platutils_win32'))
92 99
93 100 # These have to be skipped on win32 because the use echo, rm, cd, etc.
94 101 # See ticket https://bugs.launchpad.net/bugs/366982
95 102 if sys.platform == 'win32':
96 103 EXCLUDE.append(pjoin('IPython', 'testing', 'plugin', 'test_exampleip'))
97 104 EXCLUDE.append(pjoin('IPython', 'testing', 'plugin', 'dtexample'))
98 105
99 106 if not os.name == 'posix':
100 107 EXCLUDE.append(pjoin('IPython', 'utils', 'platutils_posix'))
101 108
102 109 if not have_pexpect:
103 110 EXCLUDE.append(pjoin('IPython', 'scripts', 'irunner'))
104 111
105 112 # Skip shell always because of a bug in FakeModule.
106 113 EXCLUDE.append(pjoin('IPython', 'core', 'shell'))
107 114
108 115 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
109 116 if sys.platform == 'win32':
110 117 EXCLUDE = [s.replace('\\','\\\\') for s in EXCLUDE]
111 118
112 119 return EXCLUDE
113 120
114 121 #-----------------------------------------------------------------------------
115 122 # Functions and classes
116 123 #-----------------------------------------------------------------------------
117 124
118 125 def run_iptest():
119 126 """Run the IPython test suite using nose.
120 127
121 128 This function is called when this script is **not** called with the form
122 129 `iptest all`. It simply calls nose with appropriate command line flags
123 130 and accepts all of the standard nose arguments.
124 131 """
125 132
126 133 warnings.filterwarnings('ignore',
127 134 'This will be removed soon. Use IPython.testing.util instead')
128 135
129 136 argv = sys.argv + [
130 137 # Loading ipdoctest causes problems with Twisted.
131 138 # I am removing this as a temporary fix to get the
132 139 # test suite back into working shape. Our nose
133 140 # plugin needs to be gone through with a fine
134 141 # toothed comb to find what is causing the problem.
135 142 '--with-ipdoctest',
136 143 '--ipdoctest-tests','--ipdoctest-extension=txt',
137 144 '--detailed-errors',
138 145
139 146 # We add --exe because of setuptools' imbecility (it
140 147 # blindly does chmod +x on ALL files). Nose does the
141 148 # right thing and it tries to avoid executables,
142 149 # setuptools unfortunately forces our hand here. This
143 150 # has been discussed on the distutils list and the
144 151 # setuptools devs refuse to fix this problem!
145 152 '--exe',
146 153 ]
147 154
148 155 # Detect if any tests were required by explicitly calling an IPython
149 156 # submodule or giving a specific path
150 157 has_tests = False
151 158 for arg in sys.argv:
152 159 if 'IPython' in arg or arg.endswith('.py') or \
153 160 (':' in arg and '.py' in arg):
154 161 has_tests = True
155 162 break
156 163
157 164 # If nothing was specifically requested, test full IPython
158 165 if not has_tests:
159 166 argv.append('IPython')
160 167
161 168 # Construct list of plugins, omitting the existing doctest plugin, which
162 169 # ours replaces (and extends).
163 170 EXCLUDE = make_exclude()
164 171 plugins = [IPythonDoctest(EXCLUDE)]
165 172 for p in nose.plugins.builtin.plugins:
166 173 plug = p()
167 174 if plug.name == 'doctest':
168 175 continue
169 176 plugins.append(plug)
170 177
171 178 TestProgram(argv=argv,plugins=plugins)
172 179
173 180
174 181 class IPTester(object):
175 182 """Call that calls iptest or trial in a subprocess.
176 183 """
177 184 def __init__(self,runner='iptest',params=None):
178 185 """ """
179 186 if runner == 'iptest':
180 187 self.runner = ['iptest','-v']
181 188 else:
182 189 self.runner = [find_cmd('trial')]
183 190 if params is None:
184 191 params = []
185 192 if isinstance(params,str):
186 193 params = [params]
187 194 self.params = params
188 195
189 196 # Assemble call
190 197 self.call_args = self.runner+self.params
191 198
192 199 def run(self):
193 200 """Run the stored commands"""
194 201 return subprocess.call(self.call_args)
195 202
196 203
197 204 def make_runners():
198 205 """Define the top-level packages that need to be tested.
199 206 """
200 207
201 208 nose_packages = ['config', 'core', 'extensions',
202 209 'frontend', 'lib', 'quarantine',
203 210 'scripts', 'testing', 'utils']
204 211 trial_packages = ['kernel']
205 212
206 213 if have_wx:
207 214 nose_packages.append('gui')
208 215
209 216 nose_packages = ['IPython.%s' % m for m in nose_packages ]
210 217 trial_packages = ['IPython.%s' % m for m in trial_packages ]
211 218
212 219 # Make runners
213 220 runners = dict()
214 221
215 222 nose_runners = dict(zip(nose_packages, [IPTester(params=v) for v in nose_packages]))
216 223 if have_zi and have_twisted and have_foolscap:
217 224 trial_runners = dict(zip(trial_packages, [IPTester('trial',params=v) for v in trial_packages]))
218 225 runners.update(nose_runners)
219 226 runners.update(trial_runners)
220 227
221 228 return runners
222 229
223 230
224 231 def run_iptestall():
225 232 """Run the entire IPython test suite by calling nose and trial.
226 233
227 234 This function constructs :class:`IPTester` instances for all IPython
228 235 modules and package and then runs each of them. This causes the modules
229 236 and packages of IPython to be tested each in their own subprocess using
230 237 nose or twisted.trial appropriately.
231 238 """
232 239
233 240 runners = make_runners()
234 241
235 242 # Run all test runners, tracking execution time
236 243 failed = {}
237 244 t_start = time.time()
238 245 for name,runner in runners.iteritems():
239 246 print '*'*77
240 247 print 'IPython test set:', name
241 248 res = runner.run()
242 249 if res:
243 250 failed[name] = res
244 251 t_end = time.time()
245 252 t_tests = t_end - t_start
246 253 nrunners = len(runners)
247 254 nfail = len(failed)
248 255 # summarize results
249 256 print
250 257 print '*'*77
251 258 print 'Ran %s test sets in %.3fs' % (nrunners, t_tests)
252 259 print
253 260 if not failed:
254 261 print 'OK'
255 262 else:
256 263 # If anything went wrong, point out what command to rerun manually to
257 264 # see the actual errors and individual summary
258 265 print 'ERROR - %s out of %s test sets failed.' % (nfail, nrunners)
259 266 for name in failed:
260 267 failed_runner = runners[name]
261 268 print '-'*40
262 269 print 'Runner failed:',name
263 270 print 'You may wish to rerun this one individually, with:'
264 271 print ' '.join(failed_runner.call_args)
265 272 print
266 273
267 274
268 275 def main():
269 276 if len(sys.argv) == 1:
270 277 run_iptestall()
271 278 else:
272 279 if sys.argv[1] == 'all':
273 280 run_iptestall()
274 281 else:
275 282 run_iptest()
276 283
277 284
278 285 if __name__ == '__main__':
279 286 main() No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now