diff --git a/_pytest/python.py b/_pytest/python.py index d541dd4d3..01925f539 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -977,15 +977,16 @@ def raises(ExpectedException, *args, **kwargs): Performance note: ----------------- - Similar to caught exception objects in Python, explicitly clearing local - references to returned ``py.code.ExceptionInfo`` objects can help the Python - interpreter speed up its garbage collection. + Similar to caught exception objects in Python, explicitly clearing + local references to returned ``py.code.ExceptionInfo`` objects can + help the Python interpreter speed up its garbage collection. - Clearing those references breaks a reference cycle (``ExceptionInfo`` --> - caught exception --> frame stack raising the exception --> current frame - stack --> local variables --> ``ExceptionInfo``) which makes Python keep all - objects referenced from that cycle (including all local variables in the - current frame) alive until the next cyclic garbage collection run. See the + Clearing those references breaks a reference cycle + (``ExceptionInfo`` --> caught exception --> frame stack raising + the exception --> current frame stack --> local variables --> + ``ExceptionInfo``) which makes Python keep all objects referenced + from that cycle (including all local variables in the current + frame) alive until the next cyclic garbage collection run. See the official Python ``try`` statement documentation for more detailed information. @@ -995,7 +996,16 @@ def raises(ExpectedException, *args, **kwargs): # we want to catch a AssertionError # replace our subclass with the builtin one # see https://bitbucket.org/hpk42/pytest/issue/176/pytestraises - from _pytest.assertion.util import BuiltinAssertionError as ExpectedException + from _pytest.assertion.util import BuiltinAssertionError \ + as ExpectedException + msg = ("exceptions must be old-style classes or" + " derived from BaseException, not %s") + if isinstance(ExpectedException, tuple): + for exc in ExpectedException: + if not inspect.isclass(exc): + raise TypeError(msg % type(exc)) + elif not inspect.isclass(ExpectedException): + raise TypeError(msg % type(ExpectedException)) if not args: return RaisesContext(ExpectedException) diff --git a/testing/python/raises.py b/testing/python/raises.py index 5101fecf0..5caa810e2 100644 --- a/testing/python/raises.py +++ b/testing/python/raises.py @@ -62,3 +62,10 @@ class TestRaises: '*3 passed*', ]) + def test_noclass(self): + with pytest.raises(TypeError): + pytest.raises('wrong', lambda: None) + + def test_tuple(self): + with pytest.raises((KeyError, ValueError)): + raise KeyError('oops')