VSCode Pylance v2023.9.20 with strict checking is giving me type error on first function call, but not the second. Only difference is that in first argument is wrapped in list.
def listTupleFunc(arg: list[tuple[str, tuple[str, ...]]]) -> None:
pass
listTuple = [('x', ('a', 'b'))]
listTupleFunc(listTuple) # Error here
def tupleOnlyFunc(arg: tuple[str, tuple[str, ...]]) -> None:
pass
tupleOnly = ('x', ('a', 'b'))
tupleOnlyFunc(tupleOnly) # OK
And the error message is:
Argument of type "list[tuple[Literal['x'], tuple[Literal['a'], Literal['b']]]]" cannot be assigned to parameter "arg" of type "list[tuple[str, tuple[str, ...]]]" in function "listTupleFunc"
"list[tuple[Literal['x'], tuple[Literal['a'], Literal['b']]]]" is incompatible with "list[tuple[str, tuple[str, ...]]]"
Type parameter "_T@list" is invariant, but "tuple[Literal['x'], tuple[Literal['a'], Literal['b']]]" is not the same as "tuple[str, tuple[str, ...]]"
If I change so that some of the literals are formatted, suprisingly the error disappears:
# These work OK somehow
listTuple = [(f'x', ('a', f'b'))]
listTuple = [(f'x', (f'a', 'b'))]
# But these don't
listTuple = [('x', (f'a', f'b'))]
listTuple = [(f'x', ('a', 'b'))]
Is this a bug in Pylance or am I missing something obvious? How do I get rid of the error?
2
Answers
You can cast the
listTuple
to required type.This removes the error. PyLance expects these hard coded literals as being incompetable with the general definition you used.
So, the error message is quite descriptive. When you do just:
Then the type inference rules of pyright infer:
Now, you may argue, "but
tuple[Literal['x'], tuple[Literal['a'], Literal['b']]
is a subtype oftuple[str, tuple[str, ...]]
, it should be accepted here!But look at the rest of the error message, it points out,
list
is invariant. So if you havelist[T]
, andlist[S]
andS
is a subtype ofT
, thenlist[S]
is not a subtype oflist[T]
! as you might expectPeople tend to expect parametrized types to be covariant.
list
objects have to be invariant because they are mutable (read more about this in PEP 484).Consider the following toy example:
Here is what
pyright
says on my machine:So one solution is to annotate the variable explicitly with the super type and don’t rely on type inference, in the toy example:
Or for your code:
Another alternative, if you don’t need to rely on any of the mutator methods for
list
(like.append
or.pop
, ormlist[i] = whatever
) then you can usecollections.abc.Sequence
, which is covariant:Now pyright is satisfied: