conftest.py
Go to the documentation of this file.
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 re
12 import sys
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)
29  if sys.platform != "linux":
30  # The default on Windows and macOS is "spawn": If it's not broken, don't fix it.
31  return
32 
33  # Full background: https://github.com/pybind/pybind11/issues/4105#issuecomment-1301004592
34  # In a nutshell: fork() after starting threads == flakiness in the form of deadlocks.
35  # It is actually a well-known pitfall, unfortunately without guard rails.
36  # "forkserver" is more performant than "spawn" (~9s vs ~13s for tests/test_gil_scoped.py,
37  # visit the issuecomment link above for details).
38  multiprocessing.set_start_method("forkserver")
39 
40 
41 _long_marker = re.compile(r"([0-9])L")
42 _hexadecimal = re.compile(r"0x[0-9a-fA-F]+")
43 
44 # Avoid collecting Python3 only files
45 collect_ignore = []
46 
47 
49  """For triple-quote strings"""
50  return textwrap.dedent(s.lstrip("\n").rstrip())
51 
52 
54  """For output which does not require specific line order"""
55  return sorted(_strip_and_dedent(s).splitlines())
56 
57 
59  """Explanation for a failed assert -- the a and b arguments are List[str]"""
60  return ["--- actual / +++ expected"] + [
61  line.strip("\n") for line in difflib.ndiff(a, b)
62  ]
63 
64 
65 class Output:
66  """Basic output post-processing and comparison"""
67 
68  def __init__(self, string):
69  self.string = string
70  self.explanation = []
71 
72  def __str__(self):
73  return self.string
74 
75  def __eq__(self, other):
76  # Ignore constructor/destructor output which is prefixed with "###"
77  a = [
78  line
79  for line in self.string.strip().splitlines()
80  if not line.startswith("###")
81  ]
82  b = _strip_and_dedent(other).splitlines()
83  if a == b:
84  return True
85  self.explanation = _make_explanation(a, b)
86  return False
87 
88 
90  """Custom comparison for output without strict line ordering"""
91 
92  def __eq__(self, other):
93  a = _split_and_sort(self.string)
94  b = _split_and_sort(other)
95  if a == b:
96  return True
98  return False
99 
100 
101 class Capture:
102  def __init__(self, capfd):
103  self.capfd = capfd
104  self.out = ""
105  self.err = ""
106 
107  def __enter__(self):
108  self.capfd.readouterr()
109  return self
110 
111  def __exit__(self, *args):
112  self.out, self.err = self.capfd.readouterr()
113 
114  def __eq__(self, other):
115  a = Output(self.out)
116  b = other
117  if a == b:
118  return True
119  self.explanation = a.explanation
120  return False
121 
122  def __str__(self):
123  return self.out
124 
125  def __contains__(self, item):
126  return item in self.out
127 
128  @property
129  def unordered(self):
130  return Unordered(self.out)
131 
132  @property
133  def stderr(self):
134  return Output(self.err)
135 
136 
137 @pytest.fixture()
138 def capture(capsys):
139  """Extended `capsys` with context manager and custom equality operators"""
140  return Capture(capsys)
141 
142 
144  def __init__(self, sanitizer):
145  self.sanitizer = sanitizer
146  self.string = ""
147  self.explanation = []
148 
149  def __call__(self, thing):
150  self.string = self.sanitizer(thing)
151  return self
152 
153  def __eq__(self, other):
154  a = self.string
155  b = _strip_and_dedent(other)
156  if a == b:
157  return True
158  self.explanation = _make_explanation(a.splitlines(), b.splitlines())
159  return False
160 
161 
163  s = s.strip()
164  s = s.replace("pybind11_tests.", "m.")
165  return _long_marker.sub(r"\1", s)
166 
167 
169  s = thing.__doc__
170  return _sanitize_general(s)
171 
172 
173 @pytest.fixture()
174 def doc():
175  """Sanitize docstrings and add custom failure explanation"""
176  return SanitizedString(_sanitize_docstring)
177 
178 
179 def _sanitize_message(thing):
180  s = str(thing)
181  s = _sanitize_general(s)
182  return _hexadecimal.sub("0", s)
183 
184 
185 @pytest.fixture()
186 def msg():
187  """Sanitize messages and add custom failure explanation"""
188  return SanitizedString(_sanitize_message)
189 
190 
191 def pytest_assertrepr_compare(op, left, right): # noqa: ARG001
192  """Hook to insert custom failure explanation"""
193  if hasattr(left, "explanation"):
194  return left.explanation
195  return None
196 
197 
199  """Run the garbage collector twice (needed when running
200  reference counting tests with PyPy)"""
201  gc.collect()
202  gc.collect()
203 
204 
206  pytest.suppress = contextlib.suppress
207  pytest.gc_collect = gc_collect
208 
209 
211  del config # Unused.
212  assert (
213  pybind11_tests.compiler_info is not None
214  ), "Please update pybind11_tests.cpp if this assert fails."
215  return (
216  "C++ Info:"
217  f" {pybind11_tests.compiler_info}"
218  f" {pybind11_tests.cpp_std}"
219  f" {pybind11_tests.PYBIND11_INTERNALS_ID}"
220  f" PYBIND11_SIMPLE_GIL_MANAGEMENT={pybind11_tests.PYBIND11_SIMPLE_GIL_MANAGEMENT}"
221  )
conftest.msg
def msg()
Definition: conftest.py:186
conftest.SanitizedString.__init__
def __init__(self, sanitizer)
Definition: conftest.py:144
conftest.Output.__str__
def __str__(self)
Definition: conftest.py:72
conftest.Capture.__contains__
def __contains__(self, item)
Definition: conftest.py:125
conftest._strip_and_dedent
def _strip_and_dedent(s)
Definition: conftest.py:48
conftest.Output
Definition: conftest.py:65
conftest.Capture.explanation
explanation
Definition: conftest.py:119
hasattr
bool hasattr(handle obj, handle name)
Definition: pytypes.h:853
conftest.SanitizedString.__call__
def __call__(self, thing)
Definition: conftest.py:149
conftest.pytest_configure
def pytest_configure()
Definition: conftest.py:205
conftest.SanitizedString.__eq__
def __eq__(self, other)
Definition: conftest.py:153
conftest.Capture.err
err
Definition: conftest.py:105
conftest.Capture
Definition: conftest.py:101
conftest.SanitizedString.sanitizer
sanitizer
Definition: conftest.py:145
conftest.Unordered
Definition: conftest.py:89
conftest._sanitize_message
def _sanitize_message(thing)
Definition: conftest.py:179
conftest.Unordered.__eq__
def __eq__(self, other)
Definition: conftest.py:92
conftest._make_explanation
def _make_explanation(a, b)
Definition: conftest.py:58
conftest._sanitize_general
def _sanitize_general(s)
Definition: conftest.py:162
conftest.Output.string
string
Definition: conftest.py:69
conftest.capture
def capture(capsys)
Definition: conftest.py:138
conftest.SanitizedString
Definition: conftest.py:143
conftest.Capture.__exit__
def __exit__(self, *args)
Definition: conftest.py:111
conftest.Capture.stderr
def stderr(self)
Definition: conftest.py:133
conftest.Capture.__enter__
def __enter__(self)
Definition: conftest.py:107
conftest.Output.explanation
explanation
Definition: conftest.py:70
str
Definition: pytypes.h:1524
conftest.Capture.__str__
def __str__(self)
Definition: conftest.py:122
conftest.use_multiprocessing_forkserver_on_linux
def use_multiprocessing_forkserver_on_linux()
Definition: conftest.py:28
conftest.pytest_report_header
def pytest_report_header(config)
Definition: conftest.py:210
conftest.Capture.unordered
def unordered(self)
Definition: conftest.py:129
conftest.Capture.out
out
Definition: conftest.py:104
conftest._sanitize_docstring
def _sanitize_docstring(thing)
Definition: conftest.py:168
conftest.pytest_assertrepr_compare
def pytest_assertrepr_compare(op, left, right)
Definition: conftest.py:191
conftest.doc
def doc()
Definition: conftest.py:174
conftest.SanitizedString.explanation
explanation
Definition: conftest.py:147
conftest.Capture.__eq__
def __eq__(self, other)
Definition: conftest.py:114
conftest.Capture.capfd
capfd
Definition: conftest.py:103
conftest.Output.__eq__
def __eq__(self, other)
Definition: conftest.py:75
conftest.Output.__init__
def __init__(self, string)
Definition: conftest.py:68
conftest.Capture.__init__
def __init__(self, capfd)
Definition: conftest.py:102
conftest.gc_collect
def gc_collect()
Definition: conftest.py:198
conftest.SanitizedString.string
string
Definition: conftest.py:146
conftest._split_and_sort
def _split_and_sort(s)
Definition: conftest.py:53


gtsam
Author(s):
autogenerated on Tue Jun 25 2024 03:00:37