| import pytest | |
| from pybind11_tests import exceptions as m | |
| import pybind11_cross_module_tests as cm | |
| def test_std_exception(msg): | |
| with pytest.raises(RuntimeError) as excinfo: | |
| m.throw_std_exception() | |
| assert msg(excinfo.value) == "This exception was intentionally thrown." | |
| def test_error_already_set(msg): | |
| with pytest.raises(RuntimeError) as excinfo: | |
| m.throw_already_set(False) | |
| assert msg(excinfo.value) == "Unknown internal error occurred" | |
| with pytest.raises(ValueError) as excinfo: | |
| m.throw_already_set(True) | |
| assert msg(excinfo.value) == "foo" | |
| def test_cross_module_exceptions(): | |
| with pytest.raises(RuntimeError) as excinfo: | |
| cm.raise_runtime_error() | |
| assert str(excinfo.value) == "My runtime error" | |
| with pytest.raises(ValueError) as excinfo: | |
| cm.raise_value_error() | |
| assert str(excinfo.value) == "My value error" | |
| with pytest.raises(ValueError) as excinfo: | |
| cm.throw_pybind_value_error() | |
| assert str(excinfo.value) == "pybind11 value error" | |
| with pytest.raises(TypeError) as excinfo: | |
| cm.throw_pybind_type_error() | |
| assert str(excinfo.value) == "pybind11 type error" | |
| with pytest.raises(StopIteration) as excinfo: | |
| cm.throw_stop_iteration() | |
| def test_python_call_in_catch(): | |
| d = {} | |
| assert m.python_call_in_destructor(d) is True | |
| assert d["good"] is True | |
| def test_exception_matches(): | |
| m.exception_matches() | |
| def test_custom(msg): | |
| # Can we catch a MyException? | |
| with pytest.raises(m.MyException) as excinfo: | |
| m.throws1() | |
| assert msg(excinfo.value) == "this error should go to a custom type" | |
| # Can we translate to standard Python exceptions? | |
| with pytest.raises(RuntimeError) as excinfo: | |
| m.throws2() | |
| assert msg(excinfo.value) == "this error should go to a standard Python exception" | |
| # Can we handle unknown exceptions? | |
| with pytest.raises(RuntimeError) as excinfo: | |
| m.throws3() | |
| assert msg(excinfo.value) == "Caught an unknown exception!" | |
| # Can we delegate to another handler by rethrowing? | |
| with pytest.raises(m.MyException) as excinfo: | |
| m.throws4() | |
| assert msg(excinfo.value) == "this error is rethrown" | |
| # Can we fall-through to the default handler? | |
| with pytest.raises(RuntimeError) as excinfo: | |
| m.throws_logic_error() | |
| assert msg(excinfo.value) == "this error should fall through to the standard handler" | |
| # Can we handle a helper-declared exception? | |
| with pytest.raises(m.MyException5) as excinfo: | |
| m.throws5() | |
| assert msg(excinfo.value) == "this is a helper-defined translated exception" | |
| # Exception subclassing: | |
| with pytest.raises(m.MyException5) as excinfo: | |
| m.throws5_1() | |
| assert msg(excinfo.value) == "MyException5 subclass" | |
| assert isinstance(excinfo.value, m.MyException5_1) | |
| with pytest.raises(m.MyException5_1) as excinfo: | |
| m.throws5_1() | |
| assert msg(excinfo.value) == "MyException5 subclass" | |
| with pytest.raises(m.MyException5) as excinfo: | |
| try: | |
| m.throws5() | |
| except m.MyException5_1: | |
| raise RuntimeError("Exception error: caught child from parent") | |
| assert msg(excinfo.value) == "this is a helper-defined translated exception" | |
| def test_nested_throws(capture): | |
| """Tests nested (e.g. C++ -> Python -> C++) exception handling""" | |
| def throw_myex(): | |
| raise m.MyException("nested error") | |
| def throw_myex5(): | |
| raise m.MyException5("nested error 5") | |
| # In the comments below, the exception is caught in the first step, thrown in the last step | |
| # C++ -> Python | |
| with capture: | |
| m.try_catch(m.MyException5, throw_myex5) | |
| assert str(capture).startswith("MyException5: nested error 5") | |
| # Python -> C++ -> Python | |
| with pytest.raises(m.MyException) as excinfo: | |
| m.try_catch(m.MyException5, throw_myex) | |
| assert str(excinfo.value) == "nested error" | |
| def pycatch(exctype, f, *args): | |
| try: | |
| f(*args) | |
| except m.MyException as e: | |
| print(e) | |
| # C++ -> Python -> C++ -> Python | |
| with capture: | |
| m.try_catch( | |
| m.MyException5, pycatch, m.MyException, m.try_catch, m.MyException, throw_myex5) | |
| assert str(capture).startswith("MyException5: nested error 5") | |
| # C++ -> Python -> C++ | |
| with capture: | |
| m.try_catch(m.MyException, pycatch, m.MyException5, m.throws4) | |
| assert capture == "this error is rethrown" | |
| # Python -> C++ -> Python -> C++ | |
| with pytest.raises(m.MyException5) as excinfo: | |
| m.try_catch(m.MyException, pycatch, m.MyException, m.throws5) | |
| assert str(excinfo.value) == "this is a helper-defined translated exception" |