tobgu / pyrsistent

Persistent/Immutable/Functional data structures for Python
MIT License
2.03k stars 147 forks source link

PVector seems to be invariant (mypy error) #274

Closed kulych closed 1 year ago

kulych commented 1 year ago

Hello, I encountered a problem when trying to call a function accepting PVector[str | int] with PVector[str] as an argument. Mypy raises an error even though PVector[str] should be a subtype of PVector[str | int].

The same happens (as expected), when using list as list is invariant. Sequence or tuple do not cause such error.

See the example below:

from pyrsistent.typing import PVector
from pyrsistent import pvector
from typing import Sequence

def func_pvector(a: PVector[str | int]) -> None:
    pass

pvector_str: PVector[str] = pvector(["a", "b", "c"])
# error: Argument 1 to "func_pvector" has incompatible type "PVector[str]"; expected "PVector[Union[str, int]]"  [arg-type]
func_pvector(pvector_str)

def func_list(a: list[str | int]) -> None:
    pass

list_str: list[str] = ["a", "b", "c"]
# error: Argument 1 to "func_list" has incompatible type "List[str]"; expected "List[Union[str, int]]"  [arg-type]
func_list(list_str)

def func_sequence(a: Sequence[str | int]) -> None:
    pass

sequence_str: Sequence[str] = ["a", "b", "c"]
# no error
func_sequence(sequence_str)

def func_tuple(a: tuple[str | int, ...]) -> None:
    pass

tuple_str: tuple[str, ...] = ("a", "b", "c")
# no error
func_tuple(tuple_str)

This can be solved by changing

T = TypeVar('T')

to

T = TypeVar('T', covariant=True)

I believe PVector should behave just like Sequence.