-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Don't assume direct parentage when emitting used-before-assignment
#5582
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
Changes from 13 commits
2d949d9
d16730b
fd4a266
65782ec
4b409a2
18dd196
ad3651e
8c26f64
43f708d
32b9d2d
7f4b88e
0329aa5
0a25e1a
6e767a5
ef7666b
836c457
3cdf244
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -4,6 +4,57 @@ def main(): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res = 1 / 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res = 42 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if main(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
with open(__file__, encoding="utf-8") as opened_file: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res = opened_file.readlines() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
except ZeroDivisionError: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
print(res) # [used-before-assignment] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
print(res) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def nested_except_blocks(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"""Assignments in an except are tested against possibly failing | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
assignments in try blocks at two different nesting levels.""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res = 1 / 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res = 42 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if main(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
with open(__file__, encoding="utf-8") as opened_file: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res = opened_file.readlines() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
except ZeroDivisionError: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
more_bad_division = 1 / 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
except ZeroDivisionError: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
print(more_bad_division) # [used-before-assignment] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
print(res) # [used-before-assignment] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
print(res) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
jacobtylerwalls marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def consecutive_except_blocks(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"""An assignment assumed to execute in one TryExcept should continue to be | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
assumed to execute in a consecutive TryExcept. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res = 100 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
except ZeroDivisionError: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pass | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pass | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
except ValueError: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
print(res) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+35
to
+46
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think I understand everything here. If the first except is raised and the function do not return, it means in the second one
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, we want to avoid annoying users, and so outside a TryExcept we assume the try statements executed. By that same logic we assume that outside a TryExcept its except statements did not execute -- because it would be a bit backwards to assume the try statements never execute and thus that assignments in the except always happen. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Didn't we say that like Pylance we consider that everything in a try/except can fail ? (#5384). Also, if we do not raise or return in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess a good way of putting it is that's why there are different private methods in this checker now:
We make different control flow inferences based on where the name is being used (try, except, finally, or outside). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with the points you're making here. Especially the last example is something of which I can easily imagine complaints coming from. Code with requests and databases seem to often really on such patterns. Perhaps you could add a summary of this explanation to the issue you mentioned? That way we don't lose this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
My last example was not quite right π¬ -- I neglected that subsequent handlers can't swallow exceptions raised in earlier handlers, so There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think this discussion is getting at when an I guess this could even be its own checker, so it could be enabled/disabled separately. (It would probably be easier to implement that way, given how much new logic would go into the exhaustiveness checking.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think relying on everyone knowing that But I get that this might be a little opinionated and that we'd get complaints from this, thank you for explaining.
π There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This discussion helped clarify for me that beefing up the checker to assume try statements always fail is worthy of discussion, but would need to be solved in tandem with #5524, so I suggest we keep discussing there for 2.14 or later. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def name_earlier_in_except_block(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"""Permit the name that might not have been assigned during the try block | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
to be defined inside a conditional inside the except block. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res = 1 / 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
except ZeroDivisionError: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if main(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res = 10 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res = 11 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
print(res) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
used-before-assignment:8:14:8:17:main:Using variable 'res' before assignment:UNDEFINED | ||
used-before-assignment:12:14:12:17:main:Using variable 'res' before assignment:UNDEFINED | ||
used-before-assignment:30:18:30:35:nested_except_blocks:Using variable 'more_bad_division' before assignment:UNDEFINED | ||
used-before-assignment:31:18:31:21:nested_except_blocks:Using variable 'res' before assignment:UNDEFINED |
Uh oh!
There was an error while loading. Please reload this page.