##// END OF EJS Templates
Merge pull request #1155 from minrk/postexec...
Merge pull request #1155 from minrk/postexec Be less aggressive in de-registering failing post-execute functions so that normal errors don't disable them permanently. Two changes: 1. Don't unregister failing post-exec callbacks automatically. Instead, print a message regarding the failure, pointing to new `disable_failing_post_execute` trait for skipping failing callbacks. - When this flag is False (the default), failing callbacks will continue to be called. - When True, behavior is unchanged from previous, where callbacks are only allowed to fail once. 2. protect `flush_figures()` post-exec function from user error. Invalid matplotlib data may raise inside `print_figure()`. flush_figures() is a post-exec function, so user errors should not raise. Instead, call `get_ipython().showtraceback()` if called from IPython, raising as before otherwise. closes #1154

File last commit:

r5548:38572c28
r5737:2c683b72 merge
Show More
tools.py
402 lines | 12.2 KiB | text/x-python | PythonLexer
Fernando Perez
Ensure that we don't damage the __builtins__ object after %run....
r1955 """Generic testing tools that do NOT depend on Twisted.
In particular, this module exposes a set of top-level assert* functions that
can be used in place of nose.tools.assert* in method generators (the ones in
nose can not, at least as of nose 0.10.4).
Note: our testing package contains testing.util, which does depend on Twisted
and provides utilities for tests that manage Deferreds. All testing support
tools that only depend on nose, IPython or the standard library should go here
instead.
Authors
-------
- Fernando Perez <Fernando.Perez@berkeley.edu>
"""
Brian Granger
Work to address the review comments on Fernando's branch....
r2498 from __future__ import absolute_import
#-----------------------------------------------------------------------------
Matthias BUSSONNIER
update copyright to 2011/20xx-2011...
r5390 # Copyright (C) 2009-2011 The IPython Development Team
Fernando Perez
Ensure that we don't damage the __builtins__ object after %run....
r1955 #
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
Brian Granger
Work to address the review comments on Fernando's branch....
r2498 #-----------------------------------------------------------------------------
Fernando Perez
Ensure that we don't damage the __builtins__ object after %run....
r1955
#-----------------------------------------------------------------------------
Brian Granger
Work to address the review comments on Fernando's branch....
r2498 # Imports
Fernando Perez
Ensure that we don't damage the __builtins__ object after %run....
r1955 #-----------------------------------------------------------------------------
import os
Fernando Perez
Add test utility for parsing test output from stdout/stderr
r2353 import re
Fernando Perez
Ensure that we don't damage the __builtins__ object after %run....
r1955 import sys
MinRK
put test_hist.sqlite in tempdir, to prevent polluting filesystem
r4486 import tempfile
Fernando Perez
Ensure that we don't damage the __builtins__ object after %run....
r1955
MinRK
aliases match flag pattern ('-' as wordsep, not '_')...
r4214 from contextlib import contextmanager
Thomas Kluyver
Add AssertPrints context manager to check output from tests.
r4901 from io import StringIO
MinRK
aliases match flag pattern ('-' as wordsep, not '_')...
r4214
Fernando Perez
Remove accidentally introduced runtime nose dependencies.
r2442 try:
# These tools are used by parts of the runtime, so we make the nose
# dependency optional at this point. Nose is a hard dependency to run the
# test suite, but NOT to use ipython itself.
import nose.tools as nt
has_nose = True
except ImportError:
has_nose = False
Fernando Perez
Ensure that we don't damage the __builtins__ object after %run....
r1955
Brian Granger
More work addressing review comments for Fernando's branch....
r2499 from IPython.config.loader import Config
Brian Granger
Work to address the review comments on Fernando's branch....
r2498 from IPython.utils.process import find_cmd, getoutputerror
Thomas Kluyver
Add AssertPrints context manager to check output from tests.
r4901 from IPython.utils.text import list_strings, getdefaultencoding
from IPython.utils.io import temp_pyfile, Tee
from IPython.utils import py3compat
Fernando Perez
Ensure that we don't damage the __builtins__ object after %run....
r1955
Fernando Perez
Fixes for test suite in win32 when all dependencies (esp. Twisted) are...
r2461 from . import decorators as dec
MinRK
fix skip_doctest import in testing.tools
r3905 from . import skipdoctest
Fernando Perez
Fixes for test suite in win32 when all dependencies (esp. Twisted) are...
r2461
Fernando Perez
Ensure that we don't damage the __builtins__ object after %run....
r1955 #-----------------------------------------------------------------------------
# Globals
#-----------------------------------------------------------------------------
# Make a bunch of nose.tools assert wrappers that can be used in test
# generators. This will expose an assert* function for each one in nose.tools.
_tpl = """
def %(name)s(*a,**kw):
return nt.%(name)s(*a,**kw)
"""
Fernando Perez
Remove accidentally introduced runtime nose dependencies.
r2442 if has_nose:
for _x in [a for a in dir(nt) if a.startswith('assert')]:
exec _tpl % dict(name=_x)
Fernando Perez
Ensure that we don't damage the __builtins__ object after %run....
r1955
#-----------------------------------------------------------------------------
# Functions and classes
#-----------------------------------------------------------------------------
Fernando Perez
Fixes for test suite in win32 when all dependencies (esp. Twisted) are...
r2461 # The docstring for full_path doctests differently on win32 (different path
# separator) so just skip the doctest there. The example remains informative.
MinRK
fix skip_doctest import in testing.tools
r3905 doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
Brian Granger
Fixing tests in IPython.testing.
r1982
Fernando Perez
Fixes for test suite in win32 when all dependencies (esp. Twisted) are...
r2461 @doctest_deco
Fernando Perez
Ensure that we don't damage the __builtins__ object after %run....
r1955 def full_path(startPath,files):
"""Make full paths for all the listed files, based on startPath.
Only the base part of startPath is kept, since this routine is typically
used with a script's __file__ variable as startPath. The base of startPath
is then prepended to all the listed files, forming the output list.
Brian Granger
Merging Fernando's fixes from his trunk-dev and fixing testing things....
r1973 Parameters
----------
Fernando Perez
Ensure that we don't damage the __builtins__ object after %run....
r1955 startPath : string
Initial path to use as the base for the results. This path is split
using os.path.split() and only its first component is kept.
files : string or list
One or more files.
Brian Granger
Merging Fernando's fixes from his trunk-dev and fixing testing things....
r1973 Examples
--------
Fernando Perez
Ensure that we don't damage the __builtins__ object after %run....
r1955
>>> full_path('/foo/bar.py',['a.txt','b.txt'])
['/foo/a.txt', '/foo/b.txt']
>>> full_path('/foo',['a.txt','b.txt'])
['/a.txt', '/b.txt']
If a single file is given, the output is still a list:
>>> full_path('/foo','a.txt')
['/a.txt']
"""
Brian Granger
Work to address the review comments on Fernando's branch....
r2498 files = list_strings(files)
Fernando Perez
Ensure that we don't damage the __builtins__ object after %run....
r1955 base = os.path.split(startPath)[0]
return [ os.path.join(base,f) for f in files ]
Fernando Perez
Add test utility for parsing test output from stdout/stderr
r2353
def parse_test_output(txt):
"""Parse the output of a test run and return errors, failures.
Parameters
----------
txt : str
Text output of a test run, assumed to contain a line of one of the
following forms::
'FAILED (errors=1)'
'FAILED (failures=1)'
'FAILED (errors=1, failures=1)'
Returns
-------
nerr, nfail: number of errors and failures.
"""
err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
if err_m:
nerr = int(err_m.group(1))
nfail = 0
return nerr, nfail
Bernardo B. Marques
remove all trailling spaces
r4872
Fernando Perez
Add test utility for parsing test output from stdout/stderr
r2353 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
if fail_m:
nerr = 0
nfail = int(fail_m.group(1))
return nerr, nfail
both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
re.MULTILINE)
if both_m:
nerr = int(both_m.group(1))
nfail = int(both_m.group(2))
return nerr, nfail
Bernardo B. Marques
remove all trailling spaces
r4872
Fernando Perez
Add test utility for parsing test output from stdout/stderr
r2353 # If the input didn't match any of these forms, assume no error/failures
return 0, 0
Fernando Perez
Massive amount of work to improve the test suite, restores doctests....
r2414
Fernando Perez
Add test utility for parsing test output from stdout/stderr
r2353 # So nose doesn't think this is a test
parse_test_output.__test__ = False
Fernando Perez
Massive amount of work to improve the test suite, restores doctests....
r2414
def default_argv():
"""Return a valid default argv for creating testing instances of ipython"""
Fernando Perez
Minimize stdout side effects in testing instances.
r2477 return ['--quick', # so no config file is loaded
# Other defaults to minimize side effects on stdout
MinRK
disallow no-prefix `ipython foo=bar` argument style....
r4197 '--colors=NoColor', '--no-term-title','--no-banner',
'--autocall=0']
Brian Granger
More work addressing review comments for Fernando's branch....
r2499
def default_config():
"""Return a config object with good defaults for testing."""
config = Config()
Brian Granger
Complete reorganization of InteractiveShell....
r2761 config.TerminalInteractiveShell.colors = 'NoColor'
config.TerminalTerminalInteractiveShell.term_title = False,
config.TerminalInteractiveShell.autocall = 0
MinRK
add test history db to shell.tempfiles for cleanup...
r4602 config.HistoryManager.hist_file = tempfile.mktemp(u'test_hist.sqlite')
Thomas Kluyver
Tests can no longer use db in memory: doesn't work with multiple threads.
r3712 config.HistoryManager.db_cache_size = 10000
Brian Granger
More work addressing review comments for Fernando's branch....
r2499 return config
Fernando Perez
Massive amount of work to improve the test suite, restores doctests....
r2414
Fernando Perez
Fix extensions test suite (small, but now it runs and passes!)
r2415 def ipexec(fname, options=None):
Fernando Perez
Massive amount of work to improve the test suite, restores doctests....
r2414 """Utility to call 'ipython filename'.
Starts IPython witha minimal and safe configuration to make startup as fast
as possible.
Note that this starts IPython in a subprocess!
Parameters
----------
fname : str
Name of file to be executed (should have .py or .ipy extension).
Fernando Perez
Fix extensions test suite (small, but now it runs and passes!)
r2415 options : optional, list
Extra command-line flags to be passed to IPython.
Fernando Perez
Massive amount of work to improve the test suite, restores doctests....
r2414 Returns
-------
(stdout, stderr) of ipython subprocess.
Fernando Perez
Fix extensions test suite (small, but now it runs and passes!)
r2415 """
if options is None: options = []
Bernardo B. Marques
remove all trailling spaces
r4872
Fernando Perez
Minimize stdout side effects in testing instances.
r2477 # For these subprocess calls, eliminate all prompt printing so we only see
# output from script execution
MinRK
PromptManager fixes...
r5548 prompt_opts = [ '--PromptManager.in_template=""',
'--PromptManager.in2_template=""',
'--PromptManager.out_template=""'
MinRK
catch up tests to recent changes...
r4029 ]
Fernando Perez
Minimize stdout side effects in testing instances.
r2477 cmdargs = ' '.join(default_argv() + prompt_opts + options)
Bernardo B. Marques
remove all trailling spaces
r4872
Fernando Perez
Massive amount of work to improve the test suite, restores doctests....
r2414 _ip = get_ipython()
test_dir = os.path.dirname(__file__)
Fernando Perez
Make it possible to run the tests from the source dir without installation....
r2481
Thomas Kluyver
Add AssertPrints context manager to check output from tests.
r4901 ipython_cmd = find_cmd('ipython3' if py3compat.PY3 else 'ipython')
Fernando Perez
Various fixes for IPython.core tests to pass under win32.
r2446 # Absolute path for filename
Brian Granger
Removed the top-level iptest.py and INSTALLED logic....
r2507 full_fname = os.path.join(test_dir, fname)
Fernando Perez
Robustness fixes in test suite machinery....
r2494 full_cmd = '%s %s %s' % (ipython_cmd, cmdargs, full_fname)
#print >> sys.stderr, 'FULL CMD:', full_cmd # dbg
MinRK
strip leading 'ESC[?1034h' in tests caused by `import readline`...
r4470 out = getoutputerror(full_cmd)
# `import readline` causes 'ESC[?1034h' to be the first output sometimes,
# so strip that off the front of the first line if it is found
if out:
first = out[0]
m = re.match(r'\x1b\[[^h]+h', first)
if m:
# strip initial readline escape
out = list(out)
out[0] = first[len(m.group()):]
out = tuple(out)
return out
Fernando Perez
Massive amount of work to improve the test suite, restores doctests....
r2414
Fernando Perez
Robustness fixes in test suite machinery....
r2494 def ipexec_validate(fname, expected_out, expected_err='',
Fernando Perez
Fix extensions test suite (small, but now it runs and passes!)
r2415 options=None):
Fernando Perez
Massive amount of work to improve the test suite, restores doctests....
r2414 """Utility to call 'ipython filename' and validate output/error.
This function raises an AssertionError if the validation fails.
Note that this starts IPython in a subprocess!
Parameters
----------
fname : str
Name of the file to be executed (should have .py or .ipy extension).
expected_out : str
Expected stdout of the process.
Fernando Perez
Fix extensions test suite (small, but now it runs and passes!)
r2415 expected_err : optional, str
Expected stderr of the process.
options : optional, list
Extra command-line flags to be passed to IPython.
Fernando Perez
Massive amount of work to improve the test suite, restores doctests....
r2414 Returns
-------
None
"""
Fernando Perez
Remove accidentally introduced runtime nose dependencies.
r2442 import nose.tools as nt
Bernardo B. Marques
remove all trailling spaces
r4872
MinRK
fix missing options arg to ipexec in ipexec_validate
r5249 out, err = ipexec(fname, options)
Fernando Perez
Robustness fixes in test suite machinery....
r2494 #print 'OUT', out # dbg
#print 'ERR', err # dbg
# If there are any errors, we must check those befor stdout, as they may be
# more informative than simply having an empty stdout.
if err:
if expected_err:
nt.assert_equals(err.strip(), expected_err.strip())
else:
raise ValueError('Running file %r produced error: %r' %
(fname, err))
# If no errors or output on stderr was expected, match stdout
Fernando Perez
Massive amount of work to improve the test suite, restores doctests....
r2414 nt.assert_equals(out.strip(), expected_out.strip())
Fernando Perez
Fix extensions test suite (small, but now it runs and passes!)
r2415
class TempFileMixin(object):
"""Utility class to create temporary Python/IPython files.
Meant as a mixin class for test cases."""
Bernardo B. Marques
remove all trailling spaces
r4872
Fernando Perez
Fix extensions test suite (small, but now it runs and passes!)
r2415 def mktmp(self, src, ext='.py'):
"""Make a valid python temp file."""
fname, f = temp_pyfile(src, ext)
self.tmpfile = f
self.fname = fname
Fernando Perez
Make our temp file mixin unittest-friendly....
r2907 def tearDown(self):
Fernando Perez
Various fixes for IPython.core tests to pass under win32.
r2446 if hasattr(self, 'tmpfile'):
# If the tmpfile wasn't made because of skipped tests, like in
# win32, there's nothing to cleanup.
self.tmpfile.close()
try:
os.unlink(self.fname)
except:
# On Windows, even though we close the file, we still can't
# delete it. I have no clue why
pass
Fernando Perez
Fix extensions test suite (small, but now it runs and passes!)
r2415
Thomas Kluyver
Reuse common code for inputsplitter and prefilter.
r4746 pair_fail_msg = ("Testing {0}\n\n"
Thomas Kluyver
Add testing function check_pairs to check input/output pairs against a function, and produce useful failure messages.
r4079 "In:\n"
" {1!r}\n"
"Expected:\n"
" {2!r}\n"
"Got:\n"
" {3!r}\n")
def check_pairs(func, pairs):
Bernardo B. Marques
remove all trailling spaces
r4872 """Utility function for the common case of checking a function with a
Thomas Kluyver
Add testing function check_pairs to check input/output pairs against a function, and produce useful failure messages.
r4079 sequence of input/output pairs.
Bernardo B. Marques
remove all trailling spaces
r4872
Thomas Kluyver
Add testing function check_pairs to check input/output pairs against a function, and produce useful failure messages.
r4079 Parameters
----------
func : callable
The function to be tested. Should accept a single argument.
pairs : iterable
A list of (input, expected_output) tuples.
Bernardo B. Marques
remove all trailling spaces
r4872
Thomas Kluyver
Add testing function check_pairs to check input/output pairs against a function, and produce useful failure messages.
r4079 Returns
-------
None. Raises an AssertionError if any output does not match the expected
value.
"""
Thomas Kluyver
Reuse common code for inputsplitter and prefilter.
r4746 name = getattr(func, "func_name", getattr(func, "__name__", "<unknown>"))
Thomas Kluyver
Add testing function check_pairs to check input/output pairs against a function, and produce useful failure messages.
r4079 for inp, expected in pairs:
out = func(inp)
Thomas Kluyver
Reuse common code for inputsplitter and prefilter.
r4746 assert out == expected, pair_fail_msg.format(name, inp, expected, out)
MinRK
aliases match flag pattern ('-' as wordsep, not '_')...
r4214
Thomas Kluyver
Follow Fernando's suggestions.
r4920
Thomas Kluyver
Add AssertPrints context manager to check output from tests.
r4901 if py3compat.PY3:
MyStringIO = StringIO
else:
# In Python 2, stdout/stderr can have either bytes or unicode written to them,
# so we need a class that can handle both.
class MyStringIO(StringIO):
def write(self, s):
s = py3compat.cast_unicode(s, encoding=getdefaultencoding())
super(MyStringIO, self).write(s)
notprinted_msg = """Did not find {0!r} in printed output (on {1}):
{2!r}"""
Thomas Kluyver
Follow Fernando's suggestions.
r4920
Thomas Kluyver
Add AssertPrints context manager to check output from tests.
r4901 class AssertPrints(object):
"""Context manager for testing that code prints certain text.
Examples
--------
Thomas Kluyver
Use AssertPrints in tests for autoreload extension.
r4904 >>> with AssertPrints("abc", suppress=False):
Thomas Kluyver
Add AssertPrints context manager to check output from tests.
r4901 ... print "abcd"
... print "def"
...
abcd
def
"""
Thomas Kluyver
Use AssertPrints in tests for autoreload extension.
r4904 def __init__(self, s, channel='stdout', suppress=True):
Thomas Kluyver
Add AssertPrints context manager to check output from tests.
r4901 self.s = s
self.channel = channel
Thomas Kluyver
Use AssertPrints in tests for autoreload extension.
r4904 self.suppress = suppress
Thomas Kluyver
Add AssertPrints context manager to check output from tests.
r4901
def __enter__(self):
self.orig_stream = getattr(sys, self.channel)
self.buffer = MyStringIO()
self.tee = Tee(self.buffer, channel=self.channel)
Thomas Kluyver
Use AssertPrints in tests for autoreload extension.
r4904 setattr(sys, self.channel, self.buffer if self.suppress else self.tee)
Thomas Kluyver
Add AssertPrints context manager to check output from tests.
r4901
def __exit__(self, etype, value, traceback):
self.tee.flush()
setattr(sys, self.channel, self.orig_stream)
printed = self.buffer.getvalue()
assert self.s in printed, notprinted_msg.format(self.s, self.channel, printed)
return False
Thomas Kluyver
Use AssertPrints in tests for autoreload extension.
r4904
class AssertNotPrints(AssertPrints):
"""Context manager for checking that certain output *isn't* produced.
Counterpart of AssertPrints"""
def __exit__(self, etype, value, traceback):
self.tee.flush()
setattr(sys, self.channel, self.orig_stream)
printed = self.buffer.getvalue()
assert self.s not in printed, notprinted_msg.format(self.s, self.channel, printed)
return False
Thomas Kluyver
Add AssertPrints context manager to check output from tests.
r4901
MinRK
aliases match flag pattern ('-' as wordsep, not '_')...
r4214 @contextmanager
def mute_warn():
from IPython.utils import warn
save_warn = warn.warn
warn.warn = lambda *a, **kw: None
try:
yield
finally:
Robert Kern
BUG: Allow %magic argument filenames with spaces to be specified with quotes under win32.
r4688 warn.warn = save_warn
@contextmanager
def make_tempfile(name):
""" Create an empty, named, temporary file for the duration of the context.
"""
f = open(name, 'w')
f.close()
try:
yield
finally:
os.unlink(name)