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
Python 3.9.0a2 changed how finally/return is traced #83295
Comments
The way trace function reports return-finally has changed in Python 3.9.0a2. I don't know if this change is intentional or not. (BTW: I want to put a 3.9regression keyword on this, but it doesn't exist.) Consider this code: --- 8< ---------------------------------------------------- import linecache, sys
def trace(frame, event, arg):
lineno = frame.f_lineno
print("{} {}: {}".format(event[:4], lineno, linecache.getline(__file__, lineno).rstrip()))
return trace
print(sys.version)
sys.settrace(trace)
a = []
def finally_return():
try:
return 14
finally:
a.append(16)
assert finally_return() == 14
assert a == [16]
--- 8< (My habit is to use line numbers in the lines themselves to help keep things straight.) In Python 3.7 (and before), the last traces are line 14, line 16, return 16. In Python 3.8, the last traces are line 14, line 16, line 14, return 14. In Python 3.9a1, the traces are the same as 3.8. In Python 3.9a2, the traces are now line 14, line 16, line 14, line 16, return 16. This doesn't make sense to me: why does it bounce back and forth? Full output from different versions of Python: % /usr/local/pythonz/pythons/CPython-3.7.1/bin/python3.7 bpo.py |
Looking at changes to alpha2 I think it bisects to #6641 ➜ cpython git:(5dcc06f) git checkout fee5526 && make -s -j4 > /dev/null |
Exammining the bytecode for: def finally_return():
try:
return 14
finally:
a.append(16) We have: 2 0 SETUP_FINALLY 16 (to 18) 3 2 POP_BLOCK 5 4 LOAD_GLOBAL 0 (a) 3 14 LOAD_CONST 2 (14) 5 16 RETURN_VALUE Which looks correct, except for the line number of the first RETURN_VALUE. Looking at the compiler it seems that we aren't preserving the original line number when emitting code for the finally block. |
With PR 17737 the bytecode is: 2 0 SETUP_FINALLY 16 (to 18) 3 2 POP_BLOCK 5 4 LOAD_GLOBAL 0 (a) 3 14 LOAD_CONST 2 (14) 5 >> 18 LOAD_GLOBAL 0 (a) |
Ned, I think this is fixed. Feel free to re-open if you disagree. |
Thanks, that fixes the original case in this issue. Here is another problem which seems related enough to append here instead of opening a new issue: --- 8< ---------------------------------------------------- import linecache, sys
def trace(frame, event, arg):
lineno = frame.f_lineno
print("{} {}: {}".format(event[:4], lineno, linecache.getline(__file__, lineno).rstrip()))
return trace
print(sys.version)
sys.settrace(trace)
def b(exc):
print("exc is {!r}".format(exc))
try:
raise Exception(exc)
except Exception as e:
if exc != 'expected':
raise # line 17
q = "removing this line changes the behavior"
r = "is this executed?" # line 19
return
b('expected')
try:
b('unexpected')
except:
pass
--- 8< With your fix, it reports that the raise on line 17 is followed by line 19, which can't be right: 3.9.0a2+ (heads/pr/17737:f2545467fa, Dec 29 2019, 15:38:57) Python 3.8 reported this: 3.8.1 (default, Dec 19 2019, 08:38:38) |
BTW: this is not a regression in your fix. 3.9a2 behaved this way also. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: