Skip to content
Draft
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
8 changes: 2 additions & 6 deletions .github/workflows/build_book.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,13 @@ jobs:

# Install dependencies.
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install -e '.[dev]'

# Build the book.
- name: Build
run: |
jupyter-book build docs
run: uv run --group dev jupyter-book build docs

# Deploy the book's HTML to gh-pages branch.
- name: Deploy to GitHub Pages
Expand Down
33 changes: 18 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,18 @@ on:
branches:
- master

env:
# Many color libraries just need this to be set to any value, but at least
# one distinguishes color depth, where "3" -> "256-bit color".
FORCE_COLOR: 3

jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
value:
- name: "3.8"
python-version: "3.8"
extra-install: ""
- name: "3.9"
python-version: "3.9"
extra-install: ""
Expand All @@ -28,35 +30,36 @@ jobs:
- name: "3.11"
python-version: "3.11"
extra-install: ""
- name: "3.11-pre-beartype"
python-version: "3.11"
extra-install: "pip install --upgrade --pre beartype"
- name: "3.12"
python-version: "3.12"
extra-install: ""
- name: "3.12-pre-beartype"
python-version: "3.12"
extra-install: "pip install --upgrade --pre beartype"
extra-install: "uv pip install --upgrade --pre beartype"
- name: "3.13"
python-version: "3.13"
extra-install: ""
- name: "3.13-pre-beartype"
python-version: "3.13"
extra-install: "uv pip install --upgrade --pre beartype"

name: Test ${{ matrix.value.name }}
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.value.python-version }}
uses: actions/setup-python@v2
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
with:
python-version: ${{ matrix.value.python-version }}
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install --upgrade --no-cache-dir -e '.[dev]'
uv sync --locked --group dev
${{ matrix.value.extra-install }}
- name: Test linter assertions
run: |
python check_linter_assertions.py tests/typechecked
run: uv run --frozen check_linter_assertions.py tests/typechecked
- name: Run tests
run: |
PRAGMA_VERSION=`python -c "import sys; print('.'.join(map(str, sys.version_info[:2])))"` \
pytest -v --cov=plum --cov-report term-missing
PRAGMA_VERSION=`uv run python -c "import sys; print('.'.join(map(str, sys.version_info[:2])))"` \
uv run --frozen pytest -v --cov=plum --cov-report term-missing
- name: Coveralls parallel
uses: coverallsapp/github-action@v2
with:
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ repos:
- id: check-useless-excludes

- repo: https://github.com/abravalheri/validate-pyproject
rev: v0.16
rev: v0.23
hooks:
- id: validate-pyproject

Expand Down
2 changes: 1 addition & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ version: 2
build:
os: ubuntu-22.04
tools:
python: "3.11"
python: "3.12"
jobs:
pre_build:
# Generate the Sphinx configuration for this Jupyter Book, so it builds.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ If you notice any issues with the new release, please open an issue.

# Installation

Plum requires Python 3.8 or higher.
Plum requires Python 3.9 or higher.

```bash
pip install plum-dispatch
Expand Down
6 changes: 2 additions & 4 deletions benchmark.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import Tuple

import numpy as np
from tests.util import benchmark

Expand Down Expand Up @@ -35,12 +33,12 @@ def f2(x):


@dispatch
def g2(x: Tuple[int]):
def g2(x: tuple[int]):
pass


@dispatch
def g2(x: Tuple[str]):
def g2(x: tuple[str]):
pass


Expand Down
12 changes: 6 additions & 6 deletions check_linter_assertions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
import subprocess
import sys
from collections import defaultdict
from collections.abc import Callable
from pathlib import Path
from typing import Callable, Dict, List, Tuple

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


def next_noncomment_line(index: int, lines: List[str], path: Path) -> int:
def next_noncomment_line(index: int, lines: list[str], path: Path) -> int:
"""Starting at `index`, find the next line with code.

Args:
Expand Down Expand Up @@ -70,7 +70,7 @@ def parse_assertions(source_dir: Path, linter: str) -> FileLineInfo:
return asserted_errors


def parse_mypy_line(line: str) -> Tuple[Path, int, str, str]:
def parse_mypy_line(line: str) -> tuple[Path, int, str, str]:
"""Parse a line of the output of `mypy`.

Args:
Expand All @@ -90,7 +90,7 @@ def parse_mypy_line(line: str) -> Tuple[Path, int, str, str]:
return Path(path).resolve(), int(line_number), status, message


def parse_pyright_line(line: str) -> Tuple[Path, int, str, str]:
def parse_pyright_line(line: str) -> tuple[Path, int, str, str]:
"""Parse a line of the output of `pyright`.

Args:
Expand All @@ -112,7 +112,7 @@ def parse_pyright_line(line: str) -> Tuple[Path, int, str, str]:
return Path(path.strip()).resolve(), int(line_number), status, message


parse_line: Dict[str, Callable[[str], Tuple[Path, int, str, str]]] = {
parse_line: dict[str, Callable[[str], tuple[Path, int, str, str]]] = {
"mypy": parse_mypy_line,
"pyright": parse_pyright_line,
}
Expand Down
2 changes: 1 addition & 1 deletion docs/union_aliases.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ from typing import Union
from plum import dispatch


scalar_types = sum(np.core.sctypes.values(), []) # All NumPy scalar types
scalar_types = sum(np.sctypeDict.values(), []) # All NumPy scalar types
Scalar = Union[tuple(scalar_types)] # Union of all NumPy scalar types


Expand Down
10 changes: 6 additions & 4 deletions plum/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Plum previously exported a number of types. As of recently, the user can use the
# versions from `typing`. To not break backward compatibility, we still export these
# types.
# Plum previously exported a number of types. As of recently, the user can use
# the versions from `typing`. To not break backward compatibility, we still
# export these types.
from typing import Dict, List, Tuple, Union # noqa: F401, UP035

# isort: split
from functools import partial
from typing import Dict, List, Tuple, Union # noqa: F401

from beartype import (
BeartypeConf as _BeartypeConf,
Expand Down
6 changes: 2 additions & 4 deletions plum/alias.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@
"""

from functools import wraps
from typing import List, TypeVar, Union, _type_repr

from .typing import get_args
from typing import TypeVar, Union, _type_repr, get_args

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

Expand Down Expand Up @@ -141,7 +139,7 @@ def deactivate_union_aliases() -> None:
_union_type.__str__ = _original_str


_ALIASED_UNIONS: List = []
_ALIASED_UNIONS: list = []


def set_union_alias(union: UnionT, alias: str) -> UnionT:
Expand Down
12 changes: 6 additions & 6 deletions plum/dispatcher.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import sys
from dataclasses import dataclass, field
from functools import partial
from typing import Any, Dict, Optional, Tuple, TypeVar, Union, overload
from typing import Any, Optional, TypeVar, Union, overload

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


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


Expand All @@ -34,8 +34,8 @@ class Dispatcher:
"""

warn_redefinition: bool = False
functions: Dict[str, Function] = field(default_factory=dict)
classes: Dict[str, Dict[str, Function]] = field(default_factory=dict)
functions: dict[str, Function] = field(default_factory=dict)
classes: dict[str, dict[str, Function]] = field(default_factory=dict)

@overload
def __call__(self, method: T, /, *, precedence: int = ...) -> T: ...
Expand Down Expand Up @@ -74,7 +74,7 @@ def __call__(
return self._add_method(method, None, precedence=precedence)

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

Expand Down
28 changes: 14 additions & 14 deletions plum/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from copy import copy
from functools import wraps
from types import MethodType
from typing import Any, Callable, List, Optional, Protocol, Tuple, TypeVar, Union
from typing import Any, Callable, Optional, Protocol, TypeVar, Union

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

SomeExceptionType = TypeVar("SomeExceptionType", bound=Exception)
Expand Down Expand Up @@ -96,12 +96,12 @@ def __init__(
self._warn_redefinition = warn_redefinition

# Initialise pending and resolved methods.
self._pending: List[Tuple[Callable, Optional[Signature], int]] = []
self._pending: list[tuple[Callable, Optional[Signature], int]] = []
self._resolver = Resolver(
self.__name__,
warn_redefinition=self._warn_redefinition,
)
self._resolved: List[Tuple[Callable, Signature, int]] = []
self._resolved: list[tuple[Callable, Signature, int]] = []

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

@property
def methods(self) -> List[Signature]:
def methods(self) -> list[Signature]:
"""list[:class:`.signature.Signature`]: All available methods."""
self._resolve_pending_registrations()
return self._resolver.methods
Expand All @@ -199,7 +199,7 @@ def dispatch(
return self

def dispatch_multi(
self: Self, *signatures: Union[Signature, Tuple[TypeHint, ...]]
self: Self, *signatures: Union[Signature, tuple[TypeHint, ...]]
) -> Callable[[Callable], Self]:
"""Decorator to extend the function with multiple signatures at once.

Expand Down Expand Up @@ -296,8 +296,8 @@ def _resolve_pending_registrations(self) -> None:
self.clear_cache(reregister=False)

def resolve_method(
self, target: Union[Tuple[object, ...], Signature]
) -> Tuple[Callable, TypeHint]:
self, target: Union[tuple[object, ...], Signature]
) -> tuple[Callable, TypeHint]:
"""Find the method and return type for arguments.

Args:
Expand Down Expand Up @@ -336,7 +336,7 @@ def resolve_method(

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

def _resolve_method_with_cache(
self,
args: Union[Tuple[object, ...], Signature, None] = None,
types: Optional[Tuple[TypeHint, ...]] = None,
) -> Tuple[Callable, TypeHint]:
args: Union[tuple[object, ...], Signature, None] = None,
types: Optional[tuple[TypeHint, ...]] = None,
) -> tuple[Callable, TypeHint]:
if args is None and types is None:
raise ValueError(
"Arguments `args` and `types` cannot both be `None`. "
Expand Down Expand Up @@ -525,7 +525,7 @@ def wrapped_method(*args, **kw_args):
return wrapped_method

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

Expand Down
7 changes: 4 additions & 3 deletions plum/method.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import inspect
import typing
from typing import Callable, List, Optional, Set, Tuple
from collections.abc import Callable
from typing import Optional

from rich.padding import Padding
from rich.text import Text
Expand Down Expand Up @@ -96,7 +97,7 @@ def __rich_console__(self, console, options):

def repr_mismatch(
self,
mismatches: Set[int] = frozenset(),
mismatches: set[int] = frozenset(),
varargs_matched: bool = True,
) -> str:
"""Version of `__repr__` that can print which arguments are mismatched. This
Expand Down Expand Up @@ -168,7 +169,7 @@ def __rich_console__(self, console, options):
yield Padding(sum(method_repr, Text(f"[{i}] ")), (0, 4))


def extract_arg_names(f: Callable) -> Tuple[List[str], List[str], Optional[str]]:
def extract_arg_names(f: Callable) -> tuple[list[str], list[str], Optional[str]]:
"""Extract the argument names for a function.

Args:
Expand Down
Loading
Loading