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