1 from __future__
import annotations
8 import pybind11_cross_module_tests
as cm
10 from pybind11_tests
import exceptions
as m
14 with pytest.raises(RuntimeError)
as excinfo:
15 m.throw_std_exception()
16 assert msg(excinfo.value) ==
"This exception was intentionally thrown."
20 with pytest.raises(RuntimeError)
as excinfo:
21 m.throw_already_set(
False)
24 ==
"Internal error: pybind11::error_already_set called while Python error indicator not set."
27 with pytest.raises(ValueError)
as excinfo:
28 m.throw_already_set(
True)
29 assert msg(excinfo.value) ==
"foo"
33 with pytest.raises(ValueError)
as excinfo:
35 assert msg(excinfo.value) ==
"outer"
36 assert msg(excinfo.value.__cause__) ==
"inner"
40 with pytest.raises(ValueError)
as excinfo:
41 m.raise_from_already_set()
42 assert msg(excinfo.value) ==
"outer"
43 assert msg(excinfo.value.__cause__) ==
"inner"
47 with pytest.raises(RuntimeError)
as excinfo:
48 cm.raise_runtime_error()
49 assert str(excinfo.value) ==
"My runtime error"
51 with pytest.raises(ValueError)
as excinfo:
52 cm.raise_value_error()
53 assert str(excinfo.value) ==
"My value error"
55 with pytest.raises(ValueError)
as excinfo:
56 cm.throw_pybind_value_error()
57 assert str(excinfo.value) ==
"pybind11 value error"
59 with pytest.raises(TypeError)
as excinfo:
60 cm.throw_pybind_type_error()
61 assert str(excinfo.value) ==
"pybind11 type error"
63 with pytest.raises(StopIteration)
as excinfo:
64 cm.throw_stop_iteration()
66 with pytest.raises(cm.LocalSimpleException)
as excinfo:
67 cm.throw_local_simple_error()
68 assert msg(excinfo.value) ==
"external mod"
70 with pytest.raises(KeyError)
as excinfo:
71 cm.throw_local_error()
73 assert str(excinfo.value) ==
"'just local'"
78 "env.MACOS and (env.PYPY or pybind11_tests.compiler_info.startswith('Homebrew Clang'))",
80 reason=
"See Issue #2847, PR #2999, PR #4324",
83 with pytest.raises(KeyError):
85 m.throw_should_be_translated_to_key_error()
90 assert m.python_call_in_destructor(d)
is True
91 assert d[
"good"]
is True
95 unraisable =
"PytestUnraisableExceptionWarning"
97 dec = pytest.mark.filterwarnings(f
"ignore::pytest.{unraisable}")
103 @pytest.mark.xfail(env.PYPY, reason=
"Failure on PyPy 3.8 (7.3.7)", strict=
False)
104 @ignore_pytest_unraisable_warning
109 if hasattr(sys,
"unraisablehook"):
112 default_hook = sys.__unraisablehook__
114 def hook(unraisable_hook_args):
115 exc_type, exc_value, exc_tb, err_msg, obj = unraisable_hook_args
116 if obj ==
"already_set demo":
119 default_hook(unraisable_hook_args)
123 monkeypatch.setattr(sys,
"unraisablehook", hook)
125 assert m.python_alreadyset_in_destructor(
"already_set demo")
is True
127 assert triggered
is True
129 _, captured_stderr = capsys.readouterr()
130 assert captured_stderr.startswith(
"Exception ignored in: 'already_set demo'")
131 assert captured_stderr.rstrip().endswith(
"KeyError: 'bar'")
135 assert m.exception_matches()
136 assert m.exception_matches_base()
137 assert m.modulenotfound_exception_matches_base()
142 with pytest.raises(m.MyException)
as excinfo:
144 assert msg(excinfo.value) ==
"this error should go to py::exception<MyException>"
147 with pytest.raises(m.MyExceptionUseDeprecatedOperatorCall)
as excinfo:
151 ==
"this error should go to py::exception<MyExceptionUseDeprecatedOperatorCall>"
155 with pytest.raises(RuntimeError)
as excinfo:
157 assert msg(excinfo.value) ==
"this error should go to a standard Python exception"
160 with pytest.raises(RuntimeError)
as excinfo:
162 assert msg(excinfo.value) ==
"Caught an unknown exception!"
165 with pytest.raises(m.MyException)
as excinfo:
167 assert msg(excinfo.value) ==
"this error is rethrown"
170 with pytest.raises(RuntimeError)
as excinfo:
171 m.throws_logic_error()
173 msg(excinfo.value) ==
"this error should fall through to the standard handler"
177 with pytest.raises(OverflowError)
as excinfo:
178 m.throws_overflow_error()
181 with pytest.raises(m.MyException5)
as excinfo:
183 assert msg(excinfo.value) ==
"this is a helper-defined translated exception"
186 with pytest.raises(m.MyException5)
as excinfo:
188 assert msg(excinfo.value) ==
"MyException5 subclass"
189 assert isinstance(excinfo.value, m.MyException5_1)
191 with pytest.raises(m.MyException5_1)
as excinfo:
193 assert msg(excinfo.value) ==
"MyException5 subclass"
195 with pytest.raises(m.MyException5)
as excinfo:
198 except m.MyException5_1
as err:
199 raise RuntimeError(
"Exception error: caught child from parent")
from err
200 assert msg(excinfo.value) ==
"this is a helper-defined translated exception"
204 """Tests nested (e.g. C++ -> Python -> C++) exception handling"""
207 raise m.MyException(
"nested error")
210 raise m.MyException5(
"nested error 5")
216 m.try_catch(m.MyException5, throw_myex5)
217 assert str(capture).startswith(
"MyException5: nested error 5")
220 with pytest.raises(m.MyException)
as excinfo:
221 m.try_catch(m.MyException5, throw_myex)
222 assert str(excinfo.value) ==
"nested error"
224 def pycatch(exctype, f, *args):
227 except m.MyException
as e:
240 assert str(capture).startswith(
"MyException5: nested error 5")
244 m.try_catch(m.MyException, pycatch, m.MyException5, m.throws4)
245 assert capture ==
"this error is rethrown"
248 with pytest.raises(m.MyException5)
as excinfo:
249 m.try_catch(m.MyException, pycatch, m.MyException, m.throws5)
250 assert str(excinfo.value) ==
"this is a helper-defined translated exception"
255 sys.platform.startswith(
"win32")
and "Clang" in pybind11_tests.compiler_info,
256 reason=
"Started segfaulting February 2024",
259 with pytest.raises(RuntimeError)
as excinfo:
260 m.throw_nested_exception()
261 assert str(excinfo.value) ==
"Outer Exception"
262 assert str(excinfo.value.__cause__) ==
"Inner Exception"
269 raise AttributeError(
"Example error")
271 with pytest.raises(TypeError):
272 m.simple_bool_passthrough(MyRepr())
276 """Tests that a local translator works and that the local translator from
277 the cross module is not applied"""
278 with pytest.raises(RuntimeError)
as excinfo:
280 assert msg(excinfo.value) ==
"MyException6 only handled in this module"
282 with pytest.raises(RuntimeError)
as excinfo:
283 m.throws_local_error()
284 assert not isinstance(excinfo.value, KeyError)
285 assert msg(excinfo.value) ==
"never caught"
287 with pytest.raises(Exception)
as excinfo:
288 m.throws_local_simple_error()
289 assert not isinstance(excinfo.value, cm.LocalSimpleException)
290 assert msg(excinfo.value) ==
"this mod"
294 assert m.error_already_set_what(RuntimeError,
"\ud927") == (
295 "RuntimeError: \\ud927",
301 assert m.error_already_set_what(RuntimeError, b
"\x80") == (
302 "RuntimeError: b'\\x80'",
309 if failure_point ==
"failure_point_init":
310 raise ValueError(
"triggered_failure_point_init")
315 raise ValueError(
"triggered_failure_point_str")
316 return "FlakyException.__str__"
319 @pytest.mark.parametrize(
320 (
"exc_type",
"exc_value",
"expected_what"),
322 (ValueError,
"plain_str",
"ValueError: plain_str"),
323 (ValueError, (
"tuple_elem",),
"ValueError: tuple_elem"),
324 (FlakyException, (
"happy",),
"FlakyException: FlakyException.__str__"),
328 exc_type, exc_value, expected_what
330 what, py_err_set_after_what = m.error_already_set_what(exc_type, exc_value)
331 assert not py_err_set_after_what
332 assert what == expected_what
336 with pytest.raises(RuntimeError)
as excinfo:
337 m.error_already_set_what(FlakyException, (
"failure_point_init",))
338 lines =
str(excinfo.value).splitlines()
340 assert lines[:3] == [
341 "pybind11::error_already_set: MISMATCH of original and normalized active exception types:"
342 " ORIGINAL FlakyException REPLACED BY ValueError: triggered_failure_point_init",
347 assert "test_exceptions.py(" in lines[3]
348 assert lines[3].endswith(
"): __init__")
349 assert lines[4].endswith(
350 "): _test_flaky_exception_failure_point_init_before_py_3_12"
356 what, py_err_set_after_what = m.error_already_set_what(
357 FlakyException, (
"failure_point_init",)
359 assert not py_err_set_after_what
360 lines = what.splitlines()
361 assert lines[0].endswith(
"ValueError[WITH __notes__]: triggered_failure_point_init")
362 assert lines[1] ==
"__notes__ (len=1):"
363 assert "Normalization failed:" in lines[2]
364 assert "FlakyException" in lines[2]
368 "env.PYPY and sys.version_info[:2] < (3, 12)",
369 reason=
"PyErr_NormalizeException Segmentation fault",
372 if sys.version_info[:2] < (3, 12):
379 what, py_err_set_after_what = m.error_already_set_what(
380 FlakyException, (
"failure_point_str",)
382 assert not py_err_set_after_what
383 lines = what.splitlines()
384 n = 3
if env.PYPY
and len(lines) == 3
else 5
388 "FlakyException: <MESSAGE UNAVAILABLE DUE TO ANOTHER EXCEPTION>",
390 "MESSAGE UNAVAILABLE DUE TO EXCEPTION: ValueError: triggered_failure_point_str",
398 with pytest.raises(RuntimeError)
as excinfo:
399 m.test_cross_module_interleaved_error_already_set()
400 assert str(excinfo.value)
in (
402 "RuntimeError: 2nd error.",
407 m.test_error_already_set_double_restore(
True)
408 with pytest.raises(RuntimeError)
as excinfo:
409 m.test_error_already_set_double_restore(
False)
410 assert str(excinfo.value) == (
411 "Internal error: pybind11::detail::error_fetch_and_normalize::restore()"
412 " called a second time. ORIGINAL ERROR: ValueError: Random error."
418 what = m.test_pypy_oserror_normalization()
419 assert "this_filename_must_not_exist" in what
423 with pytest.raises(RuntimeError)
as excinfo:
424 m.test_fn_cast_int(
lambda:
None)
426 assert str(excinfo.value).startswith(
427 "Unable to cast Python instance of type <class 'NoneType'> to C++ type"
432 with pytest.raises(TypeError)
as excinfo:
433 m.return_exception_void()
434 assert "Exception" in str(excinfo.value)