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

ExceptionGroup: make it generic #7626

Merged
merged 3 commits into from
Apr 15, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 36 additions & 11 deletions stdlib/builtins.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ from typing import (
SupportsInt,
SupportsRound,
TypeVar,
Union,
overload,
)
from typing_extensions import Literal, SupportsIndex, TypeGuard, final
Expand Down Expand Up @@ -1747,19 +1746,45 @@ if sys.version_info >= (3, 10):
class EncodingWarning(Warning): ...

if sys.version_info >= (3, 11):
_SplitCondition = Union[type[BaseException], tuple[type[BaseException], ...], Callable[[BaseException], bool]]
_BaseExceptionT_co = TypeVar("_BaseExceptionT_co", bound=BaseException, covariant=True)
_BaseExceptionT = TypeVar("_BaseExceptionT", bound=BaseException)
_ExceptionT_co = TypeVar("_ExceptionT_co", bound=Exception, covariant=True)
_ExceptionT = TypeVar("_ExceptionT", bound=Exception)

class BaseExceptionGroup(BaseException):
def __new__(cls: type[Self], __message: str, __exceptions: Sequence[BaseException]) -> Self: ...
class BaseExceptionGroup(BaseException, Generic[_BaseExceptionT_co]):
def __new__(cls: type[Self], __message: str, __exceptions: Sequence[_BaseExceptionT_co]) -> Self: ...
@property
def message(self) -> str: ...
@property
def exceptions(self) -> tuple[BaseException, ...]: ...
def subgroup(self: Self, __condition: _SplitCondition) -> Self | None: ...
def split(self: Self, __condition: _SplitCondition) -> tuple[Self | None, Self | None]: ...
def derive(self: Self, __excs: Sequence[BaseException]) -> Self: ...
def exceptions(self) -> tuple[_BaseExceptionT_co | BaseExceptionGroup[_BaseExceptionT_co], ...]: ...
@overload
def subgroup(
self, __condition: type[_BaseExceptionT] | tuple[type[_BaseExceptionT], ...]
) -> BaseExceptionGroup[_BaseExceptionT] | None: ...
@overload
def subgroup(self: Self, __condition: Callable[[_BaseExceptionT_co], bool]) -> Self | None: ...
Comment on lines +1760 to +1765
Copy link
Collaborator

@srittau srittau Apr 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One minor gripe I have is that _BaseExceptionT and _BaseExceptionT_co have a very similar name, which means that it's easy to miss the subtleties in cases like above. But I have no immediate idea for better names.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially had them as _BaseExceptionT and _BaseExceptionU but that seemed worse.

@overload
def split(
self: Self, __condition: type[_BaseExceptionT] | tuple[type[_BaseExceptionT], ...]
) -> tuple[BaseExceptionGroup[_BaseExceptionT] | None, Self | None]: ...
@overload
def split(self: Self, __condition: Callable[[_BaseExceptionT_co], bool]) -> tuple[Self | None, Self | None]: ...
def derive(self: Self, __excs: Sequence[_BaseExceptionT_co]) -> Self: ...
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit of a tricky one. If I read PEP 654 correctly, the __excs provided don't need to have anything in common with the exceptions of self. So a "correct" annotation would be:

def derive(self: Self, __excs: Sequence[_BaseExceptionT]) -> Self[_BaseExceptionT]: ...

But I don't think that's possible. So I'm fine with this, until someone comes up with a better alternative.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yet another use case for python/typing#548...


class ExceptionGroup(BaseExceptionGroup, Exception):
def __new__(cls: type[Self], __message: str, __exceptions: Sequence[Exception]) -> Self: ...
class ExceptionGroup(BaseExceptionGroup[_ExceptionT_co], Exception):
def __new__(cls: type[Self], __message: str, __exceptions: Sequence[_ExceptionT_co]) -> Self: ...
@property
def exceptions(self) -> tuple[Exception, ...]: ...
def exceptions(self) -> tuple[_ExceptionT_co | ExceptionGroup[_ExceptionT_co], ...]: ...
# We accept a narrower type, but that's OK.
@overload # type: ignore[override]
def subgroup(
self, __condition: type[_ExceptionT] | tuple[type[_ExceptionT], ...]
) -> ExceptionGroup[_ExceptionT] | None: ...
@overload
def subgroup(self: Self, __condition: Callable[[_ExceptionT_co], bool]) -> Self | None: ...
@overload # type: ignore[override]
def split(
self: Self, __condition: type[_ExceptionT] | tuple[type[_ExceptionT], ...]
) -> tuple[ExceptionGroup[_ExceptionT] | None, Self | None]: ...
@overload
def split(self: Self, __condition: Callable[[_ExceptionT_co], bool]) -> tuple[Self | None, Self | None]: ...