-
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
tuple length type narrowing #2474
Comments
This one is particularly nasty in the rich codebase because the |
This isn't a supported type narrowing pattern. For a full list of supported type narrowing patterns, see this documentation. Each new type narrowing pattern requires custom code and can slow down overall analysis, so we do not add new patterns unless we see signal that it's a commonly-used case that will help a significant number of pyright users. I haven't seen this use case very frequently, and it's not currently supported in mypy. So, for now, I don't think we can justify adding this. We can revisit in the future if we get additional signal. In the meantime, I recommend using a user-defined type guard defined in PEP 647. I am the author of that PEP, and one of the examples I provided specifically covers your use case. Search for |
For tracking purposes, here's the open PR for mypy that adds this type of type narrowing support: python/mypy#10367 It seems upstream was interested in merging but it got lost between releases so we'll see what happens. I do think there's value in the |
Is there some trick or workaround to TypeGuard length 1 tuples? I suspect you're aware of the pitfalls by your choice to do the two element case in the PEP. It seems to me this isn't really expressible. This is needed for rich since the not-length-1 case is large union of types so I think unless we want to make 4 or 5 typeguards we actually do have to use a cast. |
_T = TypeVar("_T")
def is_two_element_tuple(val: tuple[_T, ...]) -> TypeGuard[tuple[_T, _T]]:
return len(val) == 2
def process_tuples(tup: MultiTuple) -> object:
if not is_two_element_tuple(tup):
return tup[0]
else:
first, second = tup
return second |
I think we're fairly confident in IRC this isn't possible with TypeGuard. Your proposed solution has a number of problems with tuple unions, for example you're only checking the length 2 case when I need to separate out the length 1 tuple case from an inferred Tuple[Unknown, ...] (due to an isinstance tuple check w/ an object) - and I need to separate this in addition to a few specific sized cases where further these tuple cases don't uniformly have the same type. See https://github.com/willmcgugan/rich/blob/e6fec11cae662d26c22ed54340681cada272fc3c/rich/repr.py#L65 for my solution where the signature of |
If you provide a minimal self-contained example, I can help find a solution. |
I wrote out a long post with an example and lessons, but I've decided it's all redundant except: Apologies for burying the lead for what I really wanted from the start. To make a long story short my main problem is I didn't internalize the part of the PEP that I appreciate your time and I'll update if len() ever becomes a supported narrowing pattern in mypy (it looks they also want it to work for literals which could be interesting). It's not needed for my use case, but I can see value in the ability to narrow in both branches in a way that a len() narrowing could provide (but I suppose you could double TypeGuard). Studying my example at least gave appreciation for the complication involved in implementing this enhancement request. |
Describe the bug
pyright should support type narrowing based on tuple length to avoid the false positive in the following code snippet:
/home/gregory/Downloads/testcase/pytest/tuplesize.py:9:9 - error: Tuple size mismatch: expected 2 but received 1 (reportGeneralTypeIssues)
This came up in the rich codebase, and there's a corresponding mypy issue with an open PR: python/mypy#1178
Expected behavior
pyright should be able to type narrow tuples based on len()
VS Code extension or command-line
pyright 1.1.180 Linux commandline
The text was updated successfully, but these errors were encountered: