mirror of
https://github.com/python/cpython.git
synced 2025-10-19 16:03:42 +00:00
Merge 041ceaa1fb
into bad8d6de37
This commit is contained in:
commit
cd44b69c35
3 changed files with 47 additions and 11 deletions
|
@ -935,6 +935,32 @@ def _is_valid_dispatch_type(cls):
|
||||||
return (isinstance(cls, UnionType) and
|
return (isinstance(cls, UnionType) and
|
||||||
all(isinstance(arg, type) for arg in cls.__args__))
|
all(isinstance(arg, type) for arg in cls.__args__))
|
||||||
|
|
||||||
|
def _get_func_type_hints(func):
|
||||||
|
"""Called when type hints are needed to choose the first argument to dispatch on."""
|
||||||
|
ann = getattr(func, '__annotate__', None)
|
||||||
|
if ann is None:
|
||||||
|
raise TypeError(
|
||||||
|
f"Invalid first argument to `register()`: {func!r}. "
|
||||||
|
f"Use either `@register(some_class)` or plain `@register` "
|
||||||
|
f"on an annotated function."
|
||||||
|
)
|
||||||
|
|
||||||
|
# only import typing if annotation parsing is necessary
|
||||||
|
from typing import get_type_hints
|
||||||
|
from annotationlib import Format
|
||||||
|
|
||||||
|
type_hints = get_type_hints(func, format=Format.FORWARDREF)
|
||||||
|
type_hints.pop("return", None) # don't dispatch on return types
|
||||||
|
|
||||||
|
if not type_hints:
|
||||||
|
raise TypeError(
|
||||||
|
f"Invalid first argument to `register()`: {func!r}. "
|
||||||
|
f"Use either `@register(some_class)` or plain `@register` "
|
||||||
|
f"on a function with annotated parameters."
|
||||||
|
)
|
||||||
|
|
||||||
|
return type_hints
|
||||||
|
|
||||||
def register(cls, func=None):
|
def register(cls, func=None):
|
||||||
"""generic_func.register(cls, func) -> func
|
"""generic_func.register(cls, func) -> func
|
||||||
|
|
||||||
|
@ -951,20 +977,14 @@ def register(cls, func=None):
|
||||||
f"Invalid first argument to `register()`. "
|
f"Invalid first argument to `register()`. "
|
||||||
f"{cls!r} is not a class or union type."
|
f"{cls!r} is not a class or union type."
|
||||||
)
|
)
|
||||||
ann = getattr(cls, '__annotate__', None)
|
|
||||||
if ann is None:
|
|
||||||
raise TypeError(
|
|
||||||
f"Invalid first argument to `register()`: {cls!r}. "
|
|
||||||
f"Use either `@register(some_class)` or plain `@register` "
|
|
||||||
f"on an annotated function."
|
|
||||||
)
|
|
||||||
func = cls
|
func = cls
|
||||||
|
type_hints = _get_func_type_hints(func)
|
||||||
|
|
||||||
|
argname, cls = next(iter(type_hints.items()))
|
||||||
|
|
||||||
# only import typing if annotation parsing is necessary
|
|
||||||
from typing import get_type_hints
|
|
||||||
from annotationlib import Format, ForwardRef
|
|
||||||
argname, cls = next(iter(get_type_hints(func, format=Format.FORWARDREF).items()))
|
|
||||||
if not _is_valid_dispatch_type(cls):
|
if not _is_valid_dispatch_type(cls):
|
||||||
|
from annotationlib import ForwardRef
|
||||||
|
|
||||||
if isinstance(cls, UnionType):
|
if isinstance(cls, UnionType):
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
f"Invalid annotation for {argname!r}. "
|
f"Invalid annotation for {argname!r}. "
|
||||||
|
|
|
@ -3180,6 +3180,18 @@ def _(arg):
|
||||||
)
|
)
|
||||||
self.assertEndsWith(str(exc.exception), msg_suffix)
|
self.assertEndsWith(str(exc.exception), msg_suffix)
|
||||||
|
|
||||||
|
with self.assertRaises(TypeError) as exc:
|
||||||
|
@i.register
|
||||||
|
def _(arg) -> str:
|
||||||
|
return "I only have a return type annotation"
|
||||||
|
self.assertStartsWith(str(exc.exception), msg_prefix +
|
||||||
|
"<function TestSingleDispatch.test_invalid_registrations.<locals>._"
|
||||||
|
)
|
||||||
|
self.assertEndsWith(str(exc.exception),
|
||||||
|
". Use either `@register(some_class)` or plain `@register` on "
|
||||||
|
"a function with annotated parameters."
|
||||||
|
)
|
||||||
|
|
||||||
with self.assertRaises(TypeError) as exc:
|
with self.assertRaises(TypeError) as exc:
|
||||||
@i.register
|
@i.register
|
||||||
def _(arg: typing.Iterable[str]):
|
def _(arg: typing.Iterable[str]):
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
A :exc:`TypeError` is raised by :py:func:`functools.singledispatch`
|
||||||
|
if it is attempted to register function that only annotates its return type.
|
||||||
|
|
||||||
|
Contributed by Bartosz Sławecki in :gh:`84644`.
|
Loading…
Add table
Add a link
Reference in a new issue