Implement new pytest_warning_captured hook

This commit is contained in:
Bruno Oliveira 2018-08-25 20:41:16 -03:00
parent 10f21b423a
commit ffd47ceefc
3 changed files with 69 additions and 31 deletions

View File

@ -535,6 +535,25 @@ def pytest_logwarning(message, code, nodeid, fslocation):
"""
@hookspec(historic=True)
def pytest_warning_captured(warning, when, item):
"""
Process a warning captured by the internal pytest plugin.
:param warnings.WarningMessage warning:
The captured warning. This is the same object produced by :py:func:`warnings.catch_warnings`, and contains
the same attributes as :py:func:`warnings.showwarning`.
:param str when:
Indicates when the warning was captured. Possible values:
* ``"collect"``: during test collection.
* ``"runtest"``: during test execution.
:param pytest.Item|None item:
The item being executed if ``when == "runtest"``, else ``None``.
"""
# -------------------------------------------------------------------------
# doctest hooks
# -------------------------------------------------------------------------

View File

@ -58,7 +58,7 @@ def pytest_configure(config):
@contextmanager
def catch_warnings_for_item(item):
def deprecated_catch_warnings_for_item(item):
"""
catches the warnings generated during setup/call/teardown execution
of the given item and after it is done posts them as warnings to this
@ -80,40 +80,40 @@ def catch_warnings_for_item(item):
yield
for warning in log:
warn_msg = warning.message
unicode_warning = False
if compat._PY2 and any(
isinstance(m, compat.UNICODE_TYPES) for m in warn_msg.args
):
new_args = []
for m in warn_msg.args:
new_args.append(
compat.ascii_escaped(m)
if isinstance(m, compat.UNICODE_TYPES)
else m
)
unicode_warning = list(warn_msg.args) != new_args
warn_msg.args = new_args
msg = warnings.formatwarning(
warn_msg,
warning.category,
warning.filename,
warning.lineno,
warning.line,
item.ihook.pytest_warning_captured.call_historic(
kwargs=dict(warning=warning, when="runtest", item=item)
)
item.warn("unused", msg)
deprecated_emit_warning(item, warning)
if unicode_warning:
warnings.warn(
"Warning is using unicode non convertible to ascii, "
"converting to a safe representation:\n %s" % msg,
UnicodeWarning,
)
def deprecated_emit_warning(item, warning):
"""
Emits the deprecated ``pytest_logwarning`` for the given warning and item.
"""
warn_msg = warning.message
unicode_warning = False
if compat._PY2 and any(isinstance(m, compat.UNICODE_TYPES) for m in warn_msg.args):
new_args = []
for m in warn_msg.args:
new_args.append(
compat.ascii_escaped(m) if isinstance(m, compat.UNICODE_TYPES) else m
)
unicode_warning = list(warn_msg.args) != new_args
warn_msg.args = new_args
msg = warnings.formatwarning(
warn_msg, warning.category, warning.filename, warning.lineno, warning.line
)
item.warn("unused", msg)
if unicode_warning:
warnings.warn(
"Warning is using unicode non convertible to ascii, "
"converting to a safe representation:\n %s" % msg,
UnicodeWarning,
)
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_protocol(item):
with catch_warnings_for_item(item):
with deprecated_catch_warnings_for_item(item):
yield

View File

@ -302,3 +302,22 @@ def test_filterwarnings_mark_registration(testdir):
)
result = testdir.runpytest("--strict")
assert result.ret == 0
@pytest.mark.filterwarnings("always")
def test_warning_captured_hook(testdir, pyfile_with_warnings):
collected = []
class WarningCollector:
def pytest_warning_captured(self, warning, when, item):
collected.append((warning.category, when, item.name))
result = testdir.runpytest(plugins=[WarningCollector()])
result.stdout.fnmatch_lines(["*1 passed*"])
expected = [
(UserWarning, "runtest", "test_func"),
(RuntimeWarning, "runtest", "test_func"),
]
assert collected == expected