You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
traceback.walk_stack(None) does not behave the same as traceback.walk_stack(inspect.currentframe()) #96092
traceback.walk_stack(None) omits the calling frame, making it equivalent to traceback.walk_stack(inspect.currentframe().f_back). Given the documentation just says "If f is None, the current stack is used.", I would have expected traceback.walk_stack(None) to be equivalent to traceback.walk_stack(inspect.currentframe()).
[(<frame at 0x7f66ac559a40, file '/home/vincenttc/data/temp/test/test.py', line 10, code <module>>, 10)]
[(<frame at 0x7f66ac55fa60, file '/home/vincenttc/data/temp/test/test.py', line 7, code abc>, 7), (<frame at 0x7f66ac559a40, file '/home/vincenttc/data/temp/test/test.py', line 10, code <module>>, 10)]
[(<frame at 0x7f66ac559a40, file '/home/vincenttc/data/temp/test/test.py', line 10, code <module>>, 10)]
Note that the frame for abc is missing in the first and last line.
Your environment
CPython versions tested on: 3.8.10 (Ubuntu 20.04), 3.10.5 (Arch Linux)
>>> import traceback
>>> import inspect
>>>
>>> def abc():
... print(list(traceback.walk_stack(None)))
... print(list(traceback.walk_stack(inspect.currentframe())))
... print(list(traceback.walk_stack(inspect.currentframe().f_back)))
...
>>> abc()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in abc
File "/Users/iritkatriel/src/cpython/Lib/traceback.py", line 333, in walk_stack
f = sys._getframe().f_back.f_back.f_back.f_back
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'f_back'
I see that this function changed in
commit 5644c7b3ffd49bed58dc095be6e6148e0bb4431e
Author: Ammar Askar <ammar@ammaraskar.com>
Date: Sun Jul 4 19:14:33 2021 -0400
bpo-43950: Print columns in tracebacks (PEP 657) (GH-26958)
The traceback.c and traceback.py mechanisms now utilize the newly added code.co_positions and PyCode_Addr2Location
to print carets on the specific expressions involved in a traceback.
Co-authored-by: Pablo Galindo <Pablogsal@gmail.com>
Co-authored-by: Ammar Askar <ammar@ammaraskar.com>
Co-authored-by: Batuhan Taskaya <batuhanosmantaskaya@gmail.com>
This part:
@@ -309,7 +321,7 @@ def walk_stack(f):
current stack is used. Usually used with StackSummary.extract.
"""
if f is None:
- f = sys._getframe().f_back.f_back
+ f = sys._getframe().f_back.f_back.f_back.f_back
while f is not None:
yield f, f.f_lineno
f = f.f_back
You might expect it to print module -> outer -> inner but it would actually get module -> print_frames because that is where the walk_stack generator is consumed.
My intuition is we should fix walk_stack to return a generator that iterates over the frames from when it is called, rather than iterated over. While this is a breaking change, it seems like walk_stack(None) is almost never called in the stdlib or tests without an immediate StackSummary.extract nor did I find anything in a quick search over Github.
Thanks for the link. That use case is fine too since the generator is iterated over immediately. People tend to either pass into StackSummary.extract or iterate over it without storing the generator.
Activity
iritkatriel commentedon Sep 5, 2022
On main your code doesn't work at all:
I see that this function changed in
This part:
CC @ammaraskar @pablogsal @isidentical
pablogsal commentedon Sep 5, 2022
I am currently in release hell, @ammaraskar @isidentical can you take a look?
pythonGH-96092: restore frame height of traceback.walk_stack to that …
pythonGH-96092: restore frame height of traceback.walk_stack to that …
ammaraskar commentedon Nov 2, 2022
Added details on the root cause here: #99015 (comment)
It looks like
traceback.walk_stackwas never really meant to be called without immediately usingStackSummary.extracton it. It is a generator so the:is a bit misleading, those lines don't run when you call
traceback.walk_stackbut only when you start iterating over the generator.So if you do something like:
You might expect it to print
module -> outer -> innerbut it would actually getmodule -> print_framesbecause that is where thewalk_stackgenerator is consumed.My intuition is we should fix
walk_stackto return a generator that iterates over the frames from when it is called, rather than iterated over. While this is a breaking change, it seems likewalk_stack(None)is almost never called in the stdlib or tests without an immediateStackSummary.extractnor did I find anything in a quick search over Github.graingert commentedon Nov 3, 2022
@ammaraskar we use it here: https://github.com/dask/distributed/blob/c137ac0856af75a7ee54259ff86a15f6be1babe4/distributed/client.py#L2929
pass the desired frame to traceback.walk_stack for 3.11
ammaraskar commentedon Nov 3, 2022
Thanks for the link. That use case is fine too since the generator is iterated over immediately. People tend to either pass into
StackSummary.extractor iterate over it without storing the generator.pass the desired frame to traceback.walk_stack for 3.11
pass the desired frame to traceback.walk_stack for 3.11
pass the desired frame to traceback.walk_stack for 3.11
pass the desired frame to traceback.walk_stack for 3.11
pass the desired frame to traceback.walk_stack for 3.11
Add support for Python 3.11 (#7249)
service: Fix _get_caller_path() with Python >= 3.11
service: Include TS code module dir in `.env` search (#485)
pythongh-96092: Fix traceback.walk_stack(None) skipping too many frames
gh-96092: Fix traceback.walk_stack(None) skipping too many frames (#1…