github.com/kaydxh/golang@v0.0.131/pkg/gocv/cgo/third_path/pybind11/tests/conftest.py (about)

     1  """pytest configuration
     2  
     3  Extends output capture as needed by pybind11: ignore constructors, optional unordered lines.
     4  Adds docstring and exceptions message sanitizers.
     5  """
     6  
     7  import contextlib
     8  import difflib
     9  import gc
    10  import multiprocessing
    11  import os
    12  import re
    13  import textwrap
    14  import traceback
    15  
    16  import pytest
    17  
    18  # Early diagnostic for failed imports
    19  try:
    20      import pybind11_tests
    21  except Exception:
    22      # pytest does not show the traceback without this.
    23      traceback.print_exc()
    24      raise
    25  
    26  
    27  @pytest.fixture(scope="session", autouse=True)
    28  def always_forkserver_on_unix():
    29      if os.name == "nt":
    30          return
    31  
    32      # Full background: https://github.com/pybind/pybind11/issues/4105#issuecomment-1301004592
    33      # In a nutshell: fork() after starting threads == flakiness in the form of deadlocks.
    34      # It is actually a well-known pitfall, unfortunately without guard rails.
    35      # "forkserver" is more performant than "spawn" (~9s vs ~13s for tests/test_gil_scoped.py,
    36      # visit the issuecomment link above for details).
    37      # Windows does not have fork() and the associated pitfall, therefore it is best left
    38      # running with defaults.
    39      multiprocessing.set_start_method("forkserver")
    40  
    41  
    42  _long_marker = re.compile(r"([0-9])L")
    43  _hexadecimal = re.compile(r"0x[0-9a-fA-F]+")
    44  
    45  # Avoid collecting Python3 only files
    46  collect_ignore = []
    47  
    48  
    49  def _strip_and_dedent(s):
    50      """For triple-quote strings"""
    51      return textwrap.dedent(s.lstrip("\n").rstrip())
    52  
    53  
    54  def _split_and_sort(s):
    55      """For output which does not require specific line order"""
    56      return sorted(_strip_and_dedent(s).splitlines())
    57  
    58  
    59  def _make_explanation(a, b):
    60      """Explanation for a failed assert -- the a and b arguments are List[str]"""
    61      return ["--- actual / +++ expected"] + [
    62          line.strip("\n") for line in difflib.ndiff(a, b)
    63      ]
    64  
    65  
    66  class Output:
    67      """Basic output post-processing and comparison"""
    68  
    69      def __init__(self, string):
    70          self.string = string
    71          self.explanation = []
    72  
    73      def __str__(self):
    74          return self.string
    75  
    76      def __eq__(self, other):
    77          # Ignore constructor/destructor output which is prefixed with "###"
    78          a = [
    79              line
    80              for line in self.string.strip().splitlines()
    81              if not line.startswith("###")
    82          ]
    83          b = _strip_and_dedent(other).splitlines()
    84          if a == b:
    85              return True
    86          else:
    87              self.explanation = _make_explanation(a, b)
    88              return False
    89  
    90  
    91  class Unordered(Output):
    92      """Custom comparison for output without strict line ordering"""
    93  
    94      def __eq__(self, other):
    95          a = _split_and_sort(self.string)
    96          b = _split_and_sort(other)
    97          if a == b:
    98              return True
    99          else:
   100              self.explanation = _make_explanation(a, b)
   101              return False
   102  
   103  
   104  class Capture:
   105      def __init__(self, capfd):
   106          self.capfd = capfd
   107          self.out = ""
   108          self.err = ""
   109  
   110      def __enter__(self):
   111          self.capfd.readouterr()
   112          return self
   113  
   114      def __exit__(self, *args):
   115          self.out, self.err = self.capfd.readouterr()
   116  
   117      def __eq__(self, other):
   118          a = Output(self.out)
   119          b = other
   120          if a == b:
   121              return True
   122          else:
   123              self.explanation = a.explanation
   124              return False
   125  
   126      def __str__(self):
   127          return self.out
   128  
   129      def __contains__(self, item):
   130          return item in self.out
   131  
   132      @property
   133      def unordered(self):
   134          return Unordered(self.out)
   135  
   136      @property
   137      def stderr(self):
   138          return Output(self.err)
   139  
   140  
   141  @pytest.fixture
   142  def capture(capsys):
   143      """Extended `capsys` with context manager and custom equality operators"""
   144      return Capture(capsys)
   145  
   146  
   147  class SanitizedString:
   148      def __init__(self, sanitizer):
   149          self.sanitizer = sanitizer
   150          self.string = ""
   151          self.explanation = []
   152  
   153      def __call__(self, thing):
   154          self.string = self.sanitizer(thing)
   155          return self
   156  
   157      def __eq__(self, other):
   158          a = self.string
   159          b = _strip_and_dedent(other)
   160          if a == b:
   161              return True
   162          else:
   163              self.explanation = _make_explanation(a.splitlines(), b.splitlines())
   164              return False
   165  
   166  
   167  def _sanitize_general(s):
   168      s = s.strip()
   169      s = s.replace("pybind11_tests.", "m.")
   170      s = _long_marker.sub(r"\1", s)
   171      return s
   172  
   173  
   174  def _sanitize_docstring(thing):
   175      s = thing.__doc__
   176      s = _sanitize_general(s)
   177      return s
   178  
   179  
   180  @pytest.fixture
   181  def doc():
   182      """Sanitize docstrings and add custom failure explanation"""
   183      return SanitizedString(_sanitize_docstring)
   184  
   185  
   186  def _sanitize_message(thing):
   187      s = str(thing)
   188      s = _sanitize_general(s)
   189      s = _hexadecimal.sub("0", s)
   190      return s
   191  
   192  
   193  @pytest.fixture
   194  def msg():
   195      """Sanitize messages and add custom failure explanation"""
   196      return SanitizedString(_sanitize_message)
   197  
   198  
   199  # noinspection PyUnusedLocal
   200  def pytest_assertrepr_compare(op, left, right):
   201      """Hook to insert custom failure explanation"""
   202      if hasattr(left, "explanation"):
   203          return left.explanation
   204  
   205  
   206  @contextlib.contextmanager
   207  def suppress(exception):
   208      """Suppress the desired exception"""
   209      try:
   210          yield
   211      except exception:
   212          pass
   213  
   214  
   215  def gc_collect():
   216      """Run the garbage collector twice (needed when running
   217      reference counting tests with PyPy)"""
   218      gc.collect()
   219      gc.collect()
   220  
   221  
   222  def pytest_configure():
   223      pytest.suppress = suppress
   224      pytest.gc_collect = gc_collect
   225  
   226  
   227  def pytest_report_header(config):
   228      del config  # Unused.
   229      assert (
   230          pybind11_tests.compiler_info is not None
   231      ), "Please update pybind11_tests.cpp if this assert fails."
   232      return (
   233          "C++ Info:"
   234          f" {pybind11_tests.compiler_info}"
   235          f" {pybind11_tests.cpp_std}"
   236          f" {pybind11_tests.PYBIND11_INTERNALS_ID}"
   237          f" PYBIND11_SIMPLE_GIL_MANAGEMENT={pybind11_tests.PYBIND11_SIMPLE_GIL_MANAGEMENT}"
   238      )