diff --git a/_pytest/terminal.py b/_pytest/terminal.py index d0bb4f4b5..fbfb03232 100644 --- a/_pytest/terminal.py +++ b/_pytest/terminal.py @@ -2,6 +2,9 @@ This is a good source for looking at the various reporting hooks. """ +import operator +import itertools + from _pytest.main import EXIT_OK, EXIT_TESTSFAILED, EXIT_INTERRUPTED, \ EXIT_USAGEERROR, EXIT_NOTESTSCOLLECTED import pytest @@ -28,7 +31,7 @@ def pytest_addoption(parser): "--disable-warnings is set") group._addoption('--disable-warnings', '--disable-pytest-warnings', default=False, dest='disable_warnings', action='store_true', - help='disable warnings summary, overrides -r w flag') + help='disable warnings summary') group._addoption('-l', '--showlocals', action="store_true", dest="showlocals", default=False, help="show locals in tracebacks (disabled by default).") @@ -438,16 +441,15 @@ class TerminalReporter(object): def summary_warnings(self): if self.hasopt("w"): - warnings = self.stats.get("warnings") - if not warnings: + all_warnings = self.stats.get("warnings") + if not all_warnings: return - self.write_sep("=", "warnings summary") - for w in warnings: - msg = '' - if w.fslocation: - msg += str(w.fslocation) + ' ' - msg += w.message - self._tw.line(msg) + self.write_sep("=", "warnings summary", yellow=True, bold=False) + grouped = itertools.groupby(all_warnings, key=operator.attrgetter('nodeid')) + for nodeid, warnings in grouped: + self._tw.line(str(nodeid)) + for w in warnings: + self._tw.line(w.message) self._tw.line('-- Docs: http://doc.pytest.org/en/latest/warnings.html') def summary_passes(self): diff --git a/_pytest/warnings.py b/_pytest/warnings.py index 1458c25c3..9a91d181c 100644 --- a/_pytest/warnings.py +++ b/_pytest/warnings.py @@ -63,7 +63,7 @@ def catch_warnings_for_item(item): msg = warnings.formatwarning( warning.message, warning.category, warning.filename, warning.lineno, warning.line) - item.config.warn("unused", msg, fslocation=None) + item.warn("unused", msg) @pytest.hookimpl(hookwrapper=True) diff --git a/testing/test_warnings.py b/testing/test_warnings.py index 77eefb7e3..3b9908ef7 100644 --- a/testing/test_warnings.py +++ b/testing/test_warnings.py @@ -4,27 +4,48 @@ import pytest WARNINGS_SUMMARY_HEADER = 'warnings summary' @pytest.fixture -def pyfile_with_warnings(testdir): - testdir.makepyfile(''' - import warnings - def test_func(): - warnings.warn(PendingDeprecationWarning("functionality is pending deprecation")) - warnings.warn(DeprecationWarning("functionality is deprecated")) - ''') +def pyfile_with_warnings(testdir, request): + """ + Create a test file which calls a function in a module which generates warnings. + """ + testdir.syspathinsert() + test_name = request.function.__name__ + module_name = test_name.lstrip('test_') + '_module' + testdir.makepyfile(**{ + module_name: ''' + import warnings + def foo(): + warnings.warn(PendingDeprecationWarning("functionality is pending deprecation")) + warnings.warn(DeprecationWarning("functionality is deprecated")) + return 1 + ''', + test_name: ''' + import {module_name} + def test_func(): + assert {module_name}.foo() == 1 + '''.format(module_name=module_name) + }) def test_normal_flow(testdir, pyfile_with_warnings): + """ + Check that the warnings section is displayed, containing test node ids followed by + all warnings generated by that test node. + """ result = testdir.runpytest() result.stdout.fnmatch_lines([ '*== %s ==*' % WARNINGS_SUMMARY_HEADER, - '*test_normal_flow.py:3: PendingDeprecationWarning: functionality is pending deprecation', + '*test_normal_flow.py::test_func', + + '*normal_flow_module.py:3: PendingDeprecationWarning: functionality is pending deprecation', ' warnings.warn(PendingDeprecationWarning("functionality is pending deprecation"))', - '*test_normal_flow.py:4: DeprecationWarning: functionality is deprecated', + '*normal_flow_module.py:4: DeprecationWarning: functionality is deprecated', ' warnings.warn(DeprecationWarning("functionality is deprecated"))', '* 1 passed, 2 warnings*', ]) + assert result.stdout.str().count('test_normal_flow.py::test_func') == 1 def test_setup_teardown_warnings(testdir, pyfile_with_warnings): @@ -66,7 +87,7 @@ def test_as_errors(testdir, pyfile_with_warnings, method): result = testdir.runpytest(*args) result.stdout.fnmatch_lines([ 'E PendingDeprecationWarning: functionality is pending deprecation', - 'test_as_errors.py:3: PendingDeprecationWarning', + 'as_errors_module.py:3: PendingDeprecationWarning', '* 1 failed in *', ])