Skip to content

Commit 5b83417

Browse files
committed
Deprecate the 'message' parameter of pytest.raises
Fix #3974
1 parent 110fe24 commit 5b83417

File tree

7 files changed

+77
-37
lines changed

7 files changed

+77
-37
lines changed

changelog/3974.deprecation.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Passing the ``message`` parameter of ``pytest.raises`` now issues a ``DeprecationWarning``.
2+
3+
It is a common mistake to think this parameter will match the exception message, while in fact
4+
it only serves to provide a custom message in case the ``pytest.raises`` check fails. To avoid this
5+
mistake and because it is believed to be little used, pytest is deprecating it without providing
6+
an alternative for the moment.
7+
8+
If you have concerns about this, please comment on `issue #3974 <https://github.com/pytest-dev/pytest/issues/3974>`__.

doc/en/deprecations.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,19 @@ Below is a complete list of all pytest features which are considered deprecated.
1414
:class:`_pytest.warning_types.PytestWarning` or subclasses, which can be filtered using
1515
:ref:`standard warning filters <warnings>`.
1616

17+
``"message"`` parameter of ``pytest.raises``
18+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19+
20+
.. deprecated:: 4.1
21+
22+
It is a common mistake to think this parameter will match the exception message, while in fact
23+
it only serves to provide a custom message in case the ``pytest.raises`` check fails. To avoid this
24+
mistake and because it is believed to be little used, pytest is deprecating it without providing
25+
an alternative for the moment.
26+
27+
If you have concerns about this, please comment on `issue #3974 <https://github.com/pytest-dev/pytest/issues/3974>`__.
28+
29+
1730
``pytest.config`` global
1831
~~~~~~~~~~~~~~~~~~~~~~~~
1932

src/_pytest/deprecated.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@
5151
"getfuncargvalue is deprecated, use getfixturevalue"
5252
)
5353

54+
RAISES_MESSAGE_PARAMETER = PytestDeprecationWarning(
55+
"The 'message' parameter is deprecated.\n"
56+
"(did you mean to use `match='some regex'` to check the exception message?)\n"
57+
"Please comment on https://github.com/pytest-dev/pytest/issues/3974 "
58+
"if you have concerns about removal of this parameter."
59+
)
60+
5461
RESULT_LOG = PytestDeprecationWarning(
5562
"--result-log is deprecated and scheduled for removal in pytest 5.0.\n"
5663
"See https://docs.pytest.org/en/latest/deprecations.html#result-log-result-log for more information."

src/_pytest/python_api.py

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313
from six.moves import zip
1414

1515
import _pytest._code
16+
from _pytest import deprecated
1617
from _pytest.compat import isclass
1718
from _pytest.compat import Mapping
1819
from _pytest.compat import Sequence
1920
from _pytest.compat import STRING_TYPES
20-
from _pytest.deprecated import RAISES_EXEC
2121
from _pytest.outcomes import fail
2222

2323
BASE_TYPE = (type, STRING_TYPES)
@@ -551,29 +551,47 @@ def _is_numpy_array(obj):
551551
def raises(expected_exception, *args, **kwargs):
552552
r"""
553553
Assert that a code block/function call raises ``expected_exception``
554-
and raise a failure exception otherwise.
554+
or raise a failure exception otherwise.
555555
556-
:arg message: if specified, provides a custom failure message if the
557-
exception is not raised
558-
:arg match: if specified, asserts that the exception matches a text or regex
556+
:kwparam match: if specified, asserts that the exception matches a text or regex
559557
560-
This helper produces a ``ExceptionInfo()`` object (see below).
558+
:kwparam message: **(deprecated since 4.1)** if specified, provides a custom failure message
559+
if the exception is not raised
561560
562-
You may use this function as a context manager::
561+
.. currentmodule:: _pytest._code
562+
563+
Use ``pytest.raises`` as a context manager, which will capture the exception of the given
564+
type::
563565
564566
>>> with raises(ZeroDivisionError):
565567
... 1/0
566568
567-
.. versionchanged:: 2.10
569+
If the code block does not raise the expected exception (``ZeroDivisionError`` in the example
570+
above), or no exception at all, the check will fail instead.
571+
572+
You can also use the keyword argument ``match`` to assert that the
573+
exception matches a text or regex::
574+
575+
>>> with raises(ValueError, match='must be 0 or None'):
576+
... raise ValueError("value must be 0 or None")
577+
578+
>>> with raises(ValueError, match=r'must be \d+$'):
579+
... raise ValueError("value must be 42")
568580
569-
In the context manager form you may use the keyword argument
570-
``message`` to specify a custom failure message::
581+
The context manager produces an :class:`ExceptionInfo` object which can be used to inspect the
582+
details of the captured exception::
571583
572-
>>> with raises(ZeroDivisionError, message="Expecting ZeroDivisionError"):
573-
... pass
574-
Traceback (most recent call last):
575-
...
576-
Failed: Expecting ZeroDivisionError
584+
>>> with raises(ValueError) as exc_info:
585+
... raise ValueError("value must be 42")
586+
>>> assert exc_info.type is ValueError
587+
>>> assert exc_info.value.args[0] == "value must be 42"
588+
589+
.. deprecated:: 4.1
590+
591+
In the context manager form you may use the keyword argument
592+
``message`` to specify a custom failure message that will be displayed
593+
in case the ``pytest.raises`` check fails. This has been deprecated as it
594+
is considered error prone as users often mean to use ``match`` instead.
577595
578596
.. note::
579597
@@ -587,7 +605,7 @@ def raises(expected_exception, *args, **kwargs):
587605
>>> with raises(ValueError) as exc_info:
588606
... if value > 10:
589607
... raise ValueError("value must be <= 10")
590-
... assert exc_info.type == ValueError # this will not execute
608+
... assert exc_info.type is ValueError # this will not execute
591609
592610
Instead, the following approach must be taken (note the difference in
593611
scope)::
@@ -596,23 +614,10 @@ def raises(expected_exception, *args, **kwargs):
596614
... if value > 10:
597615
... raise ValueError("value must be <= 10")
598616
...
599-
>>> assert exc_info.type == ValueError
600-
601-
602-
Since version ``3.1`` you can use the keyword argument ``match`` to assert that the
603-
exception matches a text or regex::
604-
605-
>>> with raises(ValueError, match='must be 0 or None'):
606-
... raise ValueError("value must be 0 or None")
607-
608-
>>> with raises(ValueError, match=r'must be \d+$'):
609-
... raise ValueError("value must be 42")
617+
>>> assert exc_info.type is ValueError
610618
611619
**Legacy form**
612620
613-
The form below is fully supported but discouraged for new code because the
614-
context manager form is regarded as more readable and less error-prone.
615-
616621
It is possible to specify a callable by passing a to-be-called lambda::
617622
618623
>>> raises(ZeroDivisionError, lambda: 1/0)
@@ -627,9 +632,8 @@ def raises(expected_exception, *args, **kwargs):
627632
>>> raises(ZeroDivisionError, f, x=0)
628633
<ExceptionInfo ...>
629634
630-
.. currentmodule:: _pytest._code
631-
632-
Consult the API of ``excinfo`` objects: :class:`ExceptionInfo`.
635+
The form above is fully supported but discouraged for new code because the
636+
context manager form is regarded as more readable and less error-prone.
633637
634638
.. note::
635639
Similar to caught exception objects in Python, explicitly clearing
@@ -660,6 +664,7 @@ def raises(expected_exception, *args, **kwargs):
660664
if not args:
661665
if "message" in kwargs:
662666
message = kwargs.pop("message")
667+
warnings.warn(deprecated.RAISES_MESSAGE_PARAMETER, stacklevel=2)
663668
if "match" in kwargs:
664669
match_expr = kwargs.pop("match")
665670
if kwargs:
@@ -668,7 +673,7 @@ def raises(expected_exception, *args, **kwargs):
668673
raise TypeError(msg)
669674
return RaisesContext(expected_exception, message, match_expr)
670675
elif isinstance(args[0], str):
671-
warnings.warn(RAISES_EXEC, stacklevel=2)
676+
warnings.warn(deprecated.RAISES_EXEC, stacklevel=2)
672677
code, = args
673678
assert isinstance(code, str)
674679
frame = sys._getframe(1)

testing/deprecated_test.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,12 @@ def test_func(pytestconfig):
136136
)
137137

138138

139+
def test_raises_message_argument_deprecated():
140+
with pytest.warns(pytest.PytestDeprecationWarning):
141+
with pytest.raises(RuntimeError, message="foobar"):
142+
raise RuntimeError
143+
144+
139145
def test_pytest_plugins_in_non_top_level_conftest_deprecated(testdir):
140146
from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
141147

testing/python/raises.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,9 @@ def test_no_raise_message(self):
121121
def test_custom_raise_message(self):
122122
message = "TEST_MESSAGE"
123123
try:
124-
with pytest.raises(ValueError, message=message):
125-
pass
124+
with pytest.warns(PytestDeprecationWarning):
125+
with pytest.raises(ValueError, message=message):
126+
pass
126127
except pytest.raises.Exception as e:
127128
assert e.msg == message
128129
else:

testing/test_pytester.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ def test_assert_outcomes_after_pytest_error(testdir):
280280
testdir.makepyfile("def test_foo(): assert True")
281281

282282
result = testdir.runpytest("--unexpected-argument")
283-
with pytest.raises(ValueError, message="Pytest terminal report not found"):
283+
with pytest.raises(ValueError, match="Pytest terminal report not found"):
284284
result.assert_outcomes(passed=0)
285285

286286

0 commit comments

Comments
 (0)