Scarab  v2.9.1
Project 8 C++ Utility Library
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: ignore Python 2 vs 3 differences.
5 """
6 
7 import pytest
8 import textwrap
9 import difflib
10 import re
11 import sys
12 import contextlib
13 import platform
14 import gc
15 
16 _unicode_marker = re.compile(r'u(\'[^\']*\')')
17 _long_marker = re.compile(r'([0-9])L')
18 _hexadecimal = re.compile(r'0x[0-9a-fA-F]+')
19 
20 # test_async.py requires support for async and await
21 collect_ignore = []
22 if sys.version_info[:2] < (3, 5):
23  collect_ignore.append("test_async.py")
24 
25 
27  """For triple-quote strings"""
28  return textwrap.dedent(s.lstrip('\n').rstrip())
29 
30 
32  """For output which does not require specific line order"""
33  return sorted(_strip_and_dedent(s).splitlines())
34 
35 
37  """Explanation for a failed assert -- the a and b arguments are List[str]"""
38  return ["--- actual / +++ expected"] + [line.strip('\n') for line in difflib.ndiff(a, b)]
39 
40 
41 class Output(object):
42  """Basic output post-processing and comparison"""
43  def __init__(self, string):
44  self.string = string
45  self.explanation = []
46 
47  def __str__(self):
48  return self.string
49 
50  def __eq__(self, other):
51  # Ignore constructor/destructor output which is prefixed with "###"
52  a = [line for line in self.string.strip().splitlines() if not line.startswith("###")]
53  b = _strip_and_dedent(other).splitlines()
54  if a == b:
55  return True
56  else:
57  self.explanation = _make_explanation(a, b)
58  return False
59 
60 
62  """Custom comparison for output without strict line ordering"""
63  def __eq__(self, other):
64  a = _split_and_sort(self.string)
65  b = _split_and_sort(other)
66  if a == b:
67  return True
68  else:
70  return False
71 
72 
73 class Capture(object):
74  def __init__(self, capfd):
75  self.capfd = capfd
76  self.out = ""
77  self.err = ""
78 
79  def __enter__(self):
80  self.capfd.readouterr()
81  return self
82 
83  def __exit__(self, *args):
84  self.out, self.err = self.capfd.readouterr()
85 
86  def __eq__(self, other):
87  a = Output(self.out)
88  b = other
89  if a == b:
90  return True
91  else:
92  self.explanation = a.explanation
93  return False
94 
95  def __str__(self):
96  return self.out
97 
98  def __contains__(self, item):
99  return item in self.out
100 
101  @property
102  def unordered(self):
103  return Unordered(self.out)
104 
105  @property
106  def stderr(self):
107  return Output(self.err)
108 
109 
110 @pytest.fixture
111 def capture(capsys):
112  """Extended `capsys` with context manager and custom equality operators"""
113  return Capture(capsys)
114 
115 
116 class SanitizedString(object):
117  def __init__(self, sanitizer):
118  self.sanitizer = sanitizer
119  self.string = ""
120  self.explanation = []
121 
122  def __call__(self, thing):
123  self.string = self.sanitizer(thing)
124  return self
125 
126  def __eq__(self, other):
127  a = self.string
128  b = _strip_and_dedent(other)
129  if a == b:
130  return True
131  else:
132  self.explanation = _make_explanation(a.splitlines(), b.splitlines())
133  return False
134 
135 
137  s = s.strip()
138  s = s.replace("pybind11_tests.", "m.")
139  s = s.replace("unicode", "str")
140  s = _long_marker.sub(r"\1", s)
141  s = _unicode_marker.sub(r"\1", s)
142  return s
143 
144 
146  s = thing.__doc__
147  s = _sanitize_general(s)
148  return s
149 
150 
151 @pytest.fixture
152 def doc():
153  """Sanitize docstrings and add custom failure explanation"""
154  return SanitizedString(_sanitize_docstring)
155 
156 
157 def _sanitize_message(thing):
158  s = str(thing)
159  s = _sanitize_general(s)
160  s = _hexadecimal.sub("0", s)
161  return s
162 
163 
164 @pytest.fixture
165 def msg():
166  """Sanitize messages and add custom failure explanation"""
167  return SanitizedString(_sanitize_message)
168 
169 
170 # noinspection PyUnusedLocal
171 def pytest_assertrepr_compare(op, left, right):
172  """Hook to insert custom failure explanation"""
173  if hasattr(left, 'explanation'):
174  return left.explanation
175 
176 
177 @contextlib.contextmanager
178 def suppress(exception):
179  """Suppress the desired exception"""
180  try:
181  yield
182  except exception:
183  pass
184 
185 
187  ''' Run the garbage collector twice (needed when running
188  reference counting tests with PyPy) '''
189  gc.collect()
190  gc.collect()
191 
192 
194  """Add import suppression and test requirements to `pytest` namespace"""
195  try:
196  import numpy as np
197  except ImportError:
198  np = None
199  try:
200  import scipy
201  except ImportError:
202  scipy = None
203  try:
204  from pybind11_tests.eigen import have_eigen
205  except ImportError:
206  have_eigen = False
207  pypy = platform.python_implementation() == "PyPy"
208 
209  skipif = pytest.mark.skipif
210  pytest.suppress = suppress
211  pytest.requires_numpy = skipif(not np, reason="numpy is not installed")
212  pytest.requires_scipy = skipif(not np, reason="scipy is not installed")
213  pytest.requires_eigen_and_numpy = skipif(not have_eigen or not np,
214  reason="eigen and/or numpy are not installed")
215  pytest.requires_eigen_and_scipy = skipif(
216  not have_eigen or not scipy, reason="eigen and/or scipy are not installed")
217  pytest.unsupported_on_pypy = skipif(pypy, reason="unsupported on PyPy")
218  pytest.unsupported_on_py2 = skipif(sys.version_info.major < 3,
219  reason="unsupported on Python 2.x")
220  pytest.gc_collect = gc_collect
221 
222 
224  """Early diagnostic for test module initialization errors
225 
226  When there is an error during initialization, the first import will report the
227  real error while all subsequent imports will report nonsense. This import test
228  is done early (in the pytest configuration file, before any tests) in order to
229  avoid the noise of having all tests fail with identical error messages.
230 
231  Any possible exception is caught here and reported manually *without* the stack
232  trace. This further reduces noise since the trace would only show pytest internals
233  which are not useful for debugging pybind11 module issues.
234  """
235  # noinspection PyBroadException
236  try:
237  import pybind11_tests # noqa: F401 imported but unused
238  except Exception as e:
239  print("Failed to import pybind11_tests from pytest:")
240  print(" {}: {}".format(type(e).__name__, e))
241  sys.exit(1)
242 
243 
def _split_and_sort(s)
Definition: conftest.py:31
def __eq__(self, other)
Definition: conftest.py:50
def __init__(self, sanitizer)
Definition: conftest.py:117
def pytest_configure()
Definition: conftest.py:193
def __eq__(self, other)
Definition: conftest.py:63
def __contains__(self, item)
Definition: conftest.py:98
def gc_collect()
Definition: conftest.py:186
def __eq__(self, other)
Definition: conftest.py:126
auto format(const std::locale &loc, const CharT *fmt, const Streamable &tp) -> decltype(to_stream(std::declval< std::basic_ostream< CharT > &>(), fmt, tp), std::basic_string< CharT >
Definition: date.h:5663
def msg()
Definition: conftest.py:165
def suppress(exception)
Definition: conftest.py:178
def pytest_assertrepr_compare(op, left, right)
Definition: conftest.py:171
def _make_explanation(a, b)
Definition: conftest.py:36
def _strip_and_dedent(s)
Definition: conftest.py:26
def __exit__(self, args)
Definition: conftest.py:83
def unordered(self)
Definition: conftest.py:102
def __eq__(self, other)
Definition: conftest.py:86
def _sanitize_docstring(thing)
Definition: conftest.py:145
def _sanitize_message(thing)
Definition: conftest.py:157
def doc()
Definition: conftest.py:152
def __str__(self)
Definition: conftest.py:47
const detail::type_info * type
Definition: cast.h:453
def __init__(self, string)
Definition: conftest.py:43
def __str__(self)
Definition: conftest.py:95
return os str()
def _sanitize_general(s)
Definition: conftest.py:136
def _test_import_pybind11()
Definition: conftest.py:223
def capture(capsys)
Definition: conftest.py:111
def __call__(self, thing)
Definition: conftest.py:122
void print(Args &&...args)
Definition: pybind11.h:1849
def __init__(self, capfd)
Definition: conftest.py:74
def __enter__(self)
Definition: conftest.py:79
def stderr(self)
Definition: conftest.py:106
bool hasattr(handle obj, handle name)
Definition: pytypes.h:387