summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorTian Gao <gaogaotiantian@hotmail.com>2024-03-12 16:58:17 (GMT)
committerGitHub <noreply@github.com>2024-03-12 16:58:17 (GMT)
commitd19c2eb604b8de96f5f77bab0fdf82b44390d960 (patch)
treea8ac1e6ae52c41319d47e420e58588ea8b93855e /Lib
parent4ea9d157615e9200c0d59e114a5616b7c738ba57 (diff)
downloadcpython-d19c2eb604b8de96f5f77bab0fdf82b44390d960.zip
cpython-d19c2eb604b8de96f5f77bab0fdf82b44390d960.tar.gz
cpython-d19c2eb604b8de96f5f77bab0fdf82b44390d960.tar.bz2
[3.12] gh-90095: Make .pdbrc work properly and add some reasonable te… (#116661)
[3.12] gh-90095: Make .pdbrc work properly and add some reasonable tests (GH-110496) (cherry picked from commit 44f9a84b67c97c94f0d581ffd63b24b73fb79610)
Diffstat (limited to 'Lib')
-rwxr-xr-xLib/pdb.py46
-rw-r--r--Lib/test/test_pdb.py150
2 files changed, 101 insertions, 95 deletions
diff --git a/Lib/pdb.py b/Lib/pdb.py
index 494e640..b76a683 100755
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -299,26 +299,10 @@ class Pdb(bdb.Bdb, cmd.Cmd):
# cache it here to ensure that modifications are not overwritten.
self.curframe_locals = self.curframe.f_locals
self.set_convenience_variable(self.curframe, '_frame', self.curframe)
- return self.execRcLines()
- # Can be executed earlier than 'setup' if desired
- def execRcLines(self):
- if not self.rcLines:
- return
- # local copy because of recursion
- rcLines = self.rcLines
- rcLines.reverse()
- # execute every line only once
- self.rcLines = []
- while rcLines:
- line = rcLines.pop().strip()
- if line and line[0] != '#':
- if self.onecmd(line):
- # if onecmd returns True, the command wants to exit
- # from the interaction, save leftover rc lines
- # to execute before next interaction
- self.rcLines += reversed(rcLines)
- return True
+ if self.rcLines:
+ self.cmdqueue = self.rcLines
+ self.rcLines = []
# Override Bdb methods
@@ -431,12 +415,10 @@ class Pdb(bdb.Bdb, cmd.Cmd):
pass
else:
Pdb._previous_sigint_handler = None
- if self.setup(frame, traceback):
- # no interaction desired at this time (happens if .pdbrc contains
- # a command like "continue")
- self.forget()
- return
- self.print_stack_entry(self.stack[self.curindex])
+ self.setup(frame, traceback)
+ # if we have more commands to process, do not show the stack entry
+ if not self.cmdqueue:
+ self.print_stack_entry(self.stack[self.curindex])
self._cmdloop()
self.forget()
@@ -523,7 +505,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):
if marker >= 0:
# queue up everything after marker
next = line[marker+2:].lstrip()
- self.cmdqueue.append(next)
+ self.cmdqueue.insert(0, next)
line = line[:marker].rstrip()
# Replace all the convenience variables
@@ -547,13 +529,12 @@ class Pdb(bdb.Bdb, cmd.Cmd):
"""Handles one command line during command list definition."""
cmd, arg, line = self.parseline(line)
if not cmd:
- return
+ return False
if cmd == 'silent':
self.commands_silent[self.commands_bnum] = True
- return # continue to handle other cmd def in the cmd list
+ return False # continue to handle other cmd def in the cmd list
elif cmd == 'end':
- self.cmdqueue = []
- return 1 # end of cmd list
+ return True # end of cmd list
cmdlist = self.commands[self.commands_bnum]
if arg:
cmdlist.append(cmd+' '+arg)
@@ -567,9 +548,8 @@ class Pdb(bdb.Bdb, cmd.Cmd):
# one of the resuming commands
if func.__name__ in self.commands_resuming:
self.commands_doprompt[self.commands_bnum] = False
- self.cmdqueue = []
- return 1
- return
+ return True
+ return False
# interface abstraction functions
diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py
index 0e1b1c9..db30412 100644
--- a/Lib/test/test_pdb.py
+++ b/Lib/test/test_pdb.py
@@ -1936,13 +1936,30 @@ class PdbTestCase(unittest.TestCase):
)
return stdout, stderr
- def run_pdb_script(self, script, commands, expected_returncode=0):
+ def run_pdb_script(self, script, commands,
+ expected_returncode=0,
+ pdbrc=None,
+ remove_home=False):
"""Run 'script' lines with pdb and the pdb 'commands'."""
filename = 'main.py'
with open(filename, 'w') as f:
f.write(textwrap.dedent(script))
+
+ if pdbrc is not None:
+ with open('.pdbrc', 'w') as f:
+ f.write(textwrap.dedent(pdbrc))
+ self.addCleanup(os_helper.unlink, '.pdbrc')
self.addCleanup(os_helper.unlink, filename)
- return self._run_pdb([filename], commands, expected_returncode)
+
+ homesave = None
+ if remove_home:
+ homesave = os.environ.pop('HOME', None)
+ try:
+ stdout, stderr = self._run_pdb([filename], commands, expected_returncode)
+ finally:
+ if homesave is not None:
+ os.environ['HOME'] = homesave
+ return stdout, stderr
def run_pdb_module(self, script, commands):
"""Runs the script code as part of a module"""
@@ -2182,37 +2199,80 @@ def bœr():
self.assertRegex(res, "Restarting .* with arguments:\na b c")
self.assertRegex(res, "Restarting .* with arguments:\nd e f")
- def test_readrc_kwarg(self):
+ def test_pdbrc_basic(self):
script = textwrap.dedent("""
- import pdb; pdb.Pdb(readrc=False).set_trace()
+ a = 1
+ b = 2
+ """)
- print('hello')
+ pdbrc = textwrap.dedent("""
+ # Comments should be fine
+ n
+ p f"{a+8=}"
""")
- save_home = os.environ.pop('HOME', None)
- try:
- with os_helper.temp_cwd():
- with open('.pdbrc', 'w') as f:
- f.write("invalid\n")
-
- with open('main.py', 'w') as f:
- f.write(script)
-
- cmd = [sys.executable, 'main.py']
- proc = subprocess.Popen(
- cmd,
- stdout=subprocess.PIPE,
- stdin=subprocess.PIPE,
- stderr=subprocess.PIPE,
- )
- with proc:
- stdout, stderr = proc.communicate(b'q\n')
- self.assertNotIn(b"NameError: name 'invalid' is not defined",
- stdout)
+ stdout, stderr = self.run_pdb_script(script, 'q\n', pdbrc=pdbrc, remove_home=True)
+ self.assertIn("a+8=9", stdout)
- finally:
- if save_home is not None:
- os.environ['HOME'] = save_home
+ def test_pdbrc_alias(self):
+ script = textwrap.dedent("""
+ class A:
+ def __init__(self):
+ self.attr = 1
+ a = A()
+ b = 2
+ """)
+
+ pdbrc = textwrap.dedent("""
+ alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}")
+ until 6
+ pi a
+ """)
+
+ stdout, stderr = self.run_pdb_script(script, 'q\n', pdbrc=pdbrc, remove_home=True)
+ self.assertIn("a.attr = 1", stdout)
+
+ def test_pdbrc_semicolon(self):
+ script = textwrap.dedent("""
+ class A:
+ def __init__(self):
+ self.attr = 1
+ a = A()
+ b = 2
+ """)
+
+ pdbrc = textwrap.dedent("""
+ b 5;;c;;n
+ """)
+
+ stdout, stderr = self.run_pdb_script(script, 'q\n', pdbrc=pdbrc, remove_home=True)
+ self.assertIn("-> b = 2", stdout)
+
+ def test_pdbrc_commands(self):
+ script = textwrap.dedent("""
+ class A:
+ def __init__(self):
+ self.attr = 1
+ a = A()
+ b = 2
+ """)
+
+ pdbrc = textwrap.dedent("""
+ b 6
+ commands 1 ;; p a;; end
+ c
+ """)
+
+ stdout, stderr = self.run_pdb_script(script, 'q\n', pdbrc=pdbrc, remove_home=True)
+ self.assertIn("<__main__.A object at", stdout)
+
+ def test_readrc_kwarg(self):
+ script = textwrap.dedent("""
+ print('hello')
+ """)
+
+ stdout, stderr = self.run_pdb_script(script, 'q\n', pdbrc='invalid', remove_home=True)
+ self.assertIn("NameError: name 'invalid' is not defined", stdout)
def test_readrc_homedir(self):
save_home = os.environ.pop("HOME", None)
@@ -2227,40 +2287,6 @@ def bœr():
if save_home is not None:
os.environ["HOME"] = save_home
- def test_read_pdbrc_with_ascii_encoding(self):
- script = textwrap.dedent("""
- import pdb; pdb.Pdb().set_trace()
- print('hello')
- """)
- save_home = os.environ.pop('HOME', None)
- try:
- with os_helper.temp_cwd():
- with open('.pdbrc', 'w', encoding='utf-8') as f:
- f.write("Fran\u00E7ais")
-
- with open('main.py', 'w', encoding='utf-8') as f:
- f.write(script)
-
- cmd = [sys.executable, 'main.py']
- env = {'PYTHONIOENCODING': 'ascii'}
- if sys.platform == 'win32':
- env['PYTHONLEGACYWINDOWSSTDIO'] = 'non-empty-string'
- proc = subprocess.Popen(
- cmd,
- stdout=subprocess.PIPE,
- stdin=subprocess.PIPE,
- stderr=subprocess.PIPE,
- env={**os.environ, **env}
- )
- with proc:
- stdout, stderr = proc.communicate(b'c\n')
- self.assertIn(b"UnicodeEncodeError: \'ascii\' codec can\'t encode character "
- b"\'\\xe7\' in position 21: ordinal not in range(128)", stderr)
-
- finally:
- if save_home is not None:
- os.environ['HOME'] = save_home
-
def test_header(self):
stdout = StringIO()
header = 'Nobody expects... blah, blah, blah'