μHAL (v2.8.17)
Part of the IPbus software repository
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
conftest.py
Go to the documentation of this file.
1# -*- coding: utf-8 -*-
2"""pytest configuration
3
4Extends output capture as needed by pybind11: ignore constructors, optional unordered lines.
5Adds docstring and exceptions message sanitizers: ignore Python 2 vs 3 differences.
6"""
7
8import contextlib
9import difflib
10import gc
11import re
12import textwrap
13
14import pytest
15
16import env
17
18# Early diagnostic for failed imports
19import pybind11_tests # noqa: F401
20
21_unicode_marker = re.compile(r"u(\'[^\']*\')")
22_long_marker = re.compile(r"([0-9])L")
23_hexadecimal = re.compile(r"0x[0-9a-fA-F]+")
24
25# Avoid collecting Python3 only files
26collect_ignore = []
27if env.PY2:
28 collect_ignore.append("test_async.py")
29
30
32 """For triple-quote strings"""
33 return textwrap.dedent(s.lstrip("\n").rstrip())
34
35
37 """For output which does not require specific line order"""
38 return sorted(_strip_and_dedent(s).splitlines())
39
40
42 """Explanation for a failed assert -- the a and b arguments are List[str]"""
43 return ["--- actual / +++ expected"] + [
44 line.strip("\n") for line in difflib.ndiff(a, b)
45 ]
46
47
49 """Basic output post-processing and comparison"""
50
51 def __init__(self, string):
52 self.string = string
53 self.explanation = []
54
55 def __str__(self):
56 return self.string
57
58 def __eq__(self, other):
59 # Ignore constructor/destructor output which is prefixed with "###"
60 a = [
61 line
62 for line in self.string.strip().splitlines()
63 if not line.startswith("###")
64 ]
65 b = _strip_and_dedent(other).splitlines()
66 if a == b:
67 return True
68 else:
70 return False
71
72
74 """Custom comparison for output without strict line ordering"""
75
76 def __eq__(self, other):
77 a = _split_and_sort(self.string)
78 b = _split_and_sort(other)
79 if a == b:
80 return True
81 else:
83 return False
84
85
87 def __init__(self, capfd):
88 self.capfd = capfd
89 self.out = ""
90 self.err = ""
91
92 def __enter__(self):
93 self.capfd.readouterr()
94 return self
95
96 def __exit__(self, *args):
97 self.out, self.err = self.capfd.readouterr()
98
99 def __eq__(self, other):
100 a = Output(self.out)
101 b = other
102 if a == b:
103 return True
104 else:
105 self.explanation = a.explanation
106 return False
107
108 def __str__(self):
109 return self.out
110
111 def __contains__(self, item):
112 return item in self.out
113
114 @property
115 def unordered(self):
116 return Unordered(self.out)
117
118 @property
119 def stderr(self):
120 return Output(self.err)
121
122
123@pytest.fixture
124def capture(capsys):
125 """Extended `capsys` with context manager and custom equality operators"""
126 return Capture(capsys)
127
128
130 def __init__(self, sanitizer):
131 self.sanitizer = sanitizer
132 self.string = ""
133 self.explanation = []
134
135 def __call__(self, thing):
136 self.string = self.sanitizer(thing)
137 return self
138
139 def __eq__(self, other):
140 a = self.string
141 b = _strip_and_dedent(other)
142 if a == b:
143 return True
144 else:
145 self.explanation = _make_explanation(a.splitlines(), b.splitlines())
146 return False
147
148
150 s = s.strip()
151 s = s.replace("pybind11_tests.", "m.")
152 s = s.replace("unicode", "str")
153 s = _long_marker.sub(r"\1", s)
154 s = _unicode_marker.sub(r"\1", s)
155 return s
156
157
159 s = thing.__doc__
160 s = _sanitize_general(s)
161 return s
162
163
164@pytest.fixture
165def doc():
166 """Sanitize docstrings and add custom failure explanation"""
167 return SanitizedString(_sanitize_docstring)
168
169
171 s = str(thing)
172 s = _sanitize_general(s)
173 s = _hexadecimal.sub("0", s)
174 return s
175
176
177@pytest.fixture
178def msg():
179 """Sanitize messages and add custom failure explanation"""
180 return SanitizedString(_sanitize_message)
181
182
183# noinspection PyUnusedLocal
184def pytest_assertrepr_compare(op, left, right):
185 """Hook to insert custom failure explanation"""
186 if hasattr(left, "explanation"):
187 return left.explanation
188
189
190@contextlib.contextmanager
191def suppress(exception):
192 """Suppress the desired exception"""
193 try:
194 yield
195 except exception:
196 pass
197
198
200 """Run the garbage collector twice (needed when running
201 reference counting tests with PyPy)"""
202 gc.collect()
203 gc.collect()
204
205
207 pytest.suppress = suppress
208 pytest.gc_collect = gc_collect
def unordered(self)
Definition: conftest.py:115
def stderr(self)
Definition: conftest.py:119
def __init__(self, capfd)
Definition: conftest.py:87
def __enter__(self)
Definition: conftest.py:92
def __contains__(self, item)
Definition: conftest.py:111
def __exit__(self, *args)
Definition: conftest.py:96
def __str__(self)
Definition: conftest.py:108
def __eq__(self, other)
Definition: conftest.py:99
def __str__(self)
Definition: conftest.py:55
def __init__(self, string)
Definition: conftest.py:51
def __eq__(self, other)
Definition: conftest.py:58
def __call__(self, thing)
Definition: conftest.py:135
def __init__(self, sanitizer)
Definition: conftest.py:130
def __eq__(self, other)
Definition: conftest.py:139
def __eq__(self, other)
Definition: conftest.py:76
\rst Holds a reference to a Python object (with reference counting)
Definition: pytypes.h:259
Definition: pytypes.h:1200
bool hasattr(handle obj, handle name)
Definition: pytypes.h:517
def _sanitize_message(thing)
Definition: conftest.py:170
def pytest_assertrepr_compare(op, left, right)
Definition: conftest.py:184
def pytest_configure()
Definition: conftest.py:206
def suppress(exception)
Definition: conftest.py:191
def msg()
Definition: conftest.py:178
def _sanitize_general(s)
Definition: conftest.py:149
def _split_and_sort(s)
Definition: conftest.py:36
def _strip_and_dedent(s)
Definition: conftest.py:31
def _sanitize_docstring(thing)
Definition: conftest.py:158
def capture(capsys)
Definition: conftest.py:124
def doc()
Definition: conftest.py:165
def _make_explanation(a, b)
Definition: conftest.py:41
def gc_collect()
Definition: conftest.py:199