Skip to content

Commit

Permalink
Expanded CI pyright to use full python version matrix and fix type er…
Browse files Browse the repository at this point in the history
…rors (#101)
  • Loading branch information
jakkdl committed Jan 10, 2024
1 parent 8c371db commit 0604a05
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 26 deletions.
10 changes: 7 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,25 @@ on:

jobs:
pyright:
strategy:
fail-fast: false
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: 3.x
python-version: ${{ matrix.python-version }}
- uses: actions/cache@v3
with:
path: ~/.cache/pip
key: pip-pyright
- name: Install dependencies
run: pip install -e . pyright
- name: Run pyright
run: pyright --verifytypes exceptiongroup
run: pyright --verifytypes exceptiongroup --verbose

test:
strategy:
Expand Down
10 changes: 6 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,17 @@ source = ["exceptiongroup"]
relative_files = true

[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"if TYPE_CHECKING:"
exclude_also = [
"if TYPE_CHECKING:",
"@overload",
]

[tool.tox]
legacy_tox_ini = """
[tox]
envlist = py37, py38, py39, py310, py311, py312, pypy3
labels =
pyright = py{310,311,312}-pyright
skip_missing_interpreters = true
minversion = 4.0
Expand All @@ -87,7 +89,7 @@ extras = test
commands = python -m pytest {posargs}
usedevelop = true
[testenv:pyright]
[testenv:{py37-,py38-,py39-,py310-,py311-,py312-,}pyright]
deps = pyright
commands = pyright --verifytypes exceptiongroup
usedevelop = true
Expand Down
34 changes: 20 additions & 14 deletions src/exceptiongroup/_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
from inspect import getmro, isclass
from typing import TYPE_CHECKING, Generic, Type, TypeVar, cast, overload

if TYPE_CHECKING:
from typing import Self

_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)
# using typing.Self would require a typing_extensions dependency on py<3.11
_ExceptionGroupSelf = TypeVar("_ExceptionGroupSelf", bound="ExceptionGroup")
_BaseExceptionGroupSelf = TypeVar("_BaseExceptionGroupSelf", bound="BaseExceptionGroup")


def check_direct_subclass(
Expand Down Expand Up @@ -46,8 +46,10 @@ class BaseExceptionGroup(BaseException, Generic[_BaseExceptionT_co]):
"""A combination of multiple unrelated exceptions."""

def __new__(
cls, __message: str, __exceptions: Sequence[_BaseExceptionT_co]
) -> Self:
cls: _BaseExceptionGroupSelf,
__message: str,
__exceptions: Sequence[_BaseExceptionT_co],
) -> _BaseExceptionGroupSelf:
if not isinstance(__message, str):
raise TypeError(f"argument 1 must be str, not {type(__message)}")
if not isinstance(__exceptions, Sequence):
Expand Down Expand Up @@ -119,15 +121,16 @@ def subgroup(

@overload
def subgroup(
self, __condition: Callable[[_BaseExceptionT_co | Self], bool]
self,
__condition: Callable[[_BaseExceptionT_co | _BaseExceptionGroupSelf], bool],
) -> BaseExceptionGroup[_BaseExceptionT_co] | None:
...

def subgroup(
self,
__condition: type[_BaseExceptionT]
| tuple[type[_BaseExceptionT], ...]
| Callable[[_BaseExceptionT_co | Self], bool],
| Callable[[_BaseExceptionT_co | _BaseExceptionGroupSelf], bool],
) -> BaseExceptionGroup[_BaseExceptionT] | None:
condition = get_condition_filter(__condition)
modified = False
Expand Down Expand Up @@ -179,7 +182,8 @@ def split(

@overload
def split(
self, __condition: Callable[[_BaseExceptionT_co | Self], bool]
self,
__condition: Callable[[_BaseExceptionT_co | _BaseExceptionGroupSelf], bool],
) -> tuple[
BaseExceptionGroup[_BaseExceptionT_co] | None,
BaseExceptionGroup[_BaseExceptionT_co] | None,
Expand Down Expand Up @@ -224,14 +228,14 @@ def split(
else:
nonmatching_exceptions.append(exc)

matching_group: Self | None = None
matching_group: _BaseExceptionGroupSelf | None = None
if matching_exceptions:
matching_group = self.derive(matching_exceptions)
matching_group.__cause__ = self.__cause__
matching_group.__context__ = self.__context__
matching_group.__traceback__ = self.__traceback__

nonmatching_group: Self | None = None
nonmatching_group: _BaseExceptionGroupSelf | None = None
if nonmatching_exceptions:
nonmatching_group = self.derive(nonmatching_exceptions)
nonmatching_group.__cause__ = self.__cause__
Expand Down Expand Up @@ -269,7 +273,9 @@ def __repr__(self) -> str:


class ExceptionGroup(BaseExceptionGroup[_ExceptionT_co], Exception):
def __new__(cls, __message: str, __exceptions: Sequence[_ExceptionT_co]) -> Self:
def __new__(
cls, __message: str, __exceptions: Sequence[_ExceptionT_co]
) -> _ExceptionGroupSelf:
return super().__new__(cls, __message, __exceptions)

if TYPE_CHECKING:
Expand All @@ -288,7 +294,7 @@ def subgroup(

@overload
def subgroup(
self, __condition: Callable[[_ExceptionT_co | Self], bool]
self, __condition: Callable[[_ExceptionT_co | _ExceptionGroupSelf], bool]
) -> ExceptionGroup[_ExceptionT_co] | None:
...

Expand All @@ -310,14 +316,14 @@ def split(

@overload
def split(
self, __condition: Callable[[_ExceptionT_co | Self], bool]
self, __condition: Callable[[_ExceptionT_co | _ExceptionGroupSelf], bool]
) -> tuple[
ExceptionGroup[_ExceptionT_co] | None, ExceptionGroup[_ExceptionT_co] | None
]:
...

def split(
self: Self,
self: _ExceptionGroupSelf,
__condition: type[_ExceptionT]
| tuple[type[_ExceptionT], ...]
| Callable[[_ExceptionT_co], bool],
Expand Down
23 changes: 18 additions & 5 deletions src/exceptiongroup/_suppress.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,33 @@
import sys
from contextlib import AbstractContextManager
from types import TracebackType
from typing import TYPE_CHECKING, Optional, Type

if sys.version_info < (3, 11):
from ._exceptions import BaseExceptionGroup

if TYPE_CHECKING:
# requires python 3.9
BaseClass = AbstractContextManager[None]
else:
BaseClass = AbstractContextManager

class suppress(AbstractContextManager):

class suppress(BaseClass):
"""Backport of :class:`contextlib.suppress` from Python 3.12.1."""

def __init__(self, *exceptions):
def __init__(self, *exceptions: BaseException):
self._exceptions = exceptions

def __enter__(self):
def __enter__(self) -> None:
pass

def __exit__(self, exctype, excinst, exctb):
def __exit__(
self,
exctype: Optional[Type[BaseException]],
excinst: Optional[BaseException],
exctb: Optional[TracebackType],
) -> bool:
# Unlike isinstance and issubclass, CPython exception handling
# currently only looks at the concrete type hierarchy (ignoring
# the instance and subclass checking hooks). While Guido considers
Expand All @@ -25,7 +38,7 @@ def __exit__(self, exctype, excinst, exctb):
#
# See http://bugs.python.org/issue12029 for more details
if exctype is None:
return
return False

if issubclass(exctype, self._exceptions):
return True
Expand Down

0 comments on commit 0604a05

Please sign in to comment.