Skip to content

Commit bcac404

Browse files
authored
deps: drop py3.8, support py3.9+ (#217)
* deps: drop py3.8, support py3.9+ Signed-off-by: nstarman <[email protected]> * config(ruff): py3.9+ Signed-off-by: nstarman <[email protected]> --------- Signed-off-by: nstarman <[email protected]>
1 parent 234cc4b commit bcac404

29 files changed

+122
-172
lines changed

.github/workflows/ci.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ jobs:
1616
fail-fast: false
1717
matrix:
1818
value:
19-
- name: "3.8"
20-
python-version: "3.8"
21-
extra-install: ""
2219
- name: "3.9"
2320
python-version: "3.9"
2421
extra-install: ""
@@ -28,15 +25,18 @@ jobs:
2825
- name: "3.11"
2926
python-version: "3.11"
3027
extra-install: ""
31-
- name: "3.11-pre-beartype"
32-
python-version: "3.11"
33-
extra-install: "pip install --upgrade --pre beartype"
3428
- name: "3.12"
3529
python-version: "3.12"
3630
extra-install: ""
3731
- name: "3.12-pre-beartype"
3832
python-version: "3.12"
3933
extra-install: "pip install --upgrade --pre beartype"
34+
- name: "3.13"
35+
python-version: "3.13"
36+
extra-install: ""
37+
- name: "3.13-pre-beartype"
38+
python-version: "3.13"
39+
extra-install: "pip install --upgrade --pre beartype"
4040

4141
name: Test ${{ matrix.value.name }}
4242
steps:

.readthedocs.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ version: 2
33
build:
44
os: ubuntu-22.04
55
tools:
6-
python: "3.11"
6+
python: "3.12"
77
jobs:
88
pre_build:
99
# Generate the Sphinx configuration for this Jupyter Book, so it builds.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ If you notice any issues with the new release, please open an issue.
1717

1818
# Installation
1919

20-
Plum requires Python 3.8 or higher.
20+
Plum requires Python 3.9 or higher.
2121

2222
```bash
2323
pip install plum-dispatch

benchmark.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from typing import Tuple
2-
31
import numpy as np
42
from tests.util import benchmark
53

@@ -35,12 +33,12 @@ def f2(x):
3533

3634

3735
@dispatch
38-
def g2(x: Tuple[int]):
36+
def g2(x: tuple[int]):
3937
pass
4038

4139

4240
@dispatch
43-
def g2(x: Tuple[str]):
41+
def g2(x: tuple[str]):
4442
pass
4543

4644

check_linter_assertions.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
import subprocess
33
import sys
44
from collections import defaultdict
5+
from collections.abc import Callable
56
from pathlib import Path
6-
from typing import Callable, Dict, List, Tuple
77

8-
FileLineInfo = Dict[Path, Dict[int, List[str]]]
8+
FileLineInfo = dict[Path, dict[int, list[str]]]
99
"""type: Type of a nested dictionary that gives for a collection of files line-wise
1010
information, where the information is of the form `list[str]`."""
1111

1212

13-
def next_noncomment_line(index: int, lines: List[str], path: Path) -> int:
13+
def next_noncomment_line(index: int, lines: list[str], path: Path) -> int:
1414
"""Starting at `index`, find the next line with code.
1515
1616
Args:
@@ -70,7 +70,7 @@ def parse_assertions(source_dir: Path, linter: str) -> FileLineInfo:
7070
return asserted_errors
7171

7272

73-
def parse_mypy_line(line: str) -> Tuple[Path, int, str, str]:
73+
def parse_mypy_line(line: str) -> tuple[Path, int, str, str]:
7474
"""Parse a line of the output of `mypy`.
7575
7676
Args:
@@ -90,7 +90,7 @@ def parse_mypy_line(line: str) -> Tuple[Path, int, str, str]:
9090
return Path(path).resolve(), int(line_number), status, message
9191

9292

93-
def parse_pyright_line(line: str) -> Tuple[Path, int, str, str]:
93+
def parse_pyright_line(line: str) -> tuple[Path, int, str, str]:
9494
"""Parse a line of the output of `pyright`.
9595
9696
Args:
@@ -112,7 +112,7 @@ def parse_pyright_line(line: str) -> Tuple[Path, int, str, str]:
112112
return Path(path.strip()).resolve(), int(line_number), status, message
113113

114114

115-
parse_line: Dict[str, Callable[[str], Tuple[Path, int, str, str]]] = {
115+
parse_line: dict[str, Callable[[str], tuple[Path, int, str, str]]] = {
116116
"mypy": parse_mypy_line,
117117
"pyright": parse_pyright_line,
118118
}

docs/types.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ that all types and type hints supported by Beartype are also supported by Plum.
88
Here are a few examples:
99

1010
```python
11-
from typing import Union, Optional, List, Dict
11+
from typing import Union, Optional
1212

1313
from plum import dispatch
1414

@@ -34,7 +34,7 @@ def f(x: list) -> str:
3434

3535

3636
@dispatch
37-
def f(x: List[int]) -> str:
37+
def f(x: list[int]) -> str:
3838
return "list of int"
3939

4040

@@ -44,11 +44,11 @@ def f(x: Optional[dict]) -> Optional[str]:
4444

4545

4646
@dispatch
47-
def f(x: Dict[int, str]) -> str:
47+
def f(x: dict[int, str]) -> str:
4848
return "dict of int to str"
4949
```
5050

51-
Although parametric types such as `List[int]` and `Dict[int, str]` are fully
51+
Although parametric types such as `list[int]` and `dict[int, str]` are fully
5252
supported, they do incur a performance penalty.
5353
For optimal performance, is recommended to use parametric types only where necessary.
5454
`Union` and `Optional` do not incur a performance penalty.
@@ -85,7 +85,7 @@ Plum already opts into this behaviour and will use it once it becomes available.
8585

8686
The type system is *covariant*, as opposed to Julia's type
8787
system, which is *invariant*.
88-
For example, this means that `List[T1]` is a subtype of `List[T2]` whenever
88+
For example, this means that `list[T1]` is a subtype of `list[T2]` whenever
8989
`T1` is a subtype of `T2`.
9090

9191
## Performance and Faithful Types

plum/__init__.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
# Plum previously exported a number of types. As of recently, the user can use the
2-
# versions from `typing`. To not break backward compatibility, we still export these
3-
# types.
1+
# Plum previously exported a number of types. As of recently, the user can use
2+
# the versions from `typing`. To not break backward compatibility, we still
3+
# export these types.
4+
from typing import Dict, List, Tuple, Union # noqa: F401, UP035
5+
6+
# isort: split
47
from functools import partial
5-
from typing import Dict, List, Tuple, Union # noqa: F401
68

79
from beartype import (
810
BeartypeConf as _BeartypeConf,

plum/alias.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@
2727
"""
2828

2929
from functools import wraps
30-
from typing import List, TypeVar, Union, _type_repr
31-
32-
from .typing import get_args
30+
from typing import TypeVar, Union, _type_repr, get_args
3331

3432
__all__ = ["activate_union_aliases", "deactivate_union_aliases", "set_union_alias"]
3533

@@ -141,7 +139,7 @@ def deactivate_union_aliases() -> None:
141139
_union_type.__str__ = _original_str
142140

143141

144-
_ALIASED_UNIONS: List = []
142+
_ALIASED_UNIONS: list = []
145143

146144

147145
def set_union_alias(union: UnionT, alias: str) -> UnionT:

plum/dispatcher.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import sys
22
from dataclasses import dataclass, field
33
from functools import partial
4-
from typing import Any, Dict, Optional, Tuple, TypeVar, Union, overload
4+
from typing import Any, Optional, TypeVar, Union, overload
55

66
from .function import Function
77
from .overload import get_overloads
@@ -13,8 +13,8 @@
1313
T = TypeVar("T", bound=Callable[..., Any])
1414

1515

16-
_dataclass_kw_args: Dict[str, Any] = {}
17-
if sys.version_info >= (3, 10): # pragma: specific no cover 3.8 3.9
16+
_dataclass_kw_args: dict[str, Any] = {}
17+
if sys.version_info >= (3, 10): # pragma: specific no cover 3.9
1818
_dataclass_kw_args |= {"slots": True}
1919

2020

@@ -34,8 +34,8 @@ class Dispatcher:
3434
"""
3535

3636
warn_redefinition: bool = False
37-
functions: Dict[str, Function] = field(default_factory=dict)
38-
classes: Dict[str, Dict[str, Function]] = field(default_factory=dict)
37+
functions: dict[str, Function] = field(default_factory=dict)
38+
classes: dict[str, dict[str, Function]] = field(default_factory=dict)
3939

4040
@overload
4141
def __call__(self, method: T, /, *, precedence: int = ...) -> T: ...
@@ -74,7 +74,7 @@ def __call__(
7474
return self._add_method(method, None, precedence=precedence)
7575

7676
def multi(
77-
self, *signatures: Union[Signature, Tuple[TypeHint, ...]]
77+
self, *signatures: Union[Signature, tuple[TypeHint, ...]]
7878
) -> Callable[[Callable], Function]:
7979
"""Decorator to register multiple signatures at once.
8080

plum/function.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from copy import copy
44
from functools import wraps
55
from types import MethodType
6-
from typing import Any, Callable, List, Optional, Protocol, Tuple, TypeVar, Union
6+
from typing import Any, Callable, Optional, Protocol, TypeVar, Union
77

88
from .method import Method
99
from .resolver import AmbiguousLookupError, NotFoundLookupError, Resolver
@@ -20,7 +20,7 @@
2020
# `typing.Self` is available for Python 3.11 and higher.
2121
try: # pragma: specific no cover 3.11
2222
from typing import Self
23-
except ImportError: # pragma: specific no cover 3.8 3.9 3.10
23+
except ImportError: # pragma: specific no cover 3.10
2424
Self = TypeVar("Self", bound="Function")
2525

2626
SomeExceptionType = TypeVar("SomeExceptionType", bound=Exception)
@@ -96,12 +96,12 @@ def __init__(
9696
self._warn_redefinition = warn_redefinition
9797

9898
# Initialise pending and resolved methods.
99-
self._pending: List[Tuple[Callable, Optional[Signature], int]] = []
99+
self._pending: list[tuple[Callable, Optional[Signature], int]] = []
100100
self._resolver = Resolver(
101101
self.__name__,
102102
warn_redefinition=self._warn_redefinition,
103103
)
104-
self._resolved: List[Tuple[Callable, Signature, int]] = []
104+
self._resolved: list[tuple[Callable, Signature, int]] = []
105105

106106
@property
107107
def owner(self):
@@ -125,7 +125,7 @@ def __doc__(self) -> Optional[str]:
125125
"""
126126
try:
127127
self._resolve_pending_registrations()
128-
except NameError: # pragma: specific no cover 3.7 3.8 3.9
128+
except NameError: # pragma: specific no cover 3.9
129129
# When `staticmethod` is combined with
130130
# `from __future__ import annotations`, in Python 3.10 and higher
131131
# `staticmethod` will attempt to inherit `__doc__` (see
@@ -176,7 +176,7 @@ def __doc__(self, value: str) -> None:
176176
self._doc = value if value else ""
177177

178178
@property
179-
def methods(self) -> List[Signature]:
179+
def methods(self) -> list[Signature]:
180180
"""list[:class:`.signature.Signature`]: All available methods."""
181181
self._resolve_pending_registrations()
182182
return self._resolver.methods
@@ -199,7 +199,7 @@ def dispatch(
199199
return self
200200

201201
def dispatch_multi(
202-
self: Self, *signatures: Union[Signature, Tuple[TypeHint, ...]]
202+
self: Self, *signatures: Union[Signature, tuple[TypeHint, ...]]
203203
) -> Callable[[Callable], Self]:
204204
"""Decorator to extend the function with multiple signatures at once.
205205
@@ -296,8 +296,8 @@ def _resolve_pending_registrations(self) -> None:
296296
self.clear_cache(reregister=False)
297297

298298
def resolve_method(
299-
self, target: Union[Tuple[object, ...], Signature]
300-
) -> Tuple[Callable, TypeHint]:
299+
self, target: Union[tuple[object, ...], Signature]
300+
) -> tuple[Callable, TypeHint]:
301301
"""Find the method and return type for arguments.
302302
303303
Args:
@@ -336,7 +336,7 @@ def resolve_method(
336336

337337
def _handle_not_found_lookup_error(
338338
self, ex: NotFoundLookupError
339-
) -> Tuple[Callable, TypeHint]:
339+
) -> tuple[Callable, TypeHint]:
340340
if not self.owner:
341341
# Not in a class. Nothing we can do.
342342
raise ex from None
@@ -384,9 +384,9 @@ def __call__(self, *args, **kw_args):
384384

385385
def _resolve_method_with_cache(
386386
self,
387-
args: Union[Tuple[object, ...], Signature, None] = None,
388-
types: Optional[Tuple[TypeHint, ...]] = None,
389-
) -> Tuple[Callable, TypeHint]:
387+
args: Union[tuple[object, ...], Signature, None] = None,
388+
types: Optional[tuple[TypeHint, ...]] = None,
389+
) -> tuple[Callable, TypeHint]:
390390
if args is None and types is None:
391391
raise ValueError(
392392
"Arguments `args` and `types` cannot both be `None`. "
@@ -525,7 +525,7 @@ def wrapped_method(*args, **kw_args):
525525
return wrapped_method
526526

527527
@property
528-
def methods(self) -> List[Signature]:
528+
def methods(self) -> list[Signature]:
529529
"""list[:class:`.signature.Signature`]: All available methods."""
530530
return self._f.methods
531531

0 commit comments

Comments
 (0)