##// END OF EJS Templates
Make it possible to run the tests from the source dir without installation....
Fernando Perez -
Show More
@@ -0,0 +1,17 b''
1 #!/usr/bin/env python
2 """Test script for IPython.
3
4 The actual ipython test script to be installed with 'python setup.py install'
5 is in './scripts' directory. This file is here (ipython source root directory)
6 to facilitate non-root 'zero-installation testing' (just copy the source tree
7 somewhere and run ipython.py) and development.
8
9 You can run this script directly, type -h to see all options."""
10
11 # Ensure that the imported IPython is the local one, not a system-wide one
12 import os, sys
13 this_dir = os.path.dirname(os.path.abspath(__file__))
14 sys.path.insert(0, this_dir)
15
16 # Now proceed with execution
17 execfile(os.path.join(this_dir, 'IPython', 'scripts', 'iptest'))
@@ -1,397 +1,415 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 26 import signal
27 27 import sys
28 28 import subprocess
29 29 import tempfile
30 30 import time
31 31 import warnings
32 32
33
34 # Ugly, but necessary hack to ensure the test suite finds our version of
35 # IPython and not a possibly different one that may exist system-wide.
36 # Note that this must be done here, so the imports that come next work
37 # correctly even if IPython isn't installed yet.
38 p = os.path
39 ippath = p.abspath(p.join(p.dirname(__file__),'..','..'))
40 sys.path.insert(0, ippath)
41 #print 'ipp:', ippath # dbg
42 #import IPython; print 'IP file:', IPython.__file__ # dbg
43
33 44 # Note: monkeypatch!
34 45 # We need to monkeypatch a small problem in nose itself first, before importing
35 46 # it for actual use. This should get into nose upstream, but its release cycle
36 47 # is slow and we need it for our parametric tests to work correctly.
37 48 from IPython.testing import nosepatch
38 49 # Now, proceed to import nose itself
39 50 import nose.plugins.builtin
40 51 from nose.core import TestProgram
41 52
42 53 # Our own imports
43 54 from IPython.utils import genutils
44 55 from IPython.utils.platutils import find_cmd, FindCmdError
45 56 from IPython.testing import globalipapp
46 57 from IPython.testing import tools
47 58 from IPython.testing.plugin.ipdoctest import IPythonDoctest
48 59
49 60 pjoin = path.join
50 61
51 62 #-----------------------------------------------------------------------------
52 63 # Warnings control
53 64 #-----------------------------------------------------------------------------
54 65 # Twisted generates annoying warnings with Python 2.6, as will do other code
55 66 # that imports 'sets' as of today
56 67 warnings.filterwarnings('ignore', 'the sets module is deprecated',
57 68 DeprecationWarning )
58 69
59 70 # This one also comes from Twisted
60 71 warnings.filterwarnings('ignore', 'the sha module is deprecated',
61 72 DeprecationWarning)
62 73
63 74 #-----------------------------------------------------------------------------
64 75 # Logic for skipping doctests
65 76 #-----------------------------------------------------------------------------
66 77
67 78 def test_for(mod):
68 79 """Test to see if mod is importable."""
69 80 try:
70 81 __import__(mod)
71 82 except ImportError:
72 83 return False
73 84 else:
74 85 return True
75 86
76 87
77 88 have_curses = test_for('_curses')
78 89 have_wx = test_for('wx')
79 90 have_wx_aui = test_for('wx.aui')
80 91 have_zi = test_for('zope.interface')
81 92 have_twisted = test_for('twisted')
82 93 have_foolscap = test_for('foolscap')
83 94 have_objc = test_for('objc')
84 95 have_pexpect = test_for('pexpect')
85 96 have_gtk = test_for('gtk')
86 97 have_gobject = test_for('gobject')
87 98
88 99
89 100 def make_exclude():
90 101 """Make patterns of modules and packages to exclude from testing.
91 102
92 103 For the IPythonDoctest plugin, we need to exclude certain patterns that
93 104 cause testing problems. We should strive to minimize the number of
94 105 skipped modules, since this means untested code. As the testing
95 106 machinery solidifies, this list should eventually become empty.
96 107 These modules and packages will NOT get scanned by nose at all for tests.
97 108 """
98 109 # Simple utility to make IPython paths more readably, we need a lot of
99 110 # these below
100 111 ipjoin = lambda *paths: pjoin('IPython', *paths)
101 112
102 113 exclusions = [ipjoin('external'),
103 114 ipjoin('frontend', 'process', 'winprocess.py'),
115 # Deprecated old Shell and iplib modules, skip to avoid
116 # warnings
117 ipjoin('Shell'),
118 ipjoin('iplib'),
104 119 pjoin('IPython_doctest_plugin'),
105 120 ipjoin('quarantine'),
106 121 ipjoin('deathrow'),
107 122 ipjoin('testing', 'attic'),
108 123 # This guy is probably attic material
109 124 ipjoin('testing', 'mkdoctests'),
110 125 # Testing inputhook will need a lot of thought, to figure out
111 126 # how to have tests that don't lock up with the gui event
112 127 # loops in the picture
113 128 ipjoin('lib', 'inputhook'),
114 129 # Config files aren't really importable stand-alone
115 130 ipjoin('config', 'default'),
116 131 ipjoin('config', 'profile'),
117 132 ]
118 133
119 134 if not have_wx:
120 135 exclusions.append(ipjoin('gui'))
121 136 exclusions.append(ipjoin('frontend', 'wx'))
122 137 exclusions.append(ipjoin('lib', 'inputhookwx'))
123 138
124 139 if not have_gtk or not have_gobject:
125 140 exclusions.append(ipjoin('lib', 'inputhookgtk'))
126 141
127 142 if not have_wx_aui:
128 143 exclusions.append(ipjoin('gui', 'wx', 'wxIPython'))
129 144
130 145 if not have_objc:
131 146 exclusions.append(ipjoin('frontend', 'cocoa'))
132 147
133 148 if not sys.platform == 'win32':
134 149 exclusions.append(ipjoin('utils', 'platutils_win32'))
135 150
136 151 # These have to be skipped on win32 because the use echo, rm, cd, etc.
137 152 # See ticket https://bugs.launchpad.net/bugs/366982
138 153 if sys.platform == 'win32':
139 154 exclusions.append(ipjoin('testing', 'plugin', 'test_exampleip'))
140 155 exclusions.append(ipjoin('testing', 'plugin', 'dtexample'))
141 156
142 157 if not os.name == 'posix':
143 158 exclusions.append(ipjoin('utils', 'platutils_posix'))
144 159
145 160 if not have_pexpect:
146 161 exclusions.extend([ipjoin('scripts', 'irunner'),
147 162 ipjoin('lib', 'irunner')])
148 163
149 164 # This is scary. We still have things in frontend and testing that
150 165 # are being tested by nose that use twisted. We need to rethink
151 166 # how we are isolating dependencies in testing.
152 167 if not (have_twisted and have_zi and have_foolscap):
153 168 exclusions.extend(
154 169 [ipjoin('frontend', 'asyncfrontendbase'),
155 170 ipjoin('frontend', 'prefilterfrontend'),
156 171 ipjoin('frontend', 'frontendbase'),
157 172 ipjoin('frontend', 'linefrontendbase'),
158 173 ipjoin('frontend', 'tests', 'test_linefrontend'),
159 174 ipjoin('frontend', 'tests', 'test_frontendbase'),
160 175 ipjoin('frontend', 'tests', 'test_prefilterfrontend'),
161 176 ipjoin('frontend', 'tests', 'test_asyncfrontendbase'),
162 177 ipjoin('testing', 'parametric'),
163 178 ipjoin('testing', 'util'),
164 179 ipjoin('testing', 'tests', 'test_decorators_trial'),
165 180 ] )
166 181
167 182 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
168 183 if sys.platform == 'win32':
169 184 exclusions = [s.replace('\\','\\\\') for s in exclusions]
170 185
171 186 return exclusions
172 187
173 188
174 189 #-----------------------------------------------------------------------------
175 190 # Functions and classes
176 191 #-----------------------------------------------------------------------------
177 192
178 193 class IPTester(object):
179 194 """Call that calls iptest or trial in a subprocess.
180 195 """
181 196 #: string, name of test runner that will be called
182 197 runner = None
183 198 #: list, parameters for test runner
184 199 params = None
185 200 #: list, arguments of system call to be made to call test runner
186 201 call_args = None
187 202 #: list, process ids of subprocesses we start (for cleanup)
188 203 pids = None
189 204
190 205 def __init__(self, runner='iptest', params=None):
191 206 """Create new test runner."""
192 207 if runner == 'iptest':
193 208 # Find our own 'iptest' script OS-level entry point. Don't look
194 209 # system-wide, so we are sure we pick up *this one*. And pass
195 210 # through to subprocess call our own sys.argv
196 self.runner = tools.cmd2argv(__file__) + sys.argv[1:]
211 self.runner = tools.cmd2argv(os.path.abspath(__file__)) + \
212 sys.argv[1:]
197 213 else:
198 214 self.runner = tools.cmd2argv(os.path.abspath(find_cmd('trial')))
199 215 if params is None:
200 216 params = []
201 217 if isinstance(params, str):
202 218 params = [params]
203 219 self.params = params
204 220
205 221 # Assemble call
206 222 self.call_args = self.runner+self.params
207 223
208 224 # Store pids of anything we start to clean up on deletion, if possible
209 225 # (on posix only, since win32 has no os.kill)
210 226 self.pids = []
211 227
212 228 if sys.platform == 'win32':
213 229 def _run_cmd(self):
214 230 # On Windows, use os.system instead of subprocess.call, because I
215 231 # was having problems with subprocess and I just don't know enough
216 232 # about win32 to debug this reliably. Os.system may be the 'old
217 233 # fashioned' way to do it, but it works just fine. If someone
218 234 # later can clean this up that's fine, as long as the tests run
219 235 # reliably in win32.
220 236 return os.system(' '.join(self.call_args))
221 237 else:
222 238 def _run_cmd(self):
223 239 subp = subprocess.Popen(self.call_args)
224 240 self.pids.append(subp.pid)
225 241 # If this fails, the pid will be left in self.pids and cleaned up
226 242 # later, but if the wait call succeeds, then we can clear the
227 243 # stored pid.
228 244 retcode = subp.wait()
229 245 self.pids.pop()
230 246 return retcode
231 247
232 248 def run(self):
233 249 """Run the stored commands"""
234 250 try:
235 251 return self._run_cmd()
236 252 except:
237 253 import traceback
238 254 traceback.print_exc()
239 255 return 1 # signal failure
240 256
241 257 def __del__(self):
242 258 """Cleanup on exit by killing any leftover processes."""
243 259
244 260 if not hasattr(os, 'kill'):
245 261 return
246 262
247 263 for pid in self.pids:
248 264 try:
249 265 print 'Cleaning stale PID:', pid
250 266 os.kill(pid, signal.SIGKILL)
251 267 except OSError:
252 268 # This is just a best effort, if we fail or the process was
253 269 # really gone, ignore it.
254 270 pass
255 271
256 272
257 273 def make_runners():
258 274 """Define the top-level packages that need to be tested.
259 275 """
260 276
261 277 nose_packages = ['config', 'core', 'extensions', 'frontend', 'lib',
262 278 'scripts', 'testing', 'utils',
263 279 # Note that we list the kernel here, though the bulk of it
264 280 # is twisted-based, because nose picks up doctests that
265 281 # twisted doesn't.
266 282 'kernel']
267 283 # The machinery in kernel needs twisted for real testing
268 284 trial_packages = ['kernel']
269 285
270 286 if have_wx:
271 287 nose_packages.append('gui')
272 288
273 289 #nose_packages = ['config', 'utils'] # dbg
274 290 #trial_packages = [] # dbg
275 291
276 292 nose_packages = ['IPython.%s' % m for m in nose_packages ]
277 293 trial_packages = ['IPython.%s' % m for m in trial_packages ]
278 294
279 295 # Make runners, most with nose
280 296 nose_testers = [IPTester(params=v) for v in nose_packages]
281 297 runners = zip(nose_packages, nose_testers)
282 298
283 299 # And add twisted ones if conditions are met
284 300 if have_zi and have_twisted and have_foolscap:
285 301 trial_testers = [IPTester('trial', params=v) for v in trial_packages]
286 302 runners.extend(zip(trial_packages, trial_testers))
287 303
288 304 return runners
289 305
290 306
291 307 def run_iptest():
292 308 """Run the IPython test suite using nose.
293 309
294 310 This function is called when this script is **not** called with the form
295 311 `iptest all`. It simply calls nose with appropriate command line flags
296 312 and accepts all of the standard nose arguments.
297 313 """
298 314
299 315 warnings.filterwarnings('ignore',
300 316 'This will be removed soon. Use IPython.testing.util instead')
301 317
302 318 argv = sys.argv + [ '--detailed-errors',
303 319 # Loading ipdoctest causes problems with Twisted, but
304 320 # our test suite runner now separates things and runs
305 321 # all Twisted tests with trial.
306 322 '--with-ipdoctest',
307 323 '--ipdoctest-tests','--ipdoctest-extension=txt',
308 324
309 325 # We add --exe because of setuptools' imbecility (it
310 326 # blindly does chmod +x on ALL files). Nose does the
311 327 # right thing and it tries to avoid executables,
312 328 # setuptools unfortunately forces our hand here. This
313 329 # has been discussed on the distutils list and the
314 330 # setuptools devs refuse to fix this problem!
315 331 '--exe',
316 332 ]
317 333
318 334
319 335 # Construct list of plugins, omitting the existing doctest plugin, which
320 336 # ours replaces (and extends).
321 337 plugins = [IPythonDoctest(make_exclude())]
322 338 for p in nose.plugins.builtin.plugins:
323 339 plug = p()
324 340 if plug.name == 'doctest':
325 341 continue
326 342 plugins.append(plug)
327 343
328 344 # We need a global ipython running in this process
329 345 globalipapp.start_ipython()
330 346 # Now nose can run
331 347 TestProgram(argv=argv, plugins=plugins)
332 348
333 349
334 350 def run_iptestall():
335 351 """Run the entire IPython test suite by calling nose and trial.
336 352
337 353 This function constructs :class:`IPTester` instances for all IPython
338 354 modules and package and then runs each of them. This causes the modules
339 355 and packages of IPython to be tested each in their own subprocess using
340 356 nose or twisted.trial appropriately.
341 357 """
342 358
343 359 runners = make_runners()
344 360
345 361 # Run the test runners in a temporary dir so we can nuke it when finished
346 362 # to clean up any junk files left over by accident. This also makes it
347 363 # robust against being run in non-writeable directories by mistake, as the
348 364 # temp dir will always be user-writeable.
349 365 curdir = os.getcwd()
350 366 testdir = tempfile.gettempdir()
351 367 os.chdir(testdir)
352 368
353 369 # Run all test runners, tracking execution time
354 370 failed = []
355 371 t_start = time.time()
356 372 try:
357 373 for (name, runner) in runners:
358 374 print '*'*70
359 375 print 'IPython test group:',name
360 376 res = runner.run()
361 377 if res:
362 378 failed.append( (name, runner) )
363 379 finally:
364 380 os.chdir(curdir)
365 381 t_end = time.time()
366 382 t_tests = t_end - t_start
367 383 nrunners = len(runners)
368 384 nfail = len(failed)
369 385 # summarize results
370 386 print
371 387 print '*'*70
372 388 print 'Ran %s test groups in %.3fs' % (nrunners, t_tests)
373 389 print
374 390 if not failed:
375 391 print 'OK'
376 392 else:
377 393 # If anything went wrong, point out what command to rerun manually to
378 394 # see the actual errors and individual summary
379 395 print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners)
380 396 for name, failed_runner in failed:
381 397 print '-'*40
382 398 print 'Runner failed:',name
383 399 print 'You may wish to rerun this one individually, with:'
384 400 print ' '.join(failed_runner.call_args)
385 401 print
386 402
387 403
388 404 def main():
389 405 for arg in sys.argv[1:]:
390 406 if arg.startswith('IPython'):
407 # This is in-process
391 408 run_iptest()
392 409 else:
410 # This starts subprocesses
393 411 run_iptestall()
394 412
395 413
396 414 if __name__ == '__main__':
397 415 main()
@@ -1,315 +1,317 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 from __future__ import absolute_import
29 29
30 30 import os
31 31 import re
32 32 import sys
33 33 import tempfile
34 34
35 35 try:
36 36 # These tools are used by parts of the runtime, so we make the nose
37 37 # dependency optional at this point. Nose is a hard dependency to run the
38 38 # test suite, but NOT to use ipython itself.
39 39 import nose.tools as nt
40 40 has_nose = True
41 41 except ImportError:
42 42 has_nose = False
43 43
44 44 from IPython.utils import genutils, platutils
45 45
46 46 from . import decorators as dec
47 47
48 48 #-----------------------------------------------------------------------------
49 49 # Globals
50 50 #-----------------------------------------------------------------------------
51 51
52 52 # Make a bunch of nose.tools assert wrappers that can be used in test
53 53 # generators. This will expose an assert* function for each one in nose.tools.
54 54
55 55 _tpl = """
56 56 def %(name)s(*a,**kw):
57 57 return nt.%(name)s(*a,**kw)
58 58 """
59 59
60 60 if has_nose:
61 61 for _x in [a for a in dir(nt) if a.startswith('assert')]:
62 62 exec _tpl % dict(name=_x)
63 63
64 64 #-----------------------------------------------------------------------------
65 65 # Functions and classes
66 66 #-----------------------------------------------------------------------------
67 67
68 68 # The docstring for full_path doctests differently on win32 (different path
69 69 # separator) so just skip the doctest there. The example remains informative.
70 70 doctest_deco = dec.skip_doctest if sys.platform == 'win32' else dec.null_deco
71 71
72 72 @doctest_deco
73 73 def full_path(startPath,files):
74 74 """Make full paths for all the listed files, based on startPath.
75 75
76 76 Only the base part of startPath is kept, since this routine is typically
77 77 used with a script's __file__ variable as startPath. The base of startPath
78 78 is then prepended to all the listed files, forming the output list.
79 79
80 80 Parameters
81 81 ----------
82 82 startPath : string
83 83 Initial path to use as the base for the results. This path is split
84 84 using os.path.split() and only its first component is kept.
85 85
86 86 files : string or list
87 87 One or more files.
88 88
89 89 Examples
90 90 --------
91 91
92 92 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
93 93 ['/foo/a.txt', '/foo/b.txt']
94 94
95 95 >>> full_path('/foo',['a.txt','b.txt'])
96 96 ['/a.txt', '/b.txt']
97 97
98 98 If a single file is given, the output is still a list:
99 99 >>> full_path('/foo','a.txt')
100 100 ['/a.txt']
101 101 """
102 102
103 103 files = genutils.list_strings(files)
104 104 base = os.path.split(startPath)[0]
105 105 return [ os.path.join(base,f) for f in files ]
106 106
107 107
108 108 def parse_test_output(txt):
109 109 """Parse the output of a test run and return errors, failures.
110 110
111 111 Parameters
112 112 ----------
113 113 txt : str
114 114 Text output of a test run, assumed to contain a line of one of the
115 115 following forms::
116 116 'FAILED (errors=1)'
117 117 'FAILED (failures=1)'
118 118 'FAILED (errors=1, failures=1)'
119 119
120 120 Returns
121 121 -------
122 122 nerr, nfail: number of errors and failures.
123 123 """
124 124
125 125 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
126 126 if err_m:
127 127 nerr = int(err_m.group(1))
128 128 nfail = 0
129 129 return nerr, nfail
130 130
131 131 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
132 132 if fail_m:
133 133 nerr = 0
134 134 nfail = int(fail_m.group(1))
135 135 return nerr, nfail
136 136
137 137 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
138 138 re.MULTILINE)
139 139 if both_m:
140 140 nerr = int(both_m.group(1))
141 141 nfail = int(both_m.group(2))
142 142 return nerr, nfail
143 143
144 144 # If the input didn't match any of these forms, assume no error/failures
145 145 return 0, 0
146 146
147 147
148 148 # So nose doesn't think this is a test
149 149 parse_test_output.__test__ = False
150 150
151 151
152 152 def cmd2argv(cmd):
153 153 r"""Take the path of a command and return a list (argv-style).
154 154
155 155 For a given path ``cmd``, this returns [cmd] if cmd's extension is .exe,
156 156 .com or .bat, and ['python', cmd] otherwise.
157 157
158 158 This is mostly a Windows utility, to deal with the fact that the scripts in
159 159 Windows get wrapped in .exe entry points, so we have to call them
160 160 differently.
161 161
162 162 Parameters
163 163 ----------
164 164 cmd : string
165 165 The path of the command.
166 166
167 167 Returns
168 168 -------
169 169 argv-style list.
170 170
171 171 Examples
172 172 --------
173 173 In [2]: cmd2argv('/usr/bin/ipython')
174 174 Out[2]: ['python', '/usr/bin/ipython']
175 175
176 176 In [3]: cmd2argv(r'C:\Python26\Scripts\ipython.exe')
177 177 Out[3]: ['C:\\Python26\\Scripts\\ipython.exe']
178 178 """
179 179 ext = os.path.splitext(cmd)[1]
180 180 if ext in ['.exe', '.com', '.bat']:
181 181 return [cmd]
182 182 else:
183 183 return ['python', cmd]
184 184
185 185
186 186 def temp_pyfile(src, ext='.py'):
187 187 """Make a temporary python file, return filename and filehandle.
188 188
189 189 Parameters
190 190 ----------
191 191 src : string or list of strings (no need for ending newlines if list)
192 192 Source code to be written to the file.
193 193
194 194 ext : optional, string
195 195 Extension for the generated file.
196 196
197 197 Returns
198 198 -------
199 199 (filename, open filehandle)
200 200 It is the caller's responsibility to close the open file and unlink it.
201 201 """
202 202 fname = tempfile.mkstemp(ext)[1]
203 203 f = open(fname,'w')
204 204 f.write(src)
205 205 f.flush()
206 206 return fname, f
207 207
208 208
209 209 def default_argv():
210 210 """Return a valid default argv for creating testing instances of ipython"""
211 211
212 212 return ['--quick', # so no config file is loaded
213 213 # Other defaults to minimize side effects on stdout
214 214 '--colors=NoColor', '--no-term-title','--no-banner',
215 215 '--autocall=0']
216 216
217 217
218 218 def ipexec(fname, options=None):
219 219 """Utility to call 'ipython filename'.
220 220
221 221 Starts IPython witha minimal and safe configuration to make startup as fast
222 222 as possible.
223 223
224 224 Note that this starts IPython in a subprocess!
225 225
226 226 Parameters
227 227 ----------
228 228 fname : str
229 229 Name of file to be executed (should have .py or .ipy extension).
230 230
231 231 options : optional, list
232 232 Extra command-line flags to be passed to IPython.
233 233
234 234 Returns
235 235 -------
236 236 (stdout, stderr) of ipython subprocess.
237 237 """
238 238 if options is None: options = []
239 239
240 240 # For these subprocess calls, eliminate all prompt printing so we only see
241 241 # output from script execution
242 242 prompt_opts = ['--prompt-in1=""', '--prompt-in2=""', '--prompt-out=""']
243 243 cmdargs = ' '.join(default_argv() + prompt_opts + options)
244 244
245 245 _ip = get_ipython()
246 246 test_dir = os.path.dirname(__file__)
247
247 248 # Find the ipython script from the package we're using, so that the test
248 249 # suite can be run from the source tree without an installed IPython
249 ipython_package_dir = genutils.get_ipython_package_dir()
250 ipython_script = os.path.join(ipython_package_dir,'scripts','ipython')
250 p = os.path
251 ippath = p.abspath(p.join(p.dirname(__file__),'..','..'))
252 ipython_script = p.join(ippath, 'ipython.py')
251 253 ipython_cmd = 'python "%s"' % ipython_script
252 254 # Absolute path for filename
253 full_fname = os.path.join(test_dir, fname)
255 full_fname = p.join(test_dir, fname)
254 256 full_cmd = '%s %s "%s"' % (ipython_cmd, cmdargs, full_fname)
255 257 return genutils.getoutputerror(full_cmd)
256 258
257 259
258 260 def ipexec_validate(fname, expected_out, expected_err=None,
259 261 options=None):
260 262 """Utility to call 'ipython filename' and validate output/error.
261 263
262 264 This function raises an AssertionError if the validation fails.
263 265
264 266 Note that this starts IPython in a subprocess!
265 267
266 268 Parameters
267 269 ----------
268 270 fname : str
269 271 Name of the file to be executed (should have .py or .ipy extension).
270 272
271 273 expected_out : str
272 274 Expected stdout of the process.
273 275
274 276 expected_err : optional, str
275 277 Expected stderr of the process.
276 278
277 279 options : optional, list
278 280 Extra command-line flags to be passed to IPython.
279 281
280 282 Returns
281 283 -------
282 284 None
283 285 """
284 286
285 287 import nose.tools as nt
286 288
287 289 out, err = ipexec(fname)
288 290 nt.assert_equals(out.strip(), expected_out.strip())
289 291 if expected_err:
290 292 nt.assert_equals(err.strip(), expected_err.strip())
291 293
292 294
293 295 class TempFileMixin(object):
294 296 """Utility class to create temporary Python/IPython files.
295 297
296 298 Meant as a mixin class for test cases."""
297 299
298 300 def mktmp(self, src, ext='.py'):
299 301 """Make a valid python temp file."""
300 302 fname, f = temp_pyfile(src, ext)
301 303 self.tmpfile = f
302 304 self.fname = fname
303 305
304 306 def teardown(self):
305 307 if hasattr(self, 'tmpfile'):
306 308 # If the tmpfile wasn't made because of skipped tests, like in
307 309 # win32, there's nothing to cleanup.
308 310 self.tmpfile.close()
309 311 try:
310 312 os.unlink(self.fname)
311 313 except:
312 314 # On Windows, even though we close the file, we still can't
313 315 # delete it. I have no clue why
314 316 pass
315 317
@@ -1,11 +1,29 b''
1 1 ==============
2 2 IPython README
3 3 ==============
4 4
5 5 Overview
6 6 ========
7 7
8 Welcome to IPython. Our documentation can be found in the docs/source
9 subdirectory. We also have ``.html`` and ``.pdf`` versions of this
10 documentation available on the IPython `website <http://ipython.scipy.org>`_.
8 Welcome to IPython. Our full documentation can be found in the ``docs/dist``
9 subdirectory in ``.html`` and ``.pdf`` formats, also available online at our
10 `website <http://ipython.scipy.org>`_. The ``docs/source`` directory contains
11 the plaintext version of these manuals.
11 12
13
14 Instant running and testing
15 ===========================
16
17 You can run IPython from this directory without even installing it system-wide
18 by typing at the terminal:
19
20 .. code-block:: bash
21
22 python ipython.py
23
24 and similarly, you can execute the built-in test suite with:
25
26 .. code-block:: bash
27
28 python iptest.py
29 No newline at end of file
@@ -1,355 +1,372 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 The simplest way to test IPython is to type at the command line:
45 You can run IPython from the source download directory without even installing
46 it system-wide or having configure anything, by typing at the terminal:
47
48 .. code-block:: bash
49
50 python ipython.py
51
52 and similarly, you can execute the built-in test suite with:
53
54 .. code-block:: bash
55
56 python iptest.py
57
58
59 Once you have either installed it or at least configured your system to be
60 able to import IPython, you can run the tests with:
46 61
47 62 .. code-block:: bash
48 63
49 64 python -c "import IPython; IPython.test()"
50 65
51 66 This should work as long as IPython can be imported, even if you haven't fully
52 67 installed the user-facing scripts yet (common in a development environment).
53 After a lot of output, you should see something like:
68
69
70 Regardless of how you run things, you should eventually see something like:
54 71
55 72 .. code-block:: bash
56 73
57 74 ************************************************************************
58 75 Ran 10 test groups in 35.228s
59 76
60 77 OK
61 78
62 79 If not, there will be a message indicating which test group failed and how to
63 80 rerun that group individually.
64 81
65 82 But IPython ships with an entry point script called :file:`iptest` that offers
66 83 fine-grain control over the test process and is particularly useful for
67 84 developers; this script also manages intelligently both nose and trial,
68 85 choosing the correct test system for each of IPython's components. Running
69 86 :file:`iptest` without arguments gives output identical to that above, but with
70 87 it, you can also run specific tests with fine control. The :file:`iptest`
71 88 script is installed with IPython, but if you are running from a source tree,
72 89 you can find it in the :file:`IPython/scripts` directory and you can run
73 90 directly from there.
74 91
75 92 For example, this tests the :mod:`IPython.utils` subpackage, the :option:`-v`
76 93 option shows progress indicators:
77 94
78 95 .. code-block:: bash
79 96
80 97 maqroll[ipython]> cd IPython/scripts/
81 98 maqroll[scripts]> ./iptest -v IPython.utils
82 99 ..........................SS..SSS............................S.S.........
83 100 ...................................................
84 101 ----------------------------------------------------------------------
85 102 Ran 125 tests in 0.070s
86 103
87 104 OK (SKIP=7)
88 105
89 106 Because :file:`iptest` is based on nose, you can use all nose options and
90 107 syntax, typing ``iptest -h`` shows all available options. For example, this
91 108 lets you run the specific test :func:`test_rehashx` inside the
92 109 :mod:`test_magic` module:
93 110
94 111 .. code-block:: bash
95 112
96 113 maqroll[scripts]> ./iptest -vv IPython.core.tests.test_magic:test_rehashx
97 114 IPython.core.tests.test_magic.test_rehashx(True,) ... ok
98 115 IPython.core.tests.test_magic.test_rehashx(True,) ... ok
99 116
100 117 ----------------------------------------------------------------------
101 118 Ran 2 tests in 0.101s
102 119
103 120 OK
104 121
105 122 When developing, the :option:`--pdb` and :option:`--pdb-failures` of nose are
106 123 particularly useful, these drop you into an interactive pdb session at the
107 124 point of the error or failure respectively.
108 125
109 126 To run Twisted-using tests, use the :command:`trial` command on a per file or
110 127 package basis:
111 128
112 129 .. code-block:: bash
113 130
114 131 trial IPython.kernel
115 132
116 133
117 134 For developers: writing tests
118 135 =============================
119 136
120 137 By now IPython has a reasonable test suite, so the best way to see what's
121 138 available is to look at the :file:`tests` directory in most subpackages. But
122 139 here are a few pointers to make the process easier.
123 140
124 141
125 142 Main tools: :mod:`IPython.testing`
126 143 ----------------------------------
127 144
128 145 The :mod:`IPython.testing` package is where all of the machinery to test
129 146 IPython (rather than the tests for its various parts) lives. In particular,
130 147 the :mod:`iptest` module in there has all the smarts to control the test
131 148 process. In there, the :func:`make_exclude` function is used to build a
132 149 blacklist of exclusions, these are modules that do not get even imported for
133 150 tests. This is important so that things that would fail to even import because
134 151 of missing dependencies don't give errors to end users, as we stated above.
135 152
136 153 The :mod:`decorators` module contains a lot of useful decorators, especially
137 154 useful to mark individual tests that should be skipped under certain conditions
138 155 (rather than blacklisting the package altogether because of a missing major
139 156 dependency).
140 157
141 158 Our nose plugin for doctests
142 159 ----------------------------
143 160
144 161 The :mod:`plugin` subpackage in testing contains a nose plugin called
145 162 :mod:`ipdoctest` that teaches nose about IPython syntax, so you can write
146 163 doctests with IPython prompts. You can also mark doctest output with ``#
147 164 random`` for the output corresponding to a single input to be ignored (stronger
148 165 than using ellipsis and useful to keep it as an example). If you want the
149 166 entire docstring to be executed but none of the output from any input to be
150 167 checked, you can use the ``# all-random`` marker. The
151 168 :mod:`IPython.testing.plugin.dtexample` module contains examples of how to use
152 169 these; for reference here is how to use ``# random``::
153 170
154 171 def ranfunc():
155 172 """A function with some random output.
156 173
157 174 Normal examples are verified as usual:
158 175 >>> 1+3
159 176 4
160 177
161 178 But if you put '# random' in the output, it is ignored:
162 179 >>> 1+3
163 180 junk goes here... # random
164 181
165 182 >>> 1+2
166 183 again, anything goes #random
167 184 if multiline, the random mark is only needed once.
168 185
169 186 >>> 1+2
170 187 You can also put the random marker at the end:
171 188 # random
172 189
173 190 >>> 1+2
174 191 # random
175 192 .. or at the beginning.
176 193
177 194 More correct input is properly verified:
178 195 >>> ranfunc()
179 196 'ranfunc'
180 197 """
181 198 return 'ranfunc'
182 199
183 200 and an example of ``# all-random``::
184 201
185 202 def random_all():
186 203 """A function where we ignore the output of ALL examples.
187 204
188 205 Examples:
189 206
190 207 # all-random
191 208
192 209 This mark tells the testing machinery that all subsequent examples
193 210 should be treated as random (ignoring their output). They are still
194 211 executed, so if a they raise an error, it will be detected as such,
195 212 but their output is completely ignored.
196 213
197 214 >>> 1+3
198 215 junk goes here...
199 216
200 217 >>> 1+3
201 218 klasdfj;
202 219
203 220 In [8]: print 'hello'
204 221 world # random
205 222
206 223 In [9]: iprand()
207 224 Out[9]: 'iprand'
208 225 """
209 226 return 'iprand'
210 227
211 228
212 229 When writing docstrings, you can use the ``@skip_doctest`` decorator to
213 230 indicate that a docstring should *not* be treated as a doctest at all. The
214 231 difference betwee ``# all-random`` and ``@skip_doctest`` is that the former
215 232 executes the example but ignores output, while the latter doesn't execute any
216 233 code. ``@skip_doctest`` should be used for docstrings whose examples are
217 234 purely informational.
218 235
219 236 If a given docstring fails under certain conditions but otherwise is a good
220 237 doctest, you can use code like the following, that relies on the 'null'
221 238 decorator to leave the docstring intact where it works as a test::
222 239
223 240 # The docstring for full_path doctests differently on win32 (different path
224 241 # separator) so just skip the doctest there, and use a null decorator
225 242 # elsewhere:
226 243
227 244 doctest_deco = dec.skip_doctest if sys.platform == 'win32' else dec.null_deco
228 245
229 246 @doctest_deco
230 247 def full_path(startPath,files):
231 248 """Make full paths for all the listed files, based on startPath..."""
232 249
233 250 # function body follows...
234 251
235 252 With our nose plugin that understands IPython syntax, an extremely effective
236 253 way to write tests is to simply copy and paste an interactive session into a
237 254 docstring. You can writing this type of test, where your docstring is meant
238 255 *only* as a test, by prefixing the function name with ``doctest_`` and leaving
239 256 its body *absolutely empty* other than the docstring. In
240 257 :mod:`IPython.core.tests.test_magic` you can find several examples of this, but
241 258 for completeness sake, your code should look like this (a simple case)::
242 259
243 260 def doctest_time():
244 261 """
245 262 In [10]: %time None
246 263 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
247 264 Wall time: 0.00 s
248 265 """
249 266
250 267 This function is only analyzed for its docstring but it is not considered a
251 268 separate test, which is why its body should be empty.
252 269
253 270
254 271 Parametric tests done right
255 272 ---------------------------
256 273
257 274 If you need to run multiple tests inside the same standalone function or method
258 275 of a :class:`unittest.TestCase` subclass, IPython provides the ``parametric``
259 276 decorator for this purpose. This is superior to how test generators work in
260 277 nose, because IPython's keeps intact your stack, which makes debugging vastly
261 278 easier. For example, these are some parametric tests both in class form and as
262 279 a standalone function (choose in each situation the style that best fits the
263 280 problem at hand, since both work)::
264 281
265 282 from IPython.testing import decorators as dec
266 283
267 284 def is_smaller(i,j):
268 285 assert i<j,"%s !< %s" % (i,j)
269 286
270 287 class Tester(ParametricTestCase):
271 288
272 289 def test_parametric(self):
273 290 yield is_smaller(3, 4)
274 291 x, y = 1, 2
275 292 yield is_smaller(x, y)
276 293
277 294 @dec.parametric
278 295 def test_par_standalone():
279 296 yield is_smaller(3, 4)
280 297 x, y = 1, 2
281 298 yield is_smaller(x, y)
282 299
283 300
284 301 Writing tests for Twisted-using code
285 302 ------------------------------------
286 303
287 304 Tests of Twisted [Twisted]_ using code should be written by subclassing the
288 305 ``TestCase`` class that comes with ``twisted.trial.unittest``. Furthermore, all
289 306 :class:`Deferred` instances that are created in the test must be properly
290 307 chained and the final one *must* be the return value of the test method.
291 308
292 309 .. note::
293 310
294 311 The best place to see how to use the testing tools, are the tests for these
295 312 tools themselves, which live in :mod:`IPython.testing.tests`.
296 313
297 314
298 315 Design requirements
299 316 ===================
300 317
301 318 This section is a set of notes on the key points of the IPython testing needs,
302 319 that were used when writing the system and should be kept for reference as it
303 320 eveolves.
304 321
305 322 Testing IPython in full requires modifications to the default behavior of nose
306 323 and doctest, because the IPython prompt is not recognized to determine Python
307 324 input, and because IPython admits user input that is not valid Python (things
308 325 like ``%magics`` and ``!system commands``.
309 326
310 327 We basically need to be able to test the following types of code:
311 328
312 329 1. Pure Python files containing normal tests. These are not a problem, since
313 330 Nose will pick them up as long as they conform to the (flexible) conventions
314 331 used by nose to recognize tests.
315 332
316 333 2. Python files containing doctests. Here, we have two possibilities:
317 334 - The prompts are the usual ``>>>`` and the input is pure Python.
318 335 - The prompts are of the form ``In [1]:`` and the input can contain extended
319 336 IPython expressions.
320 337
321 338 In the first case, Nose will recognize the doctests as long as it is called
322 339 with the ``--with-doctest`` flag. But the second case will likely require
323 340 modifications or the writing of a new doctest plugin for Nose that is
324 341 IPython-aware.
325 342
326 343 3. ReStructuredText files that contain code blocks. For this type of file, we
327 344 have three distinct possibilities for the code blocks:
328 345 - They use ``>>>`` prompts.
329 346 - They use ``In [1]:`` prompts.
330 347 - They are standalone blocks of pure Python code without any prompts.
331 348
332 349 The first two cases are similar to the situation #2 above, except that in
333 350 this case the doctests must be extracted from input code blocks using
334 351 docutils instead of from the Python docstrings.
335 352
336 353 In the third case, we must have a convention for distinguishing code blocks
337 354 that are meant for execution from others that may be snippets of shell code
338 355 or other examples not meant to be run. One possibility is to assume that
339 356 all indented code blocks are meant for execution, but to have a special
340 357 docutils directive for input that should not be executed.
341 358
342 359 For those code blocks that we will execute, the convention used will simply
343 360 be that they get called and are considered successful if they run to
344 361 completion without raising errors. This is similar to what Nose does for
345 362 standalone test functions, and by putting asserts or other forms of
346 363 exception-raising statements it becomes possible to have literate examples
347 364 that double as lightweight tests.
348 365
349 366 4. Extension modules with doctests in function and method docstrings.
350 367 Currently Nose simply can't find these docstrings correctly, because the
351 368 underlying doctest DocTestFinder object fails there. Similarly to #2 above,
352 369 the docstrings could have either pure python or IPython prompts.
353 370
354 371 Of these, only 3-c (reST with standalone code blocks) is not implemented at
355 372 this point.
@@ -1,12 +1,16 b''
1 1 #!/usr/bin/env python
2 2 # -*- coding: utf-8 -*-
3 3 """IPython -- An enhanced Interactive Python
4 4
5 5 The actual ipython script to be installed with 'python setup.py install' is
6 6 in './scripts' directory. This file is here (ipython source root directory)
7 7 to facilitate non-root 'zero-installation' (just copy the source tree
8 8 somewhere and run ipython.py) and development. """
9 9
10 from IPython.core.ipapp import launch_new_instance
10 # Ensure that the imported IPython is the local one, not a system-wide one
11 import os, sys
12 this_dir = os.path.dirname(os.path.abspath(__file__))
13 sys.path.insert(0, this_dir)
11 14
12 launch_new_instance()
15 # Now proceed with execution
16 execfile(os.path.join(this_dir, 'IPython', 'scripts', 'ipython'))
General Comments 0
You need to be logged in to leave comments. Login now