-
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
Improve type inference of context manager that swallow exceptions #771
Conversation
Context managers that have a `__exit__` with a return type of `bool` or `Literal[True]` can swallow exceptions, which means that code afterwards is reachable and needs to be type checked.
Thanks for this contribution! I'm really impressed with this PR. The code flow engine is one of the more complex pieces of code in Pyright, and you managed to figure it out. That said, I see some issues with your PR that I'd like to address before I merge it. I'll try to get to it in the next few days. Thanks again! |
I would be lying if I said that I actually understand the code flow engine, but I was able to piece together just enough for this one use case haha. I'm happy to address any and all comments, and am not in a rush, so take your time. |
I spent some additional time reviewing your solution. Unfortunately, it's not going to work as written. The problem is that the code you added to the I'll need to think more about whether there's a creative way around this. Some additional background, in case you're interested. Mypy is a multi-pass analyzer — i.e. it performs type analysis for a source file as many times as necessary for all type information to "converge". Earlier versions of Pyright also used this technique, but it's very inefficient. Later versions of Pyright employ lazy evaluation, which means that the type of each node in the parse tree is evaluated only once — and only if that type is actually needed. Plus, analysis is performed in whatever order is needed. While lazy evaluation is very efficient, it places some constraints on the analyzer. One such constraint is that the reachability of control flow nodes can't depend on type evaluation. One other (smaller) issue with your solution is that it won't properly detect or report cases where variables are potentially unbound. Take for example:
In this case, b is possibly unbound because it was assigned a value only after the call to I'll continue to think about how to work around the reachability limitation. |
Thank you for spending the time to review this patch and explaining in such great detail the problem space! It makes sense that in most cases reachability can be determined statically without evaluation of all types. Looking at the code again I see that Do you think a similar approach would make sense here as well? Attempt to look at explicit type hints on |
Yeah, I think a similar approach might work, but that will involve a bunch of extra code that needs to be written, tested, and maintained. The question in my mind is whether all of that extra special-case code is worth it for this functionality. It's a pretty esoteric feature. You're the first person to report it. If this were an official part of the Python spec, then I wouldn't hesitate to support it, but it's not. So my inclination at this point is to say that it's not worth the extra code. Especially given that this is a non-standard way to handle exceptions when the language already has a perfectly good standard way to handle exceptions — a try/except statement. So my inclination at this point is to not address this issue unless/until the Python spec is updated to indicate that the return type of |
👍 sounds good to me |
This fixes #764
The typeshed has this to say:
This PR makes
pyright
follow the statement above, by adding additional code flow analysis to trackwith
blocks and check the return type of the context managers.The tests are based on python/mypy#7317 but have been modified to more closely resemble the tests in this repo.