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

Preserve changes to frame locals when going up/down in the stack frame #13051

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 19 additions & 0 deletions IPython/core/debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@ def __init__(self, color_scheme=None, completekey=None,
# list of predicates we use to skip frames
self._predicates = self.default_predicates

# To save frame locals so we can restore them on up/down
self.frame_locals = []

def set_colors(self, scheme):
"""Shorthand access to the color table scheme selector method."""
self.color_scheme_table.set_active_scheme(scheme)
Expand Down Expand Up @@ -351,6 +354,17 @@ def hidden_frames(self, stack):
ip_hide = [h if i > ip_start[0] else True for (i, h) in enumerate(ip_hide)]
return ip_hide

def preloop(self):
"""
Save a copy of all frame locals so changes to them are not lost
when going up/down in the stack frame.
"""
self.frame_locals = [
stack_entry[0].f_locals.copy() for stack_entry in self.stack
Copy link
Contributor

Choose a reason for hiding this comment

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

@ccordoba12 , is there any need to copy this dict?
If there isn't, removing copy() could fix the problem mentioned by @MrMino (I've tested locally their example, and it worked as expected).

Suggested change
stack_entry[0].f_locals.copy() for stack_entry in self.stack
stack_entry[0].f_locals for stack_entry in self.stack

If you need to keep only certain subset of changes, I would suggest to wrap the original locals with a ChainMaps at some point.

Copy link
Member Author

Choose a reason for hiding this comment

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

Could you clarify? What's a ChainMap?

Copy link
Contributor

Choose a reason for hiding this comment

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

image

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, thanks a lot for the suggestion! I'll take a look at it as soon as Io have some free time.

]
self.curframe_locals = self.frame_locals[self.curindex]
super().preloop()

def interaction(self, frame, traceback):
try:
OldPdb.interaction(self, frame, traceback)
Expand All @@ -369,6 +383,11 @@ def precmd(self, line):

return line

def postcmd(self, stop, line):
"""Set current frame locals using the ones we saved in preloop."""
self.curframe_locals = self.frame_locals[self.curindex]
return super().postcmd(stop, line)

def new_do_frame(self, arg):
OldPdb.do_frame(self, arg)

Expand Down