##// END OF EJS Templates
Fixing doctest EXCLUDES in iptest on win32....
Administrator -
Show More
@@ -1,247 +1,265 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 # Module imports
20 # Module imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import os
23 import os
24 import os.path as path
24 import os.path as path
25 import sys
25 import sys
26 import subprocess
26 import subprocess
27 import time
27 import time
28 import warnings
28 import warnings
29
29
30 import nose.plugins.builtin
30 import nose.plugins.builtin
31 from nose.core import TestProgram
31 from nose.core import TestProgram
32
32
33 from IPython.platutils import find_cmd
33 from IPython.testing.plugin.ipdoctest import IPythonDoctest
34 from IPython.testing.plugin.ipdoctest import IPythonDoctest
34
35
35 pjoin = path.join
36 pjoin = path.join
36
37
37 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
38 # Globals and constants
39 # Globals and constants
39 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
40
41
41 # For the IPythonDoctest plugin, we need to exclude certain patterns that cause
42 # For the IPythonDoctest plugin, we need to exclude certain patterns that cause
42 # testing problems. We should strive to minimize the number of skipped
43 # testing problems. We should strive to minimize the number of skipped
43 # modules, since this means untested code. As the testing machinery
44 # modules, since this means untested code. As the testing machinery
44 # solidifies, this list should eventually become empty.
45 # solidifies, this list should eventually become empty.
45 EXCLUDE = [pjoin('IPython', 'external'),
46 EXCLUDE = [pjoin('IPython', 'external'),
47 # This skip is duplicated below XXX
46 pjoin('IPython', 'platutils_win32'),
48 pjoin('IPython', 'platutils_win32'),
47 pjoin('IPython', 'frontend', 'cocoa'),
49 pjoin('IPython', 'frontend', 'cocoa'),
48 pjoin('IPython', 'frontend', 'process', 'winprocess.py'),
50 pjoin('IPython', 'frontend', 'process', 'winprocess.py'),
49 pjoin('IPython_doctest_plugin'),
51 pjoin('IPython_doctest_plugin'),
50 pjoin('IPython', 'Gnuplot'),
52 pjoin('IPython', 'Gnuplot'),
51 pjoin('IPython', 'Extensions', 'ipy_'),
53 pjoin('IPython', 'Extensions', 'ipy_'),
52 pjoin('IPython', 'Extensions', 'clearcmd'),
54 pjoin('IPython', 'Extensions', 'clearcmd'),
53 pjoin('IPython', 'Extensions', 'PhysicalQIn'),
55 pjoin('IPython', 'Extensions', 'PhysicalQInteractive'),
54 pjoin('IPython', 'Extensions', 'scitedirector'),
56 pjoin('IPython', 'Extensions', 'scitedirector'),
55 pjoin('IPython', 'Extensions', 'numeric_formats'),
57 pjoin('IPython', 'Extensions', 'numeric_formats'),
56 pjoin('IPython', 'testing', 'attic'),
58 pjoin('IPython', 'testing', 'attic'),
57 ]
59 ]
58
60
61 try:
62 import wx
63 except ImportError:
64 EXCLUDE.append(pjoin('IPython', 'Extensions', 'igrid'))
65
66 try:
67 import _curses
68 except ImportError:
69 EXCLUDE.append(pjoin('IPython', 'Extensions', 'ibrowse'))
70
71
72 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
73 if sys.platform == 'win32':
74 EXCLUDE = [s.replace('\\','\\\\') for s in EXCLUDE]
75
76
59 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
60 # Functions and classes
78 # Functions and classes
61 #-----------------------------------------------------------------------------
79 #-----------------------------------------------------------------------------
62
80
63 def run_iptest():
81 def run_iptest():
64 """Run the IPython test suite using nose.
82 """Run the IPython test suite using nose.
65
83
66 This function is called when this script is **not** called with the form
84 This function is called when this script is **not** called with the form
67 `iptest all`. It simply calls nose with appropriate command line flags
85 `iptest all`. It simply calls nose with appropriate command line flags
68 and accepts all of the standard nose arguments.
86 and accepts all of the standard nose arguments.
69 """
87 """
70
88
71 warnings.filterwarnings('ignore',
89 warnings.filterwarnings('ignore',
72 'This will be removed soon. Use IPython.testing.util instead')
90 'This will be removed soon. Use IPython.testing.util instead')
73
91
74 argv = sys.argv + [
92 argv = sys.argv + [
75 # Loading ipdoctest causes problems with Twisted.
93 # Loading ipdoctest causes problems with Twisted.
76 # I am removing this as a temporary fix to get the
94 # I am removing this as a temporary fix to get the
77 # test suite back into working shape. Our nose
95 # test suite back into working shape. Our nose
78 # plugin needs to be gone through with a fine
96 # plugin needs to be gone through with a fine
79 # toothed comb to find what is causing the problem.
97 # toothed comb to find what is causing the problem.
80 '--with-ipdoctest',
98 '--with-ipdoctest',
81 '--ipdoctest-tests','--ipdoctest-extension=txt',
99 '--ipdoctest-tests','--ipdoctest-extension=txt',
82 '--detailed-errors',
100 '--detailed-errors',
83
101
84 # We add --exe because of setuptools' imbecility (it
102 # We add --exe because of setuptools' imbecility (it
85 # blindly does chmod +x on ALL files). Nose does the
103 # blindly does chmod +x on ALL files). Nose does the
86 # right thing and it tries to avoid executables,
104 # right thing and it tries to avoid executables,
87 # setuptools unfortunately forces our hand here. This
105 # setuptools unfortunately forces our hand here. This
88 # has been discussed on the distutils list and the
106 # has been discussed on the distutils list and the
89 # setuptools devs refuse to fix this problem!
107 # setuptools devs refuse to fix this problem!
90 '--exe',
108 '--exe',
91 ]
109 ]
92
110
93 # Detect if any tests were required by explicitly calling an IPython
111 # Detect if any tests were required by explicitly calling an IPython
94 # submodule or giving a specific path
112 # submodule or giving a specific path
95 has_tests = False
113 has_tests = False
96 for arg in sys.argv:
114 for arg in sys.argv:
97 if 'IPython' in arg or arg.endswith('.py') or \
115 if 'IPython' in arg or arg.endswith('.py') or \
98 (':' in arg and '.py' in arg):
116 (':' in arg and '.py' in arg):
99 has_tests = True
117 has_tests = True
100 break
118 break
101
119
102 # If nothing was specifically requested, test full IPython
120 # If nothing was specifically requested, test full IPython
103 if not has_tests:
121 if not has_tests:
104 argv.append('IPython')
122 argv.append('IPython')
105
123
106 # Construct list of plugins, omitting the existing doctest plugin, which
124 # Construct list of plugins, omitting the existing doctest plugin, which
107 # ours replaces (and extends).
125 # ours replaces (and extends).
108 plugins = [IPythonDoctest(EXCLUDE)]
126 plugins = [IPythonDoctest(EXCLUDE)]
109 for p in nose.plugins.builtin.plugins:
127 for p in nose.plugins.builtin.plugins:
110 plug = p()
128 plug = p()
111 if plug.name == 'doctest':
129 if plug.name == 'doctest':
112 continue
130 continue
113
131
114 #print '*** adding plugin:',plug.name # dbg
132 #print '*** adding plugin:',plug.name # dbg
115 plugins.append(plug)
133 plugins.append(plug)
116
134
117 TestProgram(argv=argv,plugins=plugins)
135 TestProgram(argv=argv,plugins=plugins)
118
136
119
137
120 class IPTester(object):
138 class IPTester(object):
121 """Call that calls iptest or trial in a subprocess.
139 """Call that calls iptest or trial in a subprocess.
122 """
140 """
123 def __init__(self,runner='iptest',params=None):
141 def __init__(self,runner='iptest',params=None):
124 """ """
142 """ """
125 if runner == 'iptest':
143 if runner == 'iptest':
126 self.runner = ['iptest','-v']
144 self.runner = ['iptest','-v']
127 else:
145 else:
128 self.runner = ['trial']
146 self.runner = [find_cmd('trial')]
129 if params is None:
147 if params is None:
130 params = []
148 params = []
131 if isinstance(params,str):
149 if isinstance(params,str):
132 params = [params]
150 params = [params]
133 self.params = params
151 self.params = params
134
152
135 # Assemble call
153 # Assemble call
136 self.call_args = self.runner+self.params
154 self.call_args = self.runner+self.params
137
155
138 def run(self):
156 def run(self):
139 """Run the stored commands"""
157 """Run the stored commands"""
140 return subprocess.call(self.call_args)
158 return subprocess.call(self.call_args)
141
159
142
160
143 def make_runners():
161 def make_runners():
144 """Define the modules and packages that need to be tested.
162 """Define the modules and packages that need to be tested.
145 """
163 """
146
164
147 # This omits additional top-level modules that should not be doctested.
165 # This omits additional top-level modules that should not be doctested.
148 # XXX: Shell.py is also ommited because of a bug in the skip_doctest
166 # XXX: Shell.py is also ommited because of a bug in the skip_doctest
149 # decorator. See ticket https://bugs.launchpad.net/bugs/366209
167 # decorator. See ticket https://bugs.launchpad.net/bugs/366209
150 top_mod = \
168 top_mod = \
151 ['background_jobs.py', 'ColorANSI.py', 'completer.py', 'ConfigLoader.py',
169 ['background_jobs.py', 'ColorANSI.py', 'completer.py', 'ConfigLoader.py',
152 'CrashHandler.py', 'Debugger.py', 'deep_reload.py', 'demo.py',
170 'CrashHandler.py', 'Debugger.py', 'deep_reload.py', 'demo.py',
153 'DPyGetOpt.py', 'dtutils.py', 'excolors.py', 'FakeModule.py',
171 'DPyGetOpt.py', 'dtutils.py', 'excolors.py', 'FakeModule.py',
154 'generics.py', 'genutils.py', 'history.py', 'hooks.py', 'ipapi.py',
172 'generics.py', 'genutils.py', 'history.py', 'hooks.py', 'ipapi.py',
155 'iplib.py', 'ipmaker.py', 'ipstruct.py', 'irunner.py', 'Itpl.py',
173 'iplib.py', 'ipmaker.py', 'ipstruct.py', 'irunner.py', 'Itpl.py',
156 'Logger.py', 'macro.py', 'Magic.py', 'OInspect.py',
174 'Logger.py', 'macro.py', 'Magic.py', 'OInspect.py',
157 'OutputTrap.py', 'platutils.py', 'prefilter.py', 'Prompts.py',
175 'OutputTrap.py', 'platutils.py', 'prefilter.py', 'Prompts.py',
158 'PyColorize.py', 'Release.py', 'rlineimpl.py', 'shadowns.py',
176 'PyColorize.py', 'Release.py', 'rlineimpl.py', 'shadowns.py',
159 'shellglobals.py', 'strdispatch.py', 'twshell.py',
177 'shellglobals.py', 'strdispatch.py', 'twshell.py',
160 'ultraTB.py', 'upgrade_dir.py', 'usage.py', 'wildcard.py',
178 'ultraTB.py', 'upgrade_dir.py', 'usage.py', 'wildcard.py',
161 # See note above for why this is skipped
179 # See note above for why this is skipped
162 # 'Shell.py',
180 # 'Shell.py',
163 'winconsole.py']
181 'winconsole.py']
164
182
165 if os.name == 'posix':
183 if os.name == 'posix':
166 top_mod.append('platutils_posix.py')
184 top_mod.append('platutils_posix.py')
167 elif sys.platform == 'win32':
185 elif sys.platform == 'win32':
168 top_mod.append('platutils_win32.py')
186 top_mod.append('platutils_win32.py')
169 else:
187 else:
170 top_mod.append('platutils_dummy.py')
188 top_mod.append('platutils_dummy.py')
171
189
172 # These are tested by nose, so skip IPython.kernel
190 # These are tested by nose, so skip IPython.kernel
173 top_pack = ['config','Extensions','frontend','gui',
191 top_pack = ['config','Extensions','frontend','gui',
174 'testing','tests','tools','UserConfig']
192 'testing','tests','tools','UserConfig']
175
193
176 modules = ['IPython.%s' % m[:-3] for m in top_mod ]
194 modules = ['IPython.%s' % m[:-3] for m in top_mod ]
177 packages = ['IPython.%s' % m for m in top_pack ]
195 packages = ['IPython.%s' % m for m in top_pack ]
178
196
179 # Make runners
197 # Make runners
180 runners = dict(zip(top_pack, [IPTester(params=v) for v in packages]))
198 runners = dict(zip(top_pack, [IPTester(params=v) for v in packages]))
181
199
182 # Test IPython.kernel using trial if twisted is installed
200 # Test IPython.kernel using trial if twisted is installed
183 try:
201 try:
184 import zope.interface
202 import zope.interface
185 import twisted
203 import twisted
186 import foolscap
204 import foolscap
187 except ImportError:
205 except ImportError:
188 pass
206 pass
189 else:
207 else:
190 runners['trial'] = IPTester('trial',['IPython'])
208 runners['trial'] = IPTester('trial',['IPython'])
191
209
192 runners['modules'] = IPTester(params=modules)
210 runners['modules'] = IPTester(params=modules)
193
211
194 return runners
212 return runners
195
213
196
214
197 def run_iptestall():
215 def run_iptestall():
198 """Run the entire IPython test suite by calling nose and trial.
216 """Run the entire IPython test suite by calling nose and trial.
199
217
200 This function constructs :class:`IPTester` instances for all IPython
218 This function constructs :class:`IPTester` instances for all IPython
201 modules and package and then runs each of them. This causes the modules
219 modules and package and then runs each of them. This causes the modules
202 and packages of IPython to be tested each in their own subprocess using
220 and packages of IPython to be tested each in their own subprocess using
203 nose or twisted.trial appropriately.
221 nose or twisted.trial appropriately.
204 """
222 """
205 runners = make_runners()
223 runners = make_runners()
206 # Run all test runners, tracking execution time
224 # Run all test runners, tracking execution time
207 failed = {}
225 failed = {}
208 t_start = time.time()
226 t_start = time.time()
209 for name,runner in runners.iteritems():
227 for name,runner in runners.iteritems():
210 print '*'*77
228 print '*'*77
211 print 'IPython test set:',name
229 print 'IPython test set:',name
212 res = runner.run()
230 res = runner.run()
213 if res:
231 if res:
214 failed[name] = res
232 failed[name] = res
215 t_end = time.time()
233 t_end = time.time()
216 t_tests = t_end - t_start
234 t_tests = t_end - t_start
217 nrunners = len(runners)
235 nrunners = len(runners)
218 nfail = len(failed)
236 nfail = len(failed)
219 # summarize results
237 # summarize results
220 print
238 print
221 print '*'*77
239 print '*'*77
222 print 'Ran %s test sets in %.3fs' % (nrunners, t_tests)
240 print 'Ran %s test sets in %.3fs' % (nrunners, t_tests)
223 print
241 print
224 if not failed:
242 if not failed:
225 print 'OK'
243 print 'OK'
226 else:
244 else:
227 # If anything went wrong, point out what command to rerun manually to
245 # If anything went wrong, point out what command to rerun manually to
228 # see the actual errors and individual summary
246 # see the actual errors and individual summary
229 print 'ERROR - %s out of %s test sets failed.' % (nfail, nrunners)
247 print 'ERROR - %s out of %s test sets failed.' % (nfail, nrunners)
230 for name in failed:
248 for name in failed:
231 failed_runner = runners[name]
249 failed_runner = runners[name]
232 print '-'*40
250 print '-'*40
233 print 'Runner failed:',name
251 print 'Runner failed:',name
234 print 'You may wish to rerun this one individually, with:'
252 print 'You may wish to rerun this one individually, with:'
235 print ' '.join(failed_runner.call_args)
253 print ' '.join(failed_runner.call_args)
236 print
254 print
237
255
238
256
239 def main():
257 def main():
240 if sys.argv[1] == 'all':
258 if sys.argv[1] == 'all':
241 run_iptestall()
259 run_iptestall()
242 else:
260 else:
243 run_iptest()
261 run_iptest()
244
262
245
263
246 if __name__ == '__main__':
264 if __name__ == '__main__':
247 main() No newline at end of file
265 main()
General Comments 0
You need to be logged in to leave comments. Login now