Skip to content

Commit d3e8e23

Browse files
recwarn code cleanup and output enhancements
* use f-strings more * use pformat to ensure multi line print for longer-warning lists while keeping short ones small
1 parent 3dc17f1 commit d3e8e23

File tree

2 files changed

+28
-33
lines changed

2 files changed

+28
-33
lines changed

src/_pytest/recwarn.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Record warnings during test function execution."""
22
import re
33
import warnings
4+
from pprint import pformat
45
from types import TracebackType
56
from typing import Any
67
from typing import Callable
@@ -142,10 +143,11 @@ def warns(
142143
__tracebackhide__ = True
143144
if not args:
144145
if kwargs:
145-
msg = "Unexpected keyword arguments passed to pytest.warns: "
146-
msg += ", ".join(sorted(kwargs))
147-
msg += "\nUse context-manager form instead?"
148-
raise TypeError(msg)
146+
argnames = ", ".join(sorted(kwargs))
147+
raise TypeError(
148+
f"Unexpected keyword arguments passed to pytest.warns: {argnames}"
149+
"\nUse context-manager form instead?"
150+
)
149151
return WarningsChecker(expected_warning, match_expr=match, _ispytest=True)
150152
else:
151153
func = args[0]
@@ -191,7 +193,7 @@ def pop(self, cls: Type[Warning] = Warning) -> "warnings.WarningMessage":
191193
if issubclass(w.category, cls):
192194
return self._list.pop(i)
193195
__tracebackhide__ = True
194-
raise AssertionError("%r not found in warning list" % cls)
196+
raise AssertionError(f"{cls!r} not found in warning list")
195197

196198
def clear(self) -> None:
197199
"""Clear the list of recorded warnings."""
@@ -202,7 +204,7 @@ def clear(self) -> None:
202204
def __enter__(self) -> "WarningsRecorder": # type: ignore
203205
if self._entered:
204206
__tracebackhide__ = True
205-
raise RuntimeError("Cannot enter %r twice" % self)
207+
raise RuntimeError(f"Cannot enter {self!r} twice")
206208
_list = super().__enter__()
207209
# record=True means it's None.
208210
assert _list is not None
@@ -218,7 +220,7 @@ def __exit__(
218220
) -> None:
219221
if not self._entered:
220222
__tracebackhide__ = True
221-
raise RuntimeError("Cannot exit %r without entering first" % self)
223+
raise RuntimeError(f"Cannot exit {self!r} without entering first")
222224

223225
super().__exit__(exc_type, exc_val, exc_tb)
224226

@@ -268,16 +270,17 @@ def __exit__(
268270

269271
__tracebackhide__ = True
270272

273+
def found_str():
274+
return pformat([record.message for record in self], indent=2)
275+
271276
# only check if we're not currently handling an exception
272277
if exc_type is None and exc_val is None and exc_tb is None:
273278
if self.expected_warning is not None:
274279
if not any(issubclass(r.category, self.expected_warning) for r in self):
275280
__tracebackhide__ = True
276281
fail(
277-
"DID NOT WARN. No warnings of type {} were emitted. "
278-
"The list of emitted warnings is: {}.".format(
279-
self.expected_warning, [each.message for each in self]
280-
)
282+
f"DID NOT WARN. No warnings of type {self.expected_warning} were emitted. \n"
283+
f"The list of emitted warnings is: {found_str()}."
281284
)
282285
elif self.match_expr is not None:
283286
for r in self:
@@ -286,11 +289,8 @@ def __exit__(
286289
break
287290
else:
288291
fail(
289-
"DID NOT WARN. No warnings of type {} matching"
290-
" ('{}') were emitted. The list of emitted warnings"
291-
" is: {}.".format(
292-
self.expected_warning,
293-
self.match_expr,
294-
[each.message for each in self],
295-
)
292+
f"""\
293+
DID NOT WARN. No warnings of type {self.expected_warning} matching the regex were emitted.
294+
The regex is: {self.match_expr!r}
295+
The list of emitted warnings is: {found_str()}"""
296296
)

testing/test_recwarn.py

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import re
21
import warnings
32
from typing import Optional
43

@@ -263,23 +262,23 @@ def test_as_contextmanager(self) -> None:
263262
with pytest.warns(RuntimeWarning):
264263
warnings.warn("user", UserWarning)
265264
excinfo.match(
266-
r"DID NOT WARN. No warnings of type \(.+RuntimeWarning.+,\) were emitted. "
265+
r"DID NOT WARN. No warnings of type \(.+RuntimeWarning.+,\) were emitted. \n"
267266
r"The list of emitted warnings is: \[UserWarning\('user',?\)\]."
268267
)
269268

270269
with pytest.raises(pytest.fail.Exception) as excinfo:
271270
with pytest.warns(UserWarning):
272271
warnings.warn("runtime", RuntimeWarning)
273272
excinfo.match(
274-
r"DID NOT WARN. No warnings of type \(.+UserWarning.+,\) were emitted. "
275-
r"The list of emitted warnings is: \[RuntimeWarning\('runtime',?\)\]."
273+
r"DID NOT WARN. No warnings of type \(.+UserWarning.+,\) were emitted. \n"
274+
r"The list of emitted warnings is: \[RuntimeWarning\('runtime',?\)]."
276275
)
277276

278277
with pytest.raises(pytest.fail.Exception) as excinfo:
279278
with pytest.warns(UserWarning):
280279
pass
281280
excinfo.match(
282-
r"DID NOT WARN. No warnings of type \(.+UserWarning.+,\) were emitted. "
281+
r"DID NOT WARN. No warnings of type \(.+UserWarning.+,\) were emitted. \n"
283282
r"The list of emitted warnings is: \[\]."
284283
)
285284

@@ -289,18 +288,14 @@ def test_as_contextmanager(self) -> None:
289288
warnings.warn("runtime", RuntimeWarning)
290289
warnings.warn("import", ImportWarning)
291290

292-
message_template = (
293-
"DID NOT WARN. No warnings of type {0} were emitted. "
294-
"The list of emitted warnings is: {1}."
295-
)
296-
excinfo.match(
297-
re.escape(
298-
message_template.format(
299-
warning_classes, [each.message for each in warninfo]
300-
)
301-
)
291+
messages = [each.message for each in warninfo]
292+
expected_str = (
293+
f"DID NOT WARN. No warnings of type {warning_classes} were emitted. \n"
294+
f"The list of emitted warnings is: {messages}."
302295
)
303296

297+
assert str(excinfo.value) == expected_str
298+
304299
def test_record(self) -> None:
305300
with pytest.warns(UserWarning) as record:
306301
warnings.warn("user", UserWarning)

0 commit comments

Comments
 (0)