From 5b9d94f2da4a0a68b9da368335235d8dd9edb5e9 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Wed, 16 Nov 2022 15:39:41 -0700 Subject: [PATCH 1/4] Allow function definition locals() to be modified in the shell This still requires more testing, especially for the different shells. For the IPython shell, this requires not making a copy of locals(), but this also causes the IPython shell to pollute the locals() namespace with all its internal variables (like _0 and so on), so a better fix is needed. Fixes #26. --- pudb/debugger.py | 9 +++++---- pudb/shell.py | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pudb/debugger.py b/pudb/debugger.py index 9e7c902e..a30f8833 100644 --- a/pudb/debugger.py +++ b/pudb/debugger.py @@ -327,6 +327,7 @@ def set_frame_index(self, index): return self.curframe, lineno = self.stack[index] + self.curframe_locals = self.curframe.f_locals filename = self.curframe.f_code.co_filename @@ -1706,8 +1707,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: @@ -2060,7 +2061,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 +2769,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 diff --git a/pudb/shell.py b/pudb/shell.py index c57f2720..4b66d333 100644 --- a/pudb/shell.py +++ b/pudb/shell.py @@ -164,7 +164,7 @@ def run_ipython_shell_v10(globals, locals): def _update_ipython_ns(shell, globals, locals): """Update the IPython 0.11 namespace at every visit""" - shell.user_ns = locals.copy() + shell.user_ns = locals try: shell.user_global_ns = globals From c5d17fdfd4a3af532df665afc50191078d790f61 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 17 Nov 2022 15:42:33 -0700 Subject: [PATCH 2/4] Revert change to IPython shell to make locals editable This also causes IPython to inject all its magic variables (_, _0, get_ipython, etc.) into the locals namespace every time it is started. Unless there is some way to disable this, this is not worth this functionality, since it pollutes the variables view and also would break any code that happens to use those same variable names. --- pudb/shell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pudb/shell.py b/pudb/shell.py index 4b66d333..c57f2720 100644 --- a/pudb/shell.py +++ b/pudb/shell.py @@ -164,7 +164,7 @@ def run_ipython_shell_v10(globals, locals): def _update_ipython_ns(shell, globals, locals): """Update the IPython 0.11 namespace at every visit""" - shell.user_ns = locals + shell.user_ns = locals.copy() try: shell.user_global_ns = globals From 95ef370a97ba578addd2a075db31fa2e5bff6d24 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 17 Nov 2022 16:16:46 -0700 Subject: [PATCH 3/4] Make the var view update when executing a command in the internal shell --- pudb/debugger.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pudb/debugger.py b/pudb/debugger.py index a30f8833..d69767da 100644 --- a/pudb/debugger.py +++ b/pudb/debugger.py @@ -1838,6 +1838,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) From 82b1f15b8af4df066b1888e5d3d61a76229db355 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 22 Dec 2022 16:24:17 -0700 Subject: [PATCH 4/4] Add a comment explaining the curframe_locals behavior --- pudb/debugger.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pudb/debugger.py b/pudb/debugger.py index d69767da..9ca7cedc 100644 --- a/pudb/debugger.py +++ b/pudb/debugger.py @@ -327,6 +327,13 @@ 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