Merge pull request #11160 from lesnek/ml/fix/warinings-recorder-pop
This commit is contained in:
commit
d7dbadbffc
1
AUTHORS
1
AUTHORS
|
@ -263,6 +263,7 @@ Mickey Pashov
|
||||||
Mihai Capotă
|
Mihai Capotă
|
||||||
Mike Hoyle (hoylemd)
|
Mike Hoyle (hoylemd)
|
||||||
Mike Lundy
|
Mike Lundy
|
||||||
|
Milan Lesnek
|
||||||
Miro Hrončok
|
Miro Hrončok
|
||||||
Nathaniel Compton
|
Nathaniel Compton
|
||||||
Nathaniel Waisbrot
|
Nathaniel Waisbrot
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
:meth:`pytest.WarningsRecorder.pop` will return the most-closely-matched warning in the list,
|
||||||
|
rather than the first warning which is an instance of the requested type.
|
|
@ -206,10 +206,21 @@ class WarningsRecorder(warnings.catch_warnings): # type:ignore[type-arg]
|
||||||
return len(self._list)
|
return len(self._list)
|
||||||
|
|
||||||
def pop(self, cls: Type[Warning] = Warning) -> "warnings.WarningMessage":
|
def pop(self, cls: Type[Warning] = Warning) -> "warnings.WarningMessage":
|
||||||
"""Pop the first recorded warning, raise exception if not exists."""
|
"""Pop the first recorded warning which is an instance of ``cls``,
|
||||||
|
but not an instance of a child class of any other match.
|
||||||
|
Raises ``AssertionError`` if there is no match.
|
||||||
|
"""
|
||||||
|
best_idx: Optional[int] = None
|
||||||
for i, w in enumerate(self._list):
|
for i, w in enumerate(self._list):
|
||||||
if issubclass(w.category, cls):
|
if w.category == cls:
|
||||||
return self._list.pop(i)
|
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)
|
||||||
|
):
|
||||||
|
best_idx = i
|
||||||
|
if best_idx is not None:
|
||||||
|
return self._list.pop(best_idx)
|
||||||
__tracebackhide__ = True
|
__tracebackhide__ = True
|
||||||
raise AssertionError(f"{cls!r} not found in warning list")
|
raise AssertionError(f"{cls!r} not found in warning list")
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import warnings
|
import warnings
|
||||||
|
from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from typing import Type
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.pytester import Pytester
|
from _pytest.pytester import Pytester
|
||||||
|
@ -37,6 +39,47 @@ def test_recwarn_captures_deprecation_warning(recwarn: WarningsRecorder) -> None
|
||||||
assert recwarn.pop(DeprecationWarning)
|
assert recwarn.pop(DeprecationWarning)
|
||||||
|
|
||||||
|
|
||||||
|
class TestSubclassWarningPop:
|
||||||
|
class ParentWarning(Warning):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class ChildWarning(ParentWarning):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class ChildOfChildWarning(ChildWarning):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def raise_warnings_from_list(_warnings: List[Type[Warning]]):
|
||||||
|
for warn in _warnings:
|
||||||
|
warnings.warn(f"Warning {warn().__repr__()}", warn)
|
||||||
|
|
||||||
|
def test_pop_finds_exact_match(self):
|
||||||
|
with pytest.warns((self.ParentWarning, self.ChildWarning)) as record:
|
||||||
|
self.raise_warnings_from_list(
|
||||||
|
[self.ChildWarning, self.ParentWarning, self.ChildOfChildWarning]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(record) == 3
|
||||||
|
_warn = record.pop(self.ParentWarning)
|
||||||
|
assert _warn.category is self.ParentWarning
|
||||||
|
|
||||||
|
def test_pop_raises_if_no_match(self):
|
||||||
|
with pytest.raises(AssertionError):
|
||||||
|
with pytest.warns(self.ParentWarning) as record:
|
||||||
|
self.raise_warnings_from_list([self.ParentWarning])
|
||||||
|
record.pop(self.ChildOfChildWarning)
|
||||||
|
|
||||||
|
def test_pop_finds_best_inexact_match(self):
|
||||||
|
with pytest.warns(self.ParentWarning) as record:
|
||||||
|
self.raise_warnings_from_list(
|
||||||
|
[self.ChildOfChildWarning, self.ChildWarning, self.ChildOfChildWarning]
|
||||||
|
)
|
||||||
|
|
||||||
|
_warn = record.pop(self.ParentWarning)
|
||||||
|
assert _warn.category is self.ChildWarning
|
||||||
|
|
||||||
|
|
||||||
class TestWarningsRecorderChecker:
|
class TestWarningsRecorderChecker:
|
||||||
def test_recording(self) -> None:
|
def test_recording(self) -> None:
|
||||||
rec = WarningsRecorder(_ispytest=True)
|
rec = WarningsRecorder(_ispytest=True)
|
||||||
|
|
Loading…
Reference in New Issue