diff --git a/AUTHORS b/AUTHORS index ad9541423..eb3c016a5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -188,6 +188,7 @@ Tareq Alayan Ted Xiao Thomas Grainger Thomas Hisch +Tim Strazny Tom Dalton Tom Viner Trevor Bekolay diff --git a/_pytest/python_api.py b/_pytest/python_api.py index 0b30b7ac8..1d1617d72 100644 --- a/_pytest/python_api.py +++ b/_pytest/python_api.py @@ -584,10 +584,11 @@ def raises(expected_exception, *args, **kwargs): """ __tracebackhide__ = True - for exc in filterfalse(isclass, always_iterable(expected_exception)): - msg = ("exceptions must be old-style classes or" - " derived from BaseException, not %s") - raise TypeError(msg % type(exc)) + if not issubclass(expected_exception, BaseException): + for exc in filterfalse(isclass, always_iterable(expected_exception)): + msg = ("exceptions must be old-style classes or" + " derived from BaseException, not %s") + raise TypeError(msg % type(exc)) message = "DID NOT RAISE {0}".format(expected_exception) match_expr = None diff --git a/changelog/3372.bugfix.rst b/changelog/3372.bugfix.rst new file mode 100644 index 000000000..722bdab1e --- /dev/null +++ b/changelog/3372.bugfix.rst @@ -0,0 +1 @@ +``pytest.raises`` now works with exception classes that look like iterables. diff --git a/testing/python/raises.py b/testing/python/raises.py index 156319816..053426395 100644 --- a/testing/python/raises.py +++ b/testing/python/raises.py @@ -1,3 +1,4 @@ +from _pytest.outcomes import Failed import pytest import sys @@ -147,3 +148,20 @@ class TestRaises(object): with pytest.raises(ValueError): with pytest.raises(IndexError, match='nomatch'): int('asdf') + + def test_raises_exception_looks_iterable(self): + from six import add_metaclass + + class Meta(type(object)): + def __getitem__(self, item): + return 1/0 + + def __len__(self): + return 1 + + @add_metaclass(Meta) + class ClassLooksIterableException(Exception): + pass + + with pytest.raises(Failed, match="DID NOT RAISE "): + pytest.raises(ClassLooksIterableException, lambda: None)