Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Derive pytest.raises from AbstractContextManager #10660

Merged
merged 1 commit into from Jan 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelog/10660.bugfix.rst
@@ -0,0 +1,2 @@
Fix :py:func:`pytest.raises` to return a 'ContextManager' so that type-checkers could narrow
:code:`pytest.raises(...) if ... else nullcontext()` down to 'ContextManager' rather than 'object'.
4 changes: 2 additions & 2 deletions src/_pytest/python_api.py
Expand Up @@ -8,7 +8,7 @@
from typing import Any
from typing import Callable
from typing import cast
from typing import Generic
from typing import ContextManager
from typing import List
from typing import Mapping
from typing import Optional
Expand Down Expand Up @@ -957,7 +957,7 @@ def raises( # noqa: F811


@final
class RaisesContext(Generic[E]):
class RaisesContext(ContextManager[_pytest._code.ExceptionInfo[E]]):
def __init__(
self,
expected_exception: Union[Type[E], Tuple[Type[E], ...]],
Expand Down
11 changes: 11 additions & 0 deletions testing/typing_checks.py
Expand Up @@ -3,6 +3,11 @@
This file is not executed, it is only checked by mypy to ensure that
none of the code triggers any mypy errors.
"""
import contextlib
from typing import Optional

from typing_extensions import assert_type

import pytest


Expand All @@ -22,3 +27,9 @@ def check_fixture_ids_callable() -> None:
@pytest.mark.parametrize("func", [str, int], ids=lambda x: str(x.__name__))
def check_parametrize_ids_callable(func) -> None:
pass


def check_raises_is_a_context_manager(val: bool) -> None:
with pytest.raises(RuntimeError) if val else contextlib.nullcontext() as excinfo:
pass
assert_type(excinfo, Optional[pytest.ExceptionInfo[RuntimeError]])