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