Skip to content

Commit

Permalink
Merge branch 'master' of github.com:wesselb/plum
Browse files Browse the repository at this point in the history
  • Loading branch information
wesselb committed Jun 28, 2024
2 parents a161a5d + 595690e commit 6531b99
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 26 deletions.
3 changes: 3 additions & 0 deletions plum/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
from .type import resolve_type_hint
from .util import * # noqa: F401, F403

# Deprecated
from .util import multihash # noqa: F401, F403

# Ensure that type checking is always entirely correct! The default O(1) strategy
# is super fast, but might yield unpredictable dispatch behaviour. The O(n) strategy
# actually is not yet available, but we can already opt in to use it.
Expand Down
6 changes: 4 additions & 2 deletions plum/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ def __call__(
# set the signature argument to `None`.
return self._add_method(method, None, precedence=precedence)

def multi(self, *signatures: Union[Signature, Tuple[TypeHint, ...]]) -> Callable:
def multi(
self, *signatures: Union[Signature, Tuple[TypeHint, ...]]
) -> Callable[[Callable], Function]:
"""Decorator to register multiple signatures at once.
Args:
Expand All @@ -87,7 +89,7 @@ def multi(self, *signatures: Union[Signature, Tuple[TypeHint, ...]]) -> Callable
f"`plum.signature.Signature`."
)

def decorator(method):
def decorator(method: Callable) -> Function:
# The precedence will not be used, so we can safely set it to `None`.
return self._add_method(method, *resolved_signatures, precedence=None)

Expand Down
6 changes: 4 additions & 2 deletions plum/repr.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import types
import typing
from functools import partial
from typing import Any, Callable, Dict, Iterable, Optional
from typing import Any, Callable, Dict, Iterable, Optional, Type, TypeVar

import rich
from rich.color import Color
Expand All @@ -19,6 +19,8 @@
"rich_repr",
]

T = TypeVar("T")

path_style = Style(color=Color.from_ansi(7))
file_style = Style(bold=True, underline=True)

Expand Down Expand Up @@ -202,7 +204,7 @@ def _repr_mimebundle_from_rich_(
return data


def rich_repr(cls: Optional[type] = None, str: bool = False):
def rich_repr(cls: Optional[Type[T]] = None, str: bool = False) -> Type[T]:
"""Class decorator defining a `__repr__` method that calls :mod:`rich.`
This also sets `_repr_mimebundle_` for better rendering in Jupyter.
Expand Down
36 changes: 17 additions & 19 deletions plum/signature.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import inspect
import operator
import typing
from copy import copy
from typing import Callable, List, Set, Tuple, Union
from typing import Any, Callable, ClassVar, List, Set, Tuple, Union

from rich.segment import Segment
from typing_extensions import Self

import beartype.door
from beartype.peps import resolve_pep563 as beartype_resolve_pep563
Expand All @@ -13,7 +13,7 @@
from .repr import repr_short, rich_repr
from .type import is_faithful, resolve_type_hint
from .typing import get_type_hints
from .util import Comparable, Missing, TypeHint, multihash, wrap_lambda
from .util import Comparable, Missing, TypeHint, wrap_lambda

__all__ = ["Signature", "append_default_args"]

Expand Down Expand Up @@ -41,17 +41,17 @@ class Signature(Comparable):
is_faithful (bool): Whether this signature only uses faithful types.
"""

_default_varargs = Missing
_default_precedence = 0
_default_varargs: ClassVar = Missing
_default_precedence: ClassVar[int] = 0

__slots__ = ("types", "varargs", "precedence", "is_faithful")
__slots__: Tuple[str, ...] = ("types", "varargs", "precedence", "is_faithful")

def __init__(
self,
*types: Tuple[TypeHint, ...],
varargs: OptionalType = _default_varargs,
precedence: int = _default_precedence,
):
) -> None:
"""Instantiate a signature, which contains exactly the information necessary for
dispatch.
Expand Down Expand Up @@ -90,17 +90,15 @@ def from_callable(f: Callable, precedence: int = 0) -> "Signature":
def has_varargs(self) -> bool:
return self.varargs is not Missing

def __copy__(self):
def __copy__(self) -> Self:
cls = type(self)
copy = cls.__new__(cls)
for attr in self.__slots__:
setattr(copy, attr, getattr(self, attr))

copy.types = self.types
copy.varargs = self.varargs
copy.precedence = self.precedence
copy.is_faithful = self.is_faithful
return copy

def __rich_console__(self, console, options):
def __rich_console__(self, console, options) -> Segment:
yield Segment("Signature(")
show_comma = True
if self.types:
Expand All @@ -115,7 +113,7 @@ def __rich_console__(self, console, options):
yield Segment("precedence=" + repr(self.precedence))
yield Segment(")")

def __eq__(self, other):
def __eq__(self, other: Any) -> bool:
if isinstance(other, Signature):
return (
self.types,
Expand All @@ -131,7 +129,7 @@ def __eq__(self, other):
return False

def __hash__(self):
return multihash(Signature, *self.types, self.varargs)
return hash((Signature, *self.types, self.varargs))

def expand_varargs(self, n: int) -> Tuple[TypeHint, ...]:
"""Expand variable arguments.
Expand All @@ -148,7 +146,7 @@ def expand_varargs(self, n: int) -> Tuple[TypeHint, ...]:
else:
return self.types

def __le__(self, other) -> bool:
def __le__(self, other: "Signature") -> bool:
# If the number of types of the signatures are unequal, then the signature
# with the fewer number of types must be expanded using variable arguments.
if not (
Expand Down Expand Up @@ -226,7 +224,7 @@ def __le__(self, other) -> bool:
else:
return False

def match(self, values) -> bool:
def match(self, values: Tuple) -> bool:
"""Check whether values match the signature.
Args:
Expand Down Expand Up @@ -298,7 +296,7 @@ def compute_mismatches(self, values: Tuple) -> Tuple[Set[int], bool]:
return mismatches, varargs_matched


def inspect_signature(f) -> inspect.Signature:
def inspect_signature(f: Callable) -> inspect.Signature:
"""Wrapper of :func:`inspect.signature` which adds support for certain non-function
objects.
Expand Down Expand Up @@ -352,7 +350,7 @@ def _extract_signature(f: Callable, precedence: int = 0) -> Signature:

# Parse and resolve annotation.
if p.annotation is inspect.Parameter.empty:
annotation = typing.Any
annotation = Any
else:
annotation = resolve_type_hint(p.annotation)

Expand Down
12 changes: 9 additions & 3 deletions plum/util.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import abc
import sys
from typing import List, Sequence
import warnings
from typing import Hashable, List, Sequence

if sys.version_info.minor <= 8: # pragma: specific no cover 3.9 3.10 3.11
from typing import Callable
Expand All @@ -11,7 +12,6 @@
"Callable",
"TypeHint",
"Missing",
"multihash",
"Comparable",
"wrap_lambda",
"is_in_class",
Expand Down Expand Up @@ -47,7 +47,7 @@ def __init__(self):
raise TypeError("`Missing` cannot be instantiated.")


def multihash(*args):
def multihash(*args: Hashable) -> int:
"""Multi-argument order-sensitive hash.
Args:
Expand All @@ -56,6 +56,12 @@ def multihash(*args):
Returns:
int: Hash.
"""
warnings.warn(
"The function `multihash` is deprecated and will be removed in a future "
"version. Please use `hash(tuple(*args))` instead.",
DeprecationWarning,
stacklevel=2,
)
return hash(args)


Expand Down

0 comments on commit 6531b99

Please sign in to comment.