[py-svn] py-trunk commit 52f5dfc7ef98: * properly expose and document runtest-protocol related Exceptions
commits-noreply at bitbucket.org
commits-noreply at bitbucket.org
Tue Apr 27 21:16:51 CEST 2010
# HG changeset patch -- Bitbucket.org
# Project py-trunk
# URL http://bitbucket.org/hpk42/py-trunk/overview
# User holger krekel <holger at merlinux.eu>
# Date 1272395589 -7200
# Node ID 52f5dfc7ef98dd8d1cbca6314aae3fb83a360706
# Parent d622f7f24d98556d71e37e395e2ed0c857ad72fb
* properly expose and document runtest-protocol related Exceptions
and move all definitions to the runner plugin for now.
* also move EXIT codes to session.py, obsoleting outcome.py alltogether.
--- a/py/_plugin/pytest_pdb.py
+++ b/py/_plugin/pytest_pdb.py
@@ -3,7 +3,6 @@ interactive debugging with the Python De
"""
import py
import pdb, sys, linecache
-from py._test.outcome import Skipped
def pytest_addoption(parser):
group = parser.getgroup("general")
@@ -17,7 +16,8 @@ def pytest_configure(config):
class PdbInvoke:
def pytest_runtest_makereport(self, item, call):
- if call.excinfo and not call.excinfo.errisinstance(Skipped):
+ if call.excinfo and not \
+ call.excinfo.errisinstance(py.test.exc.Skipped):
# play well with capturing, slightly hackish
capman = item.config.pluginmanager.getplugin('capturemanager')
capman.suspendcapture()
--- a/py/_plugin/pytest_runner.py
+++ b/py/_plugin/pytest_runner.py
@@ -3,7 +3,23 @@ collect and run test items and create re
"""
import py, sys
-from py._test.outcome import Skipped
+
+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,
+ 'fail' : fail,
+ 'exit' : exit,
+ }
#
# pytest plugin hooks
@@ -141,7 +157,7 @@ class ItemTestReport(BaseReport):
self.failed = True
shortrepr = "?"
longrepr = excinfo
- elif excinfo.errisinstance(Skipped):
+ elif excinfo.errisinstance(py.test.exc.Skipped):
self.skipped = True
shortrepr = "s"
longrepr = self.item._repr_failure_py(excinfo)
@@ -180,7 +196,7 @@ class CollectReport(BaseReport):
self.result = result
else:
self.longrepr = self.collector._repr_failure_py(excinfo)
- if excinfo.errisinstance(Skipped):
+ if excinfo.errisinstance(py.test.exc.Skipped):
self.skipped = True
self.reason = str(excinfo.value)
else:
@@ -259,3 +275,125 @@ class SetupState(object):
except Exception:
col._prepare_exc = sys.exc_info()
raise
+
+# =============================================================
+# Test OutcomeExceptions and helpers for creating them.
+
+
+class OutcomeException(Exception):
+ """ OutcomeException and its subclass instances indicate and
+ contain info about test and collection outcomes.
+ """
+ def __init__(self, msg=None, excinfo=None):
+ self.msg = msg
+ self.excinfo = excinfo
+
+ def __repr__(self):
+ if self.msg:
+ return repr(self.msg)
+ return "<%s instance>" %(self.__class__.__name__,)
+ __str__ = __repr__
+
+class Skipped(OutcomeException):
+ # XXX slighly hackish: on 3k we fake to live in the builtins
+ # in order to have Skipped exception printing shorter/nicer
+ __module__ = 'builtins'
+
+class Failed(OutcomeException):
+ """ raised from an explicit call to py.test.fail() """
+
+class ExceptionFailure(Failed):
+ """ raised by py.test.raises on an exception-assertion mismatch. """
+ def __init__(self, expr, expected, msg=None, excinfo=None):
+ Failed.__init__(self, msg=msg, excinfo=excinfo)
+ self.expr = expr
+ self.expected = expected
+
+class Exit(KeyboardInterrupt):
+ """ raised by py.test.exit for immediate program exits without tracebacks and reporter/summary. """
+ def __init__(self, msg="unknown reason"):
+ self.msg = msg
+ KeyboardInterrupt.__init__(self, msg)
+
+# exposed helper methods
+
+def exit(msg):
+ """ exit testing process as if KeyboardInterrupt was triggered. """
+ __tracebackhide__ = True
+ raise Exit(msg)
+
+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
+ skipped under certain conditions like mismatching platforms or
+ dependencies. See the pytest_skipping plugin for details.
+ """
+ __tracebackhide__ = True
+ raise Skipped(msg=msg)
+
+def fail(msg=""):
+ """ explicitely fail an currently-executing test with the given Message. """
+ __tracebackhide__ = True
+ raise Failed(msg=msg)
+
+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.
+ if args[0] is a string: raise AssertionError if executing the
+ the string in the calling scope does not raise expected exception.
+ for examples:
+ x = 5
+ raises(TypeError, lambda x: x + 'hello', x=x)
+ raises(TypeError, "x + 'hello'")
+ """
+ __tracebackhide__ = True
+ assert args
+ if isinstance(args[0], str):
+ code, = args
+ assert isinstance(code, str)
+ frame = sys._getframe(1)
+ loc = frame.f_locals.copy()
+ loc.update(kwargs)
+ #print "raises frame scope: %r" % frame.f_locals
+ try:
+ code = py.code.Source(code).compile()
+ py.builtin.exec_(code, frame.f_globals, loc)
+ # XXX didn'T mean f_globals == f_locals something special?
+ # this is destroyed here ...
+ except ExpectedException:
+ return py.code.ExceptionInfo()
+ else:
+ func = args[0]
+ try:
+ func(*args[1:], **kwargs)
+ except ExpectedException:
+ return py.code.ExceptionInfo()
+ k = ", ".join(["%s=%r" % x for x in kwargs.items()])
+ if k:
+ k = ', ' + k
+ expr = '%s(%r%s)' %(getattr(func, '__name__', func), args, k)
+ raise ExceptionFailure(msg="DID NOT RAISE",
+ expr=args, expected=ExpectedException)
+
+def importorskip(modname, minversion=None):
+ """ return imported module if it has a higher __version__ than the
+ optionally specified 'minversion' - otherwise call py.test.skip()
+ with a message detailing the mismatch.
+ """
+ compile(modname, '', 'eval') # to catch syntaxerrors
+ try:
+ mod = __import__(modname, None, None, ['__doc__'])
+ except ImportError:
+ py.test.skip("could not import %r" %(modname,))
+ if minversion is None:
+ return mod
+ verattr = getattr(mod, '__version__', None)
+ if isinstance(minversion, str):
+ minver = minversion.split(".")
+ else:
+ minver = list(minversion)
+ if verattr is None or verattr.split(".") < minver:
+ py.test.skip("module %r has __version__ %r, required is: %r" %(
+ modname, verattr, minversion))
+ return mod
+
--- a/testing/plugin/test_pytest_doctest.py
+++ b/testing/plugin/test_pytest_doctest.py
@@ -45,8 +45,6 @@ class TestDoctests:
reprec.assertoutcome(failed=1)
def test_doctest_unexpected_exception(self, testdir):
- from py._test.outcome import Failed
-
p = testdir.maketxtfile("""
>>> i = 0
>>> i = 1
--- a/py/__init__.py
+++ b/py/__init__.py
@@ -38,11 +38,6 @@ py.apipkg.initpkg(__name__, dict(
# helpers for use from test functions or collectors
'__onfirstaccess__' : '._test.config:onpytestaccess',
'__doc__' : '._test:__doc__',
- 'raises' : '._test.outcome:raises',
- 'skip' : '._test.outcome:skip',
- 'importorskip' : '._test.outcome:importorskip',
- 'fail' : '._test.outcome:fail',
- 'exit' : '._test.outcome:exit',
# configuration/initialization related test api
'config' : '._test.config:config_per_process',
'ensuretemp' : '._test.config:ensuretemp',
--- a/py/_test/outcome.py
+++ /dev/null
@@ -1,136 +0,0 @@
-"""
- Test OutcomeExceptions and helpers for creating them.
- py.test.skip|fail|raises helper implementations
-
-"""
-
-import py
-import sys
-
-class OutcomeException(Exception):
- """ OutcomeException and its subclass instances indicate and
- contain info about test and collection outcomes.
- """
- def __init__(self, msg=None, excinfo=None):
- self.msg = msg
- self.excinfo = excinfo
-
- def __repr__(self):
- if self.msg:
- return repr(self.msg)
- return "<%s instance>" %(self.__class__.__name__,)
- __str__ = __repr__
-
-class Passed(OutcomeException):
- pass
-
-class Skipped(OutcomeException):
- # XXX slighly hackish: on 3k we fake to live in the builtins
- # in order to have Skipped exception printing shorter/nicer
- __module__ = 'builtins'
-
-class Failed(OutcomeException):
- pass
-
-class ExceptionFailure(Failed):
- def __init__(self, expr, expected, msg=None, excinfo=None):
- Failed.__init__(self, msg=msg, excinfo=excinfo)
- self.expr = expr
- self.expected = expected
-
-class Exit(KeyboardInterrupt):
- """ for immediate program exits without tracebacks and reporter/summary. """
- def __init__(self, msg="unknown reason"):
- self.msg = msg
- KeyboardInterrupt.__init__(self, msg)
-
-# exposed helper methods
-
-def exit(msg):
- """ exit testing process as if KeyboardInterrupt was triggered. """
- __tracebackhide__ = True
- raise Exit(msg)
-
-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
- skipped under certain conditions like mismatching platforms or
- dependencies. See the pytest_skipping plugin for details.
- """
- __tracebackhide__ = True
- raise Skipped(msg=msg)
-
-def fail(msg=""):
- """ explicitely fail this executing test with the given Message. """
- __tracebackhide__ = True
- raise Failed(msg=msg)
-
-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.
- if args[0] is a string: raise AssertionError if executing the
- the string in the calling scope does not raise expected exception.
- for examples:
- x = 5
- raises(TypeError, lambda x: x + 'hello', x=x)
- raises(TypeError, "x + 'hello'")
- """
- __tracebackhide__ = True
- assert args
- if isinstance(args[0], str):
- code, = args
- assert isinstance(code, str)
- frame = sys._getframe(1)
- loc = frame.f_locals.copy()
- loc.update(kwargs)
- #print "raises frame scope: %r" % frame.f_locals
- try:
- code = py.code.Source(code).compile()
- py.builtin.exec_(code, frame.f_globals, loc)
- # XXX didn'T mean f_globals == f_locals something special?
- # this is destroyed here ...
- except ExpectedException:
- return py.code.ExceptionInfo()
- else:
- func = args[0]
- try:
- func(*args[1:], **kwargs)
- except ExpectedException:
- return py.code.ExceptionInfo()
- k = ", ".join(["%s=%r" % x for x in kwargs.items()])
- if k:
- k = ', ' + k
- expr = '%s(%r%s)' %(getattr(func, '__name__', func), args, k)
- raise ExceptionFailure(msg="DID NOT RAISE",
- expr=args, expected=ExpectedException)
-
-def importorskip(modname, minversion=None):
- """ return imported module if it has a higher __version__ than the
- optionally specified 'minversion' - otherwise call py.test.skip()
- with a message detailing the mismatch.
- """
- compile(modname, '', 'eval') # to catch syntaxerrors
- try:
- mod = __import__(modname, None, None, ['__doc__'])
- except ImportError:
- py.test.skip("could not import %r" %(modname,))
- if minversion is None:
- return mod
- verattr = getattr(mod, '__version__', None)
- if isinstance(minversion, str):
- minver = minversion.split(".")
- else:
- minver = list(minversion)
- if verattr is None or verattr.split(".") < minver:
- py.test.skip("module %r has __version__ %r, required is: %r" %(
- modname, verattr, minversion))
- return mod
-
-
-
-# exitcodes for the command line
-EXIT_OK = 0
-EXIT_TESTSFAILED = 1
-EXIT_INTERRUPTED = 2
-EXIT_INTERNALERROR = 3
-EXIT_NOHOSTS = 4
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -9,6 +9,8 @@ Changes between 1.2.1 and 1.2.2 (release
- 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 .
- ship distribute_setup.py version 0.6.10
--- a/py/_test/pluginmanager.py
+++ b/py/_test/pluginmanager.py
@@ -4,7 +4,6 @@ managing loading and interacting with py
import py
import inspect
from py._plugin import hookspec
-from py._test.outcome import Skipped
default_plugins = (
"default runner capture mark terminal skipping tmpdir monkeypatch "
@@ -139,7 +138,7 @@ class PluginManager(object):
mod = importplugin(modname)
except KeyboardInterrupt:
raise
- except Skipped:
+ except py.test.exc.Skipped:
e = py.std.sys.exc_info()[1]
self._hints.append("skipped plugin %r: %s" %((modname, e.msg)))
else:
--- a/testing/test_config.py
+++ b/testing/test_config.py
@@ -75,13 +75,14 @@ class TestConfigAPI:
py.test.raises(KeyError, 'config.getvalue("y", o)')
def test_config_getvalueorskip(self, testdir):
- from py._test.outcome import Skipped
config = testdir.parseconfig()
- py.test.raises(Skipped, "config.getvalueorskip('hello')")
+ py.test.raises(py.test.exc.Skipped,
+ "config.getvalueorskip('hello')")
verbose = config.getvalueorskip("verbose")
assert verbose == config.option.verbose
config.option.hello = None
- py.test.raises(Skipped, "config.getvalueorskip('hello')")
+ py.test.raises(py.test.exc.Skipped,
+ "config.getvalueorskip('hello')")
def test_config_overwrite(self, testdir):
o = testdir.tmpdir
--- a/testing/root/test_py_imports.py
+++ b/testing/root/test_py_imports.py
@@ -1,7 +1,6 @@
import py
import types
import sys
-from py._test.outcome import Skipped
def checksubpackage(name):
obj = getattr(py, name)
@@ -52,7 +51,7 @@ def test_importall():
modpath = 'py.%s' % relpath
try:
check_import(modpath)
- except Skipped:
+ except py.test.exc.Skipped:
pass
def check_import(modpath):
--- a/testing/test_outcome.py
+++ b/testing/test_outcome.py
@@ -16,13 +16,12 @@ class TestRaises:
py.test.raises(ValueError, int, 'hello')
def test_raises_callable_no_exception(self):
- from py._test.outcome import ExceptionFailure
class A:
def __call__(self):
pass
try:
py.test.raises(ValueError, A())
- except ExceptionFailure:
+ except py.test.exc.ExceptionFailure:
pass
def test_pytest_exit():
@@ -41,23 +40,23 @@ def test_exception_printing_skip():
assert s.startswith("Skipped")
def test_importorskip():
- from py._test.outcome import Skipped, importorskip
- assert importorskip == py.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(Skipped, "py.test.importorskip('alskdj')")
+ 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(Skipped, """
+ py.test.raises(py.test.exc.Skipped, """
py.test.importorskip("hello123", minversion="5.0")
""")
- except Skipped:
+ except py.test.exc.Skipped:
print(py.code.ExceptionInfo())
py.test.fail("spurious skip")
--- a/testing/plugin/test_pytest_runner.py
+++ b/testing/plugin/test_pytest_runner.py
@@ -197,14 +197,13 @@ class BaseFunctionalTests:
assert rep.when == "call"
def test_exit_propagates(self, testdir):
- from py._test.outcome import Exit
try:
testdir.runitem("""
- from py._test.outcome import Exit
+ import py
def test_func():
- raise Exit()
+ raise py.test.exc.Exit()
""")
- except Exit:
+ except py.test.exc.Exit:
pass
else:
py.test.fail("did not raise")
@@ -216,7 +215,6 @@ class TestExecutionNonForked(BaseFunctio
return f
def test_keyboardinterrupt_propagates(self, testdir):
- from py._test.outcome import Exit
try:
testdir.runitem("""
def test_func():
--- a/py/_test/session.py
+++ b/py/_test/session.py
@@ -6,7 +6,13 @@
"""
import py
-from py._test import outcome
+
+# exitcodes for the command line
+EXIT_OK = 0
+EXIT_TESTSFAILED = 1
+EXIT_INTERRUPTED = 2
+EXIT_INTERNALERROR = 3
+EXIT_NOHOSTS = 4
# imports used for genitems()
Item = py.test.collect.Item
@@ -96,21 +102,21 @@ class Session(object):
""" main loop for running tests. """
self.shouldstop = False
self.sessionstarts()
- exitstatus = outcome.EXIT_OK
+ exitstatus = EXIT_OK
try:
self._mainloop(colitems)
if self._testsfailed:
- exitstatus = outcome.EXIT_TESTSFAILED
+ exitstatus = EXIT_TESTSFAILED
self.sessionfinishes(exitstatus=exitstatus)
except KeyboardInterrupt:
excinfo = py.code.ExceptionInfo()
self.config.hook.pytest_keyboard_interrupt(excinfo=excinfo)
- exitstatus = outcome.EXIT_INTERRUPTED
+ exitstatus = EXIT_INTERRUPTED
except:
excinfo = py.code.ExceptionInfo()
self.config.pluginmanager.notify_exception(excinfo)
- exitstatus = outcome.EXIT_INTERNALERROR
- if exitstatus in (outcome.EXIT_INTERNALERROR, outcome.EXIT_INTERRUPTED):
+ exitstatus = EXIT_INTERNALERROR
+ if exitstatus in (EXIT_INTERNALERROR, EXIT_INTERRUPTED):
self.sessionfinishes(exitstatus=exitstatus)
return exitstatus
--- a/testing/test_pycollect.py
+++ b/testing/test_pycollect.py
@@ -444,8 +444,7 @@ def test_modulecol_roundtrip(testdir):
class TestTracebackCutting:
def test_skip_simple(self):
- from py._test.outcome import Skipped
- excinfo = py.test.raises(Skipped, 'py.test.skip("xxx")')
+ excinfo = py.test.raises(py.test.exc.Skipped, 'py.test.skip("xxx")')
assert excinfo.traceback[-1].frame.code.name == "skip"
assert excinfo.traceback[-1].ishidden()
--- a/testing/test_deprecated_api.py
+++ b/testing/test_deprecated_api.py
@@ -1,6 +1,5 @@
import py
-from py._test.outcome import Skipped
class TestCollectDeprecated:
@@ -191,7 +190,7 @@ class TestDisabled:
l = modcol.collect()
assert len(l) == 1
recwarn.clear()
- py.test.raises(Skipped, "modcol.setup()")
+ py.test.raises(py.test.exc.Skipped, "modcol.setup()")
recwarn.pop(DeprecationWarning)
def test_disabled_class(self, recwarn, testdir):
@@ -208,7 +207,7 @@ class TestDisabled:
l = modcol.collect()
assert len(l) == 1
recwarn.clear()
- py.test.raises(Skipped, "modcol.setup()")
+ py.test.raises(py.test.exc.Skipped, "modcol.setup()")
recwarn.pop(DeprecationWarning)
def test_disabled_class_functional(self, testdir):
More information about the pytest-commit
mailing list