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

Fix false negative for used-before-assignment when an Except intervenes between Try/Finally #5583

Merged
merged 6 commits into from
Jan 15, 2022

Conversation

jacobtylerwalls
Copy link
Member

Type of Changes

Type
βœ“ πŸ› Bug fix

Description

Fixes false negative for used-before-assignment when evaluating statements in a finally block, there is a possibly failing statement in the try block, and an except handler intervenes between.

Found while working on #5582. Unhandled case from #5384 -- I had thought of this case, but didn't know how to solve it: a finally that is not the direct descendant of a try handler because we have try/except/finally. (Since we were just incrementally solving false negatives, that wasn't such a problem at the time.) After #5582, I now know how to handle it!

@Pierre-Sassoulas Pierre-Sassoulas added the False Negative πŸ¦‹ No message is emitted but something is wrong with the code label Dec 21, 2021
@Pierre-Sassoulas Pierre-Sassoulas added this to the 2.13.0 milestone Dec 21, 2021
@coveralls
Copy link

coveralls commented Dec 21, 2021

Pull Request Test Coverage Report for Build 1700068503

  • 21 of 22 (95.45%) changed or added relevant lines in 1 file are covered.
  • 92 unchanged lines in 6 files lost coverage.
  • Overall coverage increased (+0.1%) to 93.841%

Changes Missing Coverage Covered Lines Changed/Added Lines %
pylint/checkers/variables.py 21 22 95.45%
Files with Coverage Reduction New Missed Lines %
pylint/message/message_definition_store.py 1 98.28%
pylint/checkers/init.py 2 93.94%
pylint/checkers/refactoring/refactoring_checker.py 6 98.18%
pylint/checkers/stdlib.py 15 94.09%
pylint/checkers/classes/class_checker.py 29 94.5%
pylint/checkers/variables.py 39 96.18%
Totals Coverage Status
Change from base Build 1679646293: 0.1%
Covered Lines: 14688
Relevant Lines: 15652

πŸ’› - Coveralls

@jacobtylerwalls
Copy link
Member Author

jacobtylerwalls commented Dec 22, 2021

Need to test this case -- newly failing on this branch: EDIT: done in 09a7251

try:
    pass
finally:
    try:
        times = 1
    except TypeError:
        pass
    print(times)  # emits. shouldn't. and won't if the outer try goes away.

@DanielNoord
Copy link
Collaborator

@jacobtylerwalls I haven't look at this but in #5582 we discussed doing some of the changes for used-before-assignment in 2.13, get feedback, and then do some changes in 2.14. Does this fall under the same category of "perhaps wait till 2.14" or should this be reviewed for 2.13?

@jacobtylerwalls
Copy link
Member Author

jacobtylerwalls commented Jan 10, 2022

Hi @DanielNoord thanks for looking into this. I think this is the same category ("no reason to wait; fixes false negatives for assumptions we've already doc'd and merged to main") as #5582, see #5582 (comment). Happy to hear your views on this.

Copy link
Collaborator

@DanielNoord DanielNoord left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jacobtylerwalls misunderstood! Only one comment πŸ˜„

pylint/checkers/variables.py Outdated Show resolved Hide resolved
Copy link
Member

@Pierre-Sassoulas Pierre-Sassoulas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, but the rebase for this is non trivial, and there's a strange conflict in the changelog and whatsnew. Could you rebase yourself @jacobtylerwalls ?

Copy link
Member

@Pierre-Sassoulas Pierre-Sassoulas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good already, I have two questions regarding the tests.

Comment on lines 55 to 67
def try_except_finally_nested_try_finally_in_finally():
"""Don't confuse assignments in different finally statements where
one is nested inside a finally.
"""
try:
pass
finally:
try:
times = 1
except TypeError:
pass
# Don't emit: only assume the outer try failed
print(times)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand Don't confuse assignments in different finally statements. Shouldn't we raise or times be defined somewhere in the other finally statement?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring looks like it was lazily copied from above and not really updated. I'll push again and explain in the docstring how I see what is being tested and where to go from here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In rewriting the tests I discovered I could handle nesting better. So there are more tests now :-)

tests/functional/c/consider/consider_using_with_open.py Outdated Show resolved Hide resolved
Copy link
Member

@Pierre-Sassoulas Pierre-Sassoulas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work, thank you @jacobtylerwalls !

@Pierre-Sassoulas Pierre-Sassoulas merged commit 3b68aa7 into pylint-dev:main Jan 15, 2022
@jacobtylerwalls jacobtylerwalls deleted the try-except-finally branch February 3, 2022 00:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
False Negative πŸ¦‹ No message is emitted but something is wrong with the code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants