Improve error message if pytest.raises is used wrongly
If the type is not checked then an incomprehensible error will occur later. This enforces the type and raies the same exception/msg as CPython does in that case. Docstring unmodified, just re-justified for pep8 compat.
This commit is contained in:
parent
d74f852fd6
commit
faba432996
|
@ -977,15 +977,16 @@ def raises(ExpectedException, *args, **kwargs):
|
||||||
Performance note:
|
Performance note:
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
Similar to caught exception objects in Python, explicitly clearing local
|
Similar to caught exception objects in Python, explicitly clearing
|
||||||
references to returned ``py.code.ExceptionInfo`` objects can help the Python
|
local references to returned ``py.code.ExceptionInfo`` objects can
|
||||||
interpreter speed up its garbage collection.
|
help the Python interpreter speed up its garbage collection.
|
||||||
|
|
||||||
Clearing those references breaks a reference cycle (``ExceptionInfo`` -->
|
Clearing those references breaks a reference cycle
|
||||||
caught exception --> frame stack raising the exception --> current frame
|
(``ExceptionInfo`` --> caught exception --> frame stack raising
|
||||||
stack --> local variables --> ``ExceptionInfo``) which makes Python keep all
|
the exception --> current frame stack --> local variables -->
|
||||||
objects referenced from that cycle (including all local variables in the
|
``ExceptionInfo``) which makes Python keep all objects referenced
|
||||||
current frame) alive until the next cyclic garbage collection run. See the
|
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
|
official Python ``try`` statement documentation for more detailed
|
||||||
information.
|
information.
|
||||||
|
|
||||||
|
@ -995,7 +996,16 @@ def raises(ExpectedException, *args, **kwargs):
|
||||||
# we want to catch a AssertionError
|
# we want to catch a AssertionError
|
||||||
# replace our subclass with the builtin one
|
# replace our subclass with the builtin one
|
||||||
# see https://bitbucket.org/hpk42/pytest/issue/176/pytestraises
|
# 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:
|
if not args:
|
||||||
return RaisesContext(ExpectedException)
|
return RaisesContext(ExpectedException)
|
||||||
|
|
|
@ -62,3 +62,10 @@ class TestRaises:
|
||||||
'*3 passed*',
|
'*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')
|
||||||
|
|
Loading…
Reference in New Issue