diff --git a/pudb/debugger.py b/pudb/debugger.py index 9e7c902e..9ca7cedc 100644 --- a/pudb/debugger.py +++ b/pudb/debugger.py @@ -327,6 +327,14 @@ def set_frame_index(self, index): return self.curframe, lineno = self.stack[index] + # f_locals is a write-through proxy, meaning we can update local + # variables in the shell and those changes will be reflected in the + # running program. However, every time curframe.f_locals is accessed, + # it gets reset to a snapshot of its original value. So we need to + # save a copy of it to avoid this (this is the same trick used by + # pdb). See https://peps.python.org/pep-0558/ and the discussion on + # #571 for more details. + self.curframe_locals = self.curframe.f_locals filename = self.curframe.f_code.co_filename @@ -1706,8 +1714,8 @@ def cmdline_get_namespace(): from pudb.shell import SetPropagatingDict return SetPropagatingDict( - [curframe.f_locals, curframe.f_globals], - curframe.f_locals) + [self.debugger.curframe_locals, curframe.f_globals], + self.debugger.curframe_locals) def cmdline_tab_complete(w, size, key): try: @@ -1837,6 +1845,8 @@ def cmdline_exec(w, size, key): sys.stdout = prev_sys_stdout sys.stderr = prev_sys_stderr + self.update_var_view() + def cmdline_history_browse(direction): if self.cmdline_history_position == -1: self.cmdline_history_position = len(self.cmdline_history) @@ -2060,7 +2070,7 @@ def fallback(): else: runner = shell.custom_shell_dict["pudb_shell"] - runner(curframe.f_globals, curframe.f_locals) + runner(curframe.f_globals, self.debugger.curframe_locals) self.update_var_view() @@ -2768,7 +2778,7 @@ def set_current_line(self, line, source_code_provider): def update_var_view(self, locals=None, globals=None, focus_index=None): if locals is None: - locals = self.debugger.curframe.f_locals + locals = self.debugger.curframe_locals if globals is None: globals = self.debugger.curframe.f_globals