You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As I understand the arguments for not extending pytest.raises to automatically unwrap ExceptionGroupsas discussed in #11538 I've tried to use the ExceptionInfo.group_contains() method which works well enough for the runtime parts.
However since the return value of raises() ( ExceptionInfo) is generic in the exception type, the stricter type-checkers will complain about the unknown type-argument of the ExceptionGroup.
# pyright: strict
import pytest
import sys
from typing import cast
if sys.version_info < (3, 11):
from exceptiongroup import ExceptionGroup
class FooError(Exception):
pass
# Pyright will report an error for the code below as:
# Type of "exc_group_info" is partially unknown
# Type of "exc_group_info" is "ExceptionInfo[ExceptionGroup]"PylancereportUnknownVariableType
with pytest.raises(ExceptionGroup) as exc_group_info:
raise ExceptionGroup("Some error occured", [FooError("Error")])
assert exc_group_info.group_contains(FooError)
If trying to rectify this by supplying the type-argument it fails various checks in raises that checks that the argument is an instance of type which GenericAlias (that you get when indexing a generic class) is not.
# If the type is added pyright is ok but the runtime is not:
# Traceback (most recent call last):
# File ".../test.py", line 21, in <module>
# with pytest.raises(ExceptionGroup[ExceptionGroup[FooError]]) as exc_group_info:
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# File ".../.venv/lib/python3.12/site-packages/_pytest/python_api.py", line 959, in raises
# raise TypeError(msg.format(not_a))
# TypeError: expected exception must be a BaseException type, not GenericAlias
with pytest.raises(ExceptionGroup[ExceptionGroup[FooError]]) as exc_group_info:
raise ExceptionGroup("Some error occured", [FooError("Error")])
assert exc_group_info.group_contains(FooError)
The correct casting that is required to get this correct would have to be something like below.
# With the cast we can get it to work but that is quite verbose and doesn't
# catch errors of BaseExceptionGroup vs ExceptionGroup in the cast for example.
with pytest.raises(cast(type[ExceptionGroup[FooError]], ExceptionGroup)) as exc_group_info:
raise ExceptionGroup("Some error occured", [FooError("Error")])
assert exc_group_info.group_contains(FooError)
The text was updated successfully, but these errors were encountered:
tapetersen
changed the title
Using Generic Exceptions (ExceptionGroups in particular) with raises in a type-safe manner is not ideal.
Using Generic Exceptions (ExceptionGroups in particular) with raises in a type-safe manner is not ideal
Jan 7, 2025
Yep, I think calling get_origin() on generics to 'unwrap' the bare type as part of this code would be a great fix. Would you be interested in opening a PR?
As I understand the arguments for not extending
pytest.raises
to automatically unwrapExceptionGroups
as discussed in #11538 I've tried to use theExceptionInfo.group_contains()
method which works well enough for the runtime parts.However since the return value of
raises()
(ExceptionInfo
) is generic in the exception type, the stricter type-checkers will complain about the unknown type-argument of theExceptionGroup
.If trying to rectify this by supplying the type-argument it fails various checks in
raises
that checks that the argument is an instance oftype
whichGenericAlias
(that you get when indexing a generic class) is not.The correct casting that is required to get this correct would have to be something like below.
This could probably be fixed by handling generic Exceptions (or at least ExceptionGroups) explicitly in raises using https://docs.python.org/3/library/typing.html#typing.get_origin.
The text was updated successfully, but these errors were encountered: