diff --git a/changelog/4243.bugfix.rst b/changelog/4243.bugfix.rst new file mode 100644 index 000000000..6a8bed895 --- /dev/null +++ b/changelog/4243.bugfix.rst @@ -0,0 +1 @@ +Fix regression when ``stacklevel`` for warnings was passed as positional argument on python2. diff --git a/src/_pytest/recwarn.py b/src/_pytest/recwarn.py index 4049110c5..4f3ab7f29 100644 --- a/src/_pytest/recwarn.py +++ b/src/_pytest/recwarn.py @@ -156,21 +156,27 @@ class WarningsRecorder(warnings.catch_warnings): # trivial patching of `warnings.warn` seems to be enough somehow? if six.PY2: - def warn(*args, **kwargs): - kwargs.setdefault("stacklevel", 1) - kwargs["stacklevel"] += 1 + def warn(message, category=None, stacklevel=1): + # duplicate the stdlib logic due to + # bad handing in the c version of warnings + if isinstance(message, Warning): + category = message.__class__ + # Check category argument + if category is None: + category = UserWarning + assert issubclass(category, Warning) # emulate resetting the warn registry - f_globals = sys._getframe(kwargs["stacklevel"] - 1).f_globals + f_globals = sys._getframe(stacklevel).f_globals if "__warningregistry__" in f_globals: orig = f_globals["__warningregistry__"] f_globals["__warningregistry__"] = None try: - return self._saved_warn(*args, **kwargs) + return self._saved_warn(message, category, stacklevel + 1) finally: f_globals["__warningregistry__"] = orig else: - return self._saved_warn(*args, **kwargs) + return self._saved_warn(message, category, stacklevel + 1) warnings.warn, self._saved_warn = warn, warnings.warn return self diff --git a/testing/test_recwarn.py b/testing/test_recwarn.py index 726f43763..223521a5e 100644 --- a/testing/test_recwarn.py +++ b/testing/test_recwarn.py @@ -46,6 +46,12 @@ class TestWarningsRecorderChecker(object): assert values is rec.list pytest.raises(AssertionError, "rec.pop()") + @pytest.mark.issue(4243) + def test_warn_stacklevel(self): + rec = WarningsRecorder() + with rec: + warnings.warn("test", DeprecationWarning, 2) + def test_typechecking(self): from _pytest.recwarn import WarningsChecker