From 7db9d37f9e2916af7b9b9954529da83cedc93eac Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Sat, 22 Apr 2023 14:03:46 -0700 Subject: [PATCH 1/7] Add convenience variable feature --- Doc/library/pdb.rst | 13 ++++++++ Lib/pdb.py | 21 ++++++++++++ Lib/test/test_pdb.py | 78 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 5bc48a6d5f77fd..64390ecb249dad 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -263,6 +263,19 @@ the commands; the input is split at the first ``;;`` pair, even if it is in the middle of a quoted string. A workaround for strings with double semicolons is to use implicit string concatenation ``';'';'`` or ``";"";"``. +To set temporary global variables, use *convenience variable*. A *convenience +variable* is a variable whose name starts with ``$``. For example, ``$foo = 1`` +set a global variable ``$foo`` which you can use in the debugger session. The +*convenience variables* are cleared when the program resumes execution so it's +less likely to interfere with your program compared to using normal variables +like ``foo = 1``. + +There are three preset *convenience variables*: + +* ``$_frame``: the current frame you are debugging +* ``$_return``: the return value if the frame is returning +* ``$_exception``: the ``(exc_type, exc_value)`` tuple if the frame is raising an exception + .. index:: pair: .pdbrc; file triple: debugger; configuration; file diff --git a/Lib/pdb.py b/Lib/pdb.py index a3553b345a8dd3..9ba9856b128994 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -270,6 +270,8 @@ def forget(self): self.lineno = None self.stack = [] self.curindex = 0 + if hasattr(self, 'curframe') and self.curframe: + self.curframe.f_globals.pop('__pdb_convenience_variables', None) self.curframe = None self.tb_lineno.clear() @@ -288,6 +290,11 @@ def setup(self, f, tb): # locals whenever the .f_locals accessor is called, so we # cache it here to ensure that modifications are not overwritten. self.curframe_locals = self.curframe.f_locals + self.set_convenience_variable('_frame', self.curframe) + if '__return__' in self.curframe_locals: + self.set_convenience_variable('_return', self.curframe_locals['__return__']) + if '__exception__' in self.curframe_locals: + self.set_convenience_variable('_exception', self.curframe_locals['__exception__']) return self.execRcLines() # Can be executed earlier than 'setup' if desired @@ -394,6 +401,7 @@ def _cmdloop(self): self.message('--KeyboardInterrupt--') # Called before loop, handles display expressions + # Set up convenience variable containers def preloop(self): displaying = self.displaying.get(self.curframe) if displaying: @@ -477,6 +485,9 @@ def precmd(self, line): next = line[marker+2:].lstrip() self.cmdqueue.append(next) line = line[:marker].rstrip() + + # Replace all the convenience variables + line = re.sub(r'\$([a-zA-Z_][a-zA-Z0-9_]*)', r'__pdb_convenience_variables["\1"]', line) return line def onecmd(self, line): @@ -527,6 +538,15 @@ def message(self, msg): def error(self, msg): print('***', msg, file=self.stdout) + # convenience variables + + def set_convenience_variable(self, name, value): + if not hasattr(self, 'curframe') or not self.curframe: + return + if '__pdb_convenience_variables' not in self.curframe.f_globals: + self.curframe.f_globals['__pdb_convenience_variables'] = {} + self.curframe.f_globals['__pdb_convenience_variables'][name] = value + # Generic completion functions. Individual complete_foo methods can be # assigned below to one of these functions. @@ -1018,6 +1038,7 @@ def _select_frame(self, number): self.curindex = number self.curframe = self.stack[self.curindex][0] self.curframe_locals = self.curframe.f_locals + self.set_convenience_variable('_frame', self.curframe) self.print_stack_entry(self.stack[self.curindex]) self.lineno = None diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 94b441720f258c..9a6b15f6b441cf 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -746,6 +746,84 @@ def test_pdb_where_command(): (Pdb) continue """ +def test_convenience_variables(): + """Test convenience variables + + >>> def util_function(): + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... try: + ... raise Exception('test') + ... except: + ... pass + ... return 1 + + >>> def test_function(): + ... util_function() + + >>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + ... '$_frame.f_lineno', # Check frame convenience variable + ... '$a = 10', # Set a convenience variable + ... '$a', # Print its value + ... 'p $a + 2', # Do some calculation + ... 'u', # Switch frame + ... '$_frame.f_lineno', # Make sure the frame changed + ... '$a', # Make sure the value persists + ... 'd', # Go back to the original frame + ... 'next', + ... '$a', # The value should be gone + ... 'next', + ... '$_exception[1]', # Check exception convenience variable + ... 'next', + ... '$_exception', # Exception should be gone + ... 'return', + ... '$_return', # Check return convenience variable + ... 'continue', + ... ]): + ... test_function() + > (3)util_function() + -> try: + (Pdb) $_frame.f_lineno + 3 + (Pdb) $a = 10 + (Pdb) $a + 10 + (Pdb) p $a + 2 + 12 + (Pdb) u + > (2)test_function() + -> util_function() + (Pdb) $_frame.f_lineno + 2 + (Pdb) $a + 10 + (Pdb) d + > (3)util_function() + -> try: + (Pdb) next + > (4)util_function() + -> raise Exception('test') + (Pdb) $a + *** KeyError: 'a' + (Pdb) next + Exception: test + > (4)util_function() + -> raise Exception('test') + (Pdb) $_exception[1] + Exception('test') + (Pdb) next + > (5)util_function() + -> except: + (Pdb) $_exception + (, Exception('test')) + (Pdb) return + --Return-- + > (7)util_function()->1 + -> return 1 + (Pdb) $_return + 1 + (Pdb) continue + """ + def test_post_mortem(): """Test post mortem traceback debugging. From f7a11af86fde3ac51aa6933e9891021177b5ff2f Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Sat, 22 Apr 2023 14:29:08 -0700 Subject: [PATCH 2/7] Change _return to _retval --- Doc/library/pdb.rst | 2 +- Lib/pdb.py | 2 +- Lib/test/test_pdb.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 64390ecb249dad..f6bbe033ffce04 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -273,7 +273,7 @@ like ``foo = 1``. There are three preset *convenience variables*: * ``$_frame``: the current frame you are debugging -* ``$_return``: the return value if the frame is returning +* ``$_retval``: the return value if the frame is returning * ``$_exception``: the ``(exc_type, exc_value)`` tuple if the frame is raising an exception .. index:: diff --git a/Lib/pdb.py b/Lib/pdb.py index 9ba9856b128994..207ef8a3adf590 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -292,7 +292,7 @@ def setup(self, f, tb): self.curframe_locals = self.curframe.f_locals self.set_convenience_variable('_frame', self.curframe) if '__return__' in self.curframe_locals: - self.set_convenience_variable('_return', self.curframe_locals['__return__']) + self.set_convenience_variable('_retval', self.curframe_locals['__return__']) if '__exception__' in self.curframe_locals: self.set_convenience_variable('_exception', self.curframe_locals['__exception__']) return self.execRcLines() diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 9a6b15f6b441cf..a94d157d1ddaa1 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -776,7 +776,7 @@ def test_convenience_variables(): ... 'next', ... '$_exception', # Exception should be gone ... 'return', - ... '$_return', # Check return convenience variable + ... '$_retval', # Check return convenience variable ... 'continue', ... ]): ... test_function() @@ -819,7 +819,7 @@ def test_convenience_variables(): --Return-- > (7)util_function()->1 -> return 1 - (Pdb) $_return + (Pdb) $_retval 1 (Pdb) continue """ From a202abf9051efddccb3d4ee41f925b3e35a9a22c Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 22 Apr 2023 21:34:14 +0000 Subject: [PATCH 3/7] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2023-04-22-21-34-13.gh-issue-103693.SBtuLQ.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2023-04-22-21-34-13.gh-issue-103693.SBtuLQ.rst diff --git a/Misc/NEWS.d/next/Library/2023-04-22-21-34-13.gh-issue-103693.SBtuLQ.rst b/Misc/NEWS.d/next/Library/2023-04-22-21-34-13.gh-issue-103693.SBtuLQ.rst new file mode 100644 index 00000000000000..52c68bfc9ceea4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-22-21-34-13.gh-issue-103693.SBtuLQ.rst @@ -0,0 +1 @@ +Add convenience variable feature to :mod:`pdb` From 14152102b15d86ab80b2380356254bb65349f9ac Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Sun, 23 Apr 2023 12:13:10 -0700 Subject: [PATCH 4/7] Use exception value instead of tuple Make _exception non-persistent --- Doc/library/pdb.rst | 2 +- Lib/pdb.py | 20 ++++++++------------ Lib/test/test_pdb.py | 6 +++--- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index f6bbe033ffce04..4c803cec6a9fb1 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -274,7 +274,7 @@ There are three preset *convenience variables*: * ``$_frame``: the current frame you are debugging * ``$_retval``: the return value if the frame is returning -* ``$_exception``: the ``(exc_type, exc_value)`` tuple if the frame is raising an exception +* ``$_exception``: the exception if the frame is raising an exception .. index:: pair: .pdbrc; file diff --git a/Lib/pdb.py b/Lib/pdb.py index 207ef8a3adf590..e7d885ce5179ed 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -290,11 +290,7 @@ def setup(self, f, tb): # locals whenever the .f_locals accessor is called, so we # cache it here to ensure that modifications are not overwritten. self.curframe_locals = self.curframe.f_locals - self.set_convenience_variable('_frame', self.curframe) - if '__return__' in self.curframe_locals: - self.set_convenience_variable('_retval', self.curframe_locals['__return__']) - if '__exception__' in self.curframe_locals: - self.set_convenience_variable('_exception', self.curframe_locals['__exception__']) + self.set_convenience_variable(self.curframe, '_frame', self.curframe) return self.execRcLines() # Can be executed earlier than 'setup' if desired @@ -366,6 +362,7 @@ def user_return(self, frame, return_value): if self._wait_for_mainpyfile: return frame.f_locals['__return__'] = return_value + self.set_convenience_variable(frame, '_retval', return_value) self.message('--Return--') self.interaction(frame, None) @@ -376,6 +373,7 @@ def user_exception(self, frame, exc_info): return exc_type, exc_value, exc_traceback = exc_info frame.f_locals['__exception__'] = exc_type, exc_value + self.set_convenience_variable(frame, '_exception', exc_value) # An 'Internal StopIteration' exception is an exception debug event # issued by the interpreter when handling a subgenerator run with @@ -540,12 +538,10 @@ def error(self, msg): # convenience variables - def set_convenience_variable(self, name, value): - if not hasattr(self, 'curframe') or not self.curframe: - return - if '__pdb_convenience_variables' not in self.curframe.f_globals: - self.curframe.f_globals['__pdb_convenience_variables'] = {} - self.curframe.f_globals['__pdb_convenience_variables'][name] = value + def set_convenience_variable(self, frame, name, value): + if '__pdb_convenience_variables' not in frame.f_globals: + frame.f_globals['__pdb_convenience_variables'] = {} + frame.f_globals['__pdb_convenience_variables'][name] = value # Generic completion functions. Individual complete_foo methods can be # assigned below to one of these functions. @@ -1038,7 +1034,7 @@ def _select_frame(self, number): self.curindex = number self.curframe = self.stack[self.curindex][0] self.curframe_locals = self.curframe.f_locals - self.set_convenience_variable('_frame', self.curframe) + self.set_convenience_variable(self.curframe, '_frame', self.curframe) self.print_stack_entry(self.stack[self.curindex]) self.lineno = None diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index a94d157d1ddaa1..8a171c3ecd8831 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -772,7 +772,7 @@ def test_convenience_variables(): ... 'next', ... '$a', # The value should be gone ... 'next', - ... '$_exception[1]', # Check exception convenience variable + ... '$_exception', # Check exception convenience variable ... 'next', ... '$_exception', # Exception should be gone ... 'return', @@ -808,13 +808,13 @@ def test_convenience_variables(): Exception: test > (4)util_function() -> raise Exception('test') - (Pdb) $_exception[1] + (Pdb) $_exception Exception('test') (Pdb) next > (5)util_function() -> except: (Pdb) $_exception - (, Exception('test')) + *** KeyError: '_exception' (Pdb) return --Return-- > (7)util_function()->1 From ac2314875245ec90cc2da62e8c660628c4bd0a94 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Mon, 1 May 2023 15:31:20 -0700 Subject: [PATCH 5/7] Update Doc/library/pdb.rst Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> --- Doc/library/pdb.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 4c803cec6a9fb1..bdbd419a00efc4 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -265,7 +265,7 @@ is to use implicit string concatenation ``';'';'`` or ``";"";"``. To set temporary global variables, use *convenience variable*. A *convenience variable* is a variable whose name starts with ``$``. For example, ``$foo = 1`` -set a global variable ``$foo`` which you can use in the debugger session. The +sets a global variable ``$foo`` which you can use in the debugger session. The *convenience variables* are cleared when the program resumes execution so it's less likely to interfere with your program compared to using normal variables like ``foo = 1``. From 150250b9f95ba1a4676e3990595bbcb582d1049a Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Mon, 1 May 2023 15:45:02 -0700 Subject: [PATCH 6/7] Update docs and whatsnew --- Doc/library/pdb.rst | 4 +++- Doc/whatsnew/3.12.rst | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index bdbd419a00efc4..195e939772a5a1 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -263,7 +263,7 @@ the commands; the input is split at the first ``;;`` pair, even if it is in the middle of a quoted string. A workaround for strings with double semicolons is to use implicit string concatenation ``';'';'`` or ``";"";"``. -To set temporary global variables, use *convenience variable*. A *convenience +To set a temporary global variable, use *convenience variable*. A *convenience variable* is a variable whose name starts with ``$``. For example, ``$foo = 1`` sets a global variable ``$foo`` which you can use in the debugger session. The *convenience variables* are cleared when the program resumes execution so it's @@ -276,6 +276,8 @@ There are three preset *convenience variables*: * ``$_retval``: the return value if the frame is returning * ``$_exception``: the exception if the frame is raising an exception +.. versionadded:: 3.12 + .. index:: pair: .pdbrc; file triple: debugger; configuration; file diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index f9406653e625b5..3bfd8fcbf3a4f3 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -356,6 +356,14 @@ os.path * Add :func:`os.path.splitroot` to split a path into a triad ``(drive, root, tail)``. (Contributed by Barney Gale in :gh:`101000`.) +pdb +--- + +* Add convenience variables to hold values temporarily for debug session + and provide quick access to values like the current frame or the return + value. + (Contributed by Tian Gao in :gh:`103693`.) + shutil ------ From f626d36d6a1d6140b3d6cc9f6b1b14b765ade8f4 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Mon, 1 May 2023 16:04:53 -0700 Subject: [PATCH 7/7] Update Doc/library/pdb.rst Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> --- Doc/library/pdb.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 195e939772a5a1..8a386aa77368f2 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -263,7 +263,7 @@ the commands; the input is split at the first ``;;`` pair, even if it is in the middle of a quoted string. A workaround for strings with double semicolons is to use implicit string concatenation ``';'';'`` or ``";"";"``. -To set a temporary global variable, use *convenience variable*. A *convenience +To set a temporary global variable, use a *convenience variable*. A *convenience variable* is a variable whose name starts with ``$``. For example, ``$foo = 1`` sets a global variable ``$foo`` which you can use in the debugger session. The *convenience variables* are cleared when the program resumes execution so it's pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy