Skip to content
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

Cannot resolve recursive/cyclic definitions (v0.991, Python 3.8/3.9) #14219

Closed
bartfeenstra opened this issue Nov 29, 2022 · 3 comments
Closed
Labels
bug mypy got something wrong

Comments

@bartfeenstra
Copy link

Bug Report

Mypy fails to check recursive/cyclic type aliases, even with #731 being part of v0.991. However, this happens on Python 3.8 and 3.9 only (and possibly below), but not on 3.10 or 3.11.
Example:

RecursiveTypeAlias: TypeAlias = Union[bool, int, float, str, Sequence['RecursiveTypeAlias']]

for which mypy raises error: Cannot resolve name "RecursiveTypeAlias" (possible cyclic definition) [misc].

To Reproduce

Alternatively, clone https://github.com/bartfeenstra/mypy-type-alias and run tox.

Expected Behavior
Mypy not raising any errors for recursive/cyclig type aliases and correctly parsing them as it does on Python 3.10 and 3.11.

Actual Behavior
Mypy fails on recursive/cyclic type aliases with the error error: Cannot resolve name "RecursiveTypeAlias" (possible cyclic definition) [misc].

@bartfeenstra bartfeenstra added the bug mypy got something wrong label Nov 29, 2022
@JukkaL
Copy link
Collaborator

JukkaL commented Nov 29, 2022

On a recent master this works on Python 3.8:

from typing_extensions import TypeAlias
from typing import Union, Sequence

RecursiveTypeAlias: TypeAlias = Union[bool, int, float, str, Sequence['RecursiveTypeAlias']]

The issue is with imports. Mypy doesn't support this on Python 3.8:

try:
    from typing import TypeAlias  # type: ignore
except ImportError:
    from typing_extensions import TypeAlias

As a workaround, this should work:

try:
    from typing_extensions import TypeAlias
except ImportError:
    from typing import TypeAlias  # type: ignore

@bartfeenstra
Copy link
Author

I can confirm this works with mypy commit 3a3cf412b278ee7bf710742b168beed41c1c02f2 in combination with the imports turned around. Thanks!

@ssbarnea
Copy link
Contributor

ssbarnea commented Apr 30, 2023

For reference, this is the full solution that seems to currently work with py39+ and also pass mypy and ruff:

from __future__ import annotations
from collections.abc import Mapping, Sequence
from typing import Any, Union

try:
    from typing_extensions import TypeAlias
except ImportError:
    from typing import TypeAlias  # type: ignore[no-redef,attr-defined]

JSON: TypeAlias = Union[dict[str, "JSON"], list["JSON"], str, int, float, bool, None]
JSON_ro: TypeAlias = Union[
    Mapping[str, "JSON_ro"],
    Sequence["JSON_ro"],
    str,
    int,
    float,
    bool,
    None,
]

Note the awkward import fallback is needed because doing it the opposite does not work py39 or py38 either, only importing first from typing_extensions seems to be working well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong
Projects
None yet
Development

No branches or pull requests

4 participants