##// END OF EJS Templates
Adding comment about ticket https://bugs.launchpad.net/bugs/366982
Brian Granger -
Show More
@@ -1,288 +1,290 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.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 58
59 59 # For the IPythonDoctest plugin, we need to exclude certain patterns that cause
60 60 # testing problems. We should strive to minimize the number of skipped
61 61 # modules, since this means untested code. As the testing machinery
62 62 # solidifies, this list should eventually become empty.
63 63 EXCLUDE = [pjoin('IPython', 'external'),
64 64 pjoin('IPython', 'frontend', 'process', 'winprocess.py'),
65 65 pjoin('IPython_doctest_plugin'),
66 66 pjoin('IPython', 'Gnuplot'),
67 67 pjoin('IPython', 'Extensions', 'ipy_'),
68 68 pjoin('IPython', 'Extensions', 'clearcmd'),
69 69 pjoin('IPython', 'Extensions', 'PhysicalQInteractive'),
70 70 pjoin('IPython', 'Extensions', 'scitedirector'),
71 71 pjoin('IPython', 'Extensions', 'numeric_formats'),
72 72 pjoin('IPython', 'testing', 'attic'),
73 73 pjoin('IPython', 'testing', 'tutils'),
74 74 pjoin('IPython', 'testing', 'tools'),
75 75 pjoin('IPython', 'testing', 'mkdoctests')
76 76 ]
77 77
78 78 if not have_wx:
79 79 EXCLUDE.append(pjoin('IPython', 'Extensions', 'igrid'))
80 80 EXCLUDE.append(pjoin('IPython', 'gui'))
81 81 EXCLUDE.append(pjoin('IPython', 'frontend', 'wx'))
82 82
83 83 if not have_objc:
84 84 EXCLUDE.append(pjoin('IPython', 'frontend', 'cocoa'))
85 85
86 86 if not have_curses:
87 87 EXCLUDE.append(pjoin('IPython', 'Extensions', 'ibrowse'))
88 88
89 89 if not sys.platform == 'win32':
90 90 EXCLUDE.append(pjoin('IPython', 'platutils_win32'))
91 91
92 # These have to be skipped on win32 because the use echo, rm, cd, etc.
93 # See ticket https://bugs.launchpad.net/bugs/366982
92 94 if sys.platform == 'win32':
93 95 EXCLUDE.append(pjoin('IPython', 'testing', 'plugin', 'test_exampleip'))
94 96 EXCLUDE.append(pjoin('IPython', 'testing', 'plugin', 'dtexample'))
95 97
96 98 if not os.name == 'posix':
97 99 EXCLUDE.append(pjoin('IPython', 'platutils_posix'))
98 100
99 101 if not have_pexpect:
100 102 EXCLUDE.append(pjoin('IPython', 'irunner'))
101 103
102 104 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
103 105 if sys.platform == 'win32':
104 106 EXCLUDE = [s.replace('\\','\\\\') for s in EXCLUDE]
105 107
106 108
107 109 #-----------------------------------------------------------------------------
108 110 # Functions and classes
109 111 #-----------------------------------------------------------------------------
110 112
111 113 def run_iptest():
112 114 """Run the IPython test suite using nose.
113 115
114 116 This function is called when this script is **not** called with the form
115 117 `iptest all`. It simply calls nose with appropriate command line flags
116 118 and accepts all of the standard nose arguments.
117 119 """
118 120
119 121 warnings.filterwarnings('ignore',
120 122 'This will be removed soon. Use IPython.testing.util instead')
121 123
122 124 argv = sys.argv + [
123 125 # Loading ipdoctest causes problems with Twisted.
124 126 # I am removing this as a temporary fix to get the
125 127 # test suite back into working shape. Our nose
126 128 # plugin needs to be gone through with a fine
127 129 # toothed comb to find what is causing the problem.
128 130 '--with-ipdoctest',
129 131 '--ipdoctest-tests','--ipdoctest-extension=txt',
130 132 '--detailed-errors',
131 133
132 134 # We add --exe because of setuptools' imbecility (it
133 135 # blindly does chmod +x on ALL files). Nose does the
134 136 # right thing and it tries to avoid executables,
135 137 # setuptools unfortunately forces our hand here. This
136 138 # has been discussed on the distutils list and the
137 139 # setuptools devs refuse to fix this problem!
138 140 '--exe',
139 141 ]
140 142
141 143 # Detect if any tests were required by explicitly calling an IPython
142 144 # submodule or giving a specific path
143 145 has_tests = False
144 146 for arg in sys.argv:
145 147 if 'IPython' in arg or arg.endswith('.py') or \
146 148 (':' in arg and '.py' in arg):
147 149 has_tests = True
148 150 break
149 151
150 152 # If nothing was specifically requested, test full IPython
151 153 if not has_tests:
152 154 argv.append('IPython')
153 155
154 156 # Construct list of plugins, omitting the existing doctest plugin, which
155 157 # ours replaces (and extends).
156 158 plugins = [IPythonDoctest(EXCLUDE)]
157 159 for p in nose.plugins.builtin.plugins:
158 160 plug = p()
159 161 if plug.name == 'doctest':
160 162 continue
161 163
162 164 #print '*** adding plugin:',plug.name # dbg
163 165 plugins.append(plug)
164 166
165 167 TestProgram(argv=argv,plugins=plugins)
166 168
167 169
168 170 class IPTester(object):
169 171 """Call that calls iptest or trial in a subprocess.
170 172 """
171 173 def __init__(self,runner='iptest',params=None):
172 174 """ """
173 175 if runner == 'iptest':
174 176 self.runner = ['iptest','-v']
175 177 else:
176 178 self.runner = [find_cmd('trial')]
177 179 if params is None:
178 180 params = []
179 181 if isinstance(params,str):
180 182 params = [params]
181 183 self.params = params
182 184
183 185 # Assemble call
184 186 self.call_args = self.runner+self.params
185 187
186 188 def run(self):
187 189 """Run the stored commands"""
188 190 return subprocess.call(self.call_args)
189 191
190 192
191 193 def make_runners():
192 194 """Define the modules and packages that need to be tested.
193 195 """
194 196
195 197 # This omits additional top-level modules that should not be doctested.
196 198 # XXX: Shell.py is also ommited because of a bug in the skip_doctest
197 199 # decorator. See ticket https://bugs.launchpad.net/bugs/366209
198 200 top_mod = \
199 201 ['background_jobs.py', 'ColorANSI.py', 'completer.py', 'ConfigLoader.py',
200 202 'CrashHandler.py', 'Debugger.py', 'deep_reload.py', 'demo.py',
201 203 'DPyGetOpt.py', 'dtutils.py', 'excolors.py', 'FakeModule.py',
202 204 'generics.py', 'genutils.py', 'history.py', 'hooks.py', 'ipapi.py',
203 205 'iplib.py', 'ipmaker.py', 'ipstruct.py', 'Itpl.py',
204 206 'Logger.py', 'macro.py', 'Magic.py', 'OInspect.py',
205 207 'OutputTrap.py', 'platutils.py', 'prefilter.py', 'Prompts.py',
206 208 'PyColorize.py', 'Release.py', 'rlineimpl.py', 'shadowns.py',
207 209 'shellglobals.py', 'strdispatch.py', 'twshell.py',
208 210 'ultraTB.py', 'upgrade_dir.py', 'usage.py', 'wildcard.py',
209 211 # See note above for why this is skipped
210 212 # 'Shell.py',
211 213 'winconsole.py']
212 214
213 215 if have_pexpect:
214 216 top_mod.append('irunner.py')
215 217
216 218 # These are tested by nose, so skip IPython.kernel
217 219 top_pack = ['config','Extensions','frontend',
218 220 'testing','tests','tools','UserConfig']
219 221
220 222 if have_wx:
221 223 top_pack.append('gui')
222 224
223 225 modules = ['IPython.%s' % m[:-3] for m in top_mod ]
224 226 packages = ['IPython.%s' % m for m in top_pack ]
225 227
226 228 # Make runners
227 229 runners = dict(zip(top_pack, [IPTester(params=v) for v in packages]))
228 230
229 231 # Test IPython.kernel using trial if twisted is installed
230 232 if have_zi and have_twisted and have_foolscap:
231 233 runners['trial'] = IPTester('trial',['IPython'])
232 234
233 235 runners['modules'] = IPTester(params=modules)
234 236
235 237 return runners
236 238
237 239
238 240 def run_iptestall():
239 241 """Run the entire IPython test suite by calling nose and trial.
240 242
241 243 This function constructs :class:`IPTester` instances for all IPython
242 244 modules and package and then runs each of them. This causes the modules
243 245 and packages of IPython to be tested each in their own subprocess using
244 246 nose or twisted.trial appropriately.
245 247 """
246 248 runners = make_runners()
247 249 # Run all test runners, tracking execution time
248 250 failed = {}
249 251 t_start = time.time()
250 252 for name,runner in runners.iteritems():
251 253 print '*'*77
252 254 print 'IPython test set:',name
253 255 res = runner.run()
254 256 if res:
255 257 failed[name] = res
256 258 t_end = time.time()
257 259 t_tests = t_end - t_start
258 260 nrunners = len(runners)
259 261 nfail = len(failed)
260 262 # summarize results
261 263 print
262 264 print '*'*77
263 265 print 'Ran %s test sets in %.3fs' % (nrunners, t_tests)
264 266 print
265 267 if not failed:
266 268 print 'OK'
267 269 else:
268 270 # If anything went wrong, point out what command to rerun manually to
269 271 # see the actual errors and individual summary
270 272 print 'ERROR - %s out of %s test sets failed.' % (nfail, nrunners)
271 273 for name in failed:
272 274 failed_runner = runners[name]
273 275 print '-'*40
274 276 print 'Runner failed:',name
275 277 print 'You may wish to rerun this one individually, with:'
276 278 print ' '.join(failed_runner.call_args)
277 279 print
278 280
279 281
280 282 def main():
281 283 if sys.argv[1] == 'all':
282 284 run_iptestall()
283 285 else:
284 286 run_iptest()
285 287
286 288
287 289 if __name__ == '__main__':
288 290 main() No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now