Skip to content
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

Make warn-unreachable understand exception-swallowing contextmanagers #7317

Merged

Conversation

@Michael0x2a
Copy link
Collaborator

commented Aug 10, 2019

This pull request fixes #7214: it makes mypy treat any contextmanagers where the __exit__ returns bool or Literal[True] as ones that can potentially swallow exceptions.

Contextmanagers that return Any, Optional[bool], None, or Literal[False] continue to be treated as non-exception-swallowing ones.

This distinction helps the --warn-unreachable flag do the right thing in this example program:

from contextlib import suppress

def should_warn() -> str:
    with contextlib.suppress(IndexError):
        return ["a", "b", "c"][0]

def should_not_warn() -> str:
    with open("foo.txt") as f:
        return "blah"

This pull request needs the typeshed changes I made in python/typeshed#3179 before the tests and the mypy self-check will pass. Once that one gets merged, I'll update typeshed and rebase this pull request.

Michael0x2a and others added 2 commits Jul 29, 2019
This pull request fixes #7214:
it makes mypy treat any contextmanagers where the `__exit__` returns
`bool` or `Literal[True]` as ones that can potentially swallow
exceptions.

Contextmanagers that return `Optional[bool]`, None, or `Literal[False]`
continue to be treated as non-exception-swallowing ones.

This distinction helps the `--warn-unreachable` flag do the right thing
in this example program:

```python
from contextlib import suppress

def should_warn() -> str:
    with contextlib.suppress(IndexError):
        return ["a", "b", "c"][0]

def should_not_warn() -> str:
    with open("foo.txt") as f:
        return "blah"
```

This pull request needs the typeshed changes I made in
python/typeshed#3179. Once that one gets
merged, I'll update typeshed and rebase this pull request.
@ilevkivskyi

This comment has been minimized.

Copy link
Collaborator

commented Aug 16, 2019

I am going to close/re-open to trigger builds.

@ilevkivskyi ilevkivskyi reopened this Aug 16, 2019
@Michael0x2a

This comment has been minimized.

Copy link
Collaborator Author

commented Aug 16, 2019

FYI, the tests for this PR aren't going to pass -- python/typeshed#3179 needs to be landed first.

@ilevkivskyi

This comment has been minimized.

Copy link
Collaborator

commented Aug 16, 2019

Oh, I somehow thought it was already merged. We can make then a dedicated sync when this will be ready. Also there is now a bonus self-check failure (easy to fix however).

@JelleZijlstra

This comment has been minimized.

Copy link
Collaborator

commented Aug 16, 2019

I merged the typeshed PR.

Copy link
Collaborator

left a comment

Thanks! Looks good, I have several small comments.

test-data/unit/check-unreachable-code.test Outdated Show resolved Hide resolved
test-data/unit/pythoneval.test Outdated Show resolved Hide resolved
mypy/types.py Outdated Show resolved Hide resolved
mypy/checker.py Show resolved Hide resolved
mypy/checker.py Show resolved Hide resolved
self.check_with_item(expr, target, s.unanalyzed_type is None)
self.accept(s.body)
exit_ret_type = self.check_with_item(expr, target, s.unanalyzed_type is None)
if is_literal_type(exit_ret_type, "builtins.bool", False):

This comment has been minimized.

Copy link
@ilevkivskyi

ilevkivskyi Aug 23, 2019

Collaborator

Are these rules/conventions documented somewhere? I think they should be, otherwise we will just forget them (either in mypy docs, btw do we have a section about context managers?, or in typeshed). Maybe also add a link here.

This comment has been minimized.

Copy link
@Michael0x2a

Michael0x2a Aug 25, 2019

Author Collaborator

I did add some notes about these conventions to the typeshed contribution page (at the bottom of the conventions section), but this conventions currently aren't otherwise documented.

We do mention context managers once on the Protocols page -- I'll add a note about this there in a follow-up PR.

…onal is disabled
@Michael0x2a Michael0x2a force-pushed the Michael0x2a:refine-unreachable-checks-against-with branch from 4fee4b8 to b75f886 Aug 25, 2019
@Michael0x2a

This comment has been minimized.

Copy link
Collaborator Author

commented Aug 25, 2019

As an FYI, I ended up making one more change to this PR: basically, I made it so we no longer assume context managers suppress exceptions when __exit__ returns bool when strict-optional mode is disabled. I found while playing around with open(...) that we didn't necessarily preserve whether __exit__ returns bool vs Optional[bool] in that mode, so decided it'd probably be safer to just give up and bias towards retaining the old behavior.

LMK if you see a better way of handling this or if handled the no-strict-optional check incorrectly, and I can submit a follow-up PR to fix.

@Michael0x2a Michael0x2a merged commit f15d677 into python:master Aug 25, 2019
2 checks passed
2 checks passed
continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
@Michael0x2a Michael0x2a deleted the Michael0x2a:refine-unreachable-checks-against-with branch Aug 25, 2019
@ilevkivskyi

This comment has been minimized.

Copy link
Collaborator

commented Aug 26, 2019

We do mention context managers once on the Protocols page -- I'll add a note about this there in a follow-up PR.

Thanks! Sounds good to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.