diff --git a/changelog/4012.bugfix.rst b/changelog/4012.bugfix.rst new file mode 100644 index 000000000..11d8deef7 --- /dev/null +++ b/changelog/4012.bugfix.rst @@ -0,0 +1 @@ +``pytest.warn`` will capture previously-warned warnings in python2. Previously they were never raised. diff --git a/src/_pytest/recwarn.py b/src/_pytest/recwarn.py index c0121f7c1..592abdf5b 100644 --- a/src/_pytest/recwarn.py +++ b/src/_pytest/recwarn.py @@ -149,12 +149,25 @@ class WarningsRecorder(warnings.catch_warnings): raise RuntimeError("Cannot enter %r twice" % self) self._list = super(WarningsRecorder, self).__enter__() warnings.simplefilter("always") + # python3 keeps track of a "filter version", when the filters are + # updated previously seen warnings can be re-warned. python2 has no + # concept of this so we must reset the warnings registry manually. + # trivial patching of `warnings.warn` seems to be enough somehow? + if six.PY2: + + def warn(*args, **kwargs): + return self._warn(*args, **kwargs) + + warnings.warn, self._warn = warn, warnings.warn return self def __exit__(self, *exc_info): if not self._entered: __tracebackhide__ = True raise RuntimeError("Cannot exit %r without entering first" % self) + # see above where `self.mp` is assigned + if six.PY2: + warnings.warn = self._warn super(WarningsRecorder, self).__exit__(*exc_info) diff --git a/testing/test_recwarn.py b/testing/test_recwarn.py index 897f4c5e8..3ae543248 100644 --- a/testing/test_recwarn.py +++ b/testing/test_recwarn.py @@ -350,3 +350,13 @@ class TestWarns(object): with pytest.warns(UserWarning, match=r"aaa"): warnings.warn("bbbbbbbbbb", UserWarning) warnings.warn("cccccccccc", UserWarning) + + @pytest.mark.filterwarnings("ignore") + def test_can_capture_previously_warned(self): + def f(): + warnings.warn(UserWarning("ohai")) + return 10 + + assert f() == 10 + assert pytest.warns(UserWarning, f) == 10 + assert pytest.warns(UserWarning, f) == 10