classification
Title: GenericAlias does not support nested type variables
Type: behavior Stage: resolved
Components: Interpreter Core Versions: Python 3.9
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: serhiy.storchaka Nosy List: gvanrossum, levkivskyi, serhiy.storchaka
Priority: normal Keywords: patch

Created on 2020-04-27 15:57 by serhiy.storchaka, last changed 2020-05-04 08:30 by levkivskyi. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 19836 merged serhiy.storchaka, 2020-05-01 12:38
Messages (6)
msg367433 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-04-27 15:57
While trying to replace typing._GenericAlias with GenericAlias I have found that the latter does not support nested type variables.

>>> from typing import *
>>> T = TypeVar('T')
>>> X = List[List[T]]
>>> X.__parameters__
(~T,)
>>> X[int]
typing.List[typing.List[int]]
>>> Y = list[list[T]]
>>> Y.__parameters__
()
>>> Y[int]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: There are no type variables left in list[list[~T]]
msg367454 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2020-04-27 20:09
Good catch. Is there a reasonable fix?
msg367506 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-04-28 07:22
Not yet. If you don't prefer to fix it yourself, I'll do it as soon as I have time.
msg367944 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-05-02 18:03
There is a difference between PR 19836 and the typing module in handling nested unsubscribed generic aliases:

>>> from typing import *
>>> T = TypeVar('T')
>>> D1 = Dict[T, List]
>>> D2 = dict[T, List]
>>> D1.__parameters__
(~T,)
>>> D1[int]
typing.Dict[int, typing.List[~T]]
>>> D1[int].__parameters__
(~T,)
>>> D1[int][str]
typing.Dict[int, typing.List[str]]
>>> D1[int, str]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/serhiy/py/cpython/Lib/typing.py", line 267, in inner
    return func(*args, **kwds)
  File "/home/serhiy/py/cpython/Lib/typing.py", line 686, in __getitem__
    _check_generic(self, params)
  File "/home/serhiy/py/cpython/Lib/typing.py", line 221, in _check_generic
    raise TypeError(f"Too {'many' if alen > elen else 'few'} parameters for {cls};"
TypeError: Too many parameters for typing.Dict[~T, typing.List]; actual 2, expected 1
>>> D2.__parameters__
(~T, ~T)
>>> D2[int]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Too few arguments for dict[~T, typing.List]
>>> D2[int, str]
dict[int, typing.List[str]]

But this behavior is not specified and is not covered by tests.
msg368014 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-05-04 07:56
New changeset 41a64587a0fd68bcd21ba42999cd3940801dff7c by Serhiy Storchaka in branch 'master':
bpo-40408: Fix support of nested type variables in GenericAlias. (GH-19836)
https://github.com/python/cpython/commit/41a64587a0fd68bcd21ba42999cd3940801dff7c
msg368019 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2020-05-04 08:30
> But this behavior is not specified and is not covered by tests.

FWIW, to be most close to the static type checkers behavior, both D[int][str] and D[int, str] should fail for D = Dict[T, List]. Not important however, since this is a really rare corner case I think.
History
Date User Action Args
2020-05-04 08:30:23levkivskyisetmessages: + msg368019
2020-05-04 08:00:19serhiy.storchakasetstatus: open -> closed
resolution: fixed
stage: patch review -> resolved
2020-05-04 07:56:11serhiy.storchakasetmessages: + msg368014
2020-05-02 18:03:40serhiy.storchakasetmessages: + msg367944
2020-05-01 12:38:24serhiy.storchakasetkeywords: + patch
stage: patch review
pull_requests: + pull_request19154
2020-04-30 19:00:12serhiy.storchakasetassignee: serhiy.storchaka
2020-04-28 07:22:15serhiy.storchakasetmessages: + msg367506
2020-04-27 20:09:06gvanrossumsetmessages: + msg367454
2020-04-27 15:57:57serhiy.storchakacreate