Skip to content

Commit e878207

Browse files
committed
Fiat lux, inline validation
1 parent c9a1f1a commit e878207

File tree

1 file changed

+25
-26
lines changed

1 file changed

+25
-26
lines changed

Lib/functools.py

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -888,41 +888,23 @@ def _find_impl(cls, registry):
888888
match = t
889889
return registry.get(match)
890890

891-
def _get_dispatch_param(func, *, pos=0):
891+
def _get_positional_param(func, *, pos=0):
892892
if isinstance(func, (MethodType, classmethod, staticmethod)):
893893
func = func.__func__
894-
if isinstance(func, FunctionType):
894+
if isinstance(func, FunctionType) and not hasattr(func, "__wrapped__"):
895895
func_code = func.__code__
896896
try:
897897
return func_code.co_varnames[:func_code.co_argcount][pos]
898898
except IndexError:
899899
pass
900+
# Fallback path for ambiguous callables.
901+
# Follows __wrapped__, checks __signature__, __text_signature__, etc.
900902
import inspect
901903
for insp_param in list(inspect.signature(func).parameters.values())[pos:]:
902-
if insp_param.KEYWORD_ONLY or insp_param.VAR_KEYWORD:
904+
if insp_param.kind in (insp_param.KEYWORD_ONLY, insp_param.VAR_KEYWORD):
903905
break
904906
return insp_param.name
905-
raise TypeError(
906-
f"Invalid first argument to `register()`: {func!r}"
907-
f"does not accept positional arguments."
908-
) from None
909-
910-
def _get_dispatch_annotation(func, param):
911-
import annotationlib, typing
912-
annotations = typing.get_type_hints(func, format=annotationlib.Format.FORWARDREF)
913-
try:
914-
fwdref_or_typeform = annotations[param]
915-
except KeyError:
916-
raise TypeError(
917-
f"Invalid first argument to `register()`: {param!r}. "
918-
f"Add missing annotation to parameter {param!r} of {func!r} "
919-
f"or use `@register(some_class)`."
920-
) from None
921-
return fwdref_or_typeform
922-
923-
def _get_dispatch_arg_from_annotations(func, *, pos=0):
924-
param = _get_dispatch_param(func, pos=pos)
925-
return param, _get_dispatch_annotation(func, param)
907+
return None
926908

927909
def singledispatch(func):
928910
"""Single-dispatch generic function decorator.
@@ -998,9 +980,26 @@ def register(cls, func=None, _func_is_method=False):
998980

999981
# 0 for functions, 1 for methods where first argument should be skipped
1000982
argpos = _func_is_method and not isinstance(func, staticmethod)
1001-
argname, cls = _get_dispatch_arg_from_annotations(func, pos=argpos)
1002983

1003-
from annotationlib import ForwardRef
984+
argname = _get_positional_param(func, pos=argpos)
985+
if argname is None:
986+
raise TypeError(
987+
f"Invalid first argument to `register()`: {func!r} "
988+
f"does not accept positional arguments."
989+
) from None
990+
991+
from annotationlib import Format, ForwardRef
992+
import typing
993+
annotations = typing.get_type_hints(func, format=Format.FORWARDREF)
994+
995+
try:
996+
cls = annotations[argname]
997+
except KeyError:
998+
raise TypeError(
999+
f"Invalid first argument to `register()`: {func!r}. "
1000+
f"Add missing type annotation to parameter {argname!r} "
1001+
"of this function or use `@register(some_class)`."
1002+
) from None
10041003

10051004
if not _is_valid_dispatch_type(cls):
10061005
if isinstance(cls, UnionType):

0 commit comments

Comments
 (0)