mirror of
https://github.com/python/cpython.git
synced 2025-08-04 17:08:35 +00:00
bpo-41559: Change PEP 612 implementation to pure Python (#25449)
This commit is contained in:
parent
c1a9535989
commit
859577c249
4 changed files with 92 additions and 71 deletions
|
@ -443,6 +443,18 @@ class _CallableGenericAlias(GenericAlias):
|
|||
ga_args = args
|
||||
return super().__new__(cls, origin, ga_args)
|
||||
|
||||
@property
|
||||
def __parameters__(self):
|
||||
params = []
|
||||
for arg in self.__args__:
|
||||
# Looks like a genericalias
|
||||
if hasattr(arg, "__parameters__") and isinstance(arg.__parameters__, tuple):
|
||||
params.extend(arg.__parameters__)
|
||||
else:
|
||||
if _is_typevarlike(arg):
|
||||
params.append(arg)
|
||||
return tuple(dict.fromkeys(params))
|
||||
|
||||
def __repr__(self):
|
||||
if _has_special_args(self.__args__):
|
||||
return super().__repr__()
|
||||
|
@ -458,16 +470,50 @@ class _CallableGenericAlias(GenericAlias):
|
|||
|
||||
def __getitem__(self, item):
|
||||
# Called during TypeVar substitution, returns the custom subclass
|
||||
# rather than the default types.GenericAlias object.
|
||||
ga = super().__getitem__(item)
|
||||
args = ga.__args__
|
||||
# args[0] occurs due to things like Z[[int, str, bool]] from PEP 612
|
||||
if not isinstance(ga.__args__[0], tuple):
|
||||
t_result = ga.__args__[-1]
|
||||
t_args = ga.__args__[:-1]
|
||||
args = (t_args, t_result)
|
||||
return _CallableGenericAlias(Callable, args)
|
||||
# rather than the default types.GenericAlias object. Most of the
|
||||
# code is copied from typing's _GenericAlias and the builtin
|
||||
# types.GenericAlias.
|
||||
|
||||
# A special case in PEP 612 where if X = Callable[P, int],
|
||||
# then X[int, str] == X[[int, str]].
|
||||
param_len = len(self.__parameters__)
|
||||
if param_len == 0:
|
||||
raise TypeError(f'There are no type or parameter specification'
|
||||
f'variables left in {self}')
|
||||
if (param_len == 1
|
||||
and isinstance(item, (tuple, list))
|
||||
and len(item) > 1) or not isinstance(item, tuple):
|
||||
item = (item,)
|
||||
item_len = len(item)
|
||||
if item_len != param_len:
|
||||
raise TypeError(f'Too {"many" if item_len > param_len else "few"}'
|
||||
f' arguments for {self};'
|
||||
f' actual {item_len}, expected {param_len}')
|
||||
subst = dict(zip(self.__parameters__, item))
|
||||
new_args = []
|
||||
for arg in self.__args__:
|
||||
if _is_typevarlike(arg):
|
||||
arg = subst[arg]
|
||||
# Looks like a GenericAlias
|
||||
elif hasattr(arg, '__parameters__') and isinstance(arg.__parameters__, tuple):
|
||||
subparams = arg.__parameters__
|
||||
if subparams:
|
||||
subargs = tuple(subst[x] for x in subparams)
|
||||
arg = arg[subargs]
|
||||
new_args.append(arg)
|
||||
|
||||
# args[0] occurs due to things like Z[[int, str, bool]] from PEP 612
|
||||
if not isinstance(new_args[0], (tuple, list)):
|
||||
t_result = new_args[-1]
|
||||
t_args = new_args[:-1]
|
||||
new_args = (t_args, t_result)
|
||||
return _CallableGenericAlias(Callable, tuple(new_args))
|
||||
|
||||
def _is_typevarlike(arg):
|
||||
obj = type(arg)
|
||||
# looks like a TypeVar/ParamSpec
|
||||
return (obj.__module__ == 'typing'
|
||||
and obj.__name__ in {'ParamSpec', 'TypeVar'})
|
||||
|
||||
def _has_special_args(args):
|
||||
"""Checks if args[0] matches either ``...``, ``ParamSpec`` or
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue