diff --git a/AUTHORS b/AUTHORS index e2fad5e8364..413d146d351 100644 --- a/AUTHORS +++ b/AUTHORS @@ -11,6 +11,7 @@ ace2016 Adam Johnson Adam Stewart Adam Uhlir +Aditya Kumar Aditya Tripuraneni Ahn Ki-Wook Akhilesh Ramakrishnan diff --git a/changelog/15097.bugfix.rst b/changelog/15097.bugfix.rst new file mode 100644 index 00000000000..5376093d809 --- /dev/null +++ b/changelog/15097.bugfix.rst @@ -0,0 +1 @@ +:meth:`WarningsRecorder.pop() ` now returns the first matching warning again when the recorded warnings have unrelated categories, instead of the last one. diff --git a/src/_pytest/recwarn.py b/src/_pytest/recwarn.py index 3e36fc7d286..eb5a798a580 100644 --- a/src/_pytest/recwarn.py +++ b/src/_pytest/recwarn.py @@ -213,17 +213,17 @@ def pop(self, cls: type[Warning] = Warning) -> warnings.WarningMessage: but not an instance of a child class of any other match. Raises ``AssertionError`` if there is no match. """ - best_idx: int | None = None - for i, w in enumerate(self._list): - if w.category == cls: - return self._list.pop(i) # exact match, stop looking - if issubclass(w.category, cls) and ( - best_idx is None - or not issubclass(w.category, self._list[best_idx].category) + matches = [ + (i, w.category) + for i, w in enumerate(self._list) + if issubclass(w.category, cls) + ] + for i, category in matches: + if not any( + other is not category and issubclass(category, other) + for _, other in matches ): - best_idx = i - if best_idx is not None: - return self._list.pop(best_idx) + return self._list.pop(i) __tracebackhide__ = True raise AssertionError(f"{cls!r} not found in warning list") diff --git a/testing/test_recwarn.py b/testing/test_recwarn.py index d6de42a4c5c..99eef7795c2 100644 --- a/testing/test_recwarn.py +++ b/testing/test_recwarn.py @@ -82,6 +82,25 @@ def test_pop_finds_best_inexact_match(self): _warn = record.pop(self.ParentWarning) assert _warn.category is self.ChildWarning + def test_pop_finds_first_of_unrelated_matches(self): + with pytest.warns(Warning) as record: + self.raise_warnings_from_list( + [self.ChildWarning, UserWarning, DeprecationWarning] + ) + + assert record.pop().category is self.ChildWarning + assert record.pop().category is UserWarning + assert record.pop().category is DeprecationWarning + + def test_pop_skips_child_of_later_match(self): + with pytest.warns(Warning) as record: + self.raise_warnings_from_list( + [self.ChildWarning, UserWarning, self.ParentWarning] + ) + + _warn = record.pop() + assert _warn.category is UserWarning + class TestWarningsRecorderChecker: def test_recording(self) -> None: