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