-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TypeIs
narrowing for certain parameterized containers doesn't make sense
#8109
Comments
TypeIs
narrowing for list
doesn't make senseTypeIs
narrowing for certain parameterized containers doesn't make sense
These are invalid uses of If you enable basic type checking diagnostics, you will observe that pyright displays errors about your usage of The In any case, this is not a bug in pyright, so I'm closing the issue. |
Interesting. I feel like this behavior is disputable, but if I choose to pursue that, it'll be later. For now, I'll just note that I set pyright on strict mode, but Pylance didn't actually point out that this TypeIs usage is invalid. I'll see if there's a bug in my setup. EDIT: Turns out there was a rogue configuration file with |
Edit: Post left mostly as is for posterity, can be ignored, I made a mistake when considering this see very bottom of post or followup
This requirement isn't expressed in the pep for it, the actual requirement which was accepted specified it in terms of consistency:
The term "consistent with" is not extremely well defined, but the above usage meets the requirement of this for what most people would expect, and this matches the ongoing work in the PR python/typing#1743 The latter language indicating set-theoretic definitions, while not firmly in the specification at this point in time, would match this interpretation for what the behavior should be (also quoted below). This seems to support the interpretation that this should be an allowed use. The resulting narrowing in the positive case and the negative case are also well specified, but the negative narrowing might have surprising behavior to some here, as the negative would still include the non-homogenous original form.
Taking the original examples def _is_list_of_str(lst: list[str | tuple[str, object]]) -> TypeIs[list[str]]:
... # I've left out the original implementation,
# as the implementation was unsafe for what was expressed.
# however, the pep also does not say that it's an error for someone to write an unsafe typeis
def example1(thing: list[str | tuple[str, object]]):
if _is_list_of_str(thing):
# list[str]
else:
# list[str | tuple[str, object]] & ~list[str]
# notably, this could still include `str` elements This becomes more obvious when considering that all of the below are consistent with list[A | B], including the non-denotable forms. (Edit: No, these aren't consistent with as types. As values having that exact type, they could be, variance failure on my part)
|
Neither the consistency nor the subtyping rule would actually be type safe. I think the consistency rule is correct, Here's an example that type checks fine by using sequence, but will error at runtime. Code sample in pyright playground import asyncio
from typing import Sequence
from typing_extensions import TypeIs
class A: pass
class B(A):
def __init__(self, use_count: int = 0):
self.use_count = use_count
def is_seq_b(x: Sequence) -> TypeIs[Sequence[B]]:
return all(isinstance(i, B) for i in x)
async def takes_seq(x: Sequence[A]):
if is_seq_b(x):
await asyncio.sleep(10)
users = sum(i.use_count for i in x)
async def takes_list(x: list[A]):
t = asyncio.create_task(takes_seq(x))
await asyncio.sleep(1)
x.append(A())
await t
if __name__ == "__main__":
lst: list[A] = [B(i) for i in range(10)]
asyncio.run(takes_list(lst)) |
Describe the bug
When using
TypeIs
with a guard function that's meant to narrow the parameterized type of some types of containers, the type pyright infers when that function is used doesn't make sense. I didn't narrow down which containers this occurs with, but gave two as an example below.Code or Screenshots
VS Code extension or command-line
This was replicated in VSCode via Pylance, version 2024.6.1.
The text was updated successfully, but these errors were encountered: