GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — traceback.walk_stack(None) does not behave the same as traceback.walk_stack(inspect.currentframe()) · Issue #96092 · python/cpython

traceback.walk_stack(None) does not behave the same as traceback.walk_stack(inspect.currentframe()) #96092

New issue
Copy link
New issue
Copy link
Closed
#129330
Closed
traceback.walk_stack(None) does not behave the same as traceback.walk_stack(inspect.currentframe())#96092
#129330
Copy link
Labels
3.10 (EOL)end of lifeend of life3.11only security fixesonly security fixes3.12only security fixesonly security fixesstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

@VincentVanlaer
VincentVanlaer
opened on Aug 18, 2022
Issue body actions

Bug report

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()).

Example code

The following code

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()

has as output

[(<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)
  • PR: GH-96092: restore frame height of traceback.walk_stack to that of pyt… #99015
  • PR: gh-96092: Fix traceback.walk_stack(None) skipping too many frames #129330
Reacted by Finite State Machine and Daniel Golding

Activity

  1. VincentVanlaer
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    on Aug 18, 2022
  2. mdboom
    added
    3.10 (EOL)end of lifeend of life
    3.8 (EOL)end of lifeend of life
    on Aug 19, 2022
  3. iritkatriel commented on Sep 5, 2022

    @iritkatriel
    iritkatriel
    on Sep 5, 2022
    Member
    More actions

    On main your code doesn't work at all:

    >>> 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 <[email protected]>
    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 <[email protected]>
        Co-authored-by: Ammar Askar <[email protected]>
        Co-authored-by: Batuhan Taskaya <[email protected]>
    
    

    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
    
    

    CC @ammaraskar @pablogsal @isidentical

  4. iritkatriel
    added
    3.11only security fixesonly security fixes
    3.12only security fixesonly security fixes
    stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
    and removed
    3.8 (EOL)end of lifeend of life
    on Sep 5, 2022
  5. pablogsal commented on Sep 5, 2022

    @pablogsal
    pablogsal
    on Sep 5, 2022
    Member
    More actions

    I am currently in release hell, @ammaraskar @isidentical can you take a look?

  6. graingert
    added 2 commits that reference this issue on Nov 2, 2022

    pythonGH-96092: restore frame height of traceback.walk_stack to that …

    d3ae604

    pythonGH-96092: restore frame height of traceback.walk_stack to that …

    2376fe7
  7. ammaraskar commented on Nov 2, 2022

    @ammaraskar
    ammaraskar
    on Nov 2, 2022
    Member
    More actions

    Added details on the root cause here: #99015 (comment)

    It looks like traceback.walk_stack was never really meant to be called without immediately using StackSummary.extract on it. It is a generator so the:

        if f is None:
            f = sys._getframe().f_back.f_back

    is a bit misleading, those lines don't run when you call traceback.walk_stack but only when you start iterating over the generator.

    So if you do something like:

    def outer():
        return inner()
    def inner():
        return traceback.walk_stack(None)
    
    frames = outer()
    
    
    def print_frames(f):
        print(list(f))
    
    print_frames(frames)

    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.

  8. graingert commented on Nov 3, 2022

    @graingert
    graingert
    on Nov 3, 2022
    Contributor
    More actions

    @ammaraskar we use it here: https://github.com/dask/distributed/blob/c137ac0856af75a7ee54259ff86a15f6be1babe4/distributed/client.py#L2929

  9. graingert
    added a commit that references this issue on Nov 3, 2022

    pass the desired frame to traceback.walk_stack for 3.11

    35da6dd
  10. ammaraskar commented on Nov 3, 2022

    @ammaraskar
    ammaraskar
    on Nov 3, 2022
    Member
    More actions

    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.

  11. graingert
    added a commit that references this issue on Nov 9, 2022

    pass the desired frame to traceback.walk_stack for 3.11

    38cf55a
  12. graingert
    added 4 commits that reference this issue on Nov 17, 2022

    pass the desired frame to traceback.walk_stack for 3.11

    3029329

    pass the desired frame to traceback.walk_stack for 3.11

    3af29e6

    pass the desired frame to traceback.walk_stack for 3.11

    41cc625

    pass the desired frame to traceback.walk_stack for 3.11

    af34a7b
  13. graingert
    added a commit that references this issue on Dec 14, 2022

    Add support for Python 3.11 (#7249)

    64a7cae
  14. bkeryan
    added a commit that references this issue on Oct 29, 2023

    service: Fix _get_caller_path() with Python >= 3.11

    46dadaa
  15. dixonjoel
    added a commit that references this issue on Oct 30, 2023

    service: Include TS code module dir in `.env` search (#485)

    92f5abe
  16. serhiy-storchaka
    added this to Inspect issues 🔍on Mar 5, 2024
  17. ammaraskar
    added a commit that references this issue on Jan 27, 2025

    pythongh-96092: Fix traceback.walk_stack(None) skipping too many frames

    bd9d061
  18. pablogsal
    added a commit that references this issue on Feb 13, 2025

    gh-96092: Fix traceback.walk_stack(None) skipping too many frames (#1…

    f9a7d41
  19. pablogsal
    closed this as completedin #129330on Feb 13, 2025
  20. github-project-automation
    moved this to Done in Inspect issues 🔍on Feb 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.10 (EOL)end of lifeend of life3.11only security fixesonly security fixes3.12only security fixesonly security fixesstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

    Projects

    • Inspect issues 🔍
      Status
      Done
      Show more project fields

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    You are visitor 01402520 — GeezerVison does not store the pages you look up.
    Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.