diff --git a/CHANGELOG b/CHANGELOG index 2ee69f4dc..de14bcf5f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,8 +9,9 @@ Changes between 1.2.1 and 1.2.2 (release pending) - added links to the new capturelog and coverage plugins - (issue87) fix unboundlocal error in assertionold code - (issue86) improve documentation for looponfailing -- expose some internal test running exceptions under py.test.exc.* - and shift raises/importorskip etc. helper definitions to runner plugin . +- expose test outcome related exceptions as py.test.skip.Exception, + py.test.raises.Exception etc., useful mostly for plugins + doing special outcome interpreteration/tweaking - ship distribute_setup.py version 0.6.10 diff --git a/py/_plugin/pytest_pdb.py b/py/_plugin/pytest_pdb.py index e2a3bb3e2..f8b69f799 100644 --- a/py/_plugin/pytest_pdb.py +++ b/py/_plugin/pytest_pdb.py @@ -17,7 +17,7 @@ def pytest_configure(config): class PdbInvoke: def pytest_runtest_makereport(self, item, call): if call.excinfo and not \ - call.excinfo.errisinstance(py.test.exc.Skipped): + call.excinfo.errisinstance(py.test.skip.Exception): # play well with capturing, slightly hackish capman = item.config.pluginmanager.getplugin('capturemanager') capman.suspendcapture() diff --git a/py/_plugin/pytest_runner.py b/py/_plugin/pytest_runner.py index cf0f9a301..c295dbe5f 100644 --- a/py/_plugin/pytest_runner.py +++ b/py/_plugin/pytest_runner.py @@ -5,15 +5,7 @@ collect and run test items and create reports. import py, sys def pytest_namespace(): - class exc: - """ namespace holding py.test runner exceptions. """ - Skipped = Skipped - ExceptionFailure = ExceptionFailure - Failed = Failed - Exit = Exit - return { - 'exc' : exc, 'raises' : raises, 'skip' : skip, 'importorskip' : importorskip, @@ -157,7 +149,7 @@ class ItemTestReport(BaseReport): self.failed = True shortrepr = "?" longrepr = excinfo - elif excinfo.errisinstance(py.test.exc.Skipped): + elif excinfo.errisinstance(py.test.skip.Exception): self.skipped = True shortrepr = "s" longrepr = self.item._repr_failure_py(excinfo) @@ -196,7 +188,7 @@ class CollectReport(BaseReport): self.result = result else: self.longrepr = self.collector._repr_failure_py(excinfo) - if excinfo.errisinstance(py.test.exc.Skipped): + if excinfo.errisinstance(py.test.skip.Exception): self.skipped = True self.reason = str(excinfo.value) else: @@ -322,6 +314,8 @@ def exit(msg): __tracebackhide__ = True raise Exit(msg) +exit.Exception = Exit + def skip(msg=""): """ skip an executing test with the given message. Note: it's usually better use the py.test.mark.skipif marker to declare a test to be @@ -331,11 +325,15 @@ def skip(msg=""): __tracebackhide__ = True raise Skipped(msg=msg) +skip.Exception = Skipped + def fail(msg=""): """ explicitely fail an currently-executing test with the given Message. """ __tracebackhide__ = True raise Failed(msg=msg) +fail.Exception = Failed + def raises(ExpectedException, *args, **kwargs): """ if args[0] is callable: raise AssertionError if calling it with the remaining arguments does not raise the expected exception. @@ -375,6 +373,8 @@ def raises(ExpectedException, *args, **kwargs): raise ExceptionFailure(msg="DID NOT RAISE", expr=args, expected=ExpectedException) +raises.Exception = ExceptionFailure + def importorskip(modname, minversion=None): """ return imported module if it has a higher __version__ than the optionally specified 'minversion' - otherwise call py.test.skip() diff --git a/py/_test/pluginmanager.py b/py/_test/pluginmanager.py index b84a9938b..6392ff911 100644 --- a/py/_test/pluginmanager.py +++ b/py/_test/pluginmanager.py @@ -138,7 +138,7 @@ class PluginManager(object): mod = importplugin(modname) except KeyboardInterrupt: raise - except py.test.exc.Skipped: + except py.test.skip.Exception: e = py.std.sys.exc_info()[1] self._hints.append("skipped plugin %r: %s" %((modname, e.msg))) else: diff --git a/testing/plugin/test_pytest_runner.py b/testing/plugin/test_pytest_runner.py index 462069ef0..f4e9a9ff0 100644 --- a/testing/plugin/test_pytest_runner.py +++ b/testing/plugin/test_pytest_runner.py @@ -1,4 +1,4 @@ -import py +import py, sys from py._plugin import pytest_runner as runner from py._code.code import ReprExceptionInfo @@ -201,9 +201,9 @@ class BaseFunctionalTests: testdir.runitem(""" import py def test_func(): - raise py.test.exc.Exit() + raise py.test.exit.Exception() """) - except py.test.exc.Exit: + except py.test.exit.Exception: pass else: py.test.fail("did not raise") @@ -313,3 +313,91 @@ def test_runtest_in_module_ordering(testdir): assert result.stdout.fnmatch_lines([ "*2 passed*" ]) + +class TestRaises: + def test_raises(self): + py.test.raises(ValueError, "int('qwe')") + + def test_raises_exec(self): + py.test.raises(ValueError, "a,x = []") + + def test_raises_syntax_error(self): + py.test.raises(SyntaxError, "qwe qwe qwe") + + def test_raises_function(self): + py.test.raises(ValueError, int, 'hello') + + def test_raises_callable_no_exception(self): + class A: + def __call__(self): + pass + try: + py.test.raises(ValueError, A()) + except py.test.raises.Exception: + pass + +def test_pytest_exit(): + try: + py.test.exit("hello") + except py.test.exit.Exception: + excinfo = py.code.ExceptionInfo() + assert excinfo.errisinstance(KeyboardInterrupt) + +def test_pytest_fail(): + try: + py.test.fail("hello") + except py.test.fail.Exception: + excinfo = py.code.ExceptionInfo() + s = excinfo.exconly(tryshort=True) + assert s.startswith("Failed") + +def test_exception_printing_skip(): + try: + py.test.skip("hello") + except py.test.skip.Exception: + excinfo = py.code.ExceptionInfo() + s = excinfo.exconly(tryshort=True) + assert s.startswith("Skipped") + +def test_importorskip(): + importorskip = py.test.importorskip + try: + sys = importorskip("sys") + assert sys == py.std.sys + #path = py.test.importorskip("os.path") + #assert path == py.std.os.path + py.test.raises(py.test.skip.Exception, + "py.test.importorskip('alskdj')") + py.test.raises(SyntaxError, "py.test.importorskip('x y z')") + py.test.raises(SyntaxError, "py.test.importorskip('x=y')") + path = importorskip("py", minversion=".".join(py.__version__)) + mod = py.std.types.ModuleType("hello123") + mod.__version__ = "1.3" + py.test.raises(py.test.skip.Exception, """ + py.test.importorskip("hello123", minversion="5.0") + """) + except py.test.skip.Exception: + print(py.code.ExceptionInfo()) + py.test.fail("spurious skip") + +def test_importorskip_imports_last_module_part(): + import os + ospath = py.test.importorskip("os.path") + assert os.path == ospath + + +def test_pytest_cmdline_main(testdir): + p = testdir.makepyfile(""" + import sys + sys.path.insert(0, %r) + import py + def test_hello(): + assert 1 + if __name__ == '__main__': + py.test.cmdline.main([__file__]) + """ % (str(py._pydir.dirpath()))) + import subprocess + popen = subprocess.Popen([sys.executable, str(p)], stdout=subprocess.PIPE) + s = popen.stdout.read() + ret = popen.wait() + assert ret == 0 diff --git a/testing/root/test_py_imports.py b/testing/root/test_py_imports.py index 01b504431..e3cb97e14 100644 --- a/testing/root/test_py_imports.py +++ b/testing/root/test_py_imports.py @@ -51,7 +51,7 @@ def test_importall(): modpath = 'py.%s' % relpath try: check_import(modpath) - except py.test.exc.Skipped: + except py.test.skip.Exception: pass def check_import(modpath): diff --git a/testing/test_config.py b/testing/test_config.py index 5c548587e..69a1f7e24 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -76,12 +76,12 @@ class TestConfigAPI: def test_config_getvalueorskip(self, testdir): config = testdir.parseconfig() - py.test.raises(py.test.exc.Skipped, + py.test.raises(py.test.skip.Exception, "config.getvalueorskip('hello')") verbose = config.getvalueorskip("verbose") assert verbose == config.option.verbose config.option.hello = None - py.test.raises(py.test.exc.Skipped, + py.test.raises(py.test.skip.Exception, "config.getvalueorskip('hello')") def test_config_overwrite(self, testdir): diff --git a/testing/test_deprecated_api.py b/testing/test_deprecated_api.py index 8d624c880..bf513aee2 100644 --- a/testing/test_deprecated_api.py +++ b/testing/test_deprecated_api.py @@ -190,7 +190,7 @@ class TestDisabled: l = modcol.collect() assert len(l) == 1 recwarn.clear() - py.test.raises(py.test.exc.Skipped, "modcol.setup()") + py.test.raises(py.test.skip.Exception, "modcol.setup()") recwarn.pop(DeprecationWarning) def test_disabled_class(self, recwarn, testdir): @@ -207,7 +207,7 @@ class TestDisabled: l = modcol.collect() assert len(l) == 1 recwarn.clear() - py.test.raises(py.test.exc.Skipped, "modcol.setup()") + py.test.raises(py.test.skip.Exception, "modcol.setup()") recwarn.pop(DeprecationWarning) def test_disabled_class_functional(self, testdir): diff --git a/testing/test_outcome.py b/testing/test_outcome.py deleted file mode 100644 index 6cdc6409c..000000000 --- a/testing/test_outcome.py +++ /dev/null @@ -1,83 +0,0 @@ - -import py -import sys - -class TestRaises: - def test_raises(self): - py.test.raises(ValueError, "int('qwe')") - - def test_raises_exec(self): - py.test.raises(ValueError, "a,x = []") - - def test_raises_syntax_error(self): - py.test.raises(SyntaxError, "qwe qwe qwe") - - def test_raises_function(self): - py.test.raises(ValueError, int, 'hello') - - def test_raises_callable_no_exception(self): - class A: - def __call__(self): - pass - try: - py.test.raises(ValueError, A()) - except py.test.exc.ExceptionFailure: - pass - -def test_pytest_exit(): - try: - py.test.exit("hello") - except: - excinfo = py.code.ExceptionInfo() - assert excinfo.errisinstance(KeyboardInterrupt) - -def test_exception_printing_skip(): - try: - py.test.skip("hello") - except Exception: - excinfo = py.code.ExceptionInfo() - s = excinfo.exconly(tryshort=True) - assert s.startswith("Skipped") - -def test_importorskip(): - importorskip = py.test.importorskip - try: - sys = importorskip("sys") - assert sys == py.std.sys - #path = py.test.importorskip("os.path") - #assert path == py.std.os.path - py.test.raises(py.test.exc.Skipped, - "py.test.importorskip('alskdj')") - py.test.raises(SyntaxError, "py.test.importorskip('x y z')") - py.test.raises(SyntaxError, "py.test.importorskip('x=y')") - path = importorskip("py", minversion=".".join(py.__version__)) - mod = py.std.types.ModuleType("hello123") - mod.__version__ = "1.3" - py.test.raises(py.test.exc.Skipped, """ - py.test.importorskip("hello123", minversion="5.0") - """) - except py.test.exc.Skipped: - print(py.code.ExceptionInfo()) - py.test.fail("spurious skip") - -def test_importorskip_imports_last_module_part(): - import os - ospath = py.test.importorskip("os.path") - assert os.path == ospath - - -def test_pytest_cmdline_main(testdir): - p = testdir.makepyfile(""" - import sys - sys.path.insert(0, %r) - import py - def test_hello(): - assert 1 - if __name__ == '__main__': - py.test.cmdline.main([__file__]) - """ % (str(py._pydir.dirpath()))) - import subprocess - popen = subprocess.Popen([sys.executable, str(p)], stdout=subprocess.PIPE) - s = popen.stdout.read() - ret = popen.wait() - assert ret == 0 diff --git a/testing/test_pycollect.py b/testing/test_pycollect.py index 331d9e4df..416bacbcb 100644 --- a/testing/test_pycollect.py +++ b/testing/test_pycollect.py @@ -444,7 +444,7 @@ def test_modulecol_roundtrip(testdir): class TestTracebackCutting: def test_skip_simple(self): - excinfo = py.test.raises(py.test.exc.Skipped, 'py.test.skip("xxx")') + excinfo = py.test.raises(py.test.skip.Exception, 'py.test.skip("xxx")') assert excinfo.traceback[-1].frame.code.name == "skip" assert excinfo.traceback[-1].ishidden()