diff --git a/pandas/_testing/_warnings.py b/pandas/_testing/_warnings.py index 1a8fe71ae3728..e9df85eae550a 100644 --- a/pandas/_testing/_warnings.py +++ b/pandas/_testing/_warnings.py @@ -17,7 +17,7 @@ @contextmanager def assert_produces_warning( - expected_warning: type[Warning] | bool | None = Warning, + expected_warning: type[Warning] | bool | tuple[type[Warning], ...] | None = Warning, filter_level: Literal[ "error", "ignore", "always", "default", "module", "once" ] = "always", @@ -26,16 +26,17 @@ def assert_produces_warning( match: str | None = None, ): """ - Context manager for running code expected to either raise a specific - warning, or not raise any warnings. Verifies that the code raises the - expected warning, and that it does not raise any other unexpected + Context manager for running code expected to either raise a specific warning, + multiple specific warnings, or not raise any warnings. Verifies that the code + raises the expected warning(s), and that it does not raise any other unexpected warnings. It is basically a wrapper around ``warnings.catch_warnings``. Parameters ---------- - expected_warning : {Warning, False, None}, default Warning + expected_warning : {Warning, False, tuple[Warning, ...], None}, default Warning The type of Exception raised. ``exception.Warning`` is the base - class for all warnings. To check that no warning is returned, + class for all warnings. To raise multiple types of exceptions, + pass them as a tuple. To check that no warning is returned, specify ``False`` or ``None``. filter_level : str or None, default "always" Specifies whether warnings are ignored, displayed, or turned @@ -157,7 +158,7 @@ def _assert_caught_expected_warning( def _assert_caught_no_extra_warnings( *, caught_warnings: Sequence[warnings.WarningMessage], - expected_warning: type[Warning] | bool | None, + expected_warning: type[Warning] | bool | tuple[type[Warning], ...] | None, ) -> None: """Assert that no extra warnings apart from the expected ones are caught.""" extra_warnings = [] @@ -195,7 +196,7 @@ def _assert_caught_no_extra_warnings( def _is_unexpected_warning( actual_warning: warnings.WarningMessage, - expected_warning: type[Warning] | bool | None, + expected_warning: type[Warning] | bool | tuple[type[Warning], ...] | None, ) -> bool: """Check if the actual warning issued is unexpected.""" if actual_warning and not expected_warning: diff --git a/pandas/tests/util/test_assert_produces_warning.py b/pandas/tests/util/test_assert_produces_warning.py index e3eb083e1a383..70a95bd7cdb48 100644 --- a/pandas/tests/util/test_assert_produces_warning.py +++ b/pandas/tests/util/test_assert_produces_warning.py @@ -179,6 +179,14 @@ def test_same_category_different_messages_last_match(): warnings.warn("Match this", category) +def test_match_multiple_warnings(): + # https://github.com/pandas-dev/pandas/issues/47829 + category = (FutureWarning, UserWarning) + with tm.assert_produces_warning(category, match=r"^Match this"): + warnings.warn("Match this", FutureWarning) + warnings.warn("Match this too", UserWarning) + + def test_right_category_wrong_match_raises(pair_different_warnings): target_category, other_category = pair_different_warnings with pytest.raises(AssertionError, match="Did not see warning.*matching"):