##// END OF EJS Templates
Added diagnostics printout at the end of the test suite....
Fernando Perez -
Show More
@@ -1,121 +1,121 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Release data for the IPython project."""
3 3
4 4 #*****************************************************************************
5 5 # Copyright (C) 2008-2009 The IPython Development Team
6 6 # Copyright (C) 2001-2008 Fernando Perez <fperez@colorado.edu>
7 7 # Copyright (c) 2001 Janko Hauser <jhauser@zscout.de> and Nathaniel Gray
8 8 # <n8gray@caltech.edu>
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #*****************************************************************************
13 13
14 14 # Name of the package for release purposes. This is the name which labels
15 15 # the tarballs and RPMs made by distutils, so it's best to lowercase it.
16 16 name = 'ipython'
17 17
18 18 # For versions with substrings (like 0.6.16.svn), use an extra . to separate
19 19 # the new substring. We have to avoid using either dashes or underscores,
20 20 # because bdist_rpm does not accept dashes (an RPM) convention, and
21 21 # bdist_deb does not accept underscores (a Debian convention).
22 22
23 23 development = True # change this to False to do a release
24 24 version_base = '0.11'
25 25 branch = 'ipython'
26 revision = '1340'
26 revision = '1346'
27 27
28 28 if development:
29 29 if branch == 'ipython':
30 30 version = '%s.bzr.r%s' % (version_base, revision)
31 31 else:
32 32 version = '%s.bzr.r%s.%s' % (version_base, revision, branch)
33 33 else:
34 34 version = version_base
35 35
36 36
37 37 description = "An interactive computing environment for Python"
38 38
39 39 long_description = \
40 40 """
41 41 The goal of IPython is to create a comprehensive environment for
42 42 interactive and exploratory computing. To support this goal, IPython
43 43 has two main components:
44 44
45 45 * An enhanced interactive Python shell.
46 46
47 47 * An architecture for interactive parallel computing.
48 48
49 49 The enhanced interactive Python shell has the following main features:
50 50
51 51 * Comprehensive object introspection.
52 52
53 53 * Input history, persistent across sessions.
54 54
55 55 * Caching of output results during a session with automatically generated
56 56 references.
57 57
58 58 * Readline based name completion.
59 59
60 60 * Extensible system of 'magic' commands for controlling the environment and
61 61 performing many tasks related either to IPython or the operating system.
62 62
63 63 * Configuration system with easy switching between different setups (simpler
64 64 than changing $PYTHONSTARTUP environment variables every time).
65 65
66 66 * Session logging and reloading.
67 67
68 68 * Extensible syntax processing for special purpose situations.
69 69
70 70 * Access to the system shell with user-extensible alias system.
71 71
72 72 * Easily embeddable in other Python programs and wxPython GUIs.
73 73
74 74 * Integrated access to the pdb debugger and the Python profiler.
75 75
76 76 The parallel computing architecture has the following main features:
77 77
78 78 * Quickly parallelize Python code from an interactive Python/IPython session.
79 79
80 80 * A flexible and dynamic process model that be deployed on anything from
81 81 multicore workstations to supercomputers.
82 82
83 83 * An architecture that supports many different styles of parallelism, from
84 84 message passing to task farming.
85 85
86 86 * Both blocking and fully asynchronous interfaces.
87 87
88 88 * High level APIs that enable many things to be parallelized in a few lines
89 89 of code.
90 90
91 91 * Share live parallel jobs with other users securely.
92 92
93 93 * Dynamically load balanced task farming system.
94 94
95 95 * Robust error handling in parallel code.
96 96
97 97 The latest development version is always available from IPython's `Launchpad
98 98 site <http://launchpad.net/ipython>`_.
99 99 """
100 100
101 101 license = 'BSD'
102 102
103 103 authors = {'Fernando' : ('Fernando Perez','fperez.net@gmail.com'),
104 104 'Janko' : ('Janko Hauser','jhauser@zscout.de'),
105 105 'Nathan' : ('Nathaniel Gray','n8gray@caltech.edu'),
106 106 'Ville' : ('Ville Vainio','vivainio@gmail.com'),
107 107 'Brian' : ('Brian E Granger', 'ellisonbg@gmail.com'),
108 108 'Min' : ('Min Ragan-Kelley', 'benjaminrk@gmail.com')
109 109 }
110 110
111 111 author = 'The IPython Development Team'
112 112
113 113 author_email = 'ipython-dev@scipy.org'
114 114
115 115 url = 'http://ipython.scipy.org'
116 116
117 117 download_url = 'http://ipython.scipy.org/dist'
118 118
119 119 platforms = ['Linux','Mac OSX','Windows XP/2000/NT','Windows 95/98/ME']
120 120
121 121 keywords = ['Interactive','Interpreter','Shell','Parallel','Distributed']
@@ -1,450 +1,488 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 # Stdlib
24 24 import os
25 25 import os.path as path
26 import platform
26 27 import signal
27 28 import sys
28 29 import subprocess
29 30 import tempfile
30 31 import time
31 32 import warnings
32 33
33 34
34 35 # Ugly, but necessary hack to ensure the test suite finds our version of
35 36 # IPython and not a possibly different one that may exist system-wide.
36 37 # Note that this must be done here, so the imports that come next work
37 38 # correctly even if IPython isn't installed yet.
38 39 p = os.path
39 40 ippath = p.abspath(p.join(p.dirname(__file__),'..','..'))
40 41 sys.path.insert(0, ippath)
41 42
42 43 # Note: monkeypatch!
43 44 # We need to monkeypatch a small problem in nose itself first, before importing
44 45 # it for actual use. This should get into nose upstream, but its release cycle
45 46 # is slow and we need it for our parametric tests to work correctly.
46 47 from IPython.testing import nosepatch
47 48 # Now, proceed to import nose itself
48 49 import nose.plugins.builtin
49 50 from nose.core import TestProgram
50 51
51 52 # Our own imports
53 from IPython.core import release
52 54 from IPython.utils import genutils
53 55 from IPython.utils.platutils import find_cmd, FindCmdError
54 56 from IPython.testing import globalipapp
55 57 from IPython.testing import tools
56 58 from IPython.testing.plugin.ipdoctest import IPythonDoctest
57 59
58 60 pjoin = path.join
59 61
60 62
61 63 #-----------------------------------------------------------------------------
62 64 # Globals
63 65 #-----------------------------------------------------------------------------
64 66
65 67 # By default, we assume IPython has been installed. But if the test suite is
66 68 # being run from a source tree that has NOT been installed yet, this flag can
67 69 # be set to False by the entry point scripts, to let us know that we must call
68 70 # the source tree versions of the scripts which manipulate sys.path instead of
69 71 # assuming that things exist system-wide.
70 72 INSTALLED = True
71 73
72 74 #-----------------------------------------------------------------------------
73 75 # Warnings control
74 76 #-----------------------------------------------------------------------------
75 77 # Twisted generates annoying warnings with Python 2.6, as will do other code
76 78 # that imports 'sets' as of today
77 79 warnings.filterwarnings('ignore', 'the sets module is deprecated',
78 80 DeprecationWarning )
79 81
80 82 # This one also comes from Twisted
81 83 warnings.filterwarnings('ignore', 'the sha module is deprecated',
82 84 DeprecationWarning)
83 85
84 86 # Wx on Fedora11 spits these out
85 87 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
86 88 UserWarning)
87 89
88 90 #-----------------------------------------------------------------------------
89 91 # Logic for skipping doctests
90 92 #-----------------------------------------------------------------------------
91 93
92 94 def test_for(mod):
93 95 """Test to see if mod is importable."""
94 96 try:
95 97 __import__(mod)
96 98 except (ImportError, RuntimeError):
97 99 # GTK reports Runtime error if it can't be initialized even if it's
98 100 # importable.
99 101 return False
100 102 else:
101 103 return True
102 104
103 have_curses = test_for('_curses')
104 have_wx = test_for('wx')
105 have_wx_aui = test_for('wx.aui')
106 have_zi = test_for('zope.interface')
107 have_twisted = test_for('twisted')
108 have_foolscap = test_for('foolscap')
109 have_objc = test_for('objc')
110 have_pexpect = test_for('pexpect')
111 have_gtk = test_for('gtk')
112 have_gobject = test_for('gobject')
105 # Global dict where we can store information on what we have and what we don't
106 # have available at test run time
107 have = {}
108
109 have['curses'] = test_for('_curses')
110 have['wx'] = test_for('wx')
111 have['wx.aui'] = test_for('wx.aui')
112 have['zope.interface'] = test_for('zope.interface')
113 have['twisted'] = test_for('twisted')
114 have['foolscap'] = test_for('foolscap')
115 have['objc'] = test_for('objc')
116 have['pexpect'] = test_for('pexpect')
117 have['gtk'] = test_for('gtk')
118 have['gobject'] = test_for('gobject')
113 119
114 120 #-----------------------------------------------------------------------------
115 121 # Functions and classes
116 122 #-----------------------------------------------------------------------------
117 123
124 def report():
125 """Return a string with a summary report of test-related variables."""
126
127 out = [ genutils.sys_info() ]
128
129 out.append('\nRunning from an installed IPython: %s\n' % INSTALLED)
130
131 avail = []
132 not_avail = []
133
134 for k, is_avail in have.items():
135 if is_avail:
136 avail.append(k)
137 else:
138 not_avail.append(k)
139
140 if avail:
141 out.append('\nTools and libraries available at test time:\n')
142 avail.sort()
143 out.append(' ' + ' '.join(avail)+'\n')
144
145 if not_avail:
146 out.append('\nTools and libraries NOT available at test time:\n')
147 not_avail.sort()
148 out.append(' ' + ' '.join(not_avail)+'\n')
149
150 return ''.join(out)
151
152
118 153 def make_exclude():
119 154 """Make patterns of modules and packages to exclude from testing.
120 155
121 156 For the IPythonDoctest plugin, we need to exclude certain patterns that
122 157 cause testing problems. We should strive to minimize the number of
123 158 skipped modules, since this means untested code. As the testing
124 159 machinery solidifies, this list should eventually become empty.
125 160 These modules and packages will NOT get scanned by nose at all for tests.
126 161 """
127 162 # Simple utility to make IPython paths more readably, we need a lot of
128 163 # these below
129 164 ipjoin = lambda *paths: pjoin('IPython', *paths)
130 165
131 166 exclusions = [ipjoin('external'),
132 167 ipjoin('frontend', 'process', 'winprocess.py'),
133 168 # Deprecated old Shell and iplib modules, skip to avoid
134 169 # warnings
135 170 ipjoin('Shell'),
136 171 ipjoin('iplib'),
137 172 pjoin('IPython_doctest_plugin'),
138 173 ipjoin('quarantine'),
139 174 ipjoin('deathrow'),
140 175 ipjoin('testing', 'attic'),
141 176 # This guy is probably attic material
142 177 ipjoin('testing', 'mkdoctests'),
143 178 # Testing inputhook will need a lot of thought, to figure out
144 179 # how to have tests that don't lock up with the gui event
145 180 # loops in the picture
146 181 ipjoin('lib', 'inputhook'),
147 182 # Config files aren't really importable stand-alone
148 183 ipjoin('config', 'default'),
149 184 ipjoin('config', 'profile'),
150 185 ]
151 186
152 if not have_wx:
187 if not have['wx']:
153 188 exclusions.append(ipjoin('gui'))
154 189 exclusions.append(ipjoin('frontend', 'wx'))
155 190 exclusions.append(ipjoin('lib', 'inputhookwx'))
156 191
157 if not have_gtk or not have_gobject:
192 if not have['gtk'] or not have['gobject']:
158 193 exclusions.append(ipjoin('lib', 'inputhookgtk'))
159 194
160 if not have_wx_aui:
195 if not have['wx.aui']:
161 196 exclusions.append(ipjoin('gui', 'wx', 'wxIPython'))
162 197
163 if not have_objc:
198 if not have['objc']:
164 199 exclusions.append(ipjoin('frontend', 'cocoa'))
165 200
166 201 if not sys.platform == 'win32':
167 202 exclusions.append(ipjoin('utils', 'platutils_win32'))
168 203
169 204 # These have to be skipped on win32 because the use echo, rm, cd, etc.
170 205 # See ticket https://bugs.launchpad.net/bugs/366982
171 206 if sys.platform == 'win32':
172 207 exclusions.append(ipjoin('testing', 'plugin', 'test_exampleip'))
173 208 exclusions.append(ipjoin('testing', 'plugin', 'dtexample'))
174 209
175 210 if not os.name == 'posix':
176 211 exclusions.append(ipjoin('utils', 'platutils_posix'))
177 212
178 if not have_pexpect:
213 if not have['pexpect']:
179 214 exclusions.extend([ipjoin('scripts', 'irunner'),
180 215 ipjoin('lib', 'irunner')])
181 216
182 217 # This is scary. We still have things in frontend and testing that
183 218 # are being tested by nose that use twisted. We need to rethink
184 219 # how we are isolating dependencies in testing.
185 if not (have_twisted and have_zi and have_foolscap):
220 if not (have['twisted'] and have['zope.interface'] and have['foolscap']):
186 221 exclusions.extend(
187 222 [ipjoin('frontend', 'asyncfrontendbase'),
188 223 ipjoin('frontend', 'prefilterfrontend'),
189 224 ipjoin('frontend', 'frontendbase'),
190 225 ipjoin('frontend', 'linefrontendbase'),
191 226 ipjoin('frontend', 'tests', 'test_linefrontend'),
192 227 ipjoin('frontend', 'tests', 'test_frontendbase'),
193 228 ipjoin('frontend', 'tests', 'test_prefilterfrontend'),
194 229 ipjoin('frontend', 'tests', 'test_asyncfrontendbase'),
195 230 ipjoin('testing', 'parametric'),
196 231 ipjoin('testing', 'util'),
197 232 ipjoin('testing', 'tests', 'test_decorators_trial'),
198 233 ] )
199 234
200 235 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
201 236 if sys.platform == 'win32':
202 237 exclusions = [s.replace('\\','\\\\') for s in exclusions]
203 238
204 239 return exclusions
205 240
206 241
207 242 class IPTester(object):
208 243 """Call that calls iptest or trial in a subprocess.
209 244 """
210 245 #: string, name of test runner that will be called
211 246 runner = None
212 247 #: list, parameters for test runner
213 248 params = None
214 249 #: list, arguments of system call to be made to call test runner
215 250 call_args = None
216 251 #: list, process ids of subprocesses we start (for cleanup)
217 252 pids = None
218 253
219 254 def __init__(self, runner='iptest', params=None):
220 255 """Create new test runner."""
221 256 p = os.path
222 257 if runner == 'iptest':
223 258 if INSTALLED:
224 259 self.runner = tools.cmd2argv(
225 260 p.abspath(find_cmd('iptest'))) + sys.argv[1:]
226 261 else:
227 262 # Find our own 'iptest' script OS-level entry point. Don't
228 263 # look system-wide, so we are sure we pick up *this one*. And
229 264 # pass through to subprocess call our own sys.argv
230 265 ippath = p.abspath(p.join(p.dirname(__file__),'..','..'))
231 266 script = p.join(ippath, 'iptest.py')
232 267 self.runner = tools.cmd2argv(script) + sys.argv[1:]
233 268
234 269 else:
235 270 # For trial, it needs to be installed system-wide
236 271 self.runner = tools.cmd2argv(p.abspath(find_cmd('trial')))
237 272 if params is None:
238 273 params = []
239 274 if isinstance(params, str):
240 275 params = [params]
241 276 self.params = params
242 277
243 278 # Assemble call
244 279 self.call_args = self.runner+self.params
245 280
246 281 # Store pids of anything we start to clean up on deletion, if possible
247 282 # (on posix only, since win32 has no os.kill)
248 283 self.pids = []
249 284
250 285 if sys.platform == 'win32':
251 286 def _run_cmd(self):
252 287 # On Windows, use os.system instead of subprocess.call, because I
253 288 # was having problems with subprocess and I just don't know enough
254 289 # about win32 to debug this reliably. Os.system may be the 'old
255 290 # fashioned' way to do it, but it works just fine. If someone
256 291 # later can clean this up that's fine, as long as the tests run
257 292 # reliably in win32.
258 293 return os.system(' '.join(self.call_args))
259 294 else:
260 295 def _run_cmd(self):
261 296 #print >> sys.stderr, '*** CMD:', ' '.join(self.call_args) # dbg
262 297 subp = subprocess.Popen(self.call_args)
263 298 self.pids.append(subp.pid)
264 299 # If this fails, the pid will be left in self.pids and cleaned up
265 300 # later, but if the wait call succeeds, then we can clear the
266 301 # stored pid.
267 302 retcode = subp.wait()
268 303 self.pids.pop()
269 304 return retcode
270 305
271 306 def run(self):
272 307 """Run the stored commands"""
273 308 try:
274 309 return self._run_cmd()
275 310 except:
276 311 import traceback
277 312 traceback.print_exc()
278 313 return 1 # signal failure
279 314
280 315 def __del__(self):
281 316 """Cleanup on exit by killing any leftover processes."""
282 317
283 318 if not hasattr(os, 'kill'):
284 319 return
285 320
286 321 for pid in self.pids:
287 322 try:
288 323 print 'Cleaning stale PID:', pid
289 324 os.kill(pid, signal.SIGKILL)
290 325 except OSError:
291 326 # This is just a best effort, if we fail or the process was
292 327 # really gone, ignore it.
293 328 pass
294 329
295 330
296 331 def make_runners():
297 332 """Define the top-level packages that need to be tested.
298 333 """
299 334
300 335 # Packages to be tested via nose, that only depend on the stdlib
301 336 nose_pkg_names = ['config', 'core', 'extensions', 'frontend', 'lib',
302 337 'scripts', 'testing', 'utils' ]
303 338 # The machinery in kernel needs twisted for real testing
304 339 trial_pkg_names = []
305 340
306 if have_wx:
341 if have['wx']:
307 342 nose_pkg_names.append('gui')
308 343
309 344 # And add twisted ones if conditions are met
310 if have_zi and have_twisted and have_foolscap:
345 if have['zope.interface'] and have['twisted'] and have['foolscap']:
311 346 # Note that we list the kernel here, though the bulk of it is
312 347 # twisted-based, because nose picks up doctests that twisted doesn't.
313 348 nose_pkg_names.append('kernel')
314 349 trial_pkg_names.append('kernel')
315 350
316 351 # For debugging this code, only load quick stuff
317 352 #nose_pkg_names = ['core', 'extensions'] # dbg
318 353 #trial_pkg_names = [] # dbg
319 354
320 355 # Make fully qualified package names prepending 'IPython.' to our name lists
321 356 nose_packages = ['IPython.%s' % m for m in nose_pkg_names ]
322 357 trial_packages = ['IPython.%s' % m for m in trial_pkg_names ]
323 358
324 359 # Make runners
325 360 runners = [ (v, IPTester('iptest', params=v)) for v in nose_packages ]
326 361 runners.extend([ (v, IPTester('trial', params=v)) for v in trial_packages ])
327 362
328 363 return runners
329 364
330 365
331 366 def run_iptest():
332 367 """Run the IPython test suite using nose.
333 368
334 369 This function is called when this script is **not** called with the form
335 370 `iptest all`. It simply calls nose with appropriate command line flags
336 371 and accepts all of the standard nose arguments.
337 372 """
338 373
339 374 warnings.filterwarnings('ignore',
340 375 'This will be removed soon. Use IPython.testing.util instead')
341 376
342 377 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
343 378
344 379 # Loading ipdoctest causes problems with Twisted, but
345 380 # our test suite runner now separates things and runs
346 381 # all Twisted tests with trial.
347 382 '--with-ipdoctest',
348 383 '--ipdoctest-tests','--ipdoctest-extension=txt',
349 384
350 385 # We add --exe because of setuptools' imbecility (it
351 386 # blindly does chmod +x on ALL files). Nose does the
352 387 # right thing and it tries to avoid executables,
353 388 # setuptools unfortunately forces our hand here. This
354 389 # has been discussed on the distutils list and the
355 390 # setuptools devs refuse to fix this problem!
356 391 '--exe',
357 392 ]
358 393
359 394 if nose.__version__ >= '0.11':
360 395 # I don't fully understand why we need this one, but depending on what
361 396 # directory the test suite is run from, if we don't give it, 0 tests
362 397 # get run. Specifically, if the test suite is run from the source dir
363 398 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
364 399 # even if the same call done in this directory works fine). It appears
365 400 # that if the requested package is in the current dir, nose bails early
366 401 # by default. Since it's otherwise harmless, leave it in by default
367 402 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
368 403 argv.append('--traverse-namespace')
369 404
370 405 # Construct list of plugins, omitting the existing doctest plugin, which
371 406 # ours replaces (and extends).
372 407 plugins = [IPythonDoctest(make_exclude())]
373 408 for p in nose.plugins.builtin.plugins:
374 409 plug = p()
375 410 if plug.name == 'doctest':
376 411 continue
377 412 plugins.append(plug)
378 413
379 414 # We need a global ipython running in this process
380 415 globalipapp.start_ipython()
381 416 # Now nose can run
382 417 TestProgram(argv=argv, plugins=plugins)
383 418
384 419
385 420 def run_iptestall():
386 421 """Run the entire IPython test suite by calling nose and trial.
387 422
388 423 This function constructs :class:`IPTester` instances for all IPython
389 424 modules and package and then runs each of them. This causes the modules
390 425 and packages of IPython to be tested each in their own subprocess using
391 426 nose or twisted.trial appropriately.
392 427 """
393 428
394 429 runners = make_runners()
395 430
396 431 # Run the test runners in a temporary dir so we can nuke it when finished
397 432 # to clean up any junk files left over by accident. This also makes it
398 433 # robust against being run in non-writeable directories by mistake, as the
399 434 # temp dir will always be user-writeable.
400 435 curdir = os.getcwd()
401 436 testdir = tempfile.gettempdir()
402 437 os.chdir(testdir)
403 438
404 439 # Run all test runners, tracking execution time
405 440 failed = []
406 441 t_start = time.time()
407 442 try:
408 443 for (name, runner) in runners:
409 444 print '*'*70
410 445 print 'IPython test group:',name
411 446 res = runner.run()
412 447 if res:
413 448 failed.append( (name, runner) )
414 449 finally:
415 450 os.chdir(curdir)
416 451 t_end = time.time()
417 452 t_tests = t_end - t_start
418 453 nrunners = len(runners)
419 454 nfail = len(failed)
420 455 # summarize results
421 456 print
422 457 print '*'*70
458 print 'Test suite completed for system with the following information:'
459 print report()
423 460 print 'Ran %s test groups in %.3fs' % (nrunners, t_tests)
424 461 print
462 print 'Status:'
425 463 if not failed:
426 464 print 'OK'
427 465 else:
428 466 # If anything went wrong, point out what command to rerun manually to
429 467 # see the actual errors and individual summary
430 468 print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners)
431 469 for name, failed_runner in failed:
432 470 print '-'*40
433 471 print 'Runner failed:',name
434 472 print 'You may wish to rerun this one individually, with:'
435 473 print ' '.join(failed_runner.call_args)
436 474 print
437 475
438 476
439 477 def main():
440 478 for arg in sys.argv[1:]:
441 479 if arg.startswith('IPython'):
442 480 # This is in-process
443 481 run_iptest()
444 482 else:
445 483 # This starts subprocesses
446 484 run_iptestall()
447 485
448 486
449 487 if __name__ == '__main__':
450 488 main()
@@ -1,372 +1,388 b''
1 1 .. _testing:
2 2
3 3 ==========================================
4 4 Testing IPython for users and developers
5 5 ==========================================
6 6
7 7 Overview
8 8 ========
9 9
10 10 It is extremely important that all code contributed to IPython has tests.
11 11 Tests should be written as unittests, doctests or other entities that the
12 12 IPython test system can detect. See below for more details on this.
13 13
14 14 Each subpackage in IPython should have its own :file:`tests` directory that
15 15 contains all of the tests for that subpackage. All of the files in the
16 16 :file:`tests` directory should have the word "tests" in them to enable
17 17 the testing framework to find them.
18 18
19 19 In docstrings, examples (either using IPython prompts like ``In [1]:`` or
20 20 'classic' python ``>>>`` ones) can and should be included. The testing system
21 21 will detect them as doctests and will run them; it offers control to skip parts
22 22 or all of a specific doctest if the example is meant to be informative but
23 23 shows non-reproducible information (like filesystem data).
24 24
25 25 If a subpackage has any dependencies beyond the Python standard library, the
26 26 tests for that subpackage should be skipped if the dependencies are not found.
27 27 This is very important so users don't get tests failing simply because they
28 28 don't have dependencies.
29 29
30 30 The testing system we use is a hybrid of nose_ and Twisted's trial_ test runner.
31 31 We use both because nose detects more things than Twisted and allows for more
32 32 flexible (and lighter-weight) ways of writing tests; in particular we've
33 33 developed a nose plugin that allows us to paste verbatim IPython sessions and
34 34 test them as doctests, which is extremely important for us. But the parts of
35 35 IPython that depend on Twisted must be tested using trial, because only trial
36 36 manages the Twisted reactor correctly.
37 37
38 38 .. _nose: http://code.google.com/p/python-nose
39 39 .. _trial: http://twistedmatrix.com/trac/wiki/TwistedTrial
40 40
41 41
42 42 For the impatient: running the tests
43 43 ====================================
44 44
45 45 You can run IPython from the source download directory without even installing
46 46 it system-wide or having configure anything, by typing at the terminal:
47 47
48 48 .. code-block:: bash
49 49
50 50 python ipython.py
51 51
52 52 and similarly, you can execute the built-in test suite with:
53 53
54 54 .. code-block:: bash
55 55
56 56 python iptest.py
57 57
58 58
59 59 This script manages intelligently both nose and trial, choosing the correct
60 60 test system for each of IPython's components.
61 61
62 62 Once you have either installed it or at least configured your system to be
63 63 able to import IPython, you can run the tests with:
64 64
65 65 .. code-block:: bash
66 66
67 67 python -c "import IPython; IPython.test()"
68 68
69 69 This should work as long as IPython can be imported, even if you haven't fully
70 70 installed the user-facing scripts yet (common in a development environment).
71 71 Once you have installed IPython, you will have available system-wide a script
72 72 called :file:`iptest` that does the exact same as the :file:`iptest.py` script
73 73 in the source directory, so you can then test simply with:
74 74
75 75 .. code-block:: bash
76 76
77 77 iptest [args]
78 78
79 79
80 80 Regardless of how you run things, you should eventually see something like:
81 81
82 82 .. code-block:: bash
83 83
84 84 **********************************************************************
85 Ran 11 test groups in 64.117s
85 Test suite completed for system with the following information:
86 IPython version: 0.11.bzr.r1340
87 BZR revision : 1340
88 Platform info : os.name -> posix, sys.platform -> linux2
89 : Linux-2.6.31-17-generic-i686-with-Ubuntu-9.10-karmic
90 Python info : 2.6.4 (r264:75706, Dec 7 2009, 18:45:15)
91 [GCC 4.4.1]
86 92
87 OK
93 Running from an installed IPython: True
94
95 Tools and libraries available at test time:
96 curses foolscap gobject gtk pexpect twisted wx wx.aui zope.interface
97
98 Tools and libraries NOT available at test time:
99 objc
88 100
101 Ran 11 test groups in 36.244s
102
103 Status:
104 OK
89 105
90 106 If not, there will be a message indicating which test group failed and how to
91 107 rerun that group individually. For example, this tests the
92 108 :mod:`IPython.utils` subpackage, the :option:`-v` option shows progress
93 109 indicators:
94 110
95 111 .. code-block:: bash
96 112
97 113 $ python iptest.py -v IPython.utils
98 114 ..........................SS..SSS............................S.S...
99 115 .........................................................
100 116 ----------------------------------------------------------------------
101 117 Ran 125 tests in 0.119s
102 118
103 119 OK (SKIP=7)
104 120
105 121
106 122 Because the IPython test machinery is based on nose, you can use all nose
107 123 options and syntax, typing ``iptest -h`` shows all available options. For
108 124 example, this lets you run the specific test :func:`test_rehashx` inside the
109 125 :mod:`test_magic` module:
110 126
111 127 .. code-block:: bash
112 128
113 129 $ python iptest.py -vv IPython.core.tests.test_magic:test_rehashx
114 130 IPython.core.tests.test_magic.test_rehashx(True,) ... ok
115 131 IPython.core.tests.test_magic.test_rehashx(True,) ... ok
116 132
117 133 ----------------------------------------------------------------------
118 134 Ran 2 tests in 0.100s
119 135
120 136 OK
121 137
122 138 When developing, the :option:`--pdb` and :option:`--pdb-failures` of nose are
123 139 particularly useful, these drop you into an interactive pdb session at the
124 140 point of the error or failure respectively.
125 141
126 142 To run Twisted-using tests, use the :command:`trial` command on a per file or
127 143 package basis:
128 144
129 145 .. code-block:: bash
130 146
131 147 trial IPython.kernel
132 148
133 149
134 150 For developers: writing tests
135 151 =============================
136 152
137 153 By now IPython has a reasonable test suite, so the best way to see what's
138 154 available is to look at the :file:`tests` directory in most subpackages. But
139 155 here are a few pointers to make the process easier.
140 156
141 157
142 158 Main tools: :mod:`IPython.testing`
143 159 ----------------------------------
144 160
145 161 The :mod:`IPython.testing` package is where all of the machinery to test
146 162 IPython (rather than the tests for its various parts) lives. In particular,
147 163 the :mod:`iptest` module in there has all the smarts to control the test
148 164 process. In there, the :func:`make_exclude` function is used to build a
149 165 blacklist of exclusions, these are modules that do not get even imported for
150 166 tests. This is important so that things that would fail to even import because
151 167 of missing dependencies don't give errors to end users, as we stated above.
152 168
153 169 The :mod:`decorators` module contains a lot of useful decorators, especially
154 170 useful to mark individual tests that should be skipped under certain conditions
155 171 (rather than blacklisting the package altogether because of a missing major
156 172 dependency).
157 173
158 174 Our nose plugin for doctests
159 175 ----------------------------
160 176
161 177 The :mod:`plugin` subpackage in testing contains a nose plugin called
162 178 :mod:`ipdoctest` that teaches nose about IPython syntax, so you can write
163 179 doctests with IPython prompts. You can also mark doctest output with ``#
164 180 random`` for the output corresponding to a single input to be ignored (stronger
165 181 than using ellipsis and useful to keep it as an example). If you want the
166 182 entire docstring to be executed but none of the output from any input to be
167 183 checked, you can use the ``# all-random`` marker. The
168 184 :mod:`IPython.testing.plugin.dtexample` module contains examples of how to use
169 185 these; for reference here is how to use ``# random``::
170 186
171 187 def ranfunc():
172 188 """A function with some random output.
173 189
174 190 Normal examples are verified as usual:
175 191 >>> 1+3
176 192 4
177 193
178 194 But if you put '# random' in the output, it is ignored:
179 195 >>> 1+3
180 196 junk goes here... # random
181 197
182 198 >>> 1+2
183 199 again, anything goes #random
184 200 if multiline, the random mark is only needed once.
185 201
186 202 >>> 1+2
187 203 You can also put the random marker at the end:
188 204 # random
189 205
190 206 >>> 1+2
191 207 # random
192 208 .. or at the beginning.
193 209
194 210 More correct input is properly verified:
195 211 >>> ranfunc()
196 212 'ranfunc'
197 213 """
198 214 return 'ranfunc'
199 215
200 216 and an example of ``# all-random``::
201 217
202 218 def random_all():
203 219 """A function where we ignore the output of ALL examples.
204 220
205 221 Examples:
206 222
207 223 # all-random
208 224
209 225 This mark tells the testing machinery that all subsequent examples
210 226 should be treated as random (ignoring their output). They are still
211 227 executed, so if a they raise an error, it will be detected as such,
212 228 but their output is completely ignored.
213 229
214 230 >>> 1+3
215 231 junk goes here...
216 232
217 233 >>> 1+3
218 234 klasdfj;
219 235
220 236 In [8]: print 'hello'
221 237 world # random
222 238
223 239 In [9]: iprand()
224 240 Out[9]: 'iprand'
225 241 """
226 242 return 'iprand'
227 243
228 244
229 245 When writing docstrings, you can use the ``@skip_doctest`` decorator to
230 246 indicate that a docstring should *not* be treated as a doctest at all. The
231 247 difference betwee ``# all-random`` and ``@skip_doctest`` is that the former
232 248 executes the example but ignores output, while the latter doesn't execute any
233 249 code. ``@skip_doctest`` should be used for docstrings whose examples are
234 250 purely informational.
235 251
236 252 If a given docstring fails under certain conditions but otherwise is a good
237 253 doctest, you can use code like the following, that relies on the 'null'
238 254 decorator to leave the docstring intact where it works as a test::
239 255
240 256 # The docstring for full_path doctests differently on win32 (different path
241 257 # separator) so just skip the doctest there, and use a null decorator
242 258 # elsewhere:
243 259
244 260 doctest_deco = dec.skip_doctest if sys.platform == 'win32' else dec.null_deco
245 261
246 262 @doctest_deco
247 263 def full_path(startPath,files):
248 264 """Make full paths for all the listed files, based on startPath..."""
249 265
250 266 # function body follows...
251 267
252 268 With our nose plugin that understands IPython syntax, an extremely effective
253 269 way to write tests is to simply copy and paste an interactive session into a
254 270 docstring. You can writing this type of test, where your docstring is meant
255 271 *only* as a test, by prefixing the function name with ``doctest_`` and leaving
256 272 its body *absolutely empty* other than the docstring. In
257 273 :mod:`IPython.core.tests.test_magic` you can find several examples of this, but
258 274 for completeness sake, your code should look like this (a simple case)::
259 275
260 276 def doctest_time():
261 277 """
262 278 In [10]: %time None
263 279 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
264 280 Wall time: 0.00 s
265 281 """
266 282
267 283 This function is only analyzed for its docstring but it is not considered a
268 284 separate test, which is why its body should be empty.
269 285
270 286
271 287 Parametric tests done right
272 288 ---------------------------
273 289
274 290 If you need to run multiple tests inside the same standalone function or method
275 291 of a :class:`unittest.TestCase` subclass, IPython provides the ``parametric``
276 292 decorator for this purpose. This is superior to how test generators work in
277 293 nose, because IPython's keeps intact your stack, which makes debugging vastly
278 294 easier. For example, these are some parametric tests both in class form and as
279 295 a standalone function (choose in each situation the style that best fits the
280 296 problem at hand, since both work)::
281 297
282 298 from IPython.testing import decorators as dec
283 299
284 300 def is_smaller(i,j):
285 301 assert i<j,"%s !< %s" % (i,j)
286 302
287 303 class Tester(ParametricTestCase):
288 304
289 305 def test_parametric(self):
290 306 yield is_smaller(3, 4)
291 307 x, y = 1, 2
292 308 yield is_smaller(x, y)
293 309
294 310 @dec.parametric
295 311 def test_par_standalone():
296 312 yield is_smaller(3, 4)
297 313 x, y = 1, 2
298 314 yield is_smaller(x, y)
299 315
300 316
301 317 Writing tests for Twisted-using code
302 318 ------------------------------------
303 319
304 320 Tests of Twisted [Twisted]_ using code should be written by subclassing the
305 321 ``TestCase`` class that comes with ``twisted.trial.unittest``. Furthermore, all
306 322 :class:`Deferred` instances that are created in the test must be properly
307 323 chained and the final one *must* be the return value of the test method.
308 324
309 325 .. note::
310 326
311 327 The best place to see how to use the testing tools, are the tests for these
312 328 tools themselves, which live in :mod:`IPython.testing.tests`.
313 329
314 330
315 331 Design requirements
316 332 ===================
317 333
318 334 This section is a set of notes on the key points of the IPython testing needs,
319 335 that were used when writing the system and should be kept for reference as it
320 336 eveolves.
321 337
322 338 Testing IPython in full requires modifications to the default behavior of nose
323 339 and doctest, because the IPython prompt is not recognized to determine Python
324 340 input, and because IPython admits user input that is not valid Python (things
325 341 like ``%magics`` and ``!system commands``.
326 342
327 343 We basically need to be able to test the following types of code:
328 344
329 345 1. Pure Python files containing normal tests. These are not a problem, since
330 346 Nose will pick them up as long as they conform to the (flexible) conventions
331 347 used by nose to recognize tests.
332 348
333 349 2. Python files containing doctests. Here, we have two possibilities:
334 350 - The prompts are the usual ``>>>`` and the input is pure Python.
335 351 - The prompts are of the form ``In [1]:`` and the input can contain extended
336 352 IPython expressions.
337 353
338 354 In the first case, Nose will recognize the doctests as long as it is called
339 355 with the ``--with-doctest`` flag. But the second case will likely require
340 356 modifications or the writing of a new doctest plugin for Nose that is
341 357 IPython-aware.
342 358
343 359 3. ReStructuredText files that contain code blocks. For this type of file, we
344 360 have three distinct possibilities for the code blocks:
345 361 - They use ``>>>`` prompts.
346 362 - They use ``In [1]:`` prompts.
347 363 - They are standalone blocks of pure Python code without any prompts.
348 364
349 365 The first two cases are similar to the situation #2 above, except that in
350 366 this case the doctests must be extracted from input code blocks using
351 367 docutils instead of from the Python docstrings.
352 368
353 369 In the third case, we must have a convention for distinguishing code blocks
354 370 that are meant for execution from others that may be snippets of shell code
355 371 or other examples not meant to be run. One possibility is to assume that
356 372 all indented code blocks are meant for execution, but to have a special
357 373 docutils directive for input that should not be executed.
358 374
359 375 For those code blocks that we will execute, the convention used will simply
360 376 be that they get called and are considered successful if they run to
361 377 completion without raising errors. This is similar to what Nose does for
362 378 standalone test functions, and by putting asserts or other forms of
363 379 exception-raising statements it becomes possible to have literate examples
364 380 that double as lightweight tests.
365 381
366 382 4. Extension modules with doctests in function and method docstrings.
367 383 Currently Nose simply can't find these docstrings correctly, because the
368 384 underlying doctest DocTestFinder object fails there. Similarly to #2 above,
369 385 the docstrings could have either pure python or IPython prompts.
370 386
371 387 Of these, only 3-c (reST with standalone code blocks) is not implemented at
372 388 this point.
General Comments 0
You need to be logged in to leave comments. Login now