aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/pytest/py3/_pytest/python_api.py
diff options
context:
space:
mode:
authorshadchin <shadchin@yandex-team.ru>2022-02-10 16:44:39 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:44:39 +0300
commite9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (patch)
tree64175d5cadab313b3e7039ebaa06c5bc3295e274 /contrib/python/pytest/py3/_pytest/python_api.py
parent2598ef1d0aee359b4b6d5fdd1758916d5907d04f (diff)
downloadydb-e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0.tar.gz
Restoring authorship annotation for <shadchin@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/python/pytest/py3/_pytest/python_api.py')
-rw-r--r--contrib/python/pytest/py3/_pytest/python_api.py628
1 files changed, 314 insertions, 314 deletions
diff --git a/contrib/python/pytest/py3/_pytest/python_api.py b/contrib/python/pytest/py3/_pytest/python_api.py
index 9cbf5584e8..81ce4f8953 100644
--- a/contrib/python/pytest/py3/_pytest/python_api.py
+++ b/contrib/python/pytest/py3/_pytest/python_api.py
@@ -1,36 +1,36 @@
import math
import pprint
-from collections.abc import Iterable
-from collections.abc import Mapping
-from collections.abc import Sized
+from collections.abc import Iterable
+from collections.abc import Mapping
+from collections.abc import Sized
from decimal import Decimal
-from numbers import Complex
-from types import TracebackType
-from typing import Any
-from typing import Callable
-from typing import cast
-from typing import Generic
-from typing import Optional
-from typing import overload
-from typing import Pattern
-from typing import Tuple
-from typing import Type
-from typing import TYPE_CHECKING
-from typing import TypeVar
-from typing import Union
-
-if TYPE_CHECKING:
- from numpy import ndarray
-
-
+from numbers import Complex
+from types import TracebackType
+from typing import Any
+from typing import Callable
+from typing import cast
+from typing import Generic
+from typing import Optional
+from typing import overload
+from typing import Pattern
+from typing import Tuple
+from typing import Type
+from typing import TYPE_CHECKING
+from typing import TypeVar
+from typing import Union
+
+if TYPE_CHECKING:
+ from numpy import ndarray
+
+
import _pytest._code
-from _pytest.compat import final
+from _pytest.compat import final
from _pytest.compat import STRING_TYPES
from _pytest.outcomes import fail
-def _non_numeric_type_error(value, at: Optional[str]) -> TypeError:
- at_str = f" at {at}" if at else ""
+def _non_numeric_type_error(value, at: Optional[str]) -> TypeError:
+ at_str = f" at {at}" if at else ""
return TypeError(
"cannot make approximate comparisons to non-numeric values: {!r} {}".format(
value, at_str
@@ -41,15 +41,15 @@ def _non_numeric_type_error(value, at: Optional[str]) -> TypeError:
# builtin pytest.approx helper
-class ApproxBase:
- """Provide shared utilities for making approximate comparisons between
- numbers or sequences of numbers."""
+class ApproxBase:
+ """Provide shared utilities for making approximate comparisons between
+ numbers or sequences of numbers."""
# Tell numpy to use our `__eq__` operator instead of its.
__array_ufunc__ = None
__array_priority__ = 100
- def __init__(self, expected, rel=None, abs=None, nan_ok: bool = False) -> None:
+ def __init__(self, expected, rel=None, abs=None, nan_ok: bool = False) -> None:
__tracebackhide__ = True
self.expected = expected
self.abs = abs
@@ -57,32 +57,32 @@ class ApproxBase:
self.nan_ok = nan_ok
self._check_type()
- def __repr__(self) -> str:
+ def __repr__(self) -> str:
raise NotImplementedError
- def __eq__(self, actual) -> bool:
+ def __eq__(self, actual) -> bool:
return all(
a == self._approx_scalar(x) for a, x in self._yield_comparisons(actual)
)
- # Ignore type because of https://github.com/python/mypy/issues/4266.
- __hash__ = None # type: ignore
+ # Ignore type because of https://github.com/python/mypy/issues/4266.
+ __hash__ = None # type: ignore
- def __ne__(self, actual) -> bool:
+ def __ne__(self, actual) -> bool:
return not (actual == self)
- def _approx_scalar(self, x) -> "ApproxScalar":
+ def _approx_scalar(self, x) -> "ApproxScalar":
return ApproxScalar(x, rel=self.rel, abs=self.abs, nan_ok=self.nan_ok)
def _yield_comparisons(self, actual):
- """Yield all the pairs of numbers to be compared.
-
- This is used to implement the `__eq__` method.
+ """Yield all the pairs of numbers to be compared.
+
+ This is used to implement the `__eq__` method.
"""
raise NotImplementedError
- def _check_type(self) -> None:
- """Raise a TypeError if the expected value is not a valid type."""
+ def _check_type(self) -> None:
+ """Raise a TypeError if the expected value is not a valid type."""
# This is only a concern if the expected value is a sequence. In every
# other case, the approx() function ensures that the expected value has
# a numeric type. For this reason, the default is to do nothing. The
@@ -99,22 +99,22 @@ def _recursive_list_map(f, x):
class ApproxNumpy(ApproxBase):
- """Perform approximate comparisons where the expected value is numpy array."""
+ """Perform approximate comparisons where the expected value is numpy array."""
- def __repr__(self) -> str:
+ def __repr__(self) -> str:
list_scalars = _recursive_list_map(self._approx_scalar, self.expected.tolist())
- return f"approx({list_scalars!r})"
+ return f"approx({list_scalars!r})"
- def __eq__(self, actual) -> bool:
+ def __eq__(self, actual) -> bool:
import numpy as np
- # self.expected is supposed to always be an array here.
+ # self.expected is supposed to always be an array here.
if not np.isscalar(actual):
try:
actual = np.asarray(actual)
- except Exception as e:
- raise TypeError(f"cannot compare '{actual}' to numpy.ndarray") from e
+ except Exception as e:
+ raise TypeError(f"cannot compare '{actual}' to numpy.ndarray") from e
if not np.isscalar(actual) and actual.shape != self.expected.shape:
return False
@@ -130,26 +130,26 @@ class ApproxNumpy(ApproxBase):
if np.isscalar(actual):
for i in np.ndindex(self.expected.shape):
- yield actual, self.expected[i].item()
+ yield actual, self.expected[i].item()
else:
for i in np.ndindex(self.expected.shape):
- yield actual[i].item(), self.expected[i].item()
+ yield actual[i].item(), self.expected[i].item()
class ApproxMapping(ApproxBase):
- """Perform approximate comparisons where the expected value is a mapping
- with numeric values (the keys can be anything)."""
+ """Perform approximate comparisons where the expected value is a mapping
+ with numeric values (the keys can be anything)."""
- def __repr__(self) -> str:
+ def __repr__(self) -> str:
return "approx({!r})".format(
{k: self._approx_scalar(v) for k, v in self.expected.items()}
)
- def __eq__(self, actual) -> bool:
- try:
- if set(actual.keys()) != set(self.expected.keys()):
- return False
- except AttributeError:
+ def __eq__(self, actual) -> bool:
+ try:
+ if set(actual.keys()) != set(self.expected.keys()):
+ return False
+ except AttributeError:
return False
return ApproxBase.__eq__(self, actual)
@@ -158,7 +158,7 @@ class ApproxMapping(ApproxBase):
for k in self.expected.keys():
yield actual[k], self.expected[k]
- def _check_type(self) -> None:
+ def _check_type(self) -> None:
__tracebackhide__ = True
for key, value in self.expected.items():
if isinstance(value, type(self.expected)):
@@ -166,10 +166,10 @@ class ApproxMapping(ApproxBase):
raise TypeError(msg.format(key, value, pprint.pformat(self.expected)))
-class ApproxSequencelike(ApproxBase):
- """Perform approximate comparisons where the expected value is a sequence of numbers."""
+class ApproxSequencelike(ApproxBase):
+ """Perform approximate comparisons where the expected value is a sequence of numbers."""
- def __repr__(self) -> str:
+ def __repr__(self) -> str:
seq_type = type(self.expected)
if seq_type not in (tuple, list, set):
seq_type = list
@@ -177,18 +177,18 @@ class ApproxSequencelike(ApproxBase):
seq_type(self._approx_scalar(x) for x in self.expected)
)
- def __eq__(self, actual) -> bool:
- try:
- if len(actual) != len(self.expected):
- return False
- except TypeError:
+ def __eq__(self, actual) -> bool:
+ try:
+ if len(actual) != len(self.expected):
+ return False
+ except TypeError:
return False
return ApproxBase.__eq__(self, actual)
def _yield_comparisons(self, actual):
return zip(actual, self.expected)
- def _check_type(self) -> None:
+ def _check_type(self) -> None:
__tracebackhide__ = True
for index, x in enumerate(self.expected):
if isinstance(x, type(self.expected)):
@@ -197,70 +197,70 @@ class ApproxSequencelike(ApproxBase):
class ApproxScalar(ApproxBase):
- """Perform approximate comparisons where the expected value is a single number."""
-
- # Using Real should be better than this Union, but not possible yet:
- # https://github.com/python/typeshed/pull/3108
- DEFAULT_ABSOLUTE_TOLERANCE: Union[float, Decimal] = 1e-12
- DEFAULT_RELATIVE_TOLERANCE: Union[float, Decimal] = 1e-6
-
- def __repr__(self) -> str:
- """Return a string communicating both the expected value and the
- tolerance for the comparison being made.
-
- For example, ``1.0 ± 1e-6``, ``(3+4j) ± 5e-6 ∠ ±180°``.
+ """Perform approximate comparisons where the expected value is a single number."""
+
+ # Using Real should be better than this Union, but not possible yet:
+ # https://github.com/python/typeshed/pull/3108
+ DEFAULT_ABSOLUTE_TOLERANCE: Union[float, Decimal] = 1e-12
+ DEFAULT_RELATIVE_TOLERANCE: Union[float, Decimal] = 1e-6
+
+ def __repr__(self) -> str:
+ """Return a string communicating both the expected value and the
+ tolerance for the comparison being made.
+
+ For example, ``1.0 ± 1e-6``, ``(3+4j) ± 5e-6 ∠ ±180°``.
"""
- # Don't show a tolerance for values that aren't compared using
- # tolerances, i.e. non-numerics and infinities. Need to call abs to
- # handle complex numbers, e.g. (inf + 1j).
- if (not isinstance(self.expected, (Complex, Decimal))) or math.isinf(
- abs(self.expected) # type: ignore[arg-type]
- ):
+ # Don't show a tolerance for values that aren't compared using
+ # tolerances, i.e. non-numerics and infinities. Need to call abs to
+ # handle complex numbers, e.g. (inf + 1j).
+ if (not isinstance(self.expected, (Complex, Decimal))) or math.isinf(
+ abs(self.expected) # type: ignore[arg-type]
+ ):
return str(self.expected)
# If a sensible tolerance can't be calculated, self.tolerance will
# raise a ValueError. In this case, display '???'.
try:
- vetted_tolerance = f"{self.tolerance:.1e}"
- if (
- isinstance(self.expected, Complex)
- and self.expected.imag
- and not math.isinf(self.tolerance)
- ):
- vetted_tolerance += " ∠ ±180°"
+ vetted_tolerance = f"{self.tolerance:.1e}"
+ if (
+ isinstance(self.expected, Complex)
+ and self.expected.imag
+ and not math.isinf(self.tolerance)
+ ):
+ vetted_tolerance += " ∠ ±180°"
except ValueError:
vetted_tolerance = "???"
- return f"{self.expected} ± {vetted_tolerance}"
+ return f"{self.expected} ± {vetted_tolerance}"
- def __eq__(self, actual) -> bool:
- """Return whether the given value is equal to the expected value
- within the pre-specified tolerance."""
- asarray = _as_numpy_array(actual)
- if asarray is not None:
+ def __eq__(self, actual) -> bool:
+ """Return whether the given value is equal to the expected value
+ within the pre-specified tolerance."""
+ asarray = _as_numpy_array(actual)
+ if asarray is not None:
# Call ``__eq__()`` manually to prevent infinite-recursion with
# numpy<1.13. See #3748.
- return all(self.__eq__(a) for a in asarray.flat)
+ return all(self.__eq__(a) for a in asarray.flat)
# Short-circuit exact equality.
if actual == self.expected:
return True
- # If either type is non-numeric, fall back to strict equality.
- # NB: we need Complex, rather than just Number, to ensure that __abs__,
- # __sub__, and __float__ are defined.
- if not (
- isinstance(self.expected, (Complex, Decimal))
- and isinstance(actual, (Complex, Decimal))
- ):
- return False
-
+ # If either type is non-numeric, fall back to strict equality.
+ # NB: we need Complex, rather than just Number, to ensure that __abs__,
+ # __sub__, and __float__ are defined.
+ if not (
+ isinstance(self.expected, (Complex, Decimal))
+ and isinstance(actual, (Complex, Decimal))
+ ):
+ return False
+
# Allow the user to control whether NaNs are considered equal to each
# other or not. The abs() calls are for compatibility with complex
# numbers.
- if math.isnan(abs(self.expected)): # type: ignore[arg-type]
- return self.nan_ok and math.isnan(abs(actual)) # type: ignore[arg-type]
+ if math.isnan(abs(self.expected)): # type: ignore[arg-type]
+ return self.nan_ok and math.isnan(abs(actual)) # type: ignore[arg-type]
# Infinity shouldn't be approximately equal to anything but itself, but
# if there's a relative tolerance, it will be infinite and infinity
@@ -268,22 +268,22 @@ class ApproxScalar(ApproxBase):
# case would have been short circuited above, so here we can just
# return false if the expected value is infinite. The abs() call is
# for compatibility with complex numbers.
- if math.isinf(abs(self.expected)): # type: ignore[arg-type]
+ if math.isinf(abs(self.expected)): # type: ignore[arg-type]
return False
# Return true if the two numbers are within the tolerance.
- result: bool = abs(self.expected - actual) <= self.tolerance
- return result
+ result: bool = abs(self.expected - actual) <= self.tolerance
+ return result
- # Ignore type because of https://github.com/python/mypy/issues/4266.
- __hash__ = None # type: ignore
+ # Ignore type because of https://github.com/python/mypy/issues/4266.
+ __hash__ = None # type: ignore
@property
def tolerance(self):
- """Return the tolerance for the comparison.
-
- This could be either an absolute tolerance or a relative tolerance,
- depending on what the user specified or which would be larger.
+ """Return the tolerance for the comparison.
+
+ This could be either an absolute tolerance or a relative tolerance,
+ depending on what the user specified or which would be larger.
"""
def set_default(x, default):
@@ -295,7 +295,7 @@ class ApproxScalar(ApproxBase):
if absolute_tolerance < 0:
raise ValueError(
- f"absolute tolerance can't be negative: {absolute_tolerance}"
+ f"absolute tolerance can't be negative: {absolute_tolerance}"
)
if math.isnan(absolute_tolerance):
raise ValueError("absolute tolerance can't be NaN.")
@@ -317,7 +317,7 @@ class ApproxScalar(ApproxBase):
if relative_tolerance < 0:
raise ValueError(
- f"relative tolerance can't be negative: {absolute_tolerance}"
+ f"relative tolerance can't be negative: {absolute_tolerance}"
)
if math.isnan(relative_tolerance):
raise ValueError("relative tolerance can't be NaN.")
@@ -327,14 +327,14 @@ class ApproxScalar(ApproxBase):
class ApproxDecimal(ApproxScalar):
- """Perform approximate comparisons where the expected value is a Decimal."""
+ """Perform approximate comparisons where the expected value is a Decimal."""
DEFAULT_ABSOLUTE_TOLERANCE = Decimal("1e-12")
DEFAULT_RELATIVE_TOLERANCE = Decimal("1e-6")
-def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase:
- """Assert that two numbers (or two sets of numbers) are equal to each other
+def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase:
+ """Assert that two numbers (or two sets of numbers) are equal to each other
within some tolerance.
Due to the `intricacies of floating-point arithmetic`__, numbers that we
@@ -426,18 +426,18 @@ def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase:
>>> 1 + 1e-8 == approx(1, rel=1e-6, abs=1e-12)
True
- You can also use ``approx`` to compare nonnumeric types, or dicts and
- sequences containing nonnumeric types, in which case it falls back to
- strict equality. This can be useful for comparing dicts and sequences that
- can contain optional values::
-
- >>> {"required": 1.0000005, "optional": None} == approx({"required": 1, "optional": None})
- True
- >>> [None, 1.0000005] == approx([None,1])
- True
- >>> ["foo", 1.0000005] == approx([None,1])
- False
-
+ You can also use ``approx`` to compare nonnumeric types, or dicts and
+ sequences containing nonnumeric types, in which case it falls back to
+ strict equality. This can be useful for comparing dicts and sequences that
+ can contain optional values::
+
+ >>> {"required": 1.0000005, "optional": None} == approx({"required": 1, "optional": None})
+ True
+ >>> [None, 1.0000005] == approx([None,1])
+ True
+ >>> ["foo", 1.0000005] == approx([None,1])
+ False
+
If you're thinking about using ``approx``, then you might want to know how
it compares to other good ways of comparing floating-point numbers. All of
these algorithms are based on relative and absolute tolerances and should
@@ -449,7 +449,7 @@ def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase:
both ``a`` and ``b``, this test is symmetric (i.e. neither ``a`` nor
``b`` is a "reference value"). You have to specify an absolute tolerance
if you want to compare to ``0.0`` because there is no tolerance by
- default. `More information...`__
+ default. `More information...`__
__ https://docs.python.org/3/library/math.html#math.isclose
@@ -460,7 +460,7 @@ def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase:
think of ``b`` as the reference value. Support for comparing sequences
is provided by ``numpy.allclose``. `More information...`__
- __ https://numpy.org/doc/stable/reference/generated/numpy.isclose.html
+ __ https://numpy.org/doc/stable/reference/generated/numpy.isclose.html
- ``unittest.TestCase.assertAlmostEqual(a, b)``: True if ``a`` and ``b``
are within an absolute tolerance of ``1e-7``. No relative tolerance is
@@ -495,14 +495,14 @@ def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase:
follows a fixed behavior. `More information...`__
__ https://docs.python.org/3/reference/datamodel.html#object.__ge__
-
- .. versionchanged:: 3.7.1
- ``approx`` raises ``TypeError`` when it encounters a dict value or
- sequence element of nonnumeric type.
-
- .. versionchanged:: 6.1.0
- ``approx`` falls back to strict equality for nonnumeric types instead
- of raising ``TypeError``.
+
+ .. versionchanged:: 3.7.1
+ ``approx`` raises ``TypeError`` when it encounters a dict value or
+ sequence element of nonnumeric type.
+
+ .. versionchanged:: 6.1.0
+ ``approx`` falls back to strict equality for nonnumeric types instead
+ of raising ``TypeError``.
"""
# Delegate the comparison to a class that knows how to deal with the type
@@ -523,125 +523,125 @@ def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase:
__tracebackhide__ = True
if isinstance(expected, Decimal):
- cls: Type[ApproxBase] = ApproxDecimal
+ cls: Type[ApproxBase] = ApproxDecimal
elif isinstance(expected, Mapping):
cls = ApproxMapping
elif _is_numpy_array(expected):
- expected = _as_numpy_array(expected)
+ expected = _as_numpy_array(expected)
cls = ApproxNumpy
- elif (
- isinstance(expected, Iterable)
- and isinstance(expected, Sized)
- # Type ignored because the error is wrong -- not unreachable.
- and not isinstance(expected, STRING_TYPES) # type: ignore[unreachable]
- ):
- cls = ApproxSequencelike
+ elif (
+ isinstance(expected, Iterable)
+ and isinstance(expected, Sized)
+ # Type ignored because the error is wrong -- not unreachable.
+ and not isinstance(expected, STRING_TYPES) # type: ignore[unreachable]
+ ):
+ cls = ApproxSequencelike
else:
- cls = ApproxScalar
+ cls = ApproxScalar
return cls(expected, rel, abs, nan_ok)
-def _is_numpy_array(obj: object) -> bool:
+def _is_numpy_array(obj: object) -> bool:
"""
- Return true if the given object is implicitly convertible to ndarray,
- and numpy is already imported.
+ Return true if the given object is implicitly convertible to ndarray,
+ and numpy is already imported.
+ """
+ return _as_numpy_array(obj) is not None
+
+
+def _as_numpy_array(obj: object) -> Optional["ndarray"]:
+ """
+ Return an ndarray if the given object is implicitly convertible to ndarray,
+ and numpy is already imported, otherwise None.
"""
- return _as_numpy_array(obj) is not None
-
-
-def _as_numpy_array(obj: object) -> Optional["ndarray"]:
- """
- Return an ndarray if the given object is implicitly convertible to ndarray,
- and numpy is already imported, otherwise None.
- """
import sys
- np: Any = sys.modules.get("numpy")
+ np: Any = sys.modules.get("numpy")
if np is not None:
- # avoid infinite recursion on numpy scalars, which have __array__
- if np.isscalar(obj):
- return None
- elif isinstance(obj, np.ndarray):
- return obj
- elif hasattr(obj, "__array__") or hasattr("obj", "__array_interface__"):
- return np.asarray(obj)
- return None
+ # avoid infinite recursion on numpy scalars, which have __array__
+ if np.isscalar(obj):
+ return None
+ elif isinstance(obj, np.ndarray):
+ return obj
+ elif hasattr(obj, "__array__") or hasattr("obj", "__array_interface__"):
+ return np.asarray(obj)
+ return None
# builtin pytest.raises helper
-_E = TypeVar("_E", bound=BaseException)
-
-
-@overload
-def raises(
- expected_exception: Union[Type[_E], Tuple[Type[_E], ...]],
- *,
- match: Optional[Union[str, Pattern[str]]] = ...,
-) -> "RaisesContext[_E]":
- ...
-
-
-@overload
-def raises(
- expected_exception: Union[Type[_E], Tuple[Type[_E], ...]],
- func: Callable[..., Any],
- *args: Any,
- **kwargs: Any,
-) -> _pytest._code.ExceptionInfo[_E]:
- ...
-
-
-def raises(
- expected_exception: Union[Type[_E], Tuple[Type[_E], ...]], *args: Any, **kwargs: Any
-) -> Union["RaisesContext[_E]", _pytest._code.ExceptionInfo[_E]]:
- r"""Assert that a code block/function call raises ``expected_exception``
- or raise a failure exception otherwise.
-
- :kwparam match:
- If specified, a string containing a regular expression,
- or a regular expression object, that is tested against the string
- representation of the exception using ``re.search``. To match a literal
- string that may contain `special characters`__, the pattern can
- first be escaped with ``re.escape``.
-
- (This is only used when ``pytest.raises`` is used as a context manager,
- and passed through to the function otherwise.
- When using ``pytest.raises`` as a function, you can use:
- ``pytest.raises(Exc, func, match="passed on").match("my pattern")``.)
-
- __ https://docs.python.org/3/library/re.html#regular-expression-syntax
-
- .. currentmodule:: _pytest._code
-
- Use ``pytest.raises`` as a context manager, which will capture the exception of the given
- type::
-
- >>> import pytest
- >>> with pytest.raises(ZeroDivisionError):
+_E = TypeVar("_E", bound=BaseException)
+
+
+@overload
+def raises(
+ expected_exception: Union[Type[_E], Tuple[Type[_E], ...]],
+ *,
+ match: Optional[Union[str, Pattern[str]]] = ...,
+) -> "RaisesContext[_E]":
+ ...
+
+
+@overload
+def raises(
+ expected_exception: Union[Type[_E], Tuple[Type[_E], ...]],
+ func: Callable[..., Any],
+ *args: Any,
+ **kwargs: Any,
+) -> _pytest._code.ExceptionInfo[_E]:
+ ...
+
+
+def raises(
+ expected_exception: Union[Type[_E], Tuple[Type[_E], ...]], *args: Any, **kwargs: Any
+) -> Union["RaisesContext[_E]", _pytest._code.ExceptionInfo[_E]]:
+ r"""Assert that a code block/function call raises ``expected_exception``
+ or raise a failure exception otherwise.
+
+ :kwparam match:
+ If specified, a string containing a regular expression,
+ or a regular expression object, that is tested against the string
+ representation of the exception using ``re.search``. To match a literal
+ string that may contain `special characters`__, the pattern can
+ first be escaped with ``re.escape``.
+
+ (This is only used when ``pytest.raises`` is used as a context manager,
+ and passed through to the function otherwise.
+ When using ``pytest.raises`` as a function, you can use:
+ ``pytest.raises(Exc, func, match="passed on").match("my pattern")``.)
+
+ __ https://docs.python.org/3/library/re.html#regular-expression-syntax
+
+ .. currentmodule:: _pytest._code
+
+ Use ``pytest.raises`` as a context manager, which will capture the exception of the given
+ type::
+
+ >>> import pytest
+ >>> with pytest.raises(ZeroDivisionError):
... 1/0
- 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.
-
- You can also use the keyword argument ``match`` to assert that the
- exception matches a text or regex::
-
- >>> with pytest.raises(ValueError, match='must be 0 or None'):
- ... raise ValueError("value must be 0 or None")
-
- >>> with pytest.raises(ValueError, match=r'must be \d+$'):
- ... 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 pytest.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"
-
+ 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.
+
+ You can also use the keyword argument ``match`` to assert that the
+ exception matches a text or regex::
+
+ >>> with pytest.raises(ValueError, match='must be 0 or None'):
+ ... raise ValueError("value must be 0 or None")
+
+ >>> with pytest.raises(ValueError, match=r'must be \d+$'):
+ ... 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 pytest.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"
+
.. note::
When using ``pytest.raises`` as a context manager, it's worthwhile to
@@ -651,29 +651,29 @@ def raises(
not be executed. For example::
>>> value = 15
- >>> with pytest.raises(ValueError) as exc_info:
+ >>> with pytest.raises(ValueError) as exc_info:
... if value > 10:
... raise ValueError("value must be <= 10")
- ... assert exc_info.type is 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
scope)::
- >>> with pytest.raises(ValueError) as exc_info:
+ >>> with pytest.raises(ValueError) as exc_info:
... if value > 10:
... raise ValueError("value must be <= 10")
...
- >>> assert exc_info.type is ValueError
+ >>> assert exc_info.type is ValueError
- **Using with** ``pytest.mark.parametrize``
+ **Using with** ``pytest.mark.parametrize``
- When using :ref:`pytest.mark.parametrize ref`
- it is possible to parametrize tests such that
- some runs raise an exception and others do not.
+ When using :ref:`pytest.mark.parametrize ref`
+ it is possible to parametrize tests such that
+ some runs raise an exception and others do not.
- See :ref:`parametrizing_conditional_raising` for an example.
+ See :ref:`parametrizing_conditional_raising` for an example.
- **Legacy form**
+ **Legacy form**
It is possible to specify a callable by passing a to-be-called lambda::
@@ -689,8 +689,8 @@ def raises(
>>> raises(ZeroDivisionError, f, x=0)
<ExceptionInfo ...>
- 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.
+ 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.
.. note::
Similar to caught exception objects in Python, explicitly clearing
@@ -702,85 +702,85 @@ def raises(
the exception --> current frame stack --> local variables -->
``ExceptionInfo``) which makes Python keep all objects referenced
from that cycle (including all local variables in the current
- frame) alive until the next cyclic garbage collection run.
- More detailed information can be found in the official Python
- documentation for :ref:`the try statement <python:try>`.
+ frame) alive until the next cyclic garbage collection run.
+ More detailed information can be found in the official Python
+ documentation for :ref:`the try statement <python:try>`.
"""
__tracebackhide__ = True
- if isinstance(expected_exception, type):
- excepted_exceptions: Tuple[Type[_E], ...] = (expected_exception,)
- else:
- excepted_exceptions = expected_exception
- for exc in excepted_exceptions:
- if not isinstance(exc, type) or not issubclass(exc, BaseException): # type: ignore[unreachable]
- msg = "expected exception must be a BaseException type, not {}" # type: ignore[unreachable]
- not_a = exc.__name__ if isinstance(exc, type) else type(exc).__name__
- raise TypeError(msg.format(not_a))
-
- message = f"DID NOT RAISE {expected_exception}"
-
+ if isinstance(expected_exception, type):
+ excepted_exceptions: Tuple[Type[_E], ...] = (expected_exception,)
+ else:
+ excepted_exceptions = expected_exception
+ for exc in excepted_exceptions:
+ if not isinstance(exc, type) or not issubclass(exc, BaseException): # type: ignore[unreachable]
+ msg = "expected exception must be a BaseException type, not {}" # type: ignore[unreachable]
+ not_a = exc.__name__ if isinstance(exc, type) else type(exc).__name__
+ raise TypeError(msg.format(not_a))
+
+ message = f"DID NOT RAISE {expected_exception}"
+
if not args:
- match: Optional[Union[str, Pattern[str]]] = kwargs.pop("match", None)
+ match: Optional[Union[str, Pattern[str]]] = kwargs.pop("match", None)
if kwargs:
msg = "Unexpected keyword arguments passed to pytest.raises: "
- msg += ", ".join(sorted(kwargs))
- msg += "\nUse context-manager form instead?"
+ msg += ", ".join(sorted(kwargs))
+ msg += "\nUse context-manager form instead?"
raise TypeError(msg)
- return RaisesContext(expected_exception, message, match)
+ return RaisesContext(expected_exception, message, match)
else:
func = args[0]
- if not callable(func):
- raise TypeError(
- "{!r} object (type: {}) must be callable".format(func, type(func))
- )
+ if not callable(func):
+ raise TypeError(
+ "{!r} object (type: {}) must be callable".format(func, type(func))
+ )
try:
func(*args[1:], **kwargs)
- except expected_exception as e:
- # We just caught the exception - there is a traceback.
- assert e.__traceback__ is not None
- return _pytest._code.ExceptionInfo.from_exc_info(
- (type(e), e, e.__traceback__)
- )
+ except expected_exception as e:
+ # We just caught the exception - there is a traceback.
+ assert e.__traceback__ is not None
+ return _pytest._code.ExceptionInfo.from_exc_info(
+ (type(e), e, e.__traceback__)
+ )
fail(message)
-# This doesn't work with mypy for now. Use fail.Exception instead.
-raises.Exception = fail.Exception # type: ignore
+# This doesn't work with mypy for now. Use fail.Exception instead.
+raises.Exception = fail.Exception # type: ignore
-@final
-class RaisesContext(Generic[_E]):
- def __init__(
- self,
- expected_exception: Union[Type[_E], Tuple[Type[_E], ...]],
- message: str,
- match_expr: Optional[Union[str, Pattern[str]]] = None,
- ) -> None:
+@final
+class RaisesContext(Generic[_E]):
+ def __init__(
+ self,
+ expected_exception: Union[Type[_E], Tuple[Type[_E], ...]],
+ message: str,
+ match_expr: Optional[Union[str, Pattern[str]]] = None,
+ ) -> None:
self.expected_exception = expected_exception
self.message = message
self.match_expr = match_expr
- self.excinfo: Optional[_pytest._code.ExceptionInfo[_E]] = None
+ self.excinfo: Optional[_pytest._code.ExceptionInfo[_E]] = None
- def __enter__(self) -> _pytest._code.ExceptionInfo[_E]:
- self.excinfo = _pytest._code.ExceptionInfo.for_later()
+ def __enter__(self) -> _pytest._code.ExceptionInfo[_E]:
+ self.excinfo = _pytest._code.ExceptionInfo.for_later()
return self.excinfo
- def __exit__(
- self,
- exc_type: Optional[Type[BaseException]],
- exc_val: Optional[BaseException],
- exc_tb: Optional[TracebackType],
- ) -> bool:
+ def __exit__(
+ self,
+ exc_type: Optional[Type[BaseException]],
+ exc_val: Optional[BaseException],
+ exc_tb: Optional[TracebackType],
+ ) -> bool:
__tracebackhide__ = True
- if exc_type is None:
+ if exc_type is None:
fail(self.message)
- assert self.excinfo is not None
- if not issubclass(exc_type, self.expected_exception):
- return False
- # Cast to narrow the exception type now that it's verified.
- exc_info = cast(Tuple[Type[_E], _E, TracebackType], (exc_type, exc_val, exc_tb))
- self.excinfo.fill_unfilled(exc_info)
- if self.match_expr is not None:
+ assert self.excinfo is not None
+ if not issubclass(exc_type, self.expected_exception):
+ return False
+ # Cast to narrow the exception type now that it's verified.
+ exc_info = cast(Tuple[Type[_E], _E, TracebackType], (exc_type, exc_val, exc_tb))
+ self.excinfo.fill_unfilled(exc_info)
+ if self.match_expr is not None:
self.excinfo.match(self.match_expr)
- return True
+ return True