raises.py
Overview
The [raises.py](/projects/286/67496) file provides a core utility for the `pytest` testing framework to assert that code raises expected exceptions during test execution. It offers a flexible API to specify expected exceptions by type, match exception messages with regular expressions, or apply custom checks on raised exceptions.
Key functionalities include:
raises: A function and context manager to verify that a block of code or a function call raises a specified exception or matches given conditions.RaisesExc: A class representing an expectation of a single exception type or types, optionally matched by regex or custom callable.RaisesGroup: A class designed to assert and validate complex exception groups (ExceptionGrouporBaseExceptionGroup) introduced in Python 3.11 or via backports, allowing nested exception matching.Internal helpers and utilities that support matching exceptions, formatting failure reasons, and detailed error reporting.
This file is integral to pytest's assertion mechanism for exception handling in tests, helping improve test clarity and robustness by providing detailed feedback on mismatched exceptions.
Classes and Functions
raises
def raises(
expected_exception: type[E] | tuple[type[E], ...] | None = None,
*args: Any,
**kwargs: Any,
) -> RaisesExc[BaseException] | ExceptionInfo[E]:
Purpose
A versatile function and context manager to assert that a code block or a callable raises an expected exception. It supports both context manager and function-call styles.
Parameters
expected_exception:A single exception type or a tuple of exception types expected to be raised.
Can be
Noneif onlymatchorcheckparameters are used.
*args: Additional positional arguments.If provided, the first positional argument should be a callable, followed by its arguments.
**kwargs: Optional keyword arguments:match: A string or compiled regex pattern to match against the string representation of the raised exception (including its__notes__per PEP 678).check: A callable accepting the exception instance, returningTrueif it matches additional custom criteria.
Returns
When used as a context manager (no callable passed), returns a
RaisesExcinstance.When called with a callable, returns an
ExceptionInfoobject capturing the exception.
Usage Examples
# Using as a context manager
with raises(ZeroDivisionError):
1 / 0
# Using match to test exception message
with raises(ValueError, match=r"must be \d+$"):
raise ValueError("value must be 42")
# Using check callable for custom validation
with raises(OSError, check=lambda e: e.errno == errno.EACCES):
raise OSError(errno.EACCES, "no permission to view")
# Using as a function with callable
def f(x): return 1 / x
raises(ZeroDivisionError, f, 0)
Important Notes
Matching is done using
isinstance, so subclasses of the given exception types are also matched.Avoid using
raises(Exception)as it will catch all exceptions and can mask bugs.When used as a context manager, the exception must be raised within the context block; code after raising the exception won't execute.
Supports exception groups via
RaisesGroup(for Python 3.11+ or backports).
AbstractRaises
class AbstractRaises(ABC, Generic[BaseExcT_co]):
Purpose
An abstract base class providing shared functionality for checking exceptions, used by `RaisesExc` and `RaisesGroup`.
Key Methods
__init__(self, *, match: str | Pattern[str] | None, check: Callable[[BaseExcT_co], bool] | None):
Initializes with optional regex match pattern and check callable._parse_exc(self, exc, expected: str):
Parses and validates the expected exception type or generic alias._check_raw_type(expected_type, exception):
Checks if an exception is an instance of the expected type(s)._check_check(exception):
Applies thecheckcallable if provided._check_match(exception):
Matches the exception string representation against the regex pattern.matches(exception):
Abstract method to check if an exception matches the criteria.
Properties
fail_reason:
Contains the reason for match failure aftermatchesis called.
RaisesExc
class RaisesExc(AbstractRaises[BaseExcT_co_default]):
Purpose
Represents an expectation for a single exception or multiple exception types, optionally matched by regex or custom check. Constructed by `raises()` when expecting non-group exceptions.
Constructor Parameters
expected_exception: Exception type or tuple of types to expect. Optional ifmatchorcheckare provided.match: Regex pattern to match exception message.check: Callable returningTrueif exception satisfies additional conditions.
Key Methods
matches(exception):
ReturnsTrueif the exception matches the expected type, matches regex (if any), and passes the check callable.__enter__()/__exit__():
Enables use as a context manager that captures exceptions and validates them.__repr__():
Returns a string representation including expected types, match pattern, and check callable.
Usage Examples
with RaisesExc(ValueError, match="string"):
raise ValueError("string")
with RaisesExc(check=lambda e: e.args == (3, "hello")):
raise ValueError(3, "hello")
with RaisesExc(check=lambda e: type(e) is ValueError):
raise ValueError()
RaisesGroup
class RaisesGroup(AbstractRaises[BaseExceptionGroup[BaseExcT_co]]):
Purpose
A context manager class to assert that an `ExceptionGroup` or `BaseExceptionGroup` is raised, matching a specified structure of nested exceptions and subgroups.
Useful for Python 3.11+ exception groups or backports.
Allows specifying expected exceptions as types,
RaisesExc, or nestedRaisesGroupinstances.Supports options to flatten nested groups or allow matching a single unwrapped exception.
Constructor Parameters
expected_exceptionand*other_exceptions:
One or more expected exception types,RaisesExc, orRaisesGroupinstances.match: Regex pattern matching the string representation of the exception group.check: Callable for additional validation on the exception group.allow_unwrapped: Boolean to allow matching if a single expected exception is raised without wrapping in an exception group.flatten_subgroups: Boolean to flatten nested subgroups before matching.
Key Methods
matches(exception):
Validates that the exception matches the expected group structure and conditions._check_exceptions:
Internally matches expected exceptions to actual raised exceptions using a greedy algorithm.__enter__()/__exit__():
Context manager support to catch and validate exception groups.expected_type():
Returns a string representation of the expected exception group structure.
Usage Examples
with RaisesGroup(ValueError):
raise ExceptionGroup("", (ValueError(),))
with RaisesGroup(
ValueError,
RaisesExc(TypeError, match="^expected int$"),
match="^my group$",
):
raise ExceptionGroup(
"my group",
[
ValueError(),
TypeError("expected int"),
ValueError(),
],
)
with RaisesGroup(ValueError, allow_unwrapped=True):
raise ValueError
ResultHolder
class ResultHolder:
Purpose
A utility class used internally by `RaisesGroup` to keep track of match results between expected exceptions and actual raised exceptions when matching groups.
Key Methods
set_result(expected: int, actual: int, result: str | None):
Stores the match result.get_result(expected: int, actual: int) -> str | None:
Retrieves the stored result.has_result(expected: int, actual: int) -> bool:
Checks if a result is stored.no_match_for_expected(expected: list[int]) -> bool:
ReturnsTrueif all expected indices have matches.no_match_for_actual(actual: list[int]) -> bool:
ReturnsTrueif all actual indices have matches.
possible_match
def possible_match(results: ResultHolder, used: set[int] | None = None) -> bool:
Purpose
A recursive helper function to detect if there exists any possible matching between expected and actual exceptions beyond the greedy algorithm used in `RaisesGroup`.
Provides enhanced error messages when the greedy match fails but a theoretical match exists.
Important Implementation Details
Matching Algorithm in
RaisesGroup:
Uses a greedy algorithm to pair expected and actual exceptions. If the match fails, it attempts an exhaustive check to provide detailed failure reasons and hints. It warns users to use more stringent checks likeRaisesExcfor precise matching.Regex Matching and Raw Matching:
When a regex pattern is fully escaped and wrapped with^$, the code extracts a "rawmatch" version for better diff output in error messages.Support for Python < 3.11:
Uses theexceptiongroupbackport package forBaseExceptionGroupandExceptionGroupon Python versions earlier than 3.11.Use of
ExceptionInfo:
Theraisesfunction and its supporting classes interoperate withpytest'sExceptionInfoclass to capture and represent exception details for later inspection.Failing Tests:
Usespytest.outcomes.failinternally to raise assertion errors when the expected exception is not raised or does not match.Type Safety and Generics:
Extensive use of Python typing, generics, andTypeGuardto provide precise type narrowing in static analysis tools.
Interaction with Other System Components
_pytest._code.ExceptionInfo:
Used to capture and represent detailed exception information during testing._pytest.outcomes.fail:
Used internally to fail tests with appropriate messages._pytest.warning_types.PytestWarning:
Used to warn users about potentially misleading usage, e.g., empty regex patterns.Exception Group Support:
Integrates with Python 3.11+ nativeExceptionGroupor backported versions to support advanced exception matching.stringify_exceptionUtility:
Used to convert exceptions to string representations for regex matching.
Visual Diagram
classDiagram
direction TB
class AbstractRaises {
-match: Pattern[str] | None
-check: Callable[[BaseExcT_co], bool] | None
-_fail_reason: str | None
+fail_reason: str | None
+_parse_exc(exc, expected: str)
+_check_raw_type(expected_type, exception)
+_check_check(exception)
+_check_match(exception)
+matches(exception) <<abstract>>
}
class RaisesExc {
-expected_exceptions: tuple[type[BaseException], ...]
-_just_propagate: bool
+__init__(expected_exception=None, *, match=None, check=None)
+matches(exception)
+__enter__()
+__exit__(exc_type, exc_val, exc_tb)
+__repr__()
}
class RaisesGroup {
-expected_exceptions: tuple[type | RaisesExc | RaisesGroup, ...]
-allow_unwrapped: bool
-flatten_subgroups: bool
+__init__(expected_exception, *other_exceptions, allow_unwrapped=False, flatten_subgroups=False, match=None, check=None)
+matches(exception)
+_check_exceptions(_exception, actual_exceptions)
+__enter__()
+__exit__(exc_type, exc_val, exc_tb)
+expected_type()
+__repr__()
}
class ResultHolder {
-results: list[list[str | None]]
+set_result(expected, actual, result)
+get_result(expected, actual)
+has_result(expected, actual)
+no_match_for_expected(expected)
+no_match_for_actual(actual)
}
AbstractRaises <|-- RaisesExc
AbstractRaises <|-- RaisesGroup
RaisesGroup --> ResultHolder : uses
Summary
The [raises.py](/projects/286/67496) file is a fundamental component of `pytest`'s exception assertion system. It provides both simple exception type checks and advanced support for Python exception groups, offering rich APIs for precise and readable test assertions. The system uses a combination of regex matching, callable checks, and type checking to validate raised exceptions. The design emphasizes detailed failure explanations and type safety, contributing significantly to pytest's user-friendly and powerful testing capabilities.