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