Search code examples
pythontypingpylancepyright

List of single type cannot be assigned to list of union type


I wrote a python code like below

class A:
    pass

class B:
    pass

class C:
    pass

from typing import TypeVar, Union, Type, Optional, List

test = TypeVar("test", bound=A)

def wow(w: Optional[List[Union[Type["test"], Type[C]]]]):
    pass

wow([A]);

errorhighlighted

Pylance highlights the line wow([A]) as an error, so I wonder if I wrote the wrong code or if Pylance worked wrong.

enter image description here

when i remove Union part, then it worked well, so i thought there's no reason that the code should be highlighted just because i added Union. But I may be completely mistaken, so please teach me.

below is the error message that I got

Argument of type "list[Type[A]]" cannot be assigned to parameter "w" of type "List[Type[test@wow] | Type[C]] | None" in function "wow"
  Type "list[Type[A]]" cannot be assigned to type "List[Type[test@wow] | Type[C]] | None"
    "list[Type[A]]" is incompatible with "List[Type[test@wow] | Type[C]]"
      TypeVar "_T@list" is invariant
        Type "Type[A]" cannot be assigned to type "Type[test@wow] | Type[C]"
          "Type[A]" is incompatible with "Type[C]"
          Type "Type[A]" cannot be assigned to type "Type[C]"
    Type cannot be assigned to type "None"

Solution

  • This is actually almost exactly an example from pyright's type concepts docs in their section about generic types: https://github.com/microsoft/pyright/blob/main/docs/type-concepts.md#generic-types

    Essentially, because lists are mutable types, you can't assign a list[Type[A]] to be a list[Type[test@wow] | Type[C]] because if you add a Type[C] to your list[Type[A]], it would no longer be a list[Type[A]]. If you declare w to be the immutable Sequence type instead, thereby promising not to modify w, you can get rid of your type error.