github.com/kaydxh/golang@v0.0.131/pkg/gocv/cgo/third_path/pybind11/tests/test_exceptions.py (about) 1 import sys 2 3 import pytest 4 5 import env 6 import pybind11_cross_module_tests as cm 7 import pybind11_tests # noqa: F401 8 from pybind11_tests import exceptions as m 9 10 11 def 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." 15 16 17 def test_error_already_set(msg): 18 with pytest.raises(RuntimeError) as excinfo: 19 m.throw_already_set(False) 20 assert ( 21 msg(excinfo.value) 22 == "Internal error: pybind11::error_already_set called while Python error indicator not set." 23 ) 24 25 with pytest.raises(ValueError) as excinfo: 26 m.throw_already_set(True) 27 assert msg(excinfo.value) == "foo" 28 29 30 def test_raise_from(msg): 31 with pytest.raises(ValueError) as excinfo: 32 m.raise_from() 33 assert msg(excinfo.value) == "outer" 34 assert msg(excinfo.value.__cause__) == "inner" 35 36 37 def 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" 42 43 44 def 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" 48 49 with pytest.raises(ValueError) as excinfo: 50 cm.raise_value_error() 51 assert str(excinfo.value) == "My value error" 52 53 with pytest.raises(ValueError) as excinfo: 54 cm.throw_pybind_value_error() 55 assert str(excinfo.value) == "pybind11 value error" 56 57 with pytest.raises(TypeError) as excinfo: 58 cm.throw_pybind_type_error() 59 assert str(excinfo.value) == "pybind11 type error" 60 61 with pytest.raises(StopIteration) as excinfo: 62 cm.throw_stop_iteration() 63 64 with pytest.raises(cm.LocalSimpleException) as excinfo: 65 cm.throw_local_simple_error() 66 assert msg(excinfo.value) == "external mod" 67 68 with pytest.raises(KeyError) as excinfo: 69 cm.throw_local_error() 70 # KeyError is a repr of the key, so it has an extra set of quotes 71 assert str(excinfo.value) == "'just local'" 72 73 74 # TODO: FIXME 75 @pytest.mark.xfail( 76 "env.MACOS and (env.PYPY or pybind11_tests.compiler_info.startswith('Homebrew Clang'))", 77 raises=RuntimeError, 78 reason="See Issue #2847, PR #2999, PR #4324", 79 ) 80 def test_cross_module_exception_translator(): 81 with pytest.raises(KeyError): 82 # translator registered in cross_module_tests 83 m.throw_should_be_translated_to_key_error() 84 85 86 def test_python_call_in_catch(): 87 d = {} 88 assert m.python_call_in_destructor(d) is True 89 assert d["good"] is True 90 91 92 def ignore_pytest_unraisable_warning(f): 93 unraisable = "PytestUnraisableExceptionWarning" 94 if hasattr(pytest, unraisable): # Python >= 3.8 and pytest >= 6 95 dec = pytest.mark.filterwarnings(f"ignore::pytest.{unraisable}") 96 return dec(f) 97 else: 98 return f 99 100 101 # TODO: find out why this fails on PyPy, https://foss.heptapod.net/pypy/pypy/-/issues/3583 102 @pytest.mark.xfail(env.PYPY, reason="Failure on PyPy 3.8 (7.3.7)", strict=False) 103 @ignore_pytest_unraisable_warning 104 def test_python_alreadyset_in_destructor(monkeypatch, capsys): 105 hooked = False 106 triggered = False 107 108 if hasattr(sys, "unraisablehook"): # Python 3.8+ 109 hooked = True 110 # Don't take `sys.unraisablehook`, as that's overwritten by pytest 111 default_hook = sys.__unraisablehook__ 112 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": 116 nonlocal triggered 117 triggered = True 118 default_hook(unraisable_hook_args) 119 return 120 121 # Use monkeypatch so pytest can apply and remove the patch as appropriate 122 monkeypatch.setattr(sys, "unraisablehook", hook) 123 124 assert m.python_alreadyset_in_destructor("already_set demo") is True 125 if hooked: 126 assert triggered is True 127 128 _, captured_stderr = capsys.readouterr() 129 assert captured_stderr.startswith("Exception ignored in: 'already_set demo'") 130 assert captured_stderr.rstrip().endswith("KeyError: 'bar'") 131 132 133 def test_exception_matches(): 134 assert m.exception_matches() 135 assert m.exception_matches_base() 136 assert m.modulenotfound_exception_matches_base() 137 138 139 def test_custom(msg): 140 # Can we catch a MyException? 141 with pytest.raises(m.MyException) as excinfo: 142 m.throws1() 143 assert msg(excinfo.value) == "this error should go to a custom type" 144 145 # Can we translate to standard Python exceptions? 146 with pytest.raises(RuntimeError) as excinfo: 147 m.throws2() 148 assert msg(excinfo.value) == "this error should go to a standard Python exception" 149 150 # Can we handle unknown exceptions? 151 with pytest.raises(RuntimeError) as excinfo: 152 m.throws3() 153 assert msg(excinfo.value) == "Caught an unknown exception!" 154 155 # Can we delegate to another handler by rethrowing? 156 with pytest.raises(m.MyException) as excinfo: 157 m.throws4() 158 assert msg(excinfo.value) == "this error is rethrown" 159 160 # Can we fall-through to the default handler? 161 with pytest.raises(RuntimeError) as excinfo: 162 m.throws_logic_error() 163 assert ( 164 msg(excinfo.value) == "this error should fall through to the standard handler" 165 ) 166 167 # OverFlow error translation. 168 with pytest.raises(OverflowError) as excinfo: 169 m.throws_overflow_error() 170 171 # Can we handle a helper-declared exception? 172 with pytest.raises(m.MyException5) as excinfo: 173 m.throws5() 174 assert msg(excinfo.value) == "this is a helper-defined translated exception" 175 176 # Exception subclassing: 177 with pytest.raises(m.MyException5) as excinfo: 178 m.throws5_1() 179 assert msg(excinfo.value) == "MyException5 subclass" 180 assert isinstance(excinfo.value, m.MyException5_1) 181 182 with pytest.raises(m.MyException5_1) as excinfo: 183 m.throws5_1() 184 assert msg(excinfo.value) == "MyException5 subclass" 185 186 with pytest.raises(m.MyException5) as excinfo: 187 try: 188 m.throws5() 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" 192 193 194 def test_nested_throws(capture): 195 """Tests nested (e.g. C++ -> Python -> C++) exception handling""" 196 197 def throw_myex(): 198 raise m.MyException("nested error") 199 200 def throw_myex5(): 201 raise m.MyException5("nested error 5") 202 203 # In the comments below, the exception is caught in the first step, thrown in the last step 204 205 # C++ -> Python 206 with capture: 207 m.try_catch(m.MyException5, throw_myex5) 208 assert str(capture).startswith("MyException5: nested error 5") 209 210 # Python -> C++ -> Python 211 with pytest.raises(m.MyException) as excinfo: 212 m.try_catch(m.MyException5, throw_myex) 213 assert str(excinfo.value) == "nested error" 214 215 def pycatch(exctype, f, *args): 216 try: 217 f(*args) 218 except m.MyException as e: 219 print(e) 220 221 # C++ -> Python -> C++ -> Python 222 with capture: 223 m.try_catch( 224 m.MyException5, 225 pycatch, 226 m.MyException, 227 m.try_catch, 228 m.MyException, 229 throw_myex5, 230 ) 231 assert str(capture).startswith("MyException5: nested error 5") 232 233 # C++ -> Python -> C++ 234 with capture: 235 m.try_catch(m.MyException, pycatch, m.MyException5, m.throws4) 236 assert capture == "this error is rethrown" 237 238 # Python -> C++ -> Python -> C++ 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" 242 243 244 def 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" 249 250 251 # This can often happen if you wrap a pybind11 class in a Python wrapper 252 def test_invalid_repr(): 253 class MyRepr: 254 def __repr__(self): 255 raise AttributeError("Example error") 256 257 with pytest.raises(TypeError): 258 m.simple_bool_passthrough(MyRepr()) 259 260 261 def 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: 265 m.throws6() 266 assert msg(excinfo.value) == "MyException6 only handled in this module" 267 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" 272 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" 277 278 279 def test_error_already_set_message_with_unicode_surrogate(): # Issue #4288 280 assert m.error_already_set_what(RuntimeError, "\ud927") == ( 281 "RuntimeError: \\ud927", 282 False, 283 ) 284 285 286 def test_error_already_set_message_with_malformed_utf8(): 287 assert m.error_already_set_what(RuntimeError, b"\x80") == ( 288 "RuntimeError: b'\\x80'", 289 False, 290 ) 291 292 293 class FlakyException(Exception): 294 def __init__(self, failure_point): 295 if failure_point == "failure_point_init": 296 raise ValueError("triggered_failure_point_init") 297 self.failure_point = failure_point 298 299 def __str__(self): 300 if self.failure_point == "failure_point_str": 301 raise ValueError("triggered_failure_point_str") 302 return "FlakyException.__str__" 303 304 305 @pytest.mark.parametrize( 306 "exc_type, exc_value, expected_what", 307 ( 308 (ValueError, "plain_str", "ValueError: plain_str"), 309 (ValueError, ("tuple_elem",), "ValueError: tuple_elem"), 310 (FlakyException, ("happy",), "FlakyException: FlakyException.__str__"), 311 ), 312 ) 313 def test_error_already_set_what_with_happy_exceptions( 314 exc_type, exc_value, expected_what 315 ): 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 319 320 321 @pytest.mark.skipif("env.PYPY", reason="PyErr_NormalizeException Segmentation fault") 322 def test_flaky_exception_failure_point_init(): 323 with pytest.raises(RuntimeError) as excinfo: 324 m.error_already_set_what(FlakyException, ("failure_point_init",)) 325 lines = str(excinfo.value).splitlines() 326 # PyErr_NormalizeException replaces the original FlakyException with ValueError: 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", 330 "", 331 "At:", 332 ] 333 # Checking the first two lines of the traceback as formatted in error_string(): 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") 337 338 339 def test_flaky_exception_failure_point_str(): 340 what, py_err_set_after_what = m.error_already_set_what( 341 FlakyException, ("failure_point_str",) 342 ) 343 assert not py_err_set_after_what 344 lines = what.splitlines() 345 if env.PYPY and len(lines) == 3: 346 n = 3 # Traceback is missing. 347 else: 348 n = 5 349 assert ( 350 lines[:n] 351 == [ 352 "FlakyException: <MESSAGE UNAVAILABLE DUE TO ANOTHER EXCEPTION>", 353 "", 354 "MESSAGE UNAVAILABLE DUE TO EXCEPTION: ValueError: triggered_failure_point_str", 355 "", 356 "At:", 357 ][:n] 358 ) 359 360 361 def test_cross_module_interleaved_error_already_set(): 362 with pytest.raises(RuntimeError) as excinfo: 363 m.test_cross_module_interleaved_error_already_set() 364 assert str(excinfo.value) in ( 365 "2nd error.", # Almost all platforms. 366 "RuntimeError: 2nd error.", # Some PyPy builds (seen under macOS). 367 ) 368 369 370 def test_error_already_set_double_restore(): 371 m.test_error_already_set_double_restore(True) # dry_run 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." 377 ) 378 379 380 def test_pypy_oserror_normalization(): 381 # https://github.com/pybind/pybind11/issues/4075 382 what = m.test_pypy_oserror_normalization() 383 assert "this_filename_must_not_exist" in what