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

expand CI pyright to use full python version matrix and fix type errors #101

Merged
merged 8 commits into from
Jan 10, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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]
agronholm marked this conversation as resolved.
Show resolved Hide resolved
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):
agronholm marked this conversation as resolved.
Show resolved Hide resolved
"""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