6 import pybind11_cross_module_tests
as cm
8 from pybind11_tests
import exceptions
as m
12 with pytest.raises(RuntimeError)
as excinfo:
13 m.throw_std_exception()
14 assert msg(excinfo.value) ==
"This exception was intentionally thrown."
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"
31 with pytest.raises(ValueError)
as excinfo:
33 assert msg(excinfo.value) ==
"outer"
34 assert msg(excinfo.value.__cause__) ==
"inner"
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"
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",
81 with pytest.raises(KeyError):
83 m.throw_should_be_translated_to_key_error()
88 assert m.python_call_in_destructor(d)
is True
89 assert d[
"good"]
is True
93 unraisable =
"PytestUnraisableExceptionWarning"
95 dec = pytest.mark.filterwarnings(f
"ignore::pytest.{unraisable}")
101 @pytest.mark.xfail(env.PYPY, reason=
"Failure on PyPy 3.8 (7.3.7)", strict=
False)
102 @ignore_pytest_unraisable_warning
107 if hasattr(sys,
"unraisablehook"):
110 default_hook = sys.__unraisablehook__
112 def hook(unraisable_hook_args):
113 exc_type, exc_value, exc_tb, err_msg, obj = unraisable_hook_args
114 if obj ==
"already_set demo":
117 default_hook(unraisable_hook_args)
121 monkeypatch.setattr(sys,
"unraisablehook", hook)
123 assert m.python_alreadyset_in_destructor(
"already_set demo")
is True
125 assert triggered
is True
127 _, captured_stderr = capsys.readouterr()
128 assert captured_stderr.startswith(
"Exception ignored in: 'already_set demo'")
129 assert captured_stderr.rstrip().endswith(
"KeyError: 'bar'")
133 assert m.exception_matches()
134 assert m.exception_matches_base()
135 assert m.modulenotfound_exception_matches_base()
140 with pytest.raises(m.MyException)
as excinfo:
142 assert msg(excinfo.value) ==
"this error should go to a custom type"
145 with pytest.raises(RuntimeError)
as excinfo:
147 assert msg(excinfo.value) ==
"this error should go to a standard Python exception"
150 with pytest.raises(RuntimeError)
as excinfo:
152 assert msg(excinfo.value) ==
"Caught an unknown exception!"
155 with pytest.raises(m.MyException)
as excinfo:
157 assert msg(excinfo.value) ==
"this error is rethrown"
160 with pytest.raises(RuntimeError)
as excinfo:
161 m.throws_logic_error()
163 msg(excinfo.value) ==
"this error should fall through to the standard handler"
167 with pytest.raises(OverflowError)
as excinfo:
168 m.throws_overflow_error()
171 with pytest.raises(m.MyException5)
as excinfo:
173 assert msg(excinfo.value) ==
"this is a helper-defined translated exception"
176 with pytest.raises(m.MyException5)
as excinfo:
178 assert msg(excinfo.value) ==
"MyException5 subclass"
179 assert isinstance(excinfo.value, m.MyException5_1)
181 with pytest.raises(m.MyException5_1)
as excinfo:
183 assert msg(excinfo.value) ==
"MyException5 subclass"
185 with pytest.raises(m.MyException5)
as excinfo:
188 except m.MyException5_1
as err:
189 raise RuntimeError(
"Exception error: caught child from parent")
from err
190 assert msg(excinfo.value) ==
"this is a helper-defined translated exception"
194 """Tests nested (e.g. C++ -> Python -> C++) exception handling"""
197 raise m.MyException(
"nested error")
200 raise m.MyException5(
"nested error 5")
206 m.try_catch(m.MyException5, throw_myex5)
207 assert str(capture).startswith(
"MyException5: nested error 5")
210 with pytest.raises(m.MyException)
as excinfo:
211 m.try_catch(m.MyException5, throw_myex)
212 assert str(excinfo.value) ==
"nested error"
214 def pycatch(exctype, f, *args):
217 except m.MyException
as e:
230 assert str(capture).startswith(
"MyException5: nested error 5")
234 m.try_catch(m.MyException, pycatch, m.MyException5, m.throws4)
235 assert capture ==
"this error is rethrown"
238 with pytest.raises(m.MyException5)
as excinfo:
239 m.try_catch(m.MyException, pycatch, m.MyException, m.throws5)
240 assert str(excinfo.value) ==
"this is a helper-defined translated exception"
244 with pytest.raises(RuntimeError)
as excinfo:
245 m.throw_nested_exception()
246 assert str(excinfo.value) ==
"Outer Exception"
247 assert str(excinfo.value.__cause__) ==
"Inner Exception"
254 raise AttributeError(
"Example error")
256 with pytest.raises(TypeError):
257 m.simple_bool_passthrough(MyRepr())
261 """Tests that a local translator works and that the local translator from
262 the cross module is not applied"""
263 with pytest.raises(RuntimeError)
as excinfo:
265 assert msg(excinfo.value) ==
"MyException6 only handled in this module"
267 with pytest.raises(RuntimeError)
as excinfo:
268 m.throws_local_error()
269 assert not isinstance(excinfo.value, KeyError)
270 assert msg(excinfo.value) ==
"never caught"
272 with pytest.raises(Exception)
as excinfo:
273 m.throws_local_simple_error()
274 assert not isinstance(excinfo.value, cm.LocalSimpleException)
275 assert msg(excinfo.value) ==
"this mod"
279 assert m.error_already_set_what(RuntimeError,
"\ud927") == (
280 "RuntimeError: \\ud927",
286 assert m.error_already_set_what(RuntimeError, b
"\x80") == (
287 "RuntimeError: b'\\x80'",
294 if failure_point ==
"failure_point_init":
295 raise ValueError(
"triggered_failure_point_init")
300 raise ValueError(
"triggered_failure_point_str")
301 return "FlakyException.__str__"
304 @pytest.mark.parametrize(
305 (
"exc_type",
"exc_value",
"expected_what"),
307 (ValueError,
"plain_str",
"ValueError: plain_str"),
308 (ValueError, (
"tuple_elem",),
"ValueError: tuple_elem"),
309 (FlakyException, (
"happy",),
"FlakyException: FlakyException.__str__"),
313 exc_type, exc_value, expected_what
315 what, py_err_set_after_what = m.error_already_set_what(exc_type, exc_value)
316 assert not py_err_set_after_what
317 assert what == expected_what
321 with pytest.raises(RuntimeError)
as excinfo:
322 m.error_already_set_what(FlakyException, (
"failure_point_init",))
323 lines =
str(excinfo.value).splitlines()
325 assert lines[:3] == [
326 "pybind11::error_already_set: MISMATCH of original and normalized active exception types:"
327 " ORIGINAL FlakyException REPLACED BY ValueError: triggered_failure_point_init",
332 assert "test_exceptions.py(" in lines[3]
333 assert lines[3].endswith(
"): __init__")
334 assert lines[4].endswith(
335 "): _test_flaky_exception_failure_point_init_before_py_3_12"
341 what, py_err_set_after_what = m.error_already_set_what(
342 FlakyException, (
"failure_point_init",)
344 assert not py_err_set_after_what
345 lines = what.splitlines()
346 assert lines[0].endswith(
"ValueError[WITH __notes__]: triggered_failure_point_init")
347 assert lines[1] ==
"__notes__ (len=1):"
348 assert "Normalization failed:" in lines[2]
349 assert "FlakyException" in lines[2]
353 "env.PYPY and sys.version_info[:2] < (3, 12)",
354 reason=
"PyErr_NormalizeException Segmentation fault",
357 if sys.version_info[:2] < (3, 12):
364 what, py_err_set_after_what = m.error_already_set_what(
365 FlakyException, (
"failure_point_str",)
367 assert not py_err_set_after_what
368 lines = what.splitlines()
369 n = 3
if env.PYPY
and len(lines) == 3
else 5
373 "FlakyException: <MESSAGE UNAVAILABLE DUE TO ANOTHER EXCEPTION>",
375 "MESSAGE UNAVAILABLE DUE TO EXCEPTION: ValueError: triggered_failure_point_str",
383 with pytest.raises(RuntimeError)
as excinfo:
384 m.test_cross_module_interleaved_error_already_set()
385 assert str(excinfo.value)
in (
387 "RuntimeError: 2nd error.",
392 m.test_error_already_set_double_restore(
True)
393 with pytest.raises(RuntimeError)
as excinfo:
394 m.test_error_already_set_double_restore(
False)
395 assert str(excinfo.value) == (
396 "Internal error: pybind11::detail::error_fetch_and_normalize::restore()"
397 " called a second time. ORIGINAL ERROR: ValueError: Random error."
403 what = m.test_pypy_oserror_normalization()
404 assert "this_filename_must_not_exist" in what
408 with pytest.raises(RuntimeError)
as excinfo:
409 m.test_fn_cast_int(
lambda:
None)
411 assert str(excinfo.value).startswith(
412 "Unable to cast Python instance of type <class 'NoneType'> to C++ type"