[3.12] gh-112343: pdb: Use tokenize to replace convenience variables (GH-112380) (#114202)

This commit is contained in:
Tian Gao 2024-01-17 14:15:44 -08:00 committed by GitHub
parent c1890e666e
commit 2c9cf64a3f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 47 additions and 2 deletions

View file

@ -76,6 +76,7 @@
import dis
import code
import glob
import token
import pprint
import signal
import inspect
@ -467,6 +468,39 @@ def default(self, line):
except:
self._error_exc()
def _replace_convenience_variables(self, line):
"""Replace the convenience variables in 'line' with their values.
e.g. $foo is replaced by __pdb_convenience_variables["foo"].
Note: such pattern in string literals will be skipped"""
if "$" not in line:
return line
dollar_start = dollar_end = -1
replace_variables = []
try:
for t in tokenize.generate_tokens(io.StringIO(line).readline):
token_type, token_string, start, end, _ = t
if token_type == token.OP and token_string == '$':
dollar_start, dollar_end = start, end
elif start == dollar_end and token_type == token.NAME:
# line is a one-line command so we only care about column
replace_variables.append((dollar_start[1], end[1], token_string))
except tokenize.TokenError:
return line
if not replace_variables:
return line
last_end = 0
line_pieces = []
for start, end, name in replace_variables:
line_pieces.append(line[last_end:start] + f'__pdb_convenience_variables["{name}"]')
last_end = end
line_pieces.append(line[last_end:])
return ''.join(line_pieces)
def precmd(self, line):
"""Handle alias expansion and ';;' separator."""
if not line.strip():
@ -492,7 +526,8 @@ def precmd(self, line):
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)
line = self._replace_convenience_variables(line)
return line
def onecmd(self, line):

View file

@ -389,7 +389,7 @@ def test_pdb_breakpoints_preserved_across_interactive_sessions():
1 breakpoint keep yes at ...test_pdb.py:...
2 breakpoint keep yes at ...test_pdb.py:...
(Pdb) break pdb.find_function
Breakpoint 3 at ...pdb.py:97
Breakpoint 3 at ...pdb.py:...
(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at ...test_pdb.py:...
@ -770,9 +770,12 @@ def test_convenience_variables():
>>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
... '$_frame.f_lineno', # Check frame convenience variable
... '$ _frame', # This should be a syntax error
... '$a = 10', # Set a convenience variable
... '$a', # Print its value
... 'p "$a"', # Print the string $a
... 'p $a + 2', # Do some calculation
... 'p f"$a = {$a}"', # Make sure $ in string is not converted and f-string works
... 'u', # Switch frame
... '$_frame.f_lineno', # Make sure the frame changed
... '$a', # Make sure the value persists
@ -792,11 +795,17 @@ def test_convenience_variables():
-> try:
(Pdb) $_frame.f_lineno
3
(Pdb) $ _frame
*** SyntaxError: invalid syntax
(Pdb) $a = 10
(Pdb) $a
10
(Pdb) p "$a"
'$a'
(Pdb) p $a + 2
12
(Pdb) p f"$a = {$a}"
'$a = 10'
(Pdb) u
> <doctest test.test_pdb.test_convenience_variables[1]>(2)test_function()
-> util_function()

View file

@ -0,0 +1 @@
Improve handling of pdb convenience variables to avoid replacing string contents.