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

PEP 604 unions don't work with generic type aliases #12211

Closed
Eldar1205 opened this issue Feb 18, 2022 · 15 comments
Closed

PEP 604 unions don't work with generic type aliases #12211

Eldar1205 opened this issue Feb 18, 2022 · 15 comments
Labels
bug mypy got something wrong topic-pep-604 PEP 604 (union | operator) topic-type-alias TypeAlias and other type alias issues

Comments

@Eldar1205
Copy link

Bug Report

Python 3.10 new Union syntax doesn't work in a scenario old syntax did when involved with generic type aliases.

To Reproduce

Create the following definitions:

_ResponseType = TypeVar("_ResponseType")


SyncFunc: TypeAlias = Callable[..., _ResponseType]
Coro: TypeAlias = Callable[..., Coroutine[Any, Any, _ResponseType]]

SyncFuncOrCoro: TypeAlias = Coro[_ResponseType] | SyncFunc[_ResponseType]

Expected Behavior

Should work without errors, like it does when using old Union syntax:

_ResponseType = TypeVar("_ResponseType")


SyncFunc: TypeAlias = Callable[..., _ResponseType]
Coro: TypeAlias = Callable[..., Coroutine[Any, Any, _ResponseType]]

SyncFuncOrCoro: TypeAlias = Union[Coro[_ResponseType], SyncFunc[_ResponseType]]

Actual Behavior

I receive mypy error "Type application is only supported for generic classes".

Your Environment

  • Mypy version used: 0.931
  • Mypy command-line flags: N/A
  • Python version used: 3.10.2
  • Operating system and version: Windows 11
  • Mypy configuration options from mypy.ini (and other config files):

I'm using pretty strict mypy settings:

[mypy]
follow_imports = normal
ignore_errors = false
implicit_reexport = false
warn_redundant_casts = True
warn_unused_ignores = True
disallow_any_generics = True
disallow_untyped_defs = True
check_untyped_defs = True
allow_redefinition = false
local_partial_types = True
strict_optional = true
strict_equality = true
warn_unused_configs = true
warn_unreachable = true
warn_no_return = true
no_implicit_optional = true

@Eldar1205 Eldar1205 added the bug mypy got something wrong label Feb 18, 2022
@Eldar1205
Copy link
Author

Just encountered another example, seems like a bug with generic type aliases using the new Union syntax, try to replace this with new syntax:

_FieldValueType = TypeVar("_FieldValueType")
FieldExtractionResult: TypeAlias = Union[InventoryEntityField[_FieldValueType], _FieldValueType, InventoryEntityFieldStatus]

@ktbarrett
Copy link

generic type aliases

There is no such things AFAIK. PEP 613 does not mention anything about generic type aliases (a major oversight IMO). Despite that the official Python documentation on the typing module specifically mentions "generic type aliases". Find on that phrase for an example that does not work in mypy.

@hauntsaninja Are there any PEPs underway to support generic type aliases officially? I think I prefer the syntax:

Coro: TypeAlias[_ResponseType] = Callable[..., Coroutine[Any, Any, _ResponseType]]

@hauntsaninja
Copy link
Collaborator

hauntsaninja commented Feb 22, 2022

Generic type aliases are a thing that mypy claims to support, although I'm not sure if that's standard amongst type checkers: https://mypy.readthedocs.io/en/stable/generics.html#generic-type-aliases
Edit: from a quick test, looks like pyright supports this as well

Syntax is the alias is generic over whatever unbound type variables are in the RHS.

@hauntsaninja hauntsaninja changed the title Python 3.10 new Union syntax doesn't work in a scenario old syntax did PEP 604 unions don't work with generic type aliases Feb 22, 2022
@ktbarrett
Copy link

That looks like a slightly longer version of what's in the typing documentation. It also fails in mypy.

@hauntsaninja
Copy link
Collaborator

Okay, I think I found the section on typing.readthedocs.io you're referring to: https://typing.readthedocs.io/en/latest/source/libraries.html#type-aliases

The generic example there seems to work for me? https://mypy-play.net/?mypy=latest&python=3.10&gist=f8a6936bd13e7f1ac594cbdc6202f1eb

@hauntsaninja
Copy link
Collaborator

hauntsaninja commented Feb 22, 2022

Maybe I'm confused about something :-)

Anyway, to the concrete suggestion of having to explicitly list the type vars generic type aliases are generic over — I think it's fine as is? Not sure what the extra repetition gets us. The other note is that TypeAlias is not subscriptable in Python 3.10, so the suggested syntax would be unfortunate in that regard. Maybe worth emailing typing-sig.

There is a sort of separate discussion of "we should have one, true reference that spells out all the rules you need to make a standards-compliant (tm) type checker", where we can codify everything that all type checkers agree on. I think the only thing decided in that space is that PEP 484 is not a living document, so if we were to write such a thing it would have to live elsewhere. Currently a lot of the discussion for standardising semantics happens ad hoc on typing-sig or random issues. typing.readthedocs.io could be that, but it also wants to be other things — we'll see what ends up happening :-)

(Getting a little off-topic, but did want to explicitly acknowledge that OP's bug is a bug and not a very fun bug either)

@ktbarrett
Copy link

No it's me who is confused. I swear I put the example from docs.python.org/ and it was failing, even as I started playing around with it. But I just tried again and it apparently works now... Every time I try to contribute I swear this program gaslights tf out of me. I'm done.

@hauntsaninja
Copy link
Collaborator

(For what it's worth, I really appreciate your contributions! You're consistently one of the most helpful people who hangs out around here :-) )

@erictraut
Copy link

Generic type aliases are a thing that mypy claims to support, although I'm not sure if that's standard amongst type checkers.

Generic type aliases are (to the best of my knowledge) supported by all Python type checkers in a consistent manner. PEP 484 talks about type aliases. While it doesn't specifically say that type aliases can be generic, it provides samples that make it pretty clear that they are supported and how they should work.

@Eldar1205
Copy link
Author

How about the fact the explicit Union[] syntax works with mypy? The 3.10 syntax should be equivalent, so isn't it right to say that if mypy supports the pre-3.10 syntax it should support the 3.10 one as well so it's not considered a regression?

@JelleZijlstra
Copy link
Member

Yes, the original report is a bug we should fix. The discussion got sidetracked.

@KotlinIsland
Copy link
Contributor

KotlinIsland commented Jul 13, 2022

A minified example could be:

from typing import _T as T
Nullable = T | None

playground

@ilevkivskyi
Copy link
Member

cc @JukkaL it looks like this is still broken.

@erictraut
Copy link

It appears that the original bug has been fixed. I cannot repro it with mypy 1.5.

@KotlinIsland, your code sample is different from OP's. Your sample doesn't use a TypeAlias annotation, and it results in a runtime exception (for which mypy correctly generates an error).

I think this issue can be closed.

@hauntsaninja
Copy link
Collaborator

Fixed in #14181

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-pep-604 PEP 604 (union | operator) topic-type-alias TypeAlias and other type alias issues
Projects
None yet
Development

No branches or pull requests

8 participants