##// END OF EJS Templates
Fix tests for Python 2
Thomas Kluyver -
Show More
@@ -1,477 +1,481 b''
1 """Generic testing tools.
1 """Generic testing tools.
2
2
3 Authors
3 Authors
4 -------
4 -------
5 - Fernando Perez <Fernando.Perez@berkeley.edu>
5 - Fernando Perez <Fernando.Perez@berkeley.edu>
6 """
6 """
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 # Copyright (c) IPython Development Team.
10 # Copyright (c) IPython Development Team.
11 # Distributed under the terms of the Modified BSD License.
11 # Distributed under the terms of the Modified BSD License.
12
12
13 import os
13 import os
14 import re
14 import re
15 import sys
15 import sys
16 import tempfile
16 import tempfile
17
17
18 from contextlib import contextmanager
18 from contextlib import contextmanager
19 from io import StringIO
19 from io import StringIO
20 from subprocess import Popen, PIPE
20 from subprocess import Popen, PIPE
21 from unittest.mock import patch
21 try:
22 from unittest.mock import patch
23 except ImportError:
24 # Python 2 compatibility
25 from mock import patch
22
26
23 try:
27 try:
24 # These tools are used by parts of the runtime, so we make the nose
28 # These tools are used by parts of the runtime, so we make the nose
25 # dependency optional at this point. Nose is a hard dependency to run the
29 # dependency optional at this point. Nose is a hard dependency to run the
26 # test suite, but NOT to use ipython itself.
30 # test suite, but NOT to use ipython itself.
27 import nose.tools as nt
31 import nose.tools as nt
28 has_nose = True
32 has_nose = True
29 except ImportError:
33 except ImportError:
30 has_nose = False
34 has_nose = False
31
35
32 from traitlets.config.loader import Config
36 from traitlets.config.loader import Config
33 from IPython.utils.process import get_output_error_code
37 from IPython.utils.process import get_output_error_code
34 from IPython.utils.text import list_strings
38 from IPython.utils.text import list_strings
35 from IPython.utils.io import temp_pyfile, Tee
39 from IPython.utils.io import temp_pyfile, Tee
36 from IPython.utils import py3compat
40 from IPython.utils import py3compat
37 from IPython.utils.encoding import DEFAULT_ENCODING
41 from IPython.utils.encoding import DEFAULT_ENCODING
38
42
39 from . import decorators as dec
43 from . import decorators as dec
40 from . import skipdoctest
44 from . import skipdoctest
41
45
42
46
43 # The docstring for full_path doctests differently on win32 (different path
47 # The docstring for full_path doctests differently on win32 (different path
44 # separator) so just skip the doctest there. The example remains informative.
48 # separator) so just skip the doctest there. The example remains informative.
45 doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
49 doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
46
50
47 @doctest_deco
51 @doctest_deco
48 def full_path(startPath,files):
52 def full_path(startPath,files):
49 """Make full paths for all the listed files, based on startPath.
53 """Make full paths for all the listed files, based on startPath.
50
54
51 Only the base part of startPath is kept, since this routine is typically
55 Only the base part of startPath is kept, since this routine is typically
52 used with a script's ``__file__`` variable as startPath. The base of startPath
56 used with a script's ``__file__`` variable as startPath. The base of startPath
53 is then prepended to all the listed files, forming the output list.
57 is then prepended to all the listed files, forming the output list.
54
58
55 Parameters
59 Parameters
56 ----------
60 ----------
57 startPath : string
61 startPath : string
58 Initial path to use as the base for the results. This path is split
62 Initial path to use as the base for the results. This path is split
59 using os.path.split() and only its first component is kept.
63 using os.path.split() and only its first component is kept.
60
64
61 files : string or list
65 files : string or list
62 One or more files.
66 One or more files.
63
67
64 Examples
68 Examples
65 --------
69 --------
66
70
67 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
71 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
68 ['/foo/a.txt', '/foo/b.txt']
72 ['/foo/a.txt', '/foo/b.txt']
69
73
70 >>> full_path('/foo',['a.txt','b.txt'])
74 >>> full_path('/foo',['a.txt','b.txt'])
71 ['/a.txt', '/b.txt']
75 ['/a.txt', '/b.txt']
72
76
73 If a single file is given, the output is still a list::
77 If a single file is given, the output is still a list::
74
78
75 >>> full_path('/foo','a.txt')
79 >>> full_path('/foo','a.txt')
76 ['/a.txt']
80 ['/a.txt']
77 """
81 """
78
82
79 files = list_strings(files)
83 files = list_strings(files)
80 base = os.path.split(startPath)[0]
84 base = os.path.split(startPath)[0]
81 return [ os.path.join(base,f) for f in files ]
85 return [ os.path.join(base,f) for f in files ]
82
86
83
87
84 def parse_test_output(txt):
88 def parse_test_output(txt):
85 """Parse the output of a test run and return errors, failures.
89 """Parse the output of a test run and return errors, failures.
86
90
87 Parameters
91 Parameters
88 ----------
92 ----------
89 txt : str
93 txt : str
90 Text output of a test run, assumed to contain a line of one of the
94 Text output of a test run, assumed to contain a line of one of the
91 following forms::
95 following forms::
92
96
93 'FAILED (errors=1)'
97 'FAILED (errors=1)'
94 'FAILED (failures=1)'
98 'FAILED (failures=1)'
95 'FAILED (errors=1, failures=1)'
99 'FAILED (errors=1, failures=1)'
96
100
97 Returns
101 Returns
98 -------
102 -------
99 nerr, nfail
103 nerr, nfail
100 number of errors and failures.
104 number of errors and failures.
101 """
105 """
102
106
103 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
107 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
104 if err_m:
108 if err_m:
105 nerr = int(err_m.group(1))
109 nerr = int(err_m.group(1))
106 nfail = 0
110 nfail = 0
107 return nerr, nfail
111 return nerr, nfail
108
112
109 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
113 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
110 if fail_m:
114 if fail_m:
111 nerr = 0
115 nerr = 0
112 nfail = int(fail_m.group(1))
116 nfail = int(fail_m.group(1))
113 return nerr, nfail
117 return nerr, nfail
114
118
115 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
119 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
116 re.MULTILINE)
120 re.MULTILINE)
117 if both_m:
121 if both_m:
118 nerr = int(both_m.group(1))
122 nerr = int(both_m.group(1))
119 nfail = int(both_m.group(2))
123 nfail = int(both_m.group(2))
120 return nerr, nfail
124 return nerr, nfail
121
125
122 # If the input didn't match any of these forms, assume no error/failures
126 # If the input didn't match any of these forms, assume no error/failures
123 return 0, 0
127 return 0, 0
124
128
125
129
126 # So nose doesn't think this is a test
130 # So nose doesn't think this is a test
127 parse_test_output.__test__ = False
131 parse_test_output.__test__ = False
128
132
129
133
130 def default_argv():
134 def default_argv():
131 """Return a valid default argv for creating testing instances of ipython"""
135 """Return a valid default argv for creating testing instances of ipython"""
132
136
133 return ['--quick', # so no config file is loaded
137 return ['--quick', # so no config file is loaded
134 # Other defaults to minimize side effects on stdout
138 # Other defaults to minimize side effects on stdout
135 '--colors=NoColor', '--no-term-title','--no-banner',
139 '--colors=NoColor', '--no-term-title','--no-banner',
136 '--autocall=0']
140 '--autocall=0']
137
141
138
142
139 def default_config():
143 def default_config():
140 """Return a config object with good defaults for testing."""
144 """Return a config object with good defaults for testing."""
141 config = Config()
145 config = Config()
142 config.TerminalInteractiveShell.colors = 'NoColor'
146 config.TerminalInteractiveShell.colors = 'NoColor'
143 config.TerminalTerminalInteractiveShell.term_title = False,
147 config.TerminalTerminalInteractiveShell.term_title = False,
144 config.TerminalInteractiveShell.autocall = 0
148 config.TerminalInteractiveShell.autocall = 0
145 f = tempfile.NamedTemporaryFile(suffix=u'test_hist.sqlite', delete=False)
149 f = tempfile.NamedTemporaryFile(suffix=u'test_hist.sqlite', delete=False)
146 config.HistoryManager.hist_file = f.name
150 config.HistoryManager.hist_file = f.name
147 f.close()
151 f.close()
148 config.HistoryManager.db_cache_size = 10000
152 config.HistoryManager.db_cache_size = 10000
149 return config
153 return config
150
154
151
155
152 def get_ipython_cmd(as_string=False):
156 def get_ipython_cmd(as_string=False):
153 """
157 """
154 Return appropriate IPython command line name. By default, this will return
158 Return appropriate IPython command line name. By default, this will return
155 a list that can be used with subprocess.Popen, for example, but passing
159 a list that can be used with subprocess.Popen, for example, but passing
156 `as_string=True` allows for returning the IPython command as a string.
160 `as_string=True` allows for returning the IPython command as a string.
157
161
158 Parameters
162 Parameters
159 ----------
163 ----------
160 as_string: bool
164 as_string: bool
161 Flag to allow to return the command as a string.
165 Flag to allow to return the command as a string.
162 """
166 """
163 ipython_cmd = [sys.executable, "-m", "IPython"]
167 ipython_cmd = [sys.executable, "-m", "IPython"]
164
168
165 if as_string:
169 if as_string:
166 ipython_cmd = " ".join(ipython_cmd)
170 ipython_cmd = " ".join(ipython_cmd)
167
171
168 return ipython_cmd
172 return ipython_cmd
169
173
170 def ipexec(fname, options=None, commands=()):
174 def ipexec(fname, options=None, commands=()):
171 """Utility to call 'ipython filename'.
175 """Utility to call 'ipython filename'.
172
176
173 Starts IPython with a minimal and safe configuration to make startup as fast
177 Starts IPython with a minimal and safe configuration to make startup as fast
174 as possible.
178 as possible.
175
179
176 Note that this starts IPython in a subprocess!
180 Note that this starts IPython in a subprocess!
177
181
178 Parameters
182 Parameters
179 ----------
183 ----------
180 fname : str
184 fname : str
181 Name of file to be executed (should have .py or .ipy extension).
185 Name of file to be executed (should have .py or .ipy extension).
182
186
183 options : optional, list
187 options : optional, list
184 Extra command-line flags to be passed to IPython.
188 Extra command-line flags to be passed to IPython.
185
189
186 commands : optional, list
190 commands : optional, list
187 Commands to send in on stdin
191 Commands to send in on stdin
188
192
189 Returns
193 Returns
190 -------
194 -------
191 (stdout, stderr) of ipython subprocess.
195 (stdout, stderr) of ipython subprocess.
192 """
196 """
193 if options is None: options = []
197 if options is None: options = []
194
198
195 cmdargs = default_argv() + options
199 cmdargs = default_argv() + options
196
200
197 test_dir = os.path.dirname(__file__)
201 test_dir = os.path.dirname(__file__)
198
202
199 ipython_cmd = get_ipython_cmd()
203 ipython_cmd = get_ipython_cmd()
200 # Absolute path for filename
204 # Absolute path for filename
201 full_fname = os.path.join(test_dir, fname)
205 full_fname = os.path.join(test_dir, fname)
202 full_cmd = ipython_cmd + cmdargs + [full_fname]
206 full_cmd = ipython_cmd + cmdargs + [full_fname]
203 env = os.environ.copy()
207 env = os.environ.copy()
204 # FIXME: ignore all warnings in ipexec while we have shims
208 # FIXME: ignore all warnings in ipexec while we have shims
205 # should we keep suppressing warnings here, even after removing shims?
209 # should we keep suppressing warnings here, even after removing shims?
206 env['PYTHONWARNINGS'] = 'ignore'
210 env['PYTHONWARNINGS'] = 'ignore'
207 # env.pop('PYTHONWARNINGS', None) # Avoid extraneous warnings appearing on stderr
211 # env.pop('PYTHONWARNINGS', None) # Avoid extraneous warnings appearing on stderr
208 for k, v in env.items():
212 for k, v in env.items():
209 # Debug a bizarre failure we've seen on Windows:
213 # Debug a bizarre failure we've seen on Windows:
210 # TypeError: environment can only contain strings
214 # TypeError: environment can only contain strings
211 if not isinstance(v, str):
215 if not isinstance(v, str):
212 print(k, v)
216 print(k, v)
213 p = Popen(full_cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE, env=env)
217 p = Popen(full_cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE, env=env)
214 out, err = p.communicate(input=py3compat.str_to_bytes('\n'.join(commands)) or None)
218 out, err = p.communicate(input=py3compat.str_to_bytes('\n'.join(commands)) or None)
215 out, err = py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
219 out, err = py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
216 # `import readline` causes 'ESC[?1034h' to be output sometimes,
220 # `import readline` causes 'ESC[?1034h' to be output sometimes,
217 # so strip that out before doing comparisons
221 # so strip that out before doing comparisons
218 if out:
222 if out:
219 out = re.sub(r'\x1b\[[^h]+h', '', out)
223 out = re.sub(r'\x1b\[[^h]+h', '', out)
220 return out, err
224 return out, err
221
225
222
226
223 def ipexec_validate(fname, expected_out, expected_err='',
227 def ipexec_validate(fname, expected_out, expected_err='',
224 options=None, commands=()):
228 options=None, commands=()):
225 """Utility to call 'ipython filename' and validate output/error.
229 """Utility to call 'ipython filename' and validate output/error.
226
230
227 This function raises an AssertionError if the validation fails.
231 This function raises an AssertionError if the validation fails.
228
232
229 Note that this starts IPython in a subprocess!
233 Note that this starts IPython in a subprocess!
230
234
231 Parameters
235 Parameters
232 ----------
236 ----------
233 fname : str
237 fname : str
234 Name of the file to be executed (should have .py or .ipy extension).
238 Name of the file to be executed (should have .py or .ipy extension).
235
239
236 expected_out : str
240 expected_out : str
237 Expected stdout of the process.
241 Expected stdout of the process.
238
242
239 expected_err : optional, str
243 expected_err : optional, str
240 Expected stderr of the process.
244 Expected stderr of the process.
241
245
242 options : optional, list
246 options : optional, list
243 Extra command-line flags to be passed to IPython.
247 Extra command-line flags to be passed to IPython.
244
248
245 Returns
249 Returns
246 -------
250 -------
247 None
251 None
248 """
252 """
249
253
250 import nose.tools as nt
254 import nose.tools as nt
251
255
252 out, err = ipexec(fname, options, commands)
256 out, err = ipexec(fname, options, commands)
253 #print 'OUT', out # dbg
257 #print 'OUT', out # dbg
254 #print 'ERR', err # dbg
258 #print 'ERR', err # dbg
255 # If there are any errors, we must check those befor stdout, as they may be
259 # If there are any errors, we must check those befor stdout, as they may be
256 # more informative than simply having an empty stdout.
260 # more informative than simply having an empty stdout.
257 if err:
261 if err:
258 if expected_err:
262 if expected_err:
259 nt.assert_equal("\n".join(err.strip().splitlines()), "\n".join(expected_err.strip().splitlines()))
263 nt.assert_equal("\n".join(err.strip().splitlines()), "\n".join(expected_err.strip().splitlines()))
260 else:
264 else:
261 raise ValueError('Running file %r produced error: %r' %
265 raise ValueError('Running file %r produced error: %r' %
262 (fname, err))
266 (fname, err))
263 # If no errors or output on stderr was expected, match stdout
267 # If no errors or output on stderr was expected, match stdout
264 nt.assert_equal("\n".join(out.strip().splitlines()), "\n".join(expected_out.strip().splitlines()))
268 nt.assert_equal("\n".join(out.strip().splitlines()), "\n".join(expected_out.strip().splitlines()))
265
269
266
270
267 class TempFileMixin(object):
271 class TempFileMixin(object):
268 """Utility class to create temporary Python/IPython files.
272 """Utility class to create temporary Python/IPython files.
269
273
270 Meant as a mixin class for test cases."""
274 Meant as a mixin class for test cases."""
271
275
272 def mktmp(self, src, ext='.py'):
276 def mktmp(self, src, ext='.py'):
273 """Make a valid python temp file."""
277 """Make a valid python temp file."""
274 fname, f = temp_pyfile(src, ext)
278 fname, f = temp_pyfile(src, ext)
275 self.tmpfile = f
279 self.tmpfile = f
276 self.fname = fname
280 self.fname = fname
277
281
278 def tearDown(self):
282 def tearDown(self):
279 if hasattr(self, 'tmpfile'):
283 if hasattr(self, 'tmpfile'):
280 # If the tmpfile wasn't made because of skipped tests, like in
284 # If the tmpfile wasn't made because of skipped tests, like in
281 # win32, there's nothing to cleanup.
285 # win32, there's nothing to cleanup.
282 self.tmpfile.close()
286 self.tmpfile.close()
283 try:
287 try:
284 os.unlink(self.fname)
288 os.unlink(self.fname)
285 except:
289 except:
286 # On Windows, even though we close the file, we still can't
290 # On Windows, even though we close the file, we still can't
287 # delete it. I have no clue why
291 # delete it. I have no clue why
288 pass
292 pass
289
293
290 def __enter__(self):
294 def __enter__(self):
291 return self
295 return self
292
296
293 def __exit__(self, exc_type, exc_value, traceback):
297 def __exit__(self, exc_type, exc_value, traceback):
294 self.tearDown()
298 self.tearDown()
295
299
296
300
297 pair_fail_msg = ("Testing {0}\n\n"
301 pair_fail_msg = ("Testing {0}\n\n"
298 "In:\n"
302 "In:\n"
299 " {1!r}\n"
303 " {1!r}\n"
300 "Expected:\n"
304 "Expected:\n"
301 " {2!r}\n"
305 " {2!r}\n"
302 "Got:\n"
306 "Got:\n"
303 " {3!r}\n")
307 " {3!r}\n")
304 def check_pairs(func, pairs):
308 def check_pairs(func, pairs):
305 """Utility function for the common case of checking a function with a
309 """Utility function for the common case of checking a function with a
306 sequence of input/output pairs.
310 sequence of input/output pairs.
307
311
308 Parameters
312 Parameters
309 ----------
313 ----------
310 func : callable
314 func : callable
311 The function to be tested. Should accept a single argument.
315 The function to be tested. Should accept a single argument.
312 pairs : iterable
316 pairs : iterable
313 A list of (input, expected_output) tuples.
317 A list of (input, expected_output) tuples.
314
318
315 Returns
319 Returns
316 -------
320 -------
317 None. Raises an AssertionError if any output does not match the expected
321 None. Raises an AssertionError if any output does not match the expected
318 value.
322 value.
319 """
323 """
320 name = getattr(func, "func_name", getattr(func, "__name__", "<unknown>"))
324 name = getattr(func, "func_name", getattr(func, "__name__", "<unknown>"))
321 for inp, expected in pairs:
325 for inp, expected in pairs:
322 out = func(inp)
326 out = func(inp)
323 assert out == expected, pair_fail_msg.format(name, inp, expected, out)
327 assert out == expected, pair_fail_msg.format(name, inp, expected, out)
324
328
325
329
326 if py3compat.PY3:
330 if py3compat.PY3:
327 MyStringIO = StringIO
331 MyStringIO = StringIO
328 else:
332 else:
329 # In Python 2, stdout/stderr can have either bytes or unicode written to them,
333 # In Python 2, stdout/stderr can have either bytes or unicode written to them,
330 # so we need a class that can handle both.
334 # so we need a class that can handle both.
331 class MyStringIO(StringIO):
335 class MyStringIO(StringIO):
332 def write(self, s):
336 def write(self, s):
333 s = py3compat.cast_unicode(s, encoding=DEFAULT_ENCODING)
337 s = py3compat.cast_unicode(s, encoding=DEFAULT_ENCODING)
334 super(MyStringIO, self).write(s)
338 super(MyStringIO, self).write(s)
335
339
336 _re_type = type(re.compile(r''))
340 _re_type = type(re.compile(r''))
337
341
338 notprinted_msg = """Did not find {0!r} in printed output (on {1}):
342 notprinted_msg = """Did not find {0!r} in printed output (on {1}):
339 -------
343 -------
340 {2!s}
344 {2!s}
341 -------
345 -------
342 """
346 """
343
347
344 class AssertPrints(object):
348 class AssertPrints(object):
345 """Context manager for testing that code prints certain text.
349 """Context manager for testing that code prints certain text.
346
350
347 Examples
351 Examples
348 --------
352 --------
349 >>> with AssertPrints("abc", suppress=False):
353 >>> with AssertPrints("abc", suppress=False):
350 ... print("abcd")
354 ... print("abcd")
351 ... print("def")
355 ... print("def")
352 ...
356 ...
353 abcd
357 abcd
354 def
358 def
355 """
359 """
356 def __init__(self, s, channel='stdout', suppress=True):
360 def __init__(self, s, channel='stdout', suppress=True):
357 self.s = s
361 self.s = s
358 if isinstance(self.s, (py3compat.string_types, _re_type)):
362 if isinstance(self.s, (py3compat.string_types, _re_type)):
359 self.s = [self.s]
363 self.s = [self.s]
360 self.channel = channel
364 self.channel = channel
361 self.suppress = suppress
365 self.suppress = suppress
362
366
363 def __enter__(self):
367 def __enter__(self):
364 self.orig_stream = getattr(sys, self.channel)
368 self.orig_stream = getattr(sys, self.channel)
365 self.buffer = MyStringIO()
369 self.buffer = MyStringIO()
366 self.tee = Tee(self.buffer, channel=self.channel)
370 self.tee = Tee(self.buffer, channel=self.channel)
367 setattr(sys, self.channel, self.buffer if self.suppress else self.tee)
371 setattr(sys, self.channel, self.buffer if self.suppress else self.tee)
368
372
369 def __exit__(self, etype, value, traceback):
373 def __exit__(self, etype, value, traceback):
370 try:
374 try:
371 if value is not None:
375 if value is not None:
372 # If an error was raised, don't check anything else
376 # If an error was raised, don't check anything else
373 return False
377 return False
374 self.tee.flush()
378 self.tee.flush()
375 setattr(sys, self.channel, self.orig_stream)
379 setattr(sys, self.channel, self.orig_stream)
376 printed = self.buffer.getvalue()
380 printed = self.buffer.getvalue()
377 for s in self.s:
381 for s in self.s:
378 if isinstance(s, _re_type):
382 if isinstance(s, _re_type):
379 assert s.search(printed), notprinted_msg.format(s.pattern, self.channel, printed)
383 assert s.search(printed), notprinted_msg.format(s.pattern, self.channel, printed)
380 else:
384 else:
381 assert s in printed, notprinted_msg.format(s, self.channel, printed)
385 assert s in printed, notprinted_msg.format(s, self.channel, printed)
382 return False
386 return False
383 finally:
387 finally:
384 self.tee.close()
388 self.tee.close()
385
389
386 printed_msg = """Found {0!r} in printed output (on {1}):
390 printed_msg = """Found {0!r} in printed output (on {1}):
387 -------
391 -------
388 {2!s}
392 {2!s}
389 -------
393 -------
390 """
394 """
391
395
392 class AssertNotPrints(AssertPrints):
396 class AssertNotPrints(AssertPrints):
393 """Context manager for checking that certain output *isn't* produced.
397 """Context manager for checking that certain output *isn't* produced.
394
398
395 Counterpart of AssertPrints"""
399 Counterpart of AssertPrints"""
396 def __exit__(self, etype, value, traceback):
400 def __exit__(self, etype, value, traceback):
397 try:
401 try:
398 if value is not None:
402 if value is not None:
399 # If an error was raised, don't check anything else
403 # If an error was raised, don't check anything else
400 self.tee.close()
404 self.tee.close()
401 return False
405 return False
402 self.tee.flush()
406 self.tee.flush()
403 setattr(sys, self.channel, self.orig_stream)
407 setattr(sys, self.channel, self.orig_stream)
404 printed = self.buffer.getvalue()
408 printed = self.buffer.getvalue()
405 for s in self.s:
409 for s in self.s:
406 if isinstance(s, _re_type):
410 if isinstance(s, _re_type):
407 assert not s.search(printed),printed_msg.format(
411 assert not s.search(printed),printed_msg.format(
408 s.pattern, self.channel, printed)
412 s.pattern, self.channel, printed)
409 else:
413 else:
410 assert s not in printed, printed_msg.format(
414 assert s not in printed, printed_msg.format(
411 s, self.channel, printed)
415 s, self.channel, printed)
412 return False
416 return False
413 finally:
417 finally:
414 self.tee.close()
418 self.tee.close()
415
419
416 @contextmanager
420 @contextmanager
417 def mute_warn():
421 def mute_warn():
418 from IPython.utils import warn
422 from IPython.utils import warn
419 save_warn = warn.warn
423 save_warn = warn.warn
420 warn.warn = lambda *a, **kw: None
424 warn.warn = lambda *a, **kw: None
421 try:
425 try:
422 yield
426 yield
423 finally:
427 finally:
424 warn.warn = save_warn
428 warn.warn = save_warn
425
429
426 @contextmanager
430 @contextmanager
427 def make_tempfile(name):
431 def make_tempfile(name):
428 """ Create an empty, named, temporary file for the duration of the context.
432 """ Create an empty, named, temporary file for the duration of the context.
429 """
433 """
430 f = open(name, 'w')
434 f = open(name, 'w')
431 f.close()
435 f.close()
432 try:
436 try:
433 yield
437 yield
434 finally:
438 finally:
435 os.unlink(name)
439 os.unlink(name)
436
440
437 def fake_input(inputs):
441 def fake_input(inputs):
438 """Temporarily replace the input() function to return the given values
442 """Temporarily replace the input() function to return the given values
439
443
440 Use as a context manager:
444 Use as a context manager:
441
445
442 with fake_input(['result1', 'result2']):
446 with fake_input(['result1', 'result2']):
443 ...
447 ...
444
448
445 Values are returned in order. If input() is called again after the last value
449 Values are returned in order. If input() is called again after the last value
446 was used, EOFError is raised.
450 was used, EOFError is raised.
447 """
451 """
448 it = iter(inputs)
452 it = iter(inputs)
449 def mock_input(prompt=''):
453 def mock_input(prompt=''):
450 try:
454 try:
451 return next(it)
455 return next(it)
452 except StopIteration:
456 except StopIteration:
453 raise EOFError('No more inputs given')
457 raise EOFError('No more inputs given')
454
458
455 return patch('builtins.input', mock_input)
459 return patch('builtins.input', mock_input)
456
460
457 def help_output_test(subcommand=''):
461 def help_output_test(subcommand=''):
458 """test that `ipython [subcommand] -h` works"""
462 """test that `ipython [subcommand] -h` works"""
459 cmd = get_ipython_cmd() + [subcommand, '-h']
463 cmd = get_ipython_cmd() + [subcommand, '-h']
460 out, err, rc = get_output_error_code(cmd)
464 out, err, rc = get_output_error_code(cmd)
461 nt.assert_equal(rc, 0, err)
465 nt.assert_equal(rc, 0, err)
462 nt.assert_not_in("Traceback", err)
466 nt.assert_not_in("Traceback", err)
463 nt.assert_in("Options", out)
467 nt.assert_in("Options", out)
464 nt.assert_in("--help-all", out)
468 nt.assert_in("--help-all", out)
465 return out, err
469 return out, err
466
470
467
471
468 def help_all_output_test(subcommand=''):
472 def help_all_output_test(subcommand=''):
469 """test that `ipython [subcommand] --help-all` works"""
473 """test that `ipython [subcommand] --help-all` works"""
470 cmd = get_ipython_cmd() + [subcommand, '--help-all']
474 cmd = get_ipython_cmd() + [subcommand, '--help-all']
471 out, err, rc = get_output_error_code(cmd)
475 out, err, rc = get_output_error_code(cmd)
472 nt.assert_equal(rc, 0, err)
476 nt.assert_equal(rc, 0, err)
473 nt.assert_not_in("Traceback", err)
477 nt.assert_not_in("Traceback", err)
474 nt.assert_in("Options", out)
478 nt.assert_in("Options", out)
475 nt.assert_in("Class parameters", out)
479 nt.assert_in("Class parameters", out)
476 return out, err
480 return out, err
477
481
General Comments 0
You need to be logged in to leave comments. Login now