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