Skip to content

Union subtyping doesn't work with covariant type constructors Tuple and Callable #7187

Open

Description

@ilevkivskyi

Both calls in this code fail, but I think they should be allowed:

from typing import Callable, Union, Tuple

def f(x: Union[Callable[..., int], Callable[..., str]]) -> None: ...
x: Callable[..., Union[int, str]]
f(x)

def g(y: Union[Tuple[int], Tuple[str]]) -> None: ...
y: Tuple[Union[int, str]]
g(y)

Moreover, I would say types in each pair are actually equivalent.

Activity

  1. mortoray commented on Jul 17, 2019

    @mortoray

    Is there any workaround to this now? I'm trying to get my Flask return types correct.

  2. JukkaL commented on Jul 18, 2019

    @JukkaL
    Collaborator

    There are a few options. You can use an Any return type. You can use # type: ignore. Sometimes you can use an overloaded function:

    @overload
    def g(x: int) -> int: ...
    @overload
    def g(x: str) -> str: ...
    def g(x) -> Union[int, str]:
        return ...
    
    f(g)  # OK

    Perhaps the best option would to change the stubs for flask to use a union return type (the change was made in https://github.com/python/typeshed/pull/3003/files).

  3. ilevkivskyi commented on Aug 15, 2019

    @ilevkivskyi
    MemberAuthor

    (In view of coming implementation of recursive types this will be important so raising priority to high.)

  4. self-assigned this
    on Aug 15, 2019
  5. added a commit that references this issue on Aug 27, 2019
  6. jingw commented on Sep 6, 2019

    @jingw
    Contributor

    Are those types actually equivalent? Union[Callable[..., int], Callable[..., str]] sounds like a function that always returns ints or always returns strings, whereas Callable[..., Union[int, str]] is a function that can return a different thing each time. This argument does not apply to the tuple example, though it would if it was a list.

  7. ilevkivskyi commented on Sep 6, 2019

    @ilevkivskyi
    MemberAuthor

    For mypy if x has type Union[int, str] then [x, x, x] has type List[Union[int, str]], not Union[List[int], List[str]], and this is not easy to fix. So the difference you mention is not essential ATM.

    Anyway, we need to fix subtyping for unions in Callable and Tuple, it is currently broken.

  8. removed their assignment
    on Dec 9, 2019
  9. tjprescott commented on Jan 29, 2024

    @tjprescott

    Is there any movement on this? I'm trying to use mypy with Flask and the only way to make it happy is to make the return type Response which means it could be anything. Otherwise I get the Value of type variable "T_route" of function cannot be "Callable[[], Foo]"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions