typeshed icon indicating copy to clipboard operation
typeshed copied to clipboard

Recursive type aliases tracker

Open srittau opened this issue 3 years ago • 4 comments

  • [ ] mypy (python/mypy#731), supported using a flag
  • [x] pytype
  • [x] pyright
  • [x] pyre
  • [x] PyCharm

Test case:

from typing import TypeAlias

Recursive: TypeAlias = str | list["Recursive"]

def foo(r: Recursive) -> None:
    if not isinstance(r, str):
        foo(r[0])
    if not isinstance(r, list):
        r.casefold()

foo("")
foo(list(""))
foo(list(list(""), ""))

srittau avatar May 21 '22 12:05 srittau

Recursive types should work with pytype. We don't support the X | Y syntax for union types yet, so the test case has to be modified a bit, but pytype accept this:

from typing import TypeAlias, Union

Recursive: TypeAlias = Union[str, list["Recursive"]]

def foo(r: Recursive) -> None:
  if not isinstance(r, str):
    foo(r[0])
  if not isinstance(r, list):
    r.casefold()

foo("")
foo(list(""))
foo(list((list(""), "")))

(I also changed the list[...]s to list(..) in the last two lines; I assume that was a typo.)

rchen152 avatar Jun 07 '22 03:06 rchen152

FWIW mypy version in master supports this under a flag (expect it fails on the last line because of an unrelated bug in special-casing tuple literals, should be a 1-line fix).

ilevkivskyi avatar Aug 13 '22 13:08 ilevkivskyi

In general, I guess we will discover a bunch of inconsistencies in type inference in mypy (currently it is a bit arbitrary in some situations, while it should be quite consistent for recursive types, especially if invariant collections are involved, e.g. this test passes if I use Sequence)

ilevkivskyi avatar Aug 13 '22 13:08 ilevkivskyi

If I want to define nested list type should I use

NestedList = list[Union[str, "NestedList"]]
def f(l: NestedList) -> int:
   …

or

Recursive: TypeAlias = list[str | list["Recursive"]]
def f(l: Recursive) -> int:
   …

?

al-yakubovich avatar Aug 16 '22 21:08 al-yakubovich

Seems like we're all done here! We have our first recursive types successfully added to typeshed: #9134

Thanks @ilevkivskyi for all the incredible work on mypy recently to enable this!

AlexWaygood avatar Nov 08 '22 17:11 AlexWaygood

These are not working for me:

WorkerResult: TypeAlias = Result[str, str] | Result[object, str]
Worker: TypeAlias = Callable[[], WorkerResult | Worker]

gives:

Traceback (most recent call last):
  File "/app/src/app/main.py", line 17, in <module>
    Worker: TypeAlias = Callable[[], WorkerResult | Worker]
                                                    ^^^^^^
NameError: name 'Worker' is not defined

jleonard-r7 avatar Feb 24 '23 02:02 jleonard-r7

Python version 3.11.2 (which should include whatever work happened in Nov 2022 on mypy).

jleonard-r7 avatar Feb 24 '23 02:02 jleonard-r7

This issue is about support in type checkers, not at runtime. To prevent the runtime NameError you'll (still) have to enclose the name in quotes.

JelleZijlstra avatar Feb 24 '23 04:02 JelleZijlstra