Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
serhiy-storchaka opened this issue Nov 11, 2022 · 2 comments
Assignees
Labels
3.11 only security fixes 3.12 only security fixes pending The issue will be closed if no feedback is provided topic-typing type-bug An unexpected behavior, bug, or error

Comments

@serhiy-storchaka
Copy link
Member

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.

@serhiy-storchaka serhiy-storchaka added the type-bug An unexpected behavior, bug, or error label Nov 11, 2022
@serhiy-storchaka serhiy-storchaka self-assigned this Nov 11, 2022
@serhiy-storchaka serhiy-storchaka added 3.11 only security fixes topic-typing 3.12 only security fixes labels Nov 11, 2022
serhiy-storchaka added a commit to serhiy-storchaka/cpython that referenced this issue Nov 12, 2022
…ution of ParamSpec

and TypeVarTuple

* Fix substitution of TypeVarTuple and ParamSpec together in user generics.

* Fix substitution of ParamSpec followed by TypeVarTuple in generic aliases.

* Check the number of arguments in substitution in user generics containing a
  TypeVarTuple and one or more TypeVar.
serhiy-storchaka added a commit that referenced this issue Nov 29, 2022
… and TypeVarTuple (GH-99412)

* Fix substitution of TypeVarTuple and ParamSpec together in user generics.

* Fix substitution of ParamSpec followed by TypeVarTuple in generic aliases.

* Check the number of arguments in substitution in user generics containing a
  TypeVarTuple and one or more TypeVar.
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Nov 29, 2022
…ution of ParamSpec and TypeVarTuple (pythonGH-99412)

* Fix substitution of TypeVarTuple and ParamSpec together in user generics.

* Fix substitution of ParamSpec followed by TypeVarTuple in generic aliases.

* Check the number of arguments in substitution in user generics containing a
  TypeVarTuple and one or more TypeVar.
(cherry picked from commit 8f2fb7d)

Co-authored-by: Serhiy Storchaka <[email protected]>
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Nov 29, 2022
…ution of ParamSpec and TypeVarTuple (pythonGH-99412)

* Fix substitution of TypeVarTuple and ParamSpec together in user generics.

* Fix substitution of ParamSpec followed by TypeVarTuple in generic aliases.

* Check the number of arguments in substitution in user generics containing a
  TypeVarTuple and one or more TypeVar.
(cherry picked from commit 8f2fb7d)

Co-authored-by: Serhiy Storchaka <[email protected]>
miss-islington added a commit that referenced this issue Nov 29, 2022
… and TypeVarTuple (GH-99412)

* Fix substitution of TypeVarTuple and ParamSpec together in user generics.

* Fix substitution of ParamSpec followed by TypeVarTuple in generic aliases.

* Check the number of arguments in substitution in user generics containing a
  TypeVarTuple and one or more TypeVar.
(cherry picked from commit 8f2fb7d)

Co-authored-by: Serhiy Storchaka <[email protected]>
@AlexWaygood
Copy link
Member

These examples all work fine on main and on 3.11.2. It looks like they were fixed by #99412, and appropriate tests were added. Is there anything more to do here?

@AlexWaygood AlexWaygood added the pending The issue will be closed if no feedback is provided label Apr 10, 2023
@iritkatriel iritkatriel closed this as not planned Won't fix, can't repro, duplicate, stale May 20, 2023
@AlexWaygood
Copy link
Member

Closing as "completed", since this was buggy in the past, but the bug was fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.11 only security fixes 3.12 only security fixes pending The issue will be closed if no feedback is provided topic-typing type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

3 participants