Skip to content

Type substitution in generic aliases does not work if ParamSpec is followed by TypeVarTuple #99379

Description

@serhiy-storchaka

The following code:

from typing import *
P = ParamSpec('P')
Ts = TypeVarTuple('Ts')
C = Callable[P, Tuple[*Ts]]
C[[int], str, bytes]

gives an error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/serhiy/py/cpython3.11/Lib/typing.py", line 363, in inner
    return func(*args, **kwds)
           ^^^^^^^^^^^^^^^^^^^
  File "/home/serhiy/py/cpython3.11/Lib/typing.py", line 1393, in __getitem__
    new_args = self._determine_new_args(args)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/serhiy/py/cpython3.11/Lib/typing.py", line 1417, in _determine_new_args
    args = prepare(self, args)
           ^^^^^^^^^^^^^^^^^^^
  File "/home/serhiy/py/cpython3.11/Lib/typing.py", line 1229, in __typing_prepare_subst__
    return _prepare_paramspec_params(alias, args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/serhiy/py/cpython3.11/Lib/typing.py", line 297, in _prepare_paramspec_params
    _check_generic(cls, params, len(cls.__parameters__))
  File "/home/serhiy/py/cpython3.11/Lib/typing.py", line 274, in _check_generic
    raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments for {cls};"
TypeError: Too many arguments for typing.Callable[~P, typing.Tuple[*Ts]]; actual 3, expected 2

The same for the C implementation (types.GenericAlias):

import collections.abc
C = collections.abc.Callable[P, Tuple[*Ts]]
C[[int], str, bytes]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/serhiy/py/cpython3.11/Lib/_collections_abc.py", line 468, in __getitem__
    new_args = super().__getitem__(item).__args__
               ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/serhiy/py/cpython3.11/Lib/typing.py", line 1229, in __typing_prepare_subst__
    return _prepare_paramspec_params(alias, args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/serhiy/py/cpython3.11/Lib/typing.py", line 297, in _prepare_paramspec_params
    _check_generic(cls, params, len(cls.__parameters__))
  File "/home/serhiy/py/cpython3.11/Lib/typing.py", line 274, in _check_generic
    raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments for {cls};"
TypeError: Too many arguments for collections.abc.Callable[~P, typing.Tuple[*Ts]]; actual 3, expected 2

And for user generics:

T = TypeVar('T')
class A(Generic[P, T]):
    pass

B = A[P, Tuple[*Ts]]
B[[int], str, bytes]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/serhiy/py/cpython3.11/Lib/typing.py", line 363, in inner
    return func(*args, **kwds)
           ^^^^^^^^^^^^^^^^^^^
  File "/home/serhiy/py/cpython3.11/Lib/typing.py", line 1393, in __getitem__
    new_args = self._determine_new_args(args)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/serhiy/py/cpython3.11/Lib/typing.py", line 1417, in _determine_new_args
    args = prepare(self, args)
           ^^^^^^^^^^^^^^^^^^^
  File "/home/serhiy/py/cpython3.11/Lib/typing.py", line 1229, in __typing_prepare_subst__
    return _prepare_paramspec_params(alias, args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/serhiy/py/cpython3.11/Lib/typing.py", line 297, in _prepare_paramspec_params
    _check_generic(cls, params, len(cls.__parameters__))
  File "/home/serhiy/py/cpython3.11/Lib/typing.py", line 274, in _check_generic
    raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments for {cls};"
TypeError: Too many arguments for __main__.A[~P, typing.Tuple[*Ts]]; actual 3, expected 2

But it works if ParamSpec and TypeVarTuple are in different order:

class A(Generic[T, P]):
    pass

B = A[Tuple[*Ts], P]
B[str, bytes, [int]]

It is a different bug than #99344 because it happens when you substitute in a generic alias instead of a user generic.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

3.11only security fixes3.12only security fixespendingThe issue will be closed if no feedback is providedtopic-typingtype-bugAn unexpected behavior, bug, or error

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions