Merge pull request #4539 from nicoddemus/deprecate-pytest-raises-message
Deprecate the 'message' parameter of pytest.raises
This commit is contained in:
commit
15b0a89fb1
|
@ -0,0 +1,8 @@
|
||||||
|
Passing the ``message`` parameter of ``pytest.raises`` now issues a ``DeprecationWarning``.
|
||||||
|
|
||||||
|
It is a common mistake to think this parameter will match the exception message, while in fact
|
||||||
|
it only serves to provide a custom message in case the ``pytest.raises`` check fails. To avoid this
|
||||||
|
mistake and because it is believed to be little used, pytest is deprecating it without providing
|
||||||
|
an alternative for the moment.
|
||||||
|
|
||||||
|
If you have concerns about this, please comment on `issue #3974 <https://github.com/pytest-dev/pytest/issues/3974>`__.
|
|
@ -14,6 +14,19 @@ Below is a complete list of all pytest features which are considered deprecated.
|
||||||
:class:`_pytest.warning_types.PytestWarning` or subclasses, which can be filtered using
|
:class:`_pytest.warning_types.PytestWarning` or subclasses, which can be filtered using
|
||||||
:ref:`standard warning filters <warnings>`.
|
:ref:`standard warning filters <warnings>`.
|
||||||
|
|
||||||
|
``"message"`` parameter of ``pytest.raises``
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. deprecated:: 4.1
|
||||||
|
|
||||||
|
It is a common mistake to think this parameter will match the exception message, while in fact
|
||||||
|
it only serves to provide a custom message in case the ``pytest.raises`` check fails. To avoid this
|
||||||
|
mistake and because it is believed to be little used, pytest is deprecating it without providing
|
||||||
|
an alternative for the moment.
|
||||||
|
|
||||||
|
If you have concerns about this, please comment on `issue #3974 <https://github.com/pytest-dev/pytest/issues/3974>`__.
|
||||||
|
|
||||||
|
|
||||||
``pytest.config`` global
|
``pytest.config`` global
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,13 @@ GETFUNCARGVALUE = RemovedInPytest4Warning(
|
||||||
"getfuncargvalue is deprecated, use getfixturevalue"
|
"getfuncargvalue is deprecated, use getfixturevalue"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
RAISES_MESSAGE_PARAMETER = PytestDeprecationWarning(
|
||||||
|
"The 'message' parameter is deprecated.\n"
|
||||||
|
"(did you mean to use `match='some regex'` to check the exception message?)\n"
|
||||||
|
"Please comment on https://github.com/pytest-dev/pytest/issues/3974 "
|
||||||
|
"if you have concerns about removal of this parameter."
|
||||||
|
)
|
||||||
|
|
||||||
RESULT_LOG = PytestDeprecationWarning(
|
RESULT_LOG = PytestDeprecationWarning(
|
||||||
"--result-log is deprecated and scheduled for removal in pytest 5.0.\n"
|
"--result-log is deprecated and scheduled for removal in pytest 5.0.\n"
|
||||||
"See https://docs.pytest.org/en/latest/deprecations.html#result-log-result-log for more information."
|
"See https://docs.pytest.org/en/latest/deprecations.html#result-log-result-log for more information."
|
||||||
|
|
|
@ -13,11 +13,11 @@ from six.moves import filterfalse
|
||||||
from six.moves import zip
|
from six.moves import zip
|
||||||
|
|
||||||
import _pytest._code
|
import _pytest._code
|
||||||
|
from _pytest import deprecated
|
||||||
from _pytest.compat import isclass
|
from _pytest.compat import isclass
|
||||||
from _pytest.compat import Mapping
|
from _pytest.compat import Mapping
|
||||||
from _pytest.compat import Sequence
|
from _pytest.compat import Sequence
|
||||||
from _pytest.compat import STRING_TYPES
|
from _pytest.compat import STRING_TYPES
|
||||||
from _pytest.deprecated import RAISES_EXEC
|
|
||||||
from _pytest.outcomes import fail
|
from _pytest.outcomes import fail
|
||||||
|
|
||||||
BASE_TYPE = (type, STRING_TYPES)
|
BASE_TYPE = (type, STRING_TYPES)
|
||||||
|
@ -551,29 +551,47 @@ def _is_numpy_array(obj):
|
||||||
def raises(expected_exception, *args, **kwargs):
|
def raises(expected_exception, *args, **kwargs):
|
||||||
r"""
|
r"""
|
||||||
Assert that a code block/function call raises ``expected_exception``
|
Assert that a code block/function call raises ``expected_exception``
|
||||||
and raise a failure exception otherwise.
|
or raise a failure exception otherwise.
|
||||||
|
|
||||||
:arg message: if specified, provides a custom failure message if the
|
:kwparam match: if specified, asserts that the exception matches a text or regex
|
||||||
exception is not raised
|
|
||||||
:arg match: if specified, asserts that the exception matches a text or regex
|
|
||||||
|
|
||||||
This helper produces a ``ExceptionInfo()`` object (see below).
|
:kwparam message: **(deprecated since 4.1)** if specified, provides a custom failure message
|
||||||
|
if the exception is not raised
|
||||||
|
|
||||||
You may use this function as a context manager::
|
.. currentmodule:: _pytest._code
|
||||||
|
|
||||||
|
Use ``pytest.raises`` as a context manager, which will capture the exception of the given
|
||||||
|
type::
|
||||||
|
|
||||||
>>> with raises(ZeroDivisionError):
|
>>> with raises(ZeroDivisionError):
|
||||||
... 1/0
|
... 1/0
|
||||||
|
|
||||||
.. versionchanged:: 2.10
|
If the code block does not raise the expected exception (``ZeroDivisionError`` in the example
|
||||||
|
above), or no exception at all, the check will fail instead.
|
||||||
|
|
||||||
In the context manager form you may use the keyword argument
|
You can also use the keyword argument ``match`` to assert that the
|
||||||
``message`` to specify a custom failure message::
|
exception matches a text or regex::
|
||||||
|
|
||||||
>>> with raises(ZeroDivisionError, message="Expecting ZeroDivisionError"):
|
>>> with raises(ValueError, match='must be 0 or None'):
|
||||||
... pass
|
... raise ValueError("value must be 0 or None")
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
>>> with raises(ValueError, match=r'must be \d+$'):
|
||||||
Failed: Expecting ZeroDivisionError
|
... raise ValueError("value must be 42")
|
||||||
|
|
||||||
|
The context manager produces an :class:`ExceptionInfo` object which can be used to inspect the
|
||||||
|
details of the captured exception::
|
||||||
|
|
||||||
|
>>> with raises(ValueError) as exc_info:
|
||||||
|
... raise ValueError("value must be 42")
|
||||||
|
>>> assert exc_info.type is ValueError
|
||||||
|
>>> assert exc_info.value.args[0] == "value must be 42"
|
||||||
|
|
||||||
|
.. deprecated:: 4.1
|
||||||
|
|
||||||
|
In the context manager form you may use the keyword argument
|
||||||
|
``message`` to specify a custom failure message that will be displayed
|
||||||
|
in case the ``pytest.raises`` check fails. This has been deprecated as it
|
||||||
|
is considered error prone as users often mean to use ``match`` instead.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@ -587,7 +605,7 @@ def raises(expected_exception, *args, **kwargs):
|
||||||
>>> with raises(ValueError) as exc_info:
|
>>> with raises(ValueError) as exc_info:
|
||||||
... if value > 10:
|
... if value > 10:
|
||||||
... raise ValueError("value must be <= 10")
|
... raise ValueError("value must be <= 10")
|
||||||
... assert exc_info.type == ValueError # this will not execute
|
... assert exc_info.type is ValueError # this will not execute
|
||||||
|
|
||||||
Instead, the following approach must be taken (note the difference in
|
Instead, the following approach must be taken (note the difference in
|
||||||
scope)::
|
scope)::
|
||||||
|
@ -596,23 +614,10 @@ def raises(expected_exception, *args, **kwargs):
|
||||||
... if value > 10:
|
... if value > 10:
|
||||||
... raise ValueError("value must be <= 10")
|
... raise ValueError("value must be <= 10")
|
||||||
...
|
...
|
||||||
>>> assert exc_info.type == ValueError
|
>>> assert exc_info.type is ValueError
|
||||||
|
|
||||||
|
|
||||||
Since version ``3.1`` you can use the keyword argument ``match`` to assert that the
|
|
||||||
exception matches a text or regex::
|
|
||||||
|
|
||||||
>>> with raises(ValueError, match='must be 0 or None'):
|
|
||||||
... raise ValueError("value must be 0 or None")
|
|
||||||
|
|
||||||
>>> with raises(ValueError, match=r'must be \d+$'):
|
|
||||||
... raise ValueError("value must be 42")
|
|
||||||
|
|
||||||
**Legacy form**
|
**Legacy form**
|
||||||
|
|
||||||
The form below is fully supported but discouraged for new code because the
|
|
||||||
context manager form is regarded as more readable and less error-prone.
|
|
||||||
|
|
||||||
It is possible to specify a callable by passing a to-be-called lambda::
|
It is possible to specify a callable by passing a to-be-called lambda::
|
||||||
|
|
||||||
>>> raises(ZeroDivisionError, lambda: 1/0)
|
>>> raises(ZeroDivisionError, lambda: 1/0)
|
||||||
|
@ -627,9 +632,8 @@ def raises(expected_exception, *args, **kwargs):
|
||||||
>>> raises(ZeroDivisionError, f, x=0)
|
>>> raises(ZeroDivisionError, f, x=0)
|
||||||
<ExceptionInfo ...>
|
<ExceptionInfo ...>
|
||||||
|
|
||||||
.. currentmodule:: _pytest._code
|
The form above is fully supported but discouraged for new code because the
|
||||||
|
context manager form is regarded as more readable and less error-prone.
|
||||||
Consult the API of ``excinfo`` objects: :class:`ExceptionInfo`.
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
Similar to caught exception objects in Python, explicitly clearing
|
Similar to caught exception objects in Python, explicitly clearing
|
||||||
|
@ -660,6 +664,7 @@ def raises(expected_exception, *args, **kwargs):
|
||||||
if not args:
|
if not args:
|
||||||
if "message" in kwargs:
|
if "message" in kwargs:
|
||||||
message = kwargs.pop("message")
|
message = kwargs.pop("message")
|
||||||
|
warnings.warn(deprecated.RAISES_MESSAGE_PARAMETER, stacklevel=2)
|
||||||
if "match" in kwargs:
|
if "match" in kwargs:
|
||||||
match_expr = kwargs.pop("match")
|
match_expr = kwargs.pop("match")
|
||||||
if kwargs:
|
if kwargs:
|
||||||
|
@ -668,7 +673,7 @@ def raises(expected_exception, *args, **kwargs):
|
||||||
raise TypeError(msg)
|
raise TypeError(msg)
|
||||||
return RaisesContext(expected_exception, message, match_expr)
|
return RaisesContext(expected_exception, message, match_expr)
|
||||||
elif isinstance(args[0], str):
|
elif isinstance(args[0], str):
|
||||||
warnings.warn(RAISES_EXEC, stacklevel=2)
|
warnings.warn(deprecated.RAISES_EXEC, stacklevel=2)
|
||||||
code, = args
|
code, = args
|
||||||
assert isinstance(code, str)
|
assert isinstance(code, str)
|
||||||
frame = sys._getframe(1)
|
frame = sys._getframe(1)
|
||||||
|
|
|
@ -136,6 +136,12 @@ def test_pytest_catchlog_deprecated(testdir, plugin):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_raises_message_argument_deprecated():
|
||||||
|
with pytest.warns(pytest.PytestDeprecationWarning):
|
||||||
|
with pytest.raises(RuntimeError, message="foobar"):
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
|
||||||
def test_pytest_plugins_in_non_top_level_conftest_deprecated(testdir):
|
def test_pytest_plugins_in_non_top_level_conftest_deprecated(testdir):
|
||||||
from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
|
from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
|
||||||
|
|
||||||
|
|
|
@ -121,8 +121,9 @@ class TestRaises(object):
|
||||||
def test_custom_raise_message(self):
|
def test_custom_raise_message(self):
|
||||||
message = "TEST_MESSAGE"
|
message = "TEST_MESSAGE"
|
||||||
try:
|
try:
|
||||||
with pytest.raises(ValueError, message=message):
|
with pytest.warns(PytestDeprecationWarning):
|
||||||
pass
|
with pytest.raises(ValueError, message=message):
|
||||||
|
pass
|
||||||
except pytest.raises.Exception as e:
|
except pytest.raises.Exception as e:
|
||||||
assert e.msg == message
|
assert e.msg == message
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -280,7 +280,7 @@ def test_assert_outcomes_after_pytest_error(testdir):
|
||||||
testdir.makepyfile("def test_foo(): assert True")
|
testdir.makepyfile("def test_foo(): assert True")
|
||||||
|
|
||||||
result = testdir.runpytest("--unexpected-argument")
|
result = testdir.runpytest("--unexpected-argument")
|
||||||
with pytest.raises(ValueError, message="Pytest terminal report not found"):
|
with pytest.raises(ValueError, match="Pytest terminal report not found"):
|
||||||
result.assert_outcomes(passed=0)
|
result.assert_outcomes(passed=0)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue