Title: PEP 585 and ForwardRef
Type: behavior Stage: patch review
Components: Versions: Python 3.9
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: BTaskaya, eric.smith, gvanrossum, joperez, levkivskyi, lukasz.langa, wyz23x2
Priority: normal Keywords: patch

Created on 2020-07-22 20:16 by joperez, last changed 2020-09-10 11:58 by wyz23x2.

Messages (4)
msg374105 - (view) Author: Joseph Perez (joperez) * Date: 2020-07-22 20:16
PEP 585 current implementation (3.10.0a0) differs from current Generic implementation about ForwardRef, as illustrated bellow:
from dataclasses import dataclass, field
from typing import get_type_hints, List, ForwardRef

class Node:
    children: list["Node"] = field(default_factory=list)
    children2: List["Node"] = field(default_factory=list)

assert get_type_hints(Node) == {"children": list["Node"], "children2": List[Node]}
assert List["Node"].__args__ == (ForwardRef("Node"),)
assert list["Node"].__args__ == ("Node",) # No ForwardRef here, so no evaluation by get_type_hints
There is indeed no kind of ForwardRef for `list` arguments. As shown in the example, this affects the result of get_type_hints for recursive types handling.

He could be "fixed" in 2 lines in `typing._eval_type` with something like this :
def _eval_type(t, globalns, localns, recursive_guard=frozenset()):
    if isinstance(t, str):
        t = ForwardRef(t)
    if isinstance(t, ForwardRef):
but it's kind of hacky/dirty.

It's true that this issue will not concern legacy code, 3.9 still being not released. So developers of libraries using get_type_hints could add in their documentation that `from __future__ import annotations` is mandatory for recursive types with PEP 585 (I think I will do it).

By the way, Guido has quickly given his opinion about it in PR 21553: "We probably will not ever support this: importing ForwardRef from the built-in generic alias code would be problematic, and once from __future__ import annotations is always on there's no need to quote the argument anyway." (So feel free to close this issue)
msg374107 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2020-07-22 20:19
I think mentioning this in the docs is the best we can do in 3.9, and for 3.10 the point will be moot. The next release is release candidate 1, so we're well past the point where we can implement new functionality.
msg374109 - (view) Author: Joseph Perez (joperez) * Date: 2020-07-22 20:38
However, PEP 563 will not solve the recursive type alias issue like `A = list["A"]` but this is a minor concern.
msg374291 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2020-07-25 22:08
Hm, recursive type aliases are an interesting issue. We may be able to do better there for 3.10, even if we can't fix it for 3.9 (or at least not for 3.9.0).

But in the meantime maybe you can come up with a PR that adds a note to the typing docs in 3.10 explaining that `list["int"]` will not be resolved to `list[int]`, even though it works for `List["int"]`?
Date User Action Args
2020-09-10 11:58:46wyz23x2setpull_requests: - pull_request21248
2020-09-10 11:53:35wyz23x2setpull_requests: + pull_request21248
2020-09-10 11:52:55wyz23x2setpull_requests: - pull_request21247
2020-09-10 11:30:17wyz23x2setpull_requests: + pull_request21247
2020-09-10 11:28:59wyz23x2setpull_requests: - pull_request21245
2020-09-10 11:24:23wyz23x2setkeywords: + patch
nosy: + wyz23x2

pull_requests: + pull_request21245
stage: patch review
2020-08-03 23:39:26vstinnersetnosy: - vstinner
2020-07-25 22:08:37gvanrossumsetmessages: + msg374291
2020-07-22 20:38:41joperezsetmessages: + msg374109
2020-07-22 20:19:34gvanrossumsetmessages: + msg374107
2020-07-22 20:16:14joperezcreate