6import pybind11_cross_module_tests
as cm
8from pybind11_tests
import exceptions
as m
11def test_std_exception(msg):
12 with pytest.raises(RuntimeError)
as excinfo:
13 m.throw_std_exception()
14 assert msg(excinfo.value) ==
"This exception was intentionally thrown."
17def test_error_already_set(msg):
18 with pytest.raises(RuntimeError)
as excinfo:
19 m.throw_already_set(
False)
22 ==
"Internal error: pybind11::error_already_set called while Python error indicator not set."
25 with pytest.raises(ValueError)
as excinfo:
26 m.throw_already_set(
True)
27 assert msg(excinfo.value) ==
"foo"
30def test_raise_from(msg):
31 with pytest.raises(ValueError)
as excinfo:
33 assert msg(excinfo.value) ==
"outer"
34 assert msg(excinfo.value.__cause__) ==
"inner"
37def test_raise_from_already_set(msg):
38 with pytest.raises(ValueError)
as excinfo:
39 m.raise_from_already_set()
40 assert msg(excinfo.value) ==
"outer"
41 assert msg(excinfo.value.__cause__) ==
"inner"
44def test_cross_module_exceptions(msg):
45 with pytest.raises(RuntimeError)
as excinfo:
46 cm.raise_runtime_error()
47 assert str(excinfo.value) ==
"My runtime error"
49 with pytest.raises(ValueError)
as excinfo:
50 cm.raise_value_error()
51 assert str(excinfo.value) ==
"My value error"
53 with pytest.raises(ValueError)
as excinfo:
54 cm.throw_pybind_value_error()
55 assert str(excinfo.value) ==
"pybind11 value error"
57 with pytest.raises(TypeError)
as excinfo:
58 cm.throw_pybind_type_error()
59 assert str(excinfo.value) ==
"pybind11 type error"
61 with pytest.raises(StopIteration)
as excinfo:
62 cm.throw_stop_iteration()
64 with pytest.raises(cm.LocalSimpleException)
as excinfo:
65 cm.throw_local_simple_error()
66 assert msg(excinfo.value) ==
"external mod"
68 with pytest.raises(KeyError)
as excinfo:
69 cm.throw_local_error()
71 assert str(excinfo.value) ==
"'just local'"
76 "env.MACOS and (env.PYPY or pybind11_tests.compiler_info.startswith('Homebrew Clang'))",
78 reason=
"See Issue #2847, PR #2999, PR #4324",
80def test_cross_module_exception_translator():
81 with pytest.raises(KeyError):
83 m.throw_should_be_translated_to_key_error()
86def test_python_call_in_catch():
88 assert m.python_call_in_destructor(d)
is True
89 assert d[
"good"]
is True
92def ignore_pytest_unraisable_warning(f):
93 unraisable =
"PytestUnraisableExceptionWarning"
95 dec = pytest.mark.filterwarnings(f
"ignore::pytest.{unraisable}")
102@pytest.mark.xfail(env.PYPY, reason="Failure on PyPy 3.8 (7.3.7)", strict=False)
103@ignore_pytest_unraisable_warning
104def test_python_alreadyset_in_destructor(monkeypatch, capsys):
108 if hasattr(sys,
"unraisablehook"):
111 default_hook = sys.__unraisablehook__
113 def hook(unraisable_hook_args):
114 exc_type, exc_value, exc_tb, err_msg, obj = unraisable_hook_args
115 if obj ==
"already_set demo":
118 default_hook(unraisable_hook_args)
122 monkeypatch.setattr(sys,
"unraisablehook", hook)
124 assert m.python_alreadyset_in_destructor(
"already_set demo")
is True
126 assert triggered
is True
128 _, captured_stderr = capsys.readouterr()
129 assert captured_stderr.startswith(
"Exception ignored in: 'already_set demo'")
130 assert captured_stderr.rstrip().endswith(
"KeyError: 'bar'")
133def test_exception_matches():
134 assert m.exception_matches()
135 assert m.exception_matches_base()
136 assert m.modulenotfound_exception_matches_base()
141 with pytest.raises(m.MyException)
as excinfo:
143 assert msg(excinfo.value) ==
"this error should go to a custom type"
146 with pytest.raises(RuntimeError)
as excinfo:
148 assert msg(excinfo.value) ==
"this error should go to a standard Python exception"
151 with pytest.raises(RuntimeError)
as excinfo:
153 assert msg(excinfo.value) ==
"Caught an unknown exception!"
156 with pytest.raises(m.MyException)
as excinfo:
158 assert msg(excinfo.value) ==
"this error is rethrown"
161 with pytest.raises(RuntimeError)
as excinfo:
162 m.throws_logic_error()
164 msg(excinfo.value) ==
"this error should fall through to the standard handler"
168 with pytest.raises(OverflowError)
as excinfo:
169 m.throws_overflow_error()
172 with pytest.raises(m.MyException5)
as excinfo:
174 assert msg(excinfo.value) ==
"this is a helper-defined translated exception"
177 with pytest.raises(m.MyException5)
as excinfo:
179 assert msg(excinfo.value) ==
"MyException5 subclass"
180 assert isinstance(excinfo.value, m.MyException5_1)
182 with pytest.raises(m.MyException5_1)
as excinfo:
184 assert msg(excinfo.value) ==
"MyException5 subclass"
186 with pytest.raises(m.MyException5)
as excinfo:
189 except m.MyException5_1
as err:
190 raise RuntimeError(
"Exception error: caught child from parent")
from err
191 assert msg(excinfo.value) ==
"this is a helper-defined translated exception"
194def test_nested_throws(capture):
195 """Tests nested (e.g. C++ -> Python -> C++) exception handling"""
198 raise m.MyException(
"nested error")
201 raise m.MyException5(
"nested error 5")
207 m.try_catch(m.MyException5, throw_myex5)
208 assert str(capture).startswith(
"MyException5: nested error 5")
211 with pytest.raises(m.MyException)
as excinfo:
212 m.try_catch(m.MyException5, throw_myex)
213 assert str(excinfo.value) ==
"nested error"
215 def pycatch(exctype, f, *args):
218 except m.MyException
as e:
231 assert str(capture).startswith(
"MyException5: nested error 5")
235 m.try_catch(m.MyException, pycatch, m.MyException5, m.throws4)
236 assert capture ==
"this error is rethrown"
239 with pytest.raises(m.MyException5)
as excinfo:
240 m.try_catch(m.MyException, pycatch, m.MyException, m.throws5)
241 assert str(excinfo.value) ==
"this is a helper-defined translated exception"
244def test_throw_nested_exception():
245 with pytest.raises(RuntimeError)
as excinfo:
246 m.throw_nested_exception()
247 assert str(excinfo.value) ==
"Outer Exception"
248 assert str(excinfo.value.__cause__) ==
"Inner Exception"
252def test_invalid_repr():
255 raise AttributeError(
"Example error")
257 with pytest.raises(TypeError):
258 m.simple_bool_passthrough(MyRepr())
261def test_local_translator(msg):
262 """Tests that a local translator works and that the local translator from
263 the cross module is not applied
"""
264 with pytest.raises(RuntimeError)
as excinfo:
266 assert msg(excinfo.value) ==
"MyException6 only handled in this module"
268 with pytest.raises(RuntimeError)
as excinfo:
269 m.throws_local_error()
270 assert not isinstance(excinfo.value, KeyError)
271 assert msg(excinfo.value) ==
"never caught"
273 with pytest.raises(Exception)
as excinfo:
274 m.throws_local_simple_error()
275 assert not isinstance(excinfo.value, cm.LocalSimpleException)
276 assert msg(excinfo.value) ==
"this mod"
280 assert m.error_already_set_what(RuntimeError,
"\ud927") == (
281 "RuntimeError: \\ud927",
287 assert m.error_already_set_what(RuntimeError, b
"\x80") == (
288 "RuntimeError: b'\\x80'",
295 if failure_point ==
"failure_point_init":
296 raise ValueError(
"triggered_failure_point_init")
301 raise ValueError(
"triggered_failure_point_str")
302 return "FlakyException.__str__"
305@pytest.mark.parametrize(
306 "exc_type, exc_value, expected_what",
308 (ValueError,
"plain_str",
"ValueError: plain_str"),
309 (ValueError, (
"tuple_elem",),
"ValueError: tuple_elem"),
310 (FlakyException, (
"happy",),
"FlakyException: FlakyException.__str__"),
314 exc_type, exc_value, expected_what
316 what, py_err_set_after_what = m.error_already_set_what(exc_type, exc_value)
317 assert not py_err_set_after_what
318 assert what == expected_what
321@pytest.mark.skipif("env.PYPY", reason="PyErr_NormalizeException Segmentation fault")
323 with pytest.raises(RuntimeError)
as excinfo:
324 m.error_already_set_what(FlakyException, (
"failure_point_init",))
325 lines =
str(excinfo.value).splitlines()
327 assert lines[:3] == [
328 "pybind11::error_already_set: MISMATCH of original and normalized active exception types:"
329 " ORIGINAL FlakyException REPLACED BY ValueError: triggered_failure_point_init",
334 assert "test_exceptions.py(" in lines[3]
335 assert lines[3].endswith(
"): __init__")
336 assert lines[4].endswith(
"): test_flaky_exception_failure_point_init")
340 what, py_err_set_after_what = m.error_already_set_what(
341 FlakyException, (
"failure_point_str",)
343 assert not py_err_set_after_what
344 lines = what.splitlines()
345 if env.PYPY
and len(lines) == 3:
352 "FlakyException: <MESSAGE UNAVAILABLE DUE TO ANOTHER EXCEPTION>",
354 "MESSAGE UNAVAILABLE DUE TO EXCEPTION: ValueError: triggered_failure_point_str",
362 with pytest.raises(RuntimeError)
as excinfo:
363 m.test_cross_module_interleaved_error_already_set()
364 assert str(excinfo.value)
in (
366 "RuntimeError: 2nd error.",
371 m.test_error_already_set_double_restore(
True)
372 with pytest.raises(RuntimeError)
as excinfo:
373 m.test_error_already_set_double_restore(
False)
374 assert str(excinfo.value) == (
375 "Internal error: pybind11::detail::error_fetch_and_normalize::restore()"
376 " called a second time. ORIGINAL ERROR: ValueError: Random error."
382 what = m.test_pypy_oserror_normalization()
383 assert "this_filename_must_not_exist" in what
def __init__(self, failure_point)
bool hasattr(handle obj, handle name)
bool isinstance(handle obj)
\rst Return true if obj is an instance of T.
size_t len(handle h)
Get the length of a Python object.
def test_error_already_set_message_with_unicode_surrogate()
def test_cross_module_interleaved_error_already_set()
def test_error_already_set_what_with_happy_exceptions(exc_type, exc_value, expected_what)
def test_flaky_exception_failure_point_str()
def test_flaky_exception_failure_point_init()
def test_error_already_set_message_with_malformed_utf8()
def test_error_already_set_double_restore()
def test_pypy_oserror_normalization()