##// END OF EJS Templates
fix skip_doctest import in testing.tools
MinRK -
Show More
@@ -1,279 +1,280 b''
1 1 """Generic testing tools that do NOT depend on Twisted.
2 2
3 3 In particular, this module exposes a set of top-level assert* functions that
4 4 can be used in place of nose.tools.assert* in method generators (the ones in
5 5 nose can not, at least as of nose 0.10.4).
6 6
7 7 Note: our testing package contains testing.util, which does depend on Twisted
8 8 and provides utilities for tests that manage Deferreds. All testing support
9 9 tools that only depend on nose, IPython or the standard library should go here
10 10 instead.
11 11
12 12
13 13 Authors
14 14 -------
15 15 - Fernando Perez <Fernando.Perez@berkeley.edu>
16 16 """
17 17
18 18 from __future__ import absolute_import
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Copyright (C) 2009 The IPython Development Team
22 22 #
23 23 # Distributed under the terms of the BSD License. The full license is in
24 24 # the file COPYING, distributed as part of this software.
25 25 #-----------------------------------------------------------------------------
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Imports
29 29 #-----------------------------------------------------------------------------
30 30
31 31 import os
32 32 import re
33 33 import sys
34 34
35 35 try:
36 36 # These tools are used by parts of the runtime, so we make the nose
37 37 # dependency optional at this point. Nose is a hard dependency to run the
38 38 # test suite, but NOT to use ipython itself.
39 39 import nose.tools as nt
40 40 has_nose = True
41 41 except ImportError:
42 42 has_nose = False
43 43
44 44 from IPython.config.loader import Config
45 45 from IPython.utils.process import find_cmd, getoutputerror
46 46 from IPython.utils.text import list_strings
47 47 from IPython.utils.io import temp_pyfile
48 48
49 49 from . import decorators as dec
50 from . import skipdoctest
50 51
51 52 #-----------------------------------------------------------------------------
52 53 # Globals
53 54 #-----------------------------------------------------------------------------
54 55
55 56 # Make a bunch of nose.tools assert wrappers that can be used in test
56 57 # generators. This will expose an assert* function for each one in nose.tools.
57 58
58 59 _tpl = """
59 60 def %(name)s(*a,**kw):
60 61 return nt.%(name)s(*a,**kw)
61 62 """
62 63
63 64 if has_nose:
64 65 for _x in [a for a in dir(nt) if a.startswith('assert')]:
65 66 exec _tpl % dict(name=_x)
66 67
67 68 #-----------------------------------------------------------------------------
68 69 # Functions and classes
69 70 #-----------------------------------------------------------------------------
70 71
71 72 # The docstring for full_path doctests differently on win32 (different path
72 73 # separator) so just skip the doctest there. The example remains informative.
73 doctest_deco = dec.skip_doctest if sys.platform == 'win32' else dec.null_deco
74 doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
74 75
75 76 @doctest_deco
76 77 def full_path(startPath,files):
77 78 """Make full paths for all the listed files, based on startPath.
78 79
79 80 Only the base part of startPath is kept, since this routine is typically
80 81 used with a script's __file__ variable as startPath. The base of startPath
81 82 is then prepended to all the listed files, forming the output list.
82 83
83 84 Parameters
84 85 ----------
85 86 startPath : string
86 87 Initial path to use as the base for the results. This path is split
87 88 using os.path.split() and only its first component is kept.
88 89
89 90 files : string or list
90 91 One or more files.
91 92
92 93 Examples
93 94 --------
94 95
95 96 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
96 97 ['/foo/a.txt', '/foo/b.txt']
97 98
98 99 >>> full_path('/foo',['a.txt','b.txt'])
99 100 ['/a.txt', '/b.txt']
100 101
101 102 If a single file is given, the output is still a list:
102 103 >>> full_path('/foo','a.txt')
103 104 ['/a.txt']
104 105 """
105 106
106 107 files = list_strings(files)
107 108 base = os.path.split(startPath)[0]
108 109 return [ os.path.join(base,f) for f in files ]
109 110
110 111
111 112 def parse_test_output(txt):
112 113 """Parse the output of a test run and return errors, failures.
113 114
114 115 Parameters
115 116 ----------
116 117 txt : str
117 118 Text output of a test run, assumed to contain a line of one of the
118 119 following forms::
119 120 'FAILED (errors=1)'
120 121 'FAILED (failures=1)'
121 122 'FAILED (errors=1, failures=1)'
122 123
123 124 Returns
124 125 -------
125 126 nerr, nfail: number of errors and failures.
126 127 """
127 128
128 129 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
129 130 if err_m:
130 131 nerr = int(err_m.group(1))
131 132 nfail = 0
132 133 return nerr, nfail
133 134
134 135 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
135 136 if fail_m:
136 137 nerr = 0
137 138 nfail = int(fail_m.group(1))
138 139 return nerr, nfail
139 140
140 141 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
141 142 re.MULTILINE)
142 143 if both_m:
143 144 nerr = int(both_m.group(1))
144 145 nfail = int(both_m.group(2))
145 146 return nerr, nfail
146 147
147 148 # If the input didn't match any of these forms, assume no error/failures
148 149 return 0, 0
149 150
150 151
151 152 # So nose doesn't think this is a test
152 153 parse_test_output.__test__ = False
153 154
154 155
155 156 def default_argv():
156 157 """Return a valid default argv for creating testing instances of ipython"""
157 158
158 159 return ['--quick', # so no config file is loaded
159 160 # Other defaults to minimize side effects on stdout
160 161 '--colors=NoColor', '--no-term-title','--no-banner',
161 162 '--autocall=0']
162 163
163 164
164 165 def default_config():
165 166 """Return a config object with good defaults for testing."""
166 167 config = Config()
167 168 config.TerminalInteractiveShell.colors = 'NoColor'
168 169 config.TerminalTerminalInteractiveShell.term_title = False,
169 170 config.TerminalInteractiveShell.autocall = 0
170 171 config.HistoryManager.hist_file = u'test_hist.sqlite'
171 172 config.HistoryManager.db_cache_size = 10000
172 173 return config
173 174
174 175
175 176 def ipexec(fname, options=None):
176 177 """Utility to call 'ipython filename'.
177 178
178 179 Starts IPython witha minimal and safe configuration to make startup as fast
179 180 as possible.
180 181
181 182 Note that this starts IPython in a subprocess!
182 183
183 184 Parameters
184 185 ----------
185 186 fname : str
186 187 Name of file to be executed (should have .py or .ipy extension).
187 188
188 189 options : optional, list
189 190 Extra command-line flags to be passed to IPython.
190 191
191 192 Returns
192 193 -------
193 194 (stdout, stderr) of ipython subprocess.
194 195 """
195 196 if options is None: options = []
196 197
197 198 # For these subprocess calls, eliminate all prompt printing so we only see
198 199 # output from script execution
199 200 prompt_opts = ['--prompt-in1=""', '--prompt-in2=""', '--prompt-out=""']
200 201 cmdargs = ' '.join(default_argv() + prompt_opts + options)
201 202
202 203 _ip = get_ipython()
203 204 test_dir = os.path.dirname(__file__)
204 205
205 206 ipython_cmd = find_cmd('ipython')
206 207 # Absolute path for filename
207 208 full_fname = os.path.join(test_dir, fname)
208 209 full_cmd = '%s %s %s' % (ipython_cmd, cmdargs, full_fname)
209 210 #print >> sys.stderr, 'FULL CMD:', full_cmd # dbg
210 211 return getoutputerror(full_cmd)
211 212
212 213
213 214 def ipexec_validate(fname, expected_out, expected_err='',
214 215 options=None):
215 216 """Utility to call 'ipython filename' and validate output/error.
216 217
217 218 This function raises an AssertionError if the validation fails.
218 219
219 220 Note that this starts IPython in a subprocess!
220 221
221 222 Parameters
222 223 ----------
223 224 fname : str
224 225 Name of the file to be executed (should have .py or .ipy extension).
225 226
226 227 expected_out : str
227 228 Expected stdout of the process.
228 229
229 230 expected_err : optional, str
230 231 Expected stderr of the process.
231 232
232 233 options : optional, list
233 234 Extra command-line flags to be passed to IPython.
234 235
235 236 Returns
236 237 -------
237 238 None
238 239 """
239 240
240 241 import nose.tools as nt
241 242
242 243 out, err = ipexec(fname)
243 244 #print 'OUT', out # dbg
244 245 #print 'ERR', err # dbg
245 246 # If there are any errors, we must check those befor stdout, as they may be
246 247 # more informative than simply having an empty stdout.
247 248 if err:
248 249 if expected_err:
249 250 nt.assert_equals(err.strip(), expected_err.strip())
250 251 else:
251 252 raise ValueError('Running file %r produced error: %r' %
252 253 (fname, err))
253 254 # If no errors or output on stderr was expected, match stdout
254 255 nt.assert_equals(out.strip(), expected_out.strip())
255 256
256 257
257 258 class TempFileMixin(object):
258 259 """Utility class to create temporary Python/IPython files.
259 260
260 261 Meant as a mixin class for test cases."""
261 262
262 263 def mktmp(self, src, ext='.py'):
263 264 """Make a valid python temp file."""
264 265 fname, f = temp_pyfile(src, ext)
265 266 self.tmpfile = f
266 267 self.fname = fname
267 268
268 269 def tearDown(self):
269 270 if hasattr(self, 'tmpfile'):
270 271 # If the tmpfile wasn't made because of skipped tests, like in
271 272 # win32, there's nothing to cleanup.
272 273 self.tmpfile.close()
273 274 try:
274 275 os.unlink(self.fname)
275 276 except:
276 277 # On Windows, even though we close the file, we still can't
277 278 # delete it. I have no clue why
278 279 pass
279 280
General Comments 0
You need to be logged in to leave comments. Login now