From 682773e0cb0b39e507b89e1cc631592a4420d17b Mon Sep 17 00:00:00 2001 From: holger krekel Date: Thu, 3 Mar 2011 12:19:17 +0100 Subject: [PATCH] fix issue30 - better handling and reporting of errors in xfail expressions --- CHANGELOG | 7 ++++-- _pytest/skipping.py | 46 ++++++++++++++++++++++++++++++---------- setup.py | 4 ++-- testing/test_skipping.py | 28 ++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4189d4493..59f3f9dd4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,10 +1,13 @@ Changes between 2.0.1 and 2.0.2 ---------------------------------------------- +- fix issue30 - better handling and error reporting for errors in xfail + expressions + - fix issue28 - setup_method and pytest_generate_tests work together -- fix issue24 - pytest_assertrepr_compare produces an in-line - exception on python3 +- fix issue23 - tmpdir argument now works on Python3.2 and WindowsXP + (which apparently starts to offer os.symlink now) - fixed some typos in the docs (thanks Victor) diff --git a/_pytest/skipping.py b/_pytest/skipping.py index 106c8518c..7587a6202 100644 --- a/_pytest/skipping.py +++ b/_pytest/skipping.py @@ -1,6 +1,7 @@ """ support for skip/xfail functions and markers. """ import py, pytest +import sys def pytest_addoption(parser): group = parser.getgroup("general") @@ -32,7 +33,28 @@ class MarkEvaluator: return bool(self.holder) __nonzero__ = __bool__ + def wasvalid(self): + return not hasattr(self, 'exc') + def istrue(self): + try: + return self._istrue() + except KeyboardInterrupt: + raise + except: + self.exc = sys.exc_info() + if isinstance(self.exc[1], SyntaxError): + msg = [" " * (self.exc[1].offset + 4) + "^",] + msg.append("SyntaxError: invalid syntax") + else: + msg = py.std.traceback.format_exception_only(*self.exc[:2]) + pytest.fail("Error evaluating %r expression\n" + " %s\n" + "%s" + %(self.name, self.expr, "\n".join(msg)), + pytrace=False) + + def _istrue(self): if self.holder: d = {'os': py.std.os, 'sys': py.std.sys, 'config': self.item.config} if self.holder.args: @@ -99,16 +121,17 @@ def pytest_runtest_makereport(__multicall__, item, call): return rep rep = __multicall__.execute() evalxfail = item._evalxfail - if not item.config.option.runxfail and evalxfail.istrue(): - if call.excinfo: - rep.outcome = "skipped" - rep.keywords['xfail'] = evalxfail.getexplanation() - elif call.when == "call": - rep.outcome = "failed" - rep.keywords['xfail'] = evalxfail.getexplanation() - else: - if 'xfail' in rep.keywords: - del rep.keywords['xfail'] + if not item.config.option.runxfail: + if evalxfail.wasvalid() and evalxfail.istrue(): + if call.excinfo: + rep.outcome = "skipped" + rep.keywords['xfail'] = evalxfail.getexplanation() + elif call.when == "call": + rep.outcome = "failed" + rep.keywords['xfail'] = evalxfail.getexplanation() + return rep + if 'xfail' in rep.keywords: + del rep.keywords['xfail'] return rep # called by terminalreporter progress reporting @@ -179,7 +202,8 @@ def cached_eval(config, expr, d): except KeyError: #import sys #print >>sys.stderr, ("cache-miss: %r" % expr) - config._evalcache[expr] = x = eval(expr, d) + exprcode = py.code.compile(expr, mode="eval") + config._evalcache[expr] = x = eval(exprcode, d) return x diff --git a/setup.py b/setup.py index d8e17a7a0..f92e14ea3 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ def main(): author='holger krekel, Guido Wesdorp, Carl Friedrich Bolz, Armin Rigo, Maciej Fijalkowski & others', author_email='holger at merlinux.eu', entry_points= make_entry_points(), - install_requires=['py>1.4.0'], + install_requires=['py>1.4.1'], classifiers=['Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', @@ -67,4 +67,4 @@ def make_entry_points(): return {'console_scripts': l} if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/testing/test_skipping.py b/testing/test_skipping.py index 46ec04b06..24dda799d 100644 --- a/testing/test_skipping.py +++ b/testing/test_skipping.py @@ -470,3 +470,31 @@ def test_reportchars(testdir): "XPASS*test_3*", "SKIP*four*", ]) + +def test_errors_in_xfail_skip_expressions(testdir): + testdir.makepyfile(""" + import pytest + @pytest.mark.skipif("asd") + def test_nameerror(): + pass + @pytest.mark.xfail("syntax error") + def test_syntax(): + pass + + def test_func(): + pass + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + "*ERROR*test_nameerror*", + "*evaluating*skipif*expression*", + "*asd*", + "*ERROR*test_syntax*", + "*evaluating*xfail*expression*", + " syntax error", + " ^", + "SyntaxError: invalid syntax", + "*1 pass*2 error*", + ]) + +