From 11ade8161070acfa3d3827ecd25952dc9ced4890 Mon Sep 17 00:00:00 2001 From: Maxim Ivanov Date: Mon, 19 Oct 2020 23:07:41 +0700 Subject: [PATCH 1/6] TST: add tests for matching warning messages --- pandas/tests/_testing/test_warnings.py | 136 +++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 pandas/tests/_testing/test_warnings.py diff --git a/pandas/tests/_testing/test_warnings.py b/pandas/tests/_testing/test_warnings.py new file mode 100644 index 0000000000000..59cf1ea004f47 --- /dev/null +++ b/pandas/tests/_testing/test_warnings.py @@ -0,0 +1,136 @@ +"""" +Test module for testing ``pandas._testing.assert_produces_warning``. +""" + +import warnings + +import pytest + +from pandas.errors import DtypeWarning, PerformanceWarning + +from pandas._testing import assert_produces_warning + + +@pytest.fixture( + params=[ + RuntimeWarning, + ResourceWarning, + UserWarning, + FutureWarning, + DeprecationWarning, + PerformanceWarning, + DtypeWarning, + ], +) +def category(request): + """Return unique warning. + + Useful for testing behavior of assert_produces_warning with various categories. + """ + return request.param + + +@pytest.fixture( + params=[ + (RuntimeWarning, UserWarning), + (UserWarning, FutureWarning), + (FutureWarning, RuntimeWarning), + (DeprecationWarning, PerformanceWarning), + (PerformanceWarning, FutureWarning), + (DtypeWarning, DeprecationWarning), + (ResourceWarning, DeprecationWarning), + (FutureWarning, DeprecationWarning), + ], + ids=lambda x: type(x).__name__, +) +def pair_different_warnings(request): + """Return pair or different warnings. + + Useful for testing how several different warnings are handled + in assert_produces_warning. + """ + return request.param + + +@pytest.mark.parametrize( + "message, match", + [ + ("", None), + ("", ""), + ("Warning message", r".*"), + ("Warning message", "War"), + ("Warning message", r"[Ww]arning"), + ("Warning message", "age"), + ("Warning message", r"age$"), + ("Message 12-234 with numbers", r"\d{2}-\d{3}"), + ("Message 12-234 with numbers", r"^Mes.*\d{2}-\d{3}"), + ("Message 12-234 with numbers", r"\d{2}-\d{3}\s\S+"), + ("Message, which we do not match", None), + ], +) +def test_catch_warning_category_and_match(category, message, match): + with assert_produces_warning(category, match=match): + warnings.warn(message, category) + + +@pytest.mark.parametrize( + "message, match", + [ + ("Warning message", "Not this message"), + ("Warning message", "warning"), + ("Warning message", r"\d+"), + ], +) +def test_fail_to_match(category, message, match): + msg = f"Did not see warning {repr(category.__name__)} matching" + with pytest.raises(AssertionError, match=msg): + with assert_produces_warning(category, match=match): + warnings.warn(message, category) + + +def test_fail_to_catch_actual_warning(pair_different_warnings): + expected_category, actual_category = pair_different_warnings + match = "Did not see expected warning of class" + with pytest.raises(AssertionError, match=match): + with assert_produces_warning(expected_category): + warnings.warn("warning message", actual_category) + + +def test_ignore_extra_warning(pair_different_warnings): + expected_category, extra_category = pair_different_warnings + with assert_produces_warning(expected_category, raise_on_extra_warnings=False): + warnings.warn("Expected warning", expected_category) + warnings.warn("Unexpected warning OK", extra_category) + + +def test_raise_on_extra_warning(pair_different_warnings): + expected_category, extra_category = pair_different_warnings + match = r"Caused unexpected warning\(s\)" + with pytest.raises(AssertionError, match=match): + with assert_produces_warning(expected_category): + warnings.warn("Expected warning", expected_category) + warnings.warn("Unexpected warning NOT OK", extra_category) + + +def test_same_category_different_messages_first_match(): + category = UserWarning + with assert_produces_warning(category, match=r"^Match this"): + warnings.warn("Match this", category) + warnings.warn("Do not match that", category) + warnings.warn("Do not match that either", category) + + +def test_same_category_different_messages_last_match(): + category = DeprecationWarning + with assert_produces_warning(category, match=r"^Match this"): + warnings.warn("Do not match that", category) + warnings.warn("Do not match that either", category) + warnings.warn("Match this", category) + + +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"): + with assert_produces_warning(target_category, match=r"^Match this"): + warnings.warn("Do not match it", target_category) + warnings.warn("Match this", other_category) From e61b417c6f5d6c5128388e340f748033c14ebf14 Mon Sep 17 00:00:00 2001 From: Maxim Ivanov Date: Mon, 19 Oct 2020 23:08:05 +0700 Subject: [PATCH 2/6] ENH: implement matching warning message --- pandas/_testing.py | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/pandas/_testing.py b/pandas/_testing.py index cf6272edc4c05..0a4d40c40ab5f 100644 --- a/pandas/_testing.py +++ b/pandas/_testing.py @@ -6,6 +6,7 @@ import gzip import operator import os +import re from shutil import rmtree import string import tempfile @@ -2550,6 +2551,7 @@ def assert_produces_warning( filter_level="always", check_stacklevel=True, raise_on_extra_warnings=True, + match=None, ): """ Context manager for running code expected to either raise a specific @@ -2584,6 +2586,8 @@ class for all warnings. To check that no warning is returned, raise_on_extra_warnings : bool, default True Whether extra warnings not of the type `expected_warning` should cause the test to fail. + match : str, optional + Match warning message. Examples -------- @@ -2610,6 +2614,8 @@ class for all warnings. To check that no warning is returned, with warnings.catch_warnings(record=True) as w: saw_warning = False + matched_message = False + warnings.simplefilter(filter_level) yield w extra_warnings = [] @@ -2623,15 +2629,11 @@ class for all warnings. To check that no warning is returned, if check_stacklevel and issubclass( actual_warning.category, (FutureWarning, DeprecationWarning) ): - from inspect import getframeinfo, stack + _assert_raised_with_correct_stacklevel(actual_warning) + + if match and re.search(match, str(actual_warning.message)): + matched_message = True - caller = getframeinfo(stack()[2][0]) - msg = ( - "Warning not set with correct stacklevel. " - f"File where warning is raised: {actual_warning.filename} != " - f"{caller.filename}. Warning message: {actual_warning.message}" - ) - assert actual_warning.filename == caller.filename, msg else: extra_warnings.append( ( @@ -2641,18 +2643,37 @@ class for all warnings. To check that no warning is returned, actual_warning.lineno, ) ) - if expected_warning: - msg = ( + + if expected_warning and not saw_warning: + raise AssertionError( f"Did not see expected warning of class " f"{repr(expected_warning.__name__)}" ) - assert saw_warning, msg + + if match and not matched_message: + raise AssertionError( + f"Did not see warning {repr(expected_warning.__name__)} " + f"matching {match}" + ) + if raise_on_extra_warnings and extra_warnings: raise AssertionError( f"Caused unexpected warning(s): {repr(extra_warnings)}" ) +def _assert_raised_with_correct_stacklevel(actual_warning): + from inspect import getframeinfo, stack + + caller = getframeinfo(stack()[3][0]) + msg = ( + "Warning not set with correct stacklevel. " + f"File where warning is raised: {actual_warning.filename} != " + f"{caller.filename}. Warning message: {actual_warning.message}" + ) + assert actual_warning.filename == caller.filename, msg + + class RNGContext: """ Context manager to set the numpy random number generator speed. Returns From 8f58dd10dad54c0506957bd346fa4c0429a0ff96 Mon Sep 17 00:00:00 2001 From: Maxim Ivanov Date: Tue, 20 Oct 2020 02:17:28 +0700 Subject: [PATCH 3/6] FIX: import using tm alias --- pandas/tests/_testing/test_warnings.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pandas/tests/_testing/test_warnings.py b/pandas/tests/_testing/test_warnings.py index 59cf1ea004f47..d98a8258749f3 100644 --- a/pandas/tests/_testing/test_warnings.py +++ b/pandas/tests/_testing/test_warnings.py @@ -8,7 +8,7 @@ from pandas.errors import DtypeWarning, PerformanceWarning -from pandas._testing import assert_produces_warning +import pandas._testing as tm @pytest.fixture( @@ -25,7 +25,7 @@ def category(request): """Return unique warning. - Useful for testing behavior of assert_produces_warning with various categories. + Useful for testing behavior of tm.assert_produces_warning with various categories. """ return request.param @@ -47,7 +47,7 @@ def pair_different_warnings(request): """Return pair or different warnings. Useful for testing how several different warnings are handled - in assert_produces_warning. + in tm.assert_produces_warning. """ return request.param @@ -69,7 +69,7 @@ def pair_different_warnings(request): ], ) def test_catch_warning_category_and_match(category, message, match): - with assert_produces_warning(category, match=match): + with tm.assert_produces_warning(category, match=match): warnings.warn(message, category) @@ -84,7 +84,7 @@ def test_catch_warning_category_and_match(category, message, match): def test_fail_to_match(category, message, match): msg = f"Did not see warning {repr(category.__name__)} matching" with pytest.raises(AssertionError, match=msg): - with assert_produces_warning(category, match=match): + with tm.assert_produces_warning(category, match=match): warnings.warn(message, category) @@ -92,13 +92,13 @@ def test_fail_to_catch_actual_warning(pair_different_warnings): expected_category, actual_category = pair_different_warnings match = "Did not see expected warning of class" with pytest.raises(AssertionError, match=match): - with assert_produces_warning(expected_category): + with tm.assert_produces_warning(expected_category): warnings.warn("warning message", actual_category) def test_ignore_extra_warning(pair_different_warnings): expected_category, extra_category = pair_different_warnings - with assert_produces_warning(expected_category, raise_on_extra_warnings=False): + with tm.assert_produces_warning(expected_category, raise_on_extra_warnings=False): warnings.warn("Expected warning", expected_category) warnings.warn("Unexpected warning OK", extra_category) @@ -107,14 +107,14 @@ def test_raise_on_extra_warning(pair_different_warnings): expected_category, extra_category = pair_different_warnings match = r"Caused unexpected warning\(s\)" with pytest.raises(AssertionError, match=match): - with assert_produces_warning(expected_category): + with tm.assert_produces_warning(expected_category): warnings.warn("Expected warning", expected_category) warnings.warn("Unexpected warning NOT OK", extra_category) def test_same_category_different_messages_first_match(): category = UserWarning - with assert_produces_warning(category, match=r"^Match this"): + with tm.assert_produces_warning(category, match=r"^Match this"): warnings.warn("Match this", category) warnings.warn("Do not match that", category) warnings.warn("Do not match that either", category) @@ -122,7 +122,7 @@ def test_same_category_different_messages_first_match(): def test_same_category_different_messages_last_match(): category = DeprecationWarning - with assert_produces_warning(category, match=r"^Match this"): + with tm.assert_produces_warning(category, match=r"^Match this"): warnings.warn("Do not match that", category) warnings.warn("Do not match that either", category) warnings.warn("Match this", category) @@ -131,6 +131,6 @@ def test_same_category_different_messages_last_match(): 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"): - with assert_produces_warning(target_category, match=r"^Match this"): + with tm.assert_produces_warning(target_category, match=r"^Match this"): warnings.warn("Do not match it", target_category) warnings.warn("Match this", other_category) From 155e8f3ea9a96b9592e7845c967824484704fd38 Mon Sep 17 00:00:00 2001 From: Maxim Ivanov Date: Tue, 20 Oct 2020 09:55:50 +0700 Subject: [PATCH 4/6] DOC: add newlines in fixtures docstrings --- pandas/tests/_testing/test_warnings.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pandas/tests/_testing/test_warnings.py b/pandas/tests/_testing/test_warnings.py index d98a8258749f3..53b1ffa2f9f74 100644 --- a/pandas/tests/_testing/test_warnings.py +++ b/pandas/tests/_testing/test_warnings.py @@ -23,7 +23,8 @@ ], ) def category(request): - """Return unique warning. + """ + Return unique warning. Useful for testing behavior of tm.assert_produces_warning with various categories. """ @@ -44,7 +45,8 @@ def category(request): ids=lambda x: type(x).__name__, ) def pair_different_warnings(request): - """Return pair or different warnings. + """ + Return pair or different warnings. Useful for testing how several different warnings are handled in tm.assert_produces_warning. From 29debb65249dd0cf0e28dc4b3400bf6e41184100 Mon Sep 17 00:00:00 2001 From: Maxim Ivanov Date: Tue, 20 Oct 2020 12:19:53 +0700 Subject: [PATCH 5/6] TYP: assert_produces_warning --- pandas/_testing.py | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/pandas/_testing.py b/pandas/_testing.py index 0a4d40c40ab5f..a4fdb390abf42 100644 --- a/pandas/_testing.py +++ b/pandas/_testing.py @@ -2547,11 +2547,11 @@ def wrapper(*args, **kwargs): @contextmanager def assert_produces_warning( - expected_warning=Warning, + expected_warning: Optional[Union[Type[Warning], bool]] = Warning, filter_level="always", - check_stacklevel=True, - raise_on_extra_warnings=True, - match=None, + check_stacklevel: bool = True, + raise_on_extra_warnings: bool = True, + match: Optional[str] = None, ): """ Context manager for running code expected to either raise a specific @@ -2621,9 +2621,11 @@ class for all warnings. To check that no warning is returned, extra_warnings = [] for actual_warning in w: - if expected_warning and issubclass( - actual_warning.category, expected_warning - ): + if not expected_warning: + continue + + expected_warning = cast(Type[Warning], expected_warning) + if issubclass(actual_warning.category, expected_warning): saw_warning = True if check_stacklevel and issubclass( @@ -2631,7 +2633,7 @@ class for all warnings. To check that no warning is returned, ): _assert_raised_with_correct_stacklevel(actual_warning) - if match and re.search(match, str(actual_warning.message)): + if match is not None and re.search(match, str(actual_warning.message)): matched_message = True else: @@ -2644,17 +2646,19 @@ class for all warnings. To check that no warning is returned, ) ) - if expected_warning and not saw_warning: - raise AssertionError( - f"Did not see expected warning of class " - f"{repr(expected_warning.__name__)}" - ) + if expected_warning: + expected_warning = cast(Type[Warning], expected_warning) + if not saw_warning: + raise AssertionError( + f"Did not see expected warning of class " + f"{repr(expected_warning.__name__)}" + ) - if match and not matched_message: - raise AssertionError( - f"Did not see warning {repr(expected_warning.__name__)} " - f"matching {match}" - ) + if match and not matched_message: + raise AssertionError( + f"Did not see warning {repr(expected_warning.__name__)} " + f"matching {match}" + ) if raise_on_extra_warnings and extra_warnings: raise AssertionError( @@ -2662,7 +2666,9 @@ class for all warnings. To check that no warning is returned, ) -def _assert_raised_with_correct_stacklevel(actual_warning): +def _assert_raised_with_correct_stacklevel( + actual_warning: warnings.WarningMessage, +) -> None: from inspect import getframeinfo, stack caller = getframeinfo(stack()[3][0]) From e0896df519d590f14987e59d061cee22987288df Mon Sep 17 00:00:00 2001 From: Maxim Ivanov Date: Tue, 20 Oct 2020 14:39:44 +0700 Subject: [PATCH 6/6] MOVE: tests to test_assert_produces_warning --- pandas/tests/_testing/test_warnings.py | 138 ------------------ .../util/test_assert_produces_warning.py | 132 +++++++++++++++++ 2 files changed, 132 insertions(+), 138 deletions(-) delete mode 100644 pandas/tests/_testing/test_warnings.py diff --git a/pandas/tests/_testing/test_warnings.py b/pandas/tests/_testing/test_warnings.py deleted file mode 100644 index 53b1ffa2f9f74..0000000000000 --- a/pandas/tests/_testing/test_warnings.py +++ /dev/null @@ -1,138 +0,0 @@ -"""" -Test module for testing ``pandas._testing.assert_produces_warning``. -""" - -import warnings - -import pytest - -from pandas.errors import DtypeWarning, PerformanceWarning - -import pandas._testing as tm - - -@pytest.fixture( - params=[ - RuntimeWarning, - ResourceWarning, - UserWarning, - FutureWarning, - DeprecationWarning, - PerformanceWarning, - DtypeWarning, - ], -) -def category(request): - """ - Return unique warning. - - Useful for testing behavior of tm.assert_produces_warning with various categories. - """ - return request.param - - -@pytest.fixture( - params=[ - (RuntimeWarning, UserWarning), - (UserWarning, FutureWarning), - (FutureWarning, RuntimeWarning), - (DeprecationWarning, PerformanceWarning), - (PerformanceWarning, FutureWarning), - (DtypeWarning, DeprecationWarning), - (ResourceWarning, DeprecationWarning), - (FutureWarning, DeprecationWarning), - ], - ids=lambda x: type(x).__name__, -) -def pair_different_warnings(request): - """ - Return pair or different warnings. - - Useful for testing how several different warnings are handled - in tm.assert_produces_warning. - """ - return request.param - - -@pytest.mark.parametrize( - "message, match", - [ - ("", None), - ("", ""), - ("Warning message", r".*"), - ("Warning message", "War"), - ("Warning message", r"[Ww]arning"), - ("Warning message", "age"), - ("Warning message", r"age$"), - ("Message 12-234 with numbers", r"\d{2}-\d{3}"), - ("Message 12-234 with numbers", r"^Mes.*\d{2}-\d{3}"), - ("Message 12-234 with numbers", r"\d{2}-\d{3}\s\S+"), - ("Message, which we do not match", None), - ], -) -def test_catch_warning_category_and_match(category, message, match): - with tm.assert_produces_warning(category, match=match): - warnings.warn(message, category) - - -@pytest.mark.parametrize( - "message, match", - [ - ("Warning message", "Not this message"), - ("Warning message", "warning"), - ("Warning message", r"\d+"), - ], -) -def test_fail_to_match(category, message, match): - msg = f"Did not see warning {repr(category.__name__)} matching" - with pytest.raises(AssertionError, match=msg): - with tm.assert_produces_warning(category, match=match): - warnings.warn(message, category) - - -def test_fail_to_catch_actual_warning(pair_different_warnings): - expected_category, actual_category = pair_different_warnings - match = "Did not see expected warning of class" - with pytest.raises(AssertionError, match=match): - with tm.assert_produces_warning(expected_category): - warnings.warn("warning message", actual_category) - - -def test_ignore_extra_warning(pair_different_warnings): - expected_category, extra_category = pair_different_warnings - with tm.assert_produces_warning(expected_category, raise_on_extra_warnings=False): - warnings.warn("Expected warning", expected_category) - warnings.warn("Unexpected warning OK", extra_category) - - -def test_raise_on_extra_warning(pair_different_warnings): - expected_category, extra_category = pair_different_warnings - match = r"Caused unexpected warning\(s\)" - with pytest.raises(AssertionError, match=match): - with tm.assert_produces_warning(expected_category): - warnings.warn("Expected warning", expected_category) - warnings.warn("Unexpected warning NOT OK", extra_category) - - -def test_same_category_different_messages_first_match(): - category = UserWarning - with tm.assert_produces_warning(category, match=r"^Match this"): - warnings.warn("Match this", category) - warnings.warn("Do not match that", category) - warnings.warn("Do not match that either", category) - - -def test_same_category_different_messages_last_match(): - category = DeprecationWarning - with tm.assert_produces_warning(category, match=r"^Match this"): - warnings.warn("Do not match that", category) - warnings.warn("Do not match that either", category) - warnings.warn("Match this", category) - - -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"): - with tm.assert_produces_warning(target_category, match=r"^Match this"): - warnings.warn("Do not match it", target_category) - warnings.warn("Match this", other_category) diff --git a/pandas/tests/util/test_assert_produces_warning.py b/pandas/tests/util/test_assert_produces_warning.py index 87765c909938d..5f87824713175 100644 --- a/pandas/tests/util/test_assert_produces_warning.py +++ b/pandas/tests/util/test_assert_produces_warning.py @@ -1,10 +1,58 @@ +"""" +Test module for testing ``pandas._testing.assert_produces_warning``. +""" import warnings import pytest +from pandas.errors import DtypeWarning, PerformanceWarning + import pandas._testing as tm +@pytest.fixture( + params=[ + RuntimeWarning, + ResourceWarning, + UserWarning, + FutureWarning, + DeprecationWarning, + PerformanceWarning, + DtypeWarning, + ], +) +def category(request): + """ + Return unique warning. + + Useful for testing behavior of tm.assert_produces_warning with various categories. + """ + return request.param + + +@pytest.fixture( + params=[ + (RuntimeWarning, UserWarning), + (UserWarning, FutureWarning), + (FutureWarning, RuntimeWarning), + (DeprecationWarning, PerformanceWarning), + (PerformanceWarning, FutureWarning), + (DtypeWarning, DeprecationWarning), + (ResourceWarning, DeprecationWarning), + (FutureWarning, DeprecationWarning), + ], + ids=lambda x: type(x).__name__, +) +def pair_different_warnings(request): + """ + Return pair or different warnings. + + Useful for testing how several different warnings are handled + in tm.assert_produces_warning. + """ + return request.param + + def f(): warnings.warn("f1", FutureWarning) warnings.warn("f2", RuntimeWarning) @@ -20,3 +68,87 @@ def test_assert_produces_warning_honors_filter(): with tm.assert_produces_warning(RuntimeWarning, raise_on_extra_warnings=False): f() + + +@pytest.mark.parametrize( + "message, match", + [ + ("", None), + ("", ""), + ("Warning message", r".*"), + ("Warning message", "War"), + ("Warning message", r"[Ww]arning"), + ("Warning message", "age"), + ("Warning message", r"age$"), + ("Message 12-234 with numbers", r"\d{2}-\d{3}"), + ("Message 12-234 with numbers", r"^Mes.*\d{2}-\d{3}"), + ("Message 12-234 with numbers", r"\d{2}-\d{3}\s\S+"), + ("Message, which we do not match", None), + ], +) +def test_catch_warning_category_and_match(category, message, match): + with tm.assert_produces_warning(category, match=match): + warnings.warn(message, category) + + +@pytest.mark.parametrize( + "message, match", + [ + ("Warning message", "Not this message"), + ("Warning message", "warning"), + ("Warning message", r"\d+"), + ], +) +def test_fail_to_match(category, message, match): + msg = f"Did not see warning {repr(category.__name__)} matching" + with pytest.raises(AssertionError, match=msg): + with tm.assert_produces_warning(category, match=match): + warnings.warn(message, category) + + +def test_fail_to_catch_actual_warning(pair_different_warnings): + expected_category, actual_category = pair_different_warnings + match = "Did not see expected warning of class" + with pytest.raises(AssertionError, match=match): + with tm.assert_produces_warning(expected_category): + warnings.warn("warning message", actual_category) + + +def test_ignore_extra_warning(pair_different_warnings): + expected_category, extra_category = pair_different_warnings + with tm.assert_produces_warning(expected_category, raise_on_extra_warnings=False): + warnings.warn("Expected warning", expected_category) + warnings.warn("Unexpected warning OK", extra_category) + + +def test_raise_on_extra_warning(pair_different_warnings): + expected_category, extra_category = pair_different_warnings + match = r"Caused unexpected warning\(s\)" + with pytest.raises(AssertionError, match=match): + with tm.assert_produces_warning(expected_category): + warnings.warn("Expected warning", expected_category) + warnings.warn("Unexpected warning NOT OK", extra_category) + + +def test_same_category_different_messages_first_match(): + category = UserWarning + with tm.assert_produces_warning(category, match=r"^Match this"): + warnings.warn("Match this", category) + warnings.warn("Do not match that", category) + warnings.warn("Do not match that either", category) + + +def test_same_category_different_messages_last_match(): + category = DeprecationWarning + with tm.assert_produces_warning(category, match=r"^Match this"): + warnings.warn("Do not match that", category) + warnings.warn("Do not match that either", category) + warnings.warn("Match this", category) + + +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"): + with tm.assert_produces_warning(target_category, match=r"^Match this"): + warnings.warn("Do not match it", target_category) + warnings.warn("Match this", other_category)