mirror of https://github.com/python/cpython.git
[3.11] gh-91162: Fix substitution of unpacked tuples in generic aliases (GH-92335) (#92484)
* gh-91162: Fix substitution of unpacked tuples in generic aliases (GH-92335)
(cherry picked from commit 9d25db9db1
)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
* Regenerate ABI file
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: Pablo Galindo <pablogsal@gmail.com>
This commit is contained in:
parent
b425d887aa
commit
00f8fe9564
File diff suppressed because it is too large
Load Diff
|
@ -201,8 +201,9 @@ struct _Py_global_strings {
|
||||||
STRUCT_FOR_ID(__subclasshook__)
|
STRUCT_FOR_ID(__subclasshook__)
|
||||||
STRUCT_FOR_ID(__truediv__)
|
STRUCT_FOR_ID(__truediv__)
|
||||||
STRUCT_FOR_ID(__trunc__)
|
STRUCT_FOR_ID(__trunc__)
|
||||||
|
STRUCT_FOR_ID(__typing_is_unpacked_typevartuple__)
|
||||||
STRUCT_FOR_ID(__typing_subst__)
|
STRUCT_FOR_ID(__typing_subst__)
|
||||||
STRUCT_FOR_ID(__typing_unpacked__)
|
STRUCT_FOR_ID(__typing_unpacked_tuple_args__)
|
||||||
STRUCT_FOR_ID(__warningregistry__)
|
STRUCT_FOR_ID(__warningregistry__)
|
||||||
STRUCT_FOR_ID(__weakref__)
|
STRUCT_FOR_ID(__weakref__)
|
||||||
STRUCT_FOR_ID(__xor__)
|
STRUCT_FOR_ID(__xor__)
|
||||||
|
|
|
@ -824,8 +824,9 @@ extern "C" {
|
||||||
INIT_ID(__subclasshook__), \
|
INIT_ID(__subclasshook__), \
|
||||||
INIT_ID(__truediv__), \
|
INIT_ID(__truediv__), \
|
||||||
INIT_ID(__trunc__), \
|
INIT_ID(__trunc__), \
|
||||||
|
INIT_ID(__typing_is_unpacked_typevartuple__), \
|
||||||
INIT_ID(__typing_subst__), \
|
INIT_ID(__typing_subst__), \
|
||||||
INIT_ID(__typing_unpacked__), \
|
INIT_ID(__typing_unpacked_tuple_args__), \
|
||||||
INIT_ID(__warningregistry__), \
|
INIT_ID(__warningregistry__), \
|
||||||
INIT_ID(__weakref__), \
|
INIT_ID(__weakref__), \
|
||||||
INIT_ID(__xor__), \
|
INIT_ID(__xor__), \
|
||||||
|
|
|
@ -603,22 +603,10 @@ class C(Generic[T]): pass
|
||||||
('generic[T]', '[int]', 'generic[int]'),
|
('generic[T]', '[int]', 'generic[int]'),
|
||||||
('generic[T]', '[int, str]', 'TypeError'),
|
('generic[T]', '[int, str]', 'TypeError'),
|
||||||
('generic[T]', '[tuple_type[int, ...]]', 'generic[tuple_type[int, ...]]'),
|
('generic[T]', '[tuple_type[int, ...]]', 'generic[tuple_type[int, ...]]'),
|
||||||
# Should raise TypeError: a) according to the tentative spec,
|
('generic[T]', '[*tuple_type[int]]', 'generic[int]'),
|
||||||
# unpacked types cannot be used as arguments to aliases that expect
|
('generic[T]', '[*tuple_type[()]]', 'TypeError'),
|
||||||
# a fixed number of arguments; b) it's equivalent to generic[()].
|
('generic[T]', '[*tuple_type[int, str]]', 'TypeError'),
|
||||||
('generic[T]', '[*tuple[()]]', 'generic[*tuple[()]]'),
|
('generic[T]', '[*tuple_type[int, ...]]', 'TypeError'),
|
||||||
('generic[T]', '[*Tuple[()]]', 'TypeError'),
|
|
||||||
# Should raise TypeError according to the tentative spec: unpacked
|
|
||||||
# types cannot be used as arguments to aliases that expect a fixed
|
|
||||||
# number of arguments.
|
|
||||||
('generic[T]', '[*tuple[int]]', 'generic[*tuple[int]]'),
|
|
||||||
('generic[T]', '[*Tuple[int]]', 'TypeError'),
|
|
||||||
# Ditto.
|
|
||||||
('generic[T]', '[*tuple[int, str]]', 'generic[*tuple[int, str]]'),
|
|
||||||
('generic[T]', '[*Tuple[int, str]]', 'TypeError'),
|
|
||||||
# Ditto.
|
|
||||||
('generic[T]', '[*tuple[int, ...]]', 'generic[*tuple[int, ...]]'),
|
|
||||||
('generic[T]', '[*Tuple[int, ...]]', 'TypeError'),
|
|
||||||
('generic[T]', '[*Ts]', 'TypeError'),
|
('generic[T]', '[*Ts]', 'TypeError'),
|
||||||
('generic[T]', '[T, *Ts]', 'TypeError'),
|
('generic[T]', '[T, *Ts]', 'TypeError'),
|
||||||
('generic[T]', '[*Ts, T]', 'TypeError'),
|
('generic[T]', '[*Ts, T]', 'TypeError'),
|
||||||
|
@ -664,23 +652,29 @@ class C(Generic[T1, T2]): pass
|
||||||
('generic[T1, T2]', '[int, str]', 'generic[int, str]'),
|
('generic[T1, T2]', '[int, str]', 'generic[int, str]'),
|
||||||
('generic[T1, T2]', '[int, str, bool]', 'TypeError'),
|
('generic[T1, T2]', '[int, str, bool]', 'TypeError'),
|
||||||
('generic[T1, T2]', '[*tuple_type[int]]', 'TypeError'),
|
('generic[T1, T2]', '[*tuple_type[int]]', 'TypeError'),
|
||||||
('generic[T1, T2]', '[*tuple_type[int, str]]', 'TypeError'),
|
('generic[T1, T2]', '[*tuple_type[int, str]]', 'generic[int, str]'),
|
||||||
('generic[T1, T2]', '[*tuple_type[int, str, bool]]', 'TypeError'),
|
('generic[T1, T2]', '[*tuple_type[int, str, bool]]', 'TypeError'),
|
||||||
|
|
||||||
# Should raise TypeError according to the tentative spec: unpacked
|
('generic[T1, T2]', '[int, *tuple_type[str]]', 'generic[int, str]'),
|
||||||
# types cannot be used as arguments to aliases that expect a fixed
|
('generic[T1, T2]', '[*tuple_type[int], str]', 'generic[int, str]'),
|
||||||
# number of arguments.
|
('generic[T1, T2]', '[*tuple_type[int], *tuple_type[str]]', 'generic[int, str]'),
|
||||||
('generic[T1, T2]', '[*tuple[int, str], *tuple[float, bool]]', 'generic[*tuple[int, str], *tuple[float, bool]]'),
|
('generic[T1, T2]', '[*tuple_type[int, str], *tuple_type[()]]', 'generic[int, str]'),
|
||||||
('generic[T1, T2]', '[*Tuple[int, str], *Tuple[float, bool]]', 'TypeError'),
|
('generic[T1, T2]', '[*tuple_type[()], *tuple_type[int, str]]', 'generic[int, str]'),
|
||||||
|
('generic[T1, T2]', '[*tuple_type[int], *tuple_type[()]]', 'TypeError'),
|
||||||
|
('generic[T1, T2]', '[*tuple_type[()], *tuple_type[int]]', 'TypeError'),
|
||||||
|
('generic[T1, T2]', '[*tuple_type[int, str], *tuple_type[float]]', 'TypeError'),
|
||||||
|
('generic[T1, T2]', '[*tuple_type[int], *tuple_type[str, float]]', 'TypeError'),
|
||||||
|
('generic[T1, T2]', '[*tuple_type[int, str], *tuple_type[float, bool]]', 'TypeError'),
|
||||||
|
|
||||||
('generic[T1, T2]', '[tuple_type[int, ...]]', 'TypeError'),
|
('generic[T1, T2]', '[tuple_type[int, ...]]', 'TypeError'),
|
||||||
('generic[T1, T2]', '[tuple_type[int, ...], tuple_type[str, ...]]', 'generic[tuple_type[int, ...], tuple_type[str, ...]]'),
|
('generic[T1, T2]', '[tuple_type[int, ...], tuple_type[str, ...]]', 'generic[tuple_type[int, ...], tuple_type[str, ...]]'),
|
||||||
|
# Should raise TypeError according to the tentative spec: unpacked
|
||||||
|
# types cannot be used as arguments to aliases that expect a fixed
|
||||||
|
# number of arguments.
|
||||||
('generic[T1, T2]', '[*tuple_type[int, ...]]', 'TypeError'),
|
('generic[T1, T2]', '[*tuple_type[int, ...]]', 'TypeError'),
|
||||||
|
('generic[T1, T2]', '[int, *tuple_type[str, ...]]', 'TypeError'),
|
||||||
# Ditto.
|
('generic[T1, T2]', '[*tuple_type[int, ...], str]', 'TypeError'),
|
||||||
('generic[T1, T2]', '[*tuple[int, ...], *tuple[str, ...]]', 'generic[*tuple[int, ...], *tuple[str, ...]]'),
|
('generic[T1, T2]', '[*tuple_type[int, ...], *tuple_type[str, ...]]', 'TypeError'),
|
||||||
('generic[T1, T2]', '[*Tuple[int, ...], *Tuple[str, ...]]', 'TypeError'),
|
|
||||||
|
|
||||||
('generic[T1, T2]', '[*Ts]', 'TypeError'),
|
('generic[T1, T2]', '[*Ts]', 'TypeError'),
|
||||||
('generic[T1, T2]', '[T, *Ts]', 'TypeError'),
|
('generic[T1, T2]', '[T, *Ts]', 'TypeError'),
|
||||||
('generic[T1, T2]', '[*Ts, T]', 'TypeError'),
|
('generic[T1, T2]', '[*Ts, T]', 'TypeError'),
|
||||||
|
@ -720,7 +714,7 @@ class C(Generic[T1, T2, T3]): pass
|
||||||
tests = [
|
tests = [
|
||||||
# Alias # Args # Expected result
|
# Alias # Args # Expected result
|
||||||
('generic[T1, bool, T2]', '[int, str]', 'generic[int, bool, str]'),
|
('generic[T1, bool, T2]', '[int, str]', 'generic[int, bool, str]'),
|
||||||
('generic[T1, bool, T2]', '[*tuple_type[int, str]]', 'TypeError'),
|
('generic[T1, bool, T2]', '[*tuple_type[int, str]]', 'generic[int, bool, str]'),
|
||||||
]
|
]
|
||||||
|
|
||||||
for alias_template, args_template, expected_template in tests:
|
for alias_template, args_template, expected_template in tests:
|
||||||
|
@ -753,96 +747,43 @@ class C(Generic[*Ts]): pass
|
||||||
# Tuple because tuple currently behaves differently.
|
# Tuple because tuple currently behaves differently.
|
||||||
tests = [
|
tests = [
|
||||||
# Alias # Args # Expected result
|
# Alias # Args # Expected result
|
||||||
('C[*Ts]', '[()]', 'C[()]'),
|
('generic[*Ts]', '[()]', 'generic[()]'),
|
||||||
('tuple[*Ts]', '[()]', 'tuple[()]'),
|
('generic[*Ts]', '[int]', 'generic[int]'),
|
||||||
('Tuple[*Ts]', '[()]', 'Tuple[()]'),
|
('generic[*Ts]', '[int, str]', 'generic[int, str]'),
|
||||||
|
('generic[*Ts]', '[*tuple_type[int]]', 'generic[int]'),
|
||||||
('C[*Ts]', '[int]', 'C[int]'),
|
('generic[*Ts]', '[*tuple_type[*Ts]]', 'generic[*Ts]'),
|
||||||
('tuple[*Ts]', '[int]', 'tuple[int]'),
|
('generic[*Ts]', '[*tuple_type[int, str]]', 'generic[int, str]'),
|
||||||
('Tuple[*Ts]', '[int]', 'Tuple[int]'),
|
('generic[*Ts]', '[tuple_type[int, ...]]', 'generic[tuple_type[int, ...]]'),
|
||||||
|
('generic[*Ts]', '[tuple_type[int, ...], tuple_type[str, ...]]', 'generic[tuple_type[int, ...], tuple_type[str, ...]]'),
|
||||||
('C[*Ts]', '[int, str]', 'C[int, str]'),
|
('generic[*Ts]', '[*tuple_type[int, ...]]', 'generic[*tuple_type[int, ...]]'),
|
||||||
('tuple[*Ts]', '[int, str]', 'tuple[int, str]'),
|
|
||||||
('Tuple[*Ts]', '[int, str]', 'Tuple[int, str]'),
|
|
||||||
|
|
||||||
('C[*Ts]', '[*tuple_type[int]]', 'C[*tuple_type[int]]'), # Should be C[int]
|
|
||||||
('tuple[*Ts]', '[*tuple_type[int]]', 'tuple[*tuple_type[int]]'), # Should be tuple[int]
|
|
||||||
('Tuple[*Ts]', '[*tuple_type[int]]', 'Tuple[*tuple_type[int]]'), # Should be Tuple[int]
|
|
||||||
|
|
||||||
('C[*Ts]', '[*tuple_type[*Ts]]', 'C[*tuple_type[*Ts]]'), # Should be C[*Ts]
|
|
||||||
('tuple[*Ts]', '[*tuple_type[*Ts]]', 'tuple[*tuple_type[*Ts]]'), # Should be tuple[*Ts]
|
|
||||||
('Tuple[*Ts]', '[*tuple_type[*Ts]]', 'Tuple[*tuple_type[*Ts]]'), # Should be Tuple[*Ts]
|
|
||||||
|
|
||||||
('C[*Ts]', '[*tuple_type[int, str]]', 'C[*tuple_type[int, str]]'), # Should be C[int, str]
|
|
||||||
('tuple[*Ts]', '[*tuple_type[int, str]]', 'tuple[*tuple_type[int, str]]'), # Should be tuple[int, str]
|
|
||||||
('Tuple[*Ts]', '[*tuple_type[int, str]]', 'Tuple[*tuple_type[int, str]]'), # Should be Tuple[int, str]
|
|
||||||
|
|
||||||
('C[*Ts]', '[tuple_type[int, ...]]', 'C[tuple_type[int, ...]]'),
|
|
||||||
('tuple[*Ts]', '[tuple_type[int, ...]]', 'tuple[tuple_type[int, ...]]'),
|
|
||||||
('Tuple[*Ts]', '[tuple_type[int, ...]]', 'Tuple[tuple_type[int, ...]]'),
|
|
||||||
|
|
||||||
('C[*Ts]', '[tuple_type[int, ...], tuple_type[str, ...]]', 'C[tuple_type[int, ...], tuple_type[str, ...]]'),
|
|
||||||
('tuple[*Ts]', '[tuple_type[int, ...], tuple_type[str, ...]]', 'tuple[tuple_type[int, ...], tuple_type[str, ...]]'),
|
|
||||||
('Tuple[*Ts]', '[tuple_type[int, ...], tuple_type[str, ...]]', 'Tuple[tuple_type[int, ...], tuple_type[str, ...]]'),
|
|
||||||
|
|
||||||
('C[*Ts]', '[*tuple_type[int, ...]]', 'C[*tuple_type[int, ...]]'),
|
|
||||||
('tuple[*Ts]', '[*tuple_type[int, ...]]', 'tuple[*tuple_type[int, ...]]'),
|
|
||||||
('Tuple[*Ts]', '[*tuple_type[int, ...]]', 'Tuple[*tuple_type[int, ...]]'),
|
|
||||||
|
|
||||||
# Technically, multiple unpackings are forbidden by PEP 646, but we
|
# Technically, multiple unpackings are forbidden by PEP 646, but we
|
||||||
# choose to be less restrictive at runtime, to allow folks room
|
# choose to be less restrictive at runtime, to allow folks room
|
||||||
# to experiment. So all three of these should be valid.
|
# to experiment. So all three of these should be valid.
|
||||||
('C[*Ts]', '[*tuple_type[int, ...], *tuple_type[str, ...]]', 'C[*tuple_type[int, ...], *tuple_type[str, ...]]'),
|
('generic[*Ts]', '[*tuple_type[int, ...], *tuple_type[str, ...]]', 'generic[*tuple_type[int, ...], *tuple_type[str, ...]]'),
|
||||||
('tuple[*Ts]', '[*tuple_type[int, ...], *tuple_type[str, ...]]', 'tuple[*tuple_type[int, ...], *tuple_type[str, ...]]'),
|
|
||||||
('Tuple[*Ts]', '[*tuple_type[int, ...], *tuple_type[str, ...]]', 'Tuple[*tuple_type[int, ...], *tuple_type[str, ...]]'),
|
|
||||||
|
|
||||||
('C[*Ts]', '[*Ts]', 'C[*Ts]'),
|
('generic[*Ts]', '[*Ts]', 'generic[*Ts]'),
|
||||||
('tuple[*Ts]', '[*Ts]', 'tuple[*Ts]'),
|
('generic[*Ts]', '[T, *Ts]', 'generic[T, *Ts]'),
|
||||||
('Tuple[*Ts]', '[*Ts]', 'Tuple[*Ts]'),
|
('generic[*Ts]', '[*Ts, T]', 'generic[*Ts, T]'),
|
||||||
|
('generic[T, *Ts]', '[int]', 'generic[int]'),
|
||||||
|
('generic[T, *Ts]', '[int, str]', 'generic[int, str]'),
|
||||||
|
('generic[T, *Ts]', '[int, str, bool]', 'generic[int, str, bool]'),
|
||||||
|
|
||||||
('C[*Ts]', '[T, *Ts]', 'C[T, *Ts]'),
|
('generic[T, *Ts]', '[*tuple[int, ...]]', 'TypeError'), # Should be generic[int, *tuple[int, ...]]
|
||||||
('tuple[*Ts]', '[T, *Ts]', 'tuple[T, *Ts]'),
|
|
||||||
('Tuple[*Ts]', '[T, *Ts]', 'Tuple[T, *Ts]'),
|
|
||||||
|
|
||||||
('C[*Ts]', '[*Ts, T]', 'C[*Ts, T]'),
|
('generic[*Ts, T]', '[int]', 'generic[int]'),
|
||||||
('tuple[*Ts]', '[*Ts, T]', 'tuple[*Ts, T]'),
|
('generic[*Ts, T]', '[int, str]', 'generic[int, str]'),
|
||||||
('Tuple[*Ts]', '[*Ts, T]', 'Tuple[*Ts, T]'),
|
('generic[*Ts, T]', '[int, str, bool]', 'generic[int, str, bool]'),
|
||||||
|
|
||||||
('C[T, *Ts]', '[int]', 'C[int]'),
|
|
||||||
('tuple[T, *Ts]', '[int]', 'tuple[int]'),
|
|
||||||
('Tuple[T, *Ts]', '[int]', 'Tuple[int]'),
|
|
||||||
|
|
||||||
('C[T, *Ts]', '[int, str]', 'C[int, str]'),
|
|
||||||
('tuple[T, *Ts]', '[int, str]', 'tuple[int, str]'),
|
|
||||||
('Tuple[T, *Ts]', '[int, str]', 'Tuple[int, str]'),
|
|
||||||
|
|
||||||
('C[T, *Ts]', '[int, str, bool]', 'C[int, str, bool]'),
|
|
||||||
('tuple[T, *Ts]', '[int, str, bool]', 'tuple[int, str, bool]'),
|
|
||||||
('Tuple[T, *Ts]', '[int, str, bool]', 'Tuple[int, str, bool]'),
|
|
||||||
|
|
||||||
('C[T, *Ts]', '[*tuple[int, ...]]', 'C[*tuple[int, ...]]'), # Should be C[int, *tuple[int, ...]]
|
|
||||||
('C[T, *Ts]', '[*Tuple[int, ...]]', 'TypeError'), # Ditto
|
|
||||||
('tuple[T, *Ts]', '[*tuple[int, ...]]', 'tuple[*tuple[int, ...]]'), # Should be tuple[int, *tuple[int, ...]]
|
|
||||||
('tuple[T, *Ts]', '[*Tuple[int, ...]]', 'TypeError'), # Should be tuple[int, *Tuple[int, ...]]
|
|
||||||
('Tuple[T, *Ts]', '[*tuple[int, ...]]', 'Tuple[*tuple[int, ...]]'), # Should be Tuple[int, *tuple[int, ...]]
|
|
||||||
('Tuple[T, *Ts]', '[*Tuple[int, ...]]', 'TypeError'), # Should be Tuple[int, *Tuple[int, ...]]
|
|
||||||
|
|
||||||
('C[*Ts, T]', '[int]', 'C[int]'),
|
|
||||||
('tuple[*Ts, T]', '[int]', 'tuple[int]'),
|
|
||||||
('Tuple[*Ts, T]', '[int]', 'Tuple[int]'),
|
|
||||||
|
|
||||||
('C[*Ts, T]', '[int, str]', 'C[int, str]'),
|
|
||||||
('tuple[*Ts, T]', '[int, str]', 'tuple[int, str]'),
|
|
||||||
('Tuple[*Ts, T]', '[int, str]', 'Tuple[int, str]'),
|
|
||||||
|
|
||||||
('C[*Ts, T]', '[int, str, bool]', 'C[int, str, bool]'),
|
|
||||||
('tuple[*Ts, T]', '[int, str, bool]', 'tuple[int, str, bool]'),
|
|
||||||
('Tuple[*Ts, T]', '[int, str, bool]', 'Tuple[int, str, bool]'),
|
|
||||||
|
|
||||||
('generic[T, *tuple_type[int, ...]]', '[str]', 'generic[str, *tuple_type[int, ...]]'),
|
('generic[T, *tuple_type[int, ...]]', '[str]', 'generic[str, *tuple_type[int, ...]]'),
|
||||||
('generic[T1, T2, *tuple_type[int, ...]]', '[str, bool]', 'generic[str, bool, *tuple_type[int, ...]]'),
|
('generic[T1, T2, *tuple_type[int, ...]]', '[str, bool]', 'generic[str, bool, *tuple_type[int, ...]]'),
|
||||||
('generic[T1, *tuple_type[int, ...], T2]', '[str, bool]', 'generic[str, *tuple_type[int, ...], bool]'),
|
('generic[T1, *tuple_type[int, ...], T2]', '[str, bool]', 'generic[str, *tuple_type[int, ...], bool]'),
|
||||||
('generic[T1, *tuple_type[int, ...], T2]', '[str, bool, float]', 'TypeError'),
|
('generic[T1, *tuple_type[int, ...], T2]', '[str, bool, float]', 'TypeError'),
|
||||||
|
|
||||||
|
('generic[T1, *tuple_type[T2, ...]]', '[int, str]', 'generic[int, *tuple_type[str, ...]]'),
|
||||||
|
('generic[*tuple_type[T1, ...], T2]', '[int, str]', 'generic[*tuple_type[int, ...], str]'),
|
||||||
|
('generic[T1, *tuple_type[generic[*Ts], ...]]', '[int, str, bool]', 'generic[int, *tuple_type[generic[str, bool], ...]]'),
|
||||||
|
('generic[*tuple_type[generic[*Ts], ...], T1]', '[int, str, bool]', 'generic[*tuple_type[generic[int, str], ...], bool]'),
|
||||||
]
|
]
|
||||||
|
|
||||||
for alias_template, args_template, expected_template in tests:
|
for alias_template, args_template, expected_template in tests:
|
||||||
|
|
|
@ -271,6 +271,16 @@ def _check_generic(cls, parameters, elen):
|
||||||
raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments for {cls};"
|
raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments for {cls};"
|
||||||
f" actual {alen}, expected {elen}")
|
f" actual {alen}, expected {elen}")
|
||||||
|
|
||||||
|
def _unpack_args(args):
|
||||||
|
newargs = []
|
||||||
|
for arg in args:
|
||||||
|
subargs = getattr(arg, '__typing_unpacked_tuple_args__', None)
|
||||||
|
if subargs is not None and not (subargs and subargs[-1] is ...):
|
||||||
|
newargs.extend(subargs)
|
||||||
|
else:
|
||||||
|
newargs.append(arg)
|
||||||
|
return newargs
|
||||||
|
|
||||||
def _prepare_paramspec_params(cls, params):
|
def _prepare_paramspec_params(cls, params):
|
||||||
"""Prepares the parameters for a Generic containing ParamSpec
|
"""Prepares the parameters for a Generic containing ParamSpec
|
||||||
variables (internal helper).
|
variables (internal helper).
|
||||||
|
@ -893,12 +903,8 @@ def __repr__(self):
|
||||||
|
|
||||||
|
|
||||||
def _is_unpacked_typevartuple(x: Any) -> bool:
|
def _is_unpacked_typevartuple(x: Any) -> bool:
|
||||||
return (
|
return ((not isinstance(x, type)) and
|
||||||
isinstance(x, _UnpackGenericAlias)
|
getattr(x, '__typing_is_unpacked_typevartuple__', False))
|
||||||
# If x is Unpack[tuple[...]], __parameters__ will be empty.
|
|
||||||
and x.__parameters__
|
|
||||||
and isinstance(x.__parameters__[0], TypeVarTuple)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _is_typevar_like(x: Any) -> bool:
|
def _is_typevar_like(x: Any) -> bool:
|
||||||
|
@ -1011,7 +1017,8 @@ def __init__(self, name, *constraints, bound=None,
|
||||||
def __typing_subst__(self, arg):
|
def __typing_subst__(self, arg):
|
||||||
msg = "Parameters to generic types must be types."
|
msg = "Parameters to generic types must be types."
|
||||||
arg = _type_check(arg, msg, is_argument=True)
|
arg = _type_check(arg, msg, is_argument=True)
|
||||||
if (isinstance(arg, _GenericAlias) and arg.__origin__ is Unpack):
|
if ((isinstance(arg, _GenericAlias) and arg.__origin__ is Unpack) or
|
||||||
|
(isinstance(arg, GenericAlias) and getattr(arg, '__unpacked__', False))):
|
||||||
raise TypeError(f"{arg} is not valid as type argument")
|
raise TypeError(f"{arg} is not valid as type argument")
|
||||||
return arg
|
return arg
|
||||||
|
|
||||||
|
@ -1370,19 +1377,17 @@ def __getitem__(self, args):
|
||||||
if self.__origin__ in (Generic, Protocol):
|
if self.__origin__ in (Generic, Protocol):
|
||||||
# Can't subscript Generic[...] or Protocol[...].
|
# Can't subscript Generic[...] or Protocol[...].
|
||||||
raise TypeError(f"Cannot subscript already-subscripted {self}")
|
raise TypeError(f"Cannot subscript already-subscripted {self}")
|
||||||
|
if not self.__parameters__:
|
||||||
|
raise TypeError(f"{self} is not a generic class")
|
||||||
|
|
||||||
# Preprocess `args`.
|
# Preprocess `args`.
|
||||||
if not isinstance(args, tuple):
|
if not isinstance(args, tuple):
|
||||||
args = (args,)
|
args = (args,)
|
||||||
args = tuple(_type_convert(p) for p in args)
|
args = tuple(_type_convert(p) for p in args)
|
||||||
|
args = _unpack_args(args)
|
||||||
if (self._paramspec_tvars
|
if (self._paramspec_tvars
|
||||||
and any(isinstance(t, ParamSpec) for t in self.__parameters__)):
|
and any(isinstance(t, ParamSpec) for t in self.__parameters__)):
|
||||||
args = _prepare_paramspec_params(self, args)
|
args = _prepare_paramspec_params(self, args)
|
||||||
elif not any(isinstance(p, TypeVarTuple) for p in self.__parameters__):
|
|
||||||
# We only run this if there are no TypeVarTuples, because we
|
|
||||||
# don't check variadic generic arity at runtime (to reduce
|
|
||||||
# complexity of typing.py).
|
|
||||||
_check_generic(self, args, len(self.__parameters__))
|
|
||||||
|
|
||||||
new_args = self._determine_new_args(args)
|
new_args = self._determine_new_args(args)
|
||||||
r = self.copy_with(new_args)
|
r = self.copy_with(new_args)
|
||||||
|
@ -1406,16 +1411,28 @@ def _determine_new_args(self, args):
|
||||||
params = self.__parameters__
|
params = self.__parameters__
|
||||||
# In the example above, this would be {T3: str}
|
# In the example above, this would be {T3: str}
|
||||||
new_arg_by_param = {}
|
new_arg_by_param = {}
|
||||||
|
typevartuple_index = None
|
||||||
for i, param in enumerate(params):
|
for i, param in enumerate(params):
|
||||||
if isinstance(param, TypeVarTuple):
|
if isinstance(param, TypeVarTuple):
|
||||||
j = len(args) - (len(params) - i - 1)
|
if typevartuple_index is not None:
|
||||||
|
raise TypeError(f"More than one TypeVarTuple parameter in {self}")
|
||||||
|
typevartuple_index = i
|
||||||
|
|
||||||
|
alen = len(args)
|
||||||
|
plen = len(params)
|
||||||
|
if typevartuple_index is not None:
|
||||||
|
i = typevartuple_index
|
||||||
|
j = alen - (plen - i - 1)
|
||||||
if j < i:
|
if j < i:
|
||||||
raise TypeError(f"Too few arguments for {self}")
|
raise TypeError(f"Too few arguments for {self};"
|
||||||
|
f" actual {alen}, expected at least {plen-1}")
|
||||||
new_arg_by_param.update(zip(params[:i], args[:i]))
|
new_arg_by_param.update(zip(params[:i], args[:i]))
|
||||||
new_arg_by_param[param] = args[i: j]
|
new_arg_by_param[params[i]] = tuple(args[i: j])
|
||||||
new_arg_by_param.update(zip(params[i + 1:], args[j:]))
|
new_arg_by_param.update(zip(params[i + 1:], args[j:]))
|
||||||
break
|
|
||||||
else:
|
else:
|
||||||
|
if alen != plen:
|
||||||
|
raise TypeError(f"Too {'many' if alen > plen else 'few'} arguments for {self};"
|
||||||
|
f" actual {alen}, expected {plen}")
|
||||||
new_arg_by_param.update(zip(params, args))
|
new_arg_by_param.update(zip(params, args))
|
||||||
|
|
||||||
new_args = []
|
new_args = []
|
||||||
|
@ -1723,14 +1740,25 @@ def __repr__(self):
|
||||||
return '*' + repr(self.__args__[0])
|
return '*' + repr(self.__args__[0])
|
||||||
|
|
||||||
def __getitem__(self, args):
|
def __getitem__(self, args):
|
||||||
if self.__typing_unpacked__():
|
if self.__typing_is_unpacked_typevartuple__:
|
||||||
return args
|
return args
|
||||||
return super().__getitem__(args)
|
return super().__getitem__(args)
|
||||||
|
|
||||||
def __typing_unpacked__(self):
|
@property
|
||||||
# If x is Unpack[tuple[...]], __parameters__ will be empty.
|
def __typing_unpacked_tuple_args__(self):
|
||||||
return bool(self.__parameters__ and
|
assert self.__origin__ is Unpack
|
||||||
isinstance(self.__parameters__[0], TypeVarTuple))
|
assert len(self.__args__) == 1
|
||||||
|
arg, = self.__args__
|
||||||
|
if isinstance(arg, _GenericAlias):
|
||||||
|
assert arg.__origin__ is tuple
|
||||||
|
return arg.__args__
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def __typing_is_unpacked_typevartuple__(self):
|
||||||
|
assert self.__origin__ is Unpack
|
||||||
|
assert len(self.__args__) == 1
|
||||||
|
return isinstance(self.__args__[0], TypeVarTuple)
|
||||||
|
|
||||||
|
|
||||||
class Generic:
|
class Generic:
|
||||||
|
|
|
@ -320,20 +320,85 @@ subs_tvars(PyObject *obj, PyObject *params,
|
||||||
static int
|
static int
|
||||||
_is_unpacked_typevartuple(PyObject *arg)
|
_is_unpacked_typevartuple(PyObject *arg)
|
||||||
{
|
{
|
||||||
PyObject *meth;
|
PyObject *tmp;
|
||||||
int res = _PyObject_LookupAttr(arg, &_Py_ID(__typing_unpacked__), &meth);
|
if (PyType_Check(arg)) { // TODO: Add test
|
||||||
if (res > 0) {
|
return 0;
|
||||||
PyObject *tmp = PyObject_CallNoArgs(meth);
|
|
||||||
Py_DECREF(meth);
|
|
||||||
if (tmp == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
int res = _PyObject_LookupAttr(arg, &_Py_ID(__typing_is_unpacked_typevartuple__), &tmp);
|
||||||
|
if (res > 0) {
|
||||||
res = PyObject_IsTrue(tmp);
|
res = PyObject_IsTrue(tmp);
|
||||||
Py_DECREF(tmp);
|
Py_DECREF(tmp);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
_unpacked_tuple_args(PyObject *arg)
|
||||||
|
{
|
||||||
|
PyObject *result;
|
||||||
|
assert(!PyType_Check(arg));
|
||||||
|
// Fast path
|
||||||
|
if (_PyGenericAlias_Check(arg) &&
|
||||||
|
((gaobject *)arg)->starred &&
|
||||||
|
((gaobject *)arg)->origin == (PyObject *)&PyTuple_Type)
|
||||||
|
{
|
||||||
|
result = ((gaobject *)arg)->args;
|
||||||
|
Py_INCREF(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_PyObject_LookupAttr(arg, &_Py_ID(__typing_unpacked_tuple_args__), &result) > 0) {
|
||||||
|
if (result == Py_None) {
|
||||||
|
Py_DECREF(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
_unpack_args(PyObject *item)
|
||||||
|
{
|
||||||
|
PyObject *newargs = PyList_New(0);
|
||||||
|
if (newargs == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
int is_tuple = PyTuple_Check(item);
|
||||||
|
Py_ssize_t nitems = is_tuple ? PyTuple_GET_SIZE(item) : 1;
|
||||||
|
PyObject **argitems = is_tuple ? &PyTuple_GET_ITEM(item, 0) : &item;
|
||||||
|
for (Py_ssize_t i = 0; i < nitems; i++) {
|
||||||
|
item = argitems[i];
|
||||||
|
if (!PyType_Check(item)) {
|
||||||
|
PyObject *subargs = _unpacked_tuple_args(item);
|
||||||
|
if (subargs != NULL &&
|
||||||
|
PyTuple_Check(subargs) &&
|
||||||
|
!(PyTuple_GET_SIZE(subargs) &&
|
||||||
|
PyTuple_GET_ITEM(subargs, PyTuple_GET_SIZE(subargs)-1) == Py_Ellipsis))
|
||||||
|
{
|
||||||
|
if (PyList_SetSlice(newargs, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, subargs) < 0) {
|
||||||
|
Py_DECREF(subargs);
|
||||||
|
Py_DECREF(newargs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_DECREF(subargs);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Py_XDECREF(subargs);
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
Py_DECREF(newargs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (PyList_Append(newargs, item) < 0) {
|
||||||
|
Py_DECREF(newargs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Py_SETREF(newargs, PySequence_Tuple(newargs));
|
||||||
|
return newargs;
|
||||||
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
_Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObject *item)
|
_Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObject *item)
|
||||||
{
|
{
|
||||||
|
@ -343,18 +408,26 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje
|
||||||
"%R is not a generic class",
|
"%R is not a generic class",
|
||||||
self);
|
self);
|
||||||
}
|
}
|
||||||
|
item = _unpack_args(item);
|
||||||
int is_tuple = PyTuple_Check(item);
|
int is_tuple = PyTuple_Check(item);
|
||||||
Py_ssize_t nitems = is_tuple ? PyTuple_GET_SIZE(item) : 1;
|
Py_ssize_t nitems = is_tuple ? PyTuple_GET_SIZE(item) : 1;
|
||||||
PyObject **argitems = is_tuple ? &PyTuple_GET_ITEM(item, 0) : &item;
|
PyObject **argitems = is_tuple ? &PyTuple_GET_ITEM(item, 0) : &item;
|
||||||
Py_ssize_t varparam = 0;
|
Py_ssize_t varparam = nparams;
|
||||||
for (; varparam < nparams; varparam++) {
|
for (Py_ssize_t i = 0; i < nparams; i++) {
|
||||||
PyObject *param = PyTuple_GET_ITEM(parameters, varparam);
|
PyObject *param = PyTuple_GET_ITEM(parameters, i);
|
||||||
if (Py_TYPE(param)->tp_iter) { // TypeVarTuple
|
if (Py_TYPE(param)->tp_iter) { // TypeVarTuple
|
||||||
break;
|
if (varparam < nparams) {
|
||||||
|
Py_DECREF(item);
|
||||||
|
return PyErr_Format(PyExc_TypeError,
|
||||||
|
"More than one TypeVarTuple parameter in %S",
|
||||||
|
self);
|
||||||
|
}
|
||||||
|
varparam = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (varparam < nparams) {
|
if (varparam < nparams) {
|
||||||
if (nitems < nparams - 1) {
|
if (nitems < nparams - 1) {
|
||||||
|
Py_DECREF(item);
|
||||||
return PyErr_Format(PyExc_TypeError,
|
return PyErr_Format(PyExc_TypeError,
|
||||||
"Too few arguments for %R",
|
"Too few arguments for %R",
|
||||||
self);
|
self);
|
||||||
|
@ -362,10 +435,11 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (nitems != nparams) {
|
if (nitems != nparams) {
|
||||||
|
Py_DECREF(item);
|
||||||
return PyErr_Format(PyExc_TypeError,
|
return PyErr_Format(PyExc_TypeError,
|
||||||
"Too %s arguments for %R",
|
"Too %s arguments for %R; actual %zd, expected %zd",
|
||||||
nitems > nparams ? "many" : "few",
|
nitems > nparams ? "many" : "few",
|
||||||
self);
|
self, nitems, nparams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Replace all type variables (specified by parameters)
|
/* Replace all type variables (specified by parameters)
|
||||||
|
@ -377,6 +451,7 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje
|
||||||
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
|
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
|
||||||
PyObject *newargs = PyTuple_New(nargs);
|
PyObject *newargs = PyTuple_New(nargs);
|
||||||
if (newargs == NULL) {
|
if (newargs == NULL) {
|
||||||
|
Py_DECREF(item);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
for (Py_ssize_t iarg = 0, jarg = 0; iarg < nargs; iarg++) {
|
for (Py_ssize_t iarg = 0, jarg = 0; iarg < nargs; iarg++) {
|
||||||
|
@ -384,11 +459,13 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje
|
||||||
int unpack = _is_unpacked_typevartuple(arg);
|
int unpack = _is_unpacked_typevartuple(arg);
|
||||||
if (unpack < 0) {
|
if (unpack < 0) {
|
||||||
Py_DECREF(newargs);
|
Py_DECREF(newargs);
|
||||||
|
Py_DECREF(item);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
PyObject *subst;
|
PyObject *subst;
|
||||||
if (_PyObject_LookupAttr(arg, &_Py_ID(__typing_subst__), &subst) < 0) {
|
if (_PyObject_LookupAttr(arg, &_Py_ID(__typing_subst__), &subst) < 0) {
|
||||||
Py_DECREF(newargs);
|
Py_DECREF(newargs);
|
||||||
|
Py_DECREF(item);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (subst) {
|
if (subst) {
|
||||||
|
@ -397,6 +474,7 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje
|
||||||
if (iparam == varparam) {
|
if (iparam == varparam) {
|
||||||
Py_DECREF(subst);
|
Py_DECREF(subst);
|
||||||
Py_DECREF(newargs);
|
Py_DECREF(newargs);
|
||||||
|
Py_DECREF(item);
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"Substitution of bare TypeVarTuple is not supported");
|
"Substitution of bare TypeVarTuple is not supported");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -412,6 +490,7 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje
|
||||||
}
|
}
|
||||||
if (arg == NULL) {
|
if (arg == NULL) {
|
||||||
Py_DECREF(newargs);
|
Py_DECREF(newargs);
|
||||||
|
Py_DECREF(item);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (unpack) {
|
if (unpack) {
|
||||||
|
@ -419,6 +498,7 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje
|
||||||
&PyTuple_GET_ITEM(arg, 0), PyTuple_GET_SIZE(arg));
|
&PyTuple_GET_ITEM(arg, 0), PyTuple_GET_SIZE(arg));
|
||||||
Py_DECREF(arg);
|
Py_DECREF(arg);
|
||||||
if (jarg < 0) {
|
if (jarg < 0) {
|
||||||
|
Py_DECREF(item);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -428,6 +508,7 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Py_DECREF(item);
|
||||||
return newargs;
|
return newargs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,6 +535,7 @@ ga_getitem(PyObject *self, PyObject *item)
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *res = Py_GenericAlias(alias->origin, newargs);
|
PyObject *res = Py_GenericAlias(alias->origin, newargs);
|
||||||
|
((gaobject *)res)->starred = alias->starred;
|
||||||
|
|
||||||
Py_DECREF(newargs);
|
Py_DECREF(newargs);
|
||||||
return res;
|
return res;
|
||||||
|
@ -518,6 +600,7 @@ static const char* const attr_exceptions[] = {
|
||||||
"__args__",
|
"__args__",
|
||||||
"__unpacked__",
|
"__unpacked__",
|
||||||
"__parameters__",
|
"__parameters__",
|
||||||
|
"__typing_unpacked_tuple_args__",
|
||||||
"__mro_entries__",
|
"__mro_entries__",
|
||||||
"__reduce_ex__", // needed so we don't look up object.__reduce_ex__
|
"__reduce_ex__", // needed so we don't look up object.__reduce_ex__
|
||||||
"__reduce__",
|
"__reduce__",
|
||||||
|
@ -689,8 +772,20 @@ ga_parameters(PyObject *self, void *unused)
|
||||||
return alias->parameters;
|
return alias->parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
ga_unpacked_tuple_args(PyObject *self, void *unused)
|
||||||
|
{
|
||||||
|
gaobject *alias = (gaobject *)self;
|
||||||
|
if (alias->starred && alias->origin == (PyObject *)&PyTuple_Type) {
|
||||||
|
Py_INCREF(alias->args);
|
||||||
|
return alias->args;
|
||||||
|
}
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
static PyGetSetDef ga_properties[] = {
|
static PyGetSetDef ga_properties[] = {
|
||||||
{"__parameters__", ga_parameters, (setter)NULL, "Type variables in the GenericAlias.", NULL},
|
{"__parameters__", ga_parameters, (setter)NULL, "Type variables in the GenericAlias.", NULL},
|
||||||
|
{"__typing_unpacked_tuple_args__", ga_unpacked_tuple_args, (setter)NULL, NULL},
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue