FR: Type narrowing of lists based on any(isinstance) checks
Description
It would be awesome if it could narrow the type based on an all isinstance check, if possible. This does a check that all the variables are of a specific type, so the inner block should know that narrowed type.
Code sample in basedpyright playground
from typing import reveal_type
def process_list(values: list[str] | list[list[str]]) -> str:
if all(isinstance(item, str) for item in values):
reveal_type(values) # Should be narrowed to list[str]
return "Should be str"
if all(isinstance(item, list) and len(item) == 2 for item in values):
reveal_type(values) # Should be narrowed to list[list[str]]
return "Should be list[str]"
return ""
the issue is that there is no type system contract that all does what you expect it does. therefore requiring special-casing, which is not ideal
@DetachHead does builtins specialization count as a plugin?
also, did you consider this case:
def process_list(values: list[str] | list[int]):
if all(isinstance(item, str) for item in values):
values.append("i'm a string")
a: list[int] = []
process_list(a)
print(a)
i think for this particular case you might want to use any instead of all
also, did you consider this case:
class A: ...
def process_list(values: list[A] | list[list[str]]) -> str:
if all(isinstance(item, list) for item in values):
values.append(["a"])
return "Should be list[str]"
if all(isinstance(item, A) for item in values):
return "Should be A"
return ""
class ItsNotDisjoint(A, list[int]): ...
data: list[A] = [ItsNotDisjoint()]
process_list(data)
i think in an ideal world we could narrow any to some kind of list[Covariant[str]]
does builtins specialization count as a plugin?
while i don't like special-casing, don't think it necessitates a plugin since there is already a lot of special casing for builtins
def process_list(values: list[str] | list[int]): if all(isinstance(item, str) for item in values): values.append("i'm a string") a: list[int] = [] process_list(a) print(a)
good point, narrowing a list this way isn't safe because there's no way to tell what the type is if the list is empty
if the list is empty
or it's not disjoint
i guess its safe to narrow any but not all
or it's not disjoint
separate issue with narrowing in general: #1444