##// END OF EJS Templates
Fixing tests in IPython.testing.
Brian Granger -
Show More
@@ -1,282 +1,283 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 pjoin('IPython', 'testing', 'tutils')
73 pjoin('IPython', 'testing', 'tutils'),
74 pjoin('IPython', 'testing', 'tools')
74 75 ]
75 76
76 77 if not have_wx:
77 78 EXCLUDE.append(pjoin('IPython', 'Extensions', 'igrid'))
78 79 EXCLUDE.append(pjoin('IPython', 'gui'))
79 80 EXCLUDE.append(pjoin('IPython', 'frontend', 'wx'))
80 81
81 82 if not have_objc:
82 83 EXCLUDE.append(pjoin('IPython', 'frontend', 'cocoa'))
83 84
84 85 if not have_curses:
85 86 EXCLUDE.append(pjoin('IPython', 'Extensions', 'ibrowse'))
86 87
87 88 if not sys.platform == 'win32':
88 89 EXCLUDE.append(pjoin('IPython', 'platutils_win32'))
89 90
90 91 if not os.name == 'posix':
91 92 EXCLUDE.append(pjoin('IPython', 'platutils_posix'))
92 93
93 94 if not have_pexpect:
94 95 EXCLUDE.append(pjoin('IPython', 'irunner'))
95 96
96 97 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
97 98 if sys.platform == 'win32':
98 99 EXCLUDE = [s.replace('\\','\\\\') for s in EXCLUDE]
99 100
100 101
101 102 #-----------------------------------------------------------------------------
102 103 # Functions and classes
103 104 #-----------------------------------------------------------------------------
104 105
105 106 def run_iptest():
106 107 """Run the IPython test suite using nose.
107 108
108 109 This function is called when this script is **not** called with the form
109 110 `iptest all`. It simply calls nose with appropriate command line flags
110 111 and accepts all of the standard nose arguments.
111 112 """
112 113
113 114 warnings.filterwarnings('ignore',
114 115 'This will be removed soon. Use IPython.testing.util instead')
115 116
116 117 argv = sys.argv + [
117 118 # Loading ipdoctest causes problems with Twisted.
118 119 # I am removing this as a temporary fix to get the
119 120 # test suite back into working shape. Our nose
120 121 # plugin needs to be gone through with a fine
121 122 # toothed comb to find what is causing the problem.
122 123 '--with-ipdoctest',
123 124 '--ipdoctest-tests','--ipdoctest-extension=txt',
124 125 '--detailed-errors',
125 126
126 127 # We add --exe because of setuptools' imbecility (it
127 128 # blindly does chmod +x on ALL files). Nose does the
128 129 # right thing and it tries to avoid executables,
129 130 # setuptools unfortunately forces our hand here. This
130 131 # has been discussed on the distutils list and the
131 132 # setuptools devs refuse to fix this problem!
132 133 '--exe',
133 134 ]
134 135
135 136 # Detect if any tests were required by explicitly calling an IPython
136 137 # submodule or giving a specific path
137 138 has_tests = False
138 139 for arg in sys.argv:
139 140 if 'IPython' in arg or arg.endswith('.py') or \
140 141 (':' in arg and '.py' in arg):
141 142 has_tests = True
142 143 break
143 144
144 145 # If nothing was specifically requested, test full IPython
145 146 if not has_tests:
146 147 argv.append('IPython')
147 148
148 149 # Construct list of plugins, omitting the existing doctest plugin, which
149 150 # ours replaces (and extends).
150 151 plugins = [IPythonDoctest(EXCLUDE)]
151 152 for p in nose.plugins.builtin.plugins:
152 153 plug = p()
153 154 if plug.name == 'doctest':
154 155 continue
155 156
156 157 #print '*** adding plugin:',plug.name # dbg
157 158 plugins.append(plug)
158 159
159 160 TestProgram(argv=argv,plugins=plugins)
160 161
161 162
162 163 class IPTester(object):
163 164 """Call that calls iptest or trial in a subprocess.
164 165 """
165 166 def __init__(self,runner='iptest',params=None):
166 167 """ """
167 168 if runner == 'iptest':
168 169 self.runner = ['iptest','-v']
169 170 else:
170 171 self.runner = [find_cmd('trial')]
171 172 if params is None:
172 173 params = []
173 174 if isinstance(params,str):
174 175 params = [params]
175 176 self.params = params
176 177
177 178 # Assemble call
178 179 self.call_args = self.runner+self.params
179 180
180 181 def run(self):
181 182 """Run the stored commands"""
182 183 return subprocess.call(self.call_args)
183 184
184 185
185 186 def make_runners():
186 187 """Define the modules and packages that need to be tested.
187 188 """
188 189
189 190 # This omits additional top-level modules that should not be doctested.
190 191 # XXX: Shell.py is also ommited because of a bug in the skip_doctest
191 192 # decorator. See ticket https://bugs.launchpad.net/bugs/366209
192 193 top_mod = \
193 194 ['background_jobs.py', 'ColorANSI.py', 'completer.py', 'ConfigLoader.py',
194 195 'CrashHandler.py', 'Debugger.py', 'deep_reload.py', 'demo.py',
195 196 'DPyGetOpt.py', 'dtutils.py', 'excolors.py', 'FakeModule.py',
196 197 'generics.py', 'genutils.py', 'history.py', 'hooks.py', 'ipapi.py',
197 198 'iplib.py', 'ipmaker.py', 'ipstruct.py', 'Itpl.py',
198 199 'Logger.py', 'macro.py', 'Magic.py', 'OInspect.py',
199 200 'OutputTrap.py', 'platutils.py', 'prefilter.py', 'Prompts.py',
200 201 'PyColorize.py', 'Release.py', 'rlineimpl.py', 'shadowns.py',
201 202 'shellglobals.py', 'strdispatch.py', 'twshell.py',
202 203 'ultraTB.py', 'upgrade_dir.py', 'usage.py', 'wildcard.py',
203 204 # See note above for why this is skipped
204 205 # 'Shell.py',
205 206 'winconsole.py']
206 207
207 208 if have_pexpect:
208 209 top_mod.append('irunner.py')
209 210
210 211 # These are tested by nose, so skip IPython.kernel
211 212 top_pack = ['config','Extensions','frontend',
212 213 'testing','tests','tools','UserConfig']
213 214
214 215 if have_wx:
215 216 top_pack.append('gui')
216 217
217 218 modules = ['IPython.%s' % m[:-3] for m in top_mod ]
218 219 packages = ['IPython.%s' % m for m in top_pack ]
219 220
220 221 # Make runners
221 222 runners = dict(zip(top_pack, [IPTester(params=v) for v in packages]))
222 223
223 224 # Test IPython.kernel using trial if twisted is installed
224 225 if have_zi and have_twisted and have_foolscap:
225 226 runners['trial'] = IPTester('trial',['IPython'])
226 227
227 228 runners['modules'] = IPTester(params=modules)
228 229
229 230 return runners
230 231
231 232
232 233 def run_iptestall():
233 234 """Run the entire IPython test suite by calling nose and trial.
234 235
235 236 This function constructs :class:`IPTester` instances for all IPython
236 237 modules and package and then runs each of them. This causes the modules
237 238 and packages of IPython to be tested each in their own subprocess using
238 239 nose or twisted.trial appropriately.
239 240 """
240 241 runners = make_runners()
241 242 # Run all test runners, tracking execution time
242 243 failed = {}
243 244 t_start = time.time()
244 245 for name,runner in runners.iteritems():
245 246 print '*'*77
246 247 print 'IPython test set:',name
247 248 res = runner.run()
248 249 if res:
249 250 failed[name] = res
250 251 t_end = time.time()
251 252 t_tests = t_end - t_start
252 253 nrunners = len(runners)
253 254 nfail = len(failed)
254 255 # summarize results
255 256 print
256 257 print '*'*77
257 258 print 'Ran %s test sets in %.3fs' % (nrunners, t_tests)
258 259 print
259 260 if not failed:
260 261 print 'OK'
261 262 else:
262 263 # If anything went wrong, point out what command to rerun manually to
263 264 # see the actual errors and individual summary
264 265 print 'ERROR - %s out of %s test sets failed.' % (nfail, nrunners)
265 266 for name in failed:
266 267 failed_runner = runners[name]
267 268 print '-'*40
268 269 print 'Runner failed:',name
269 270 print 'You may wish to rerun this one individually, with:'
270 271 print ' '.join(failed_runner.call_args)
271 272 print
272 273
273 274
274 275 def main():
275 276 if sys.argv[1] == 'all':
276 277 run_iptestall()
277 278 else:
278 279 run_iptest()
279 280
280 281
281 282 if __name__ == '__main__':
282 283 main() No newline at end of file
@@ -1,90 +1,89 b''
1 1 """Generic testing tools that do NOT depend on Twisted.
2 2
3 3 In particular, this module exposes a set of top-level assert* functions that
4 4 can be used in place of nose.tools.assert* in method generators (the ones in
5 5 nose can not, at least as of nose 0.10.4).
6 6
7 7 Note: our testing package contains testing.util, which does depend on Twisted
8 8 and provides utilities for tests that manage Deferreds. All testing support
9 9 tools that only depend on nose, IPython or the standard library should go here
10 10 instead.
11 11
12 12
13 13 Authors
14 14 -------
15 15 - Fernando Perez <Fernando.Perez@berkeley.edu>
16 16 """
17 17
18 18 #*****************************************************************************
19 19 # Copyright (C) 2009 The IPython Development Team
20 20 #
21 21 # Distributed under the terms of the BSD License. The full license is in
22 22 # the file COPYING, distributed as part of this software.
23 23 #*****************************************************************************
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Required modules and packages
27 27 #-----------------------------------------------------------------------------
28 28
29 # Standard Python lib
30 29 import os
31 30 import sys
32 31
33 # Third-party
34 32 import nose.tools as nt
35 33
36 # From this project
37 34 from IPython.tools import utils
35 from IPython.testing import decorators as dec
38 36
39 37 #-----------------------------------------------------------------------------
40 38 # Globals
41 39 #-----------------------------------------------------------------------------
42 40
43 41 # Make a bunch of nose.tools assert wrappers that can be used in test
44 42 # generators. This will expose an assert* function for each one in nose.tools.
45 43
46 44 _tpl = """
47 45 def %(name)s(*a,**kw):
48 46 return nt.%(name)s(*a,**kw)
49 47 """
50 48
51 49 for _x in [a for a in dir(nt) if a.startswith('assert')]:
52 50 exec _tpl % dict(name=_x)
53 51
54 52 #-----------------------------------------------------------------------------
55 53 # Functions and classes
56 54 #-----------------------------------------------------------------------------
57 55
56
58 57 def full_path(startPath,files):
59 58 """Make full paths for all the listed files, based on startPath.
60 59
61 60 Only the base part of startPath is kept, since this routine is typically
62 61 used with a script's __file__ variable as startPath. The base of startPath
63 62 is then prepended to all the listed files, forming the output list.
64 63
65 64 Parameters
66 65 ----------
67 66 startPath : string
68 67 Initial path to use as the base for the results. This path is split
69 68 using os.path.split() and only its first component is kept.
70 69
71 70 files : string or list
72 71 One or more files.
73 72
74 73 Examples
75 74 --------
76 75
77 76 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
78 77 ['/foo/a.txt', '/foo/b.txt']
79 78
80 79 >>> full_path('/foo',['a.txt','b.txt'])
81 80 ['/a.txt', '/b.txt']
82 81
83 82 If a single file is given, the output is still a list:
84 83 >>> full_path('/foo','a.txt')
85 84 ['/a.txt']
86 85 """
87 86
88 87 files = utils.list_strings(files)
89 88 base = os.path.split(startPath)[0]
90 89 return [ os.path.join(base,f) for f in files ]
General Comments 0
You need to be logged in to leave comments. Login now