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 )