gh-90095: Make .pdbrc work properly and add some reasonable tests by gaogaotiantian · Pull Request #110496 · python/cpython · GitHub
Skip to content
47 changes: 13 additions & 34 deletions Lib/pdb.py
149 changes: 87 additions & 62 deletions Lib/test/test_pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -2618,13 +2618,29 @@ def _run_pdb(self, pdb_args, commands,

def run_pdb_script(self, script, commands,
expected_returncode=0,
extra_env=None):
extra_env=None,
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, extra_env)

homesave = None
Comment thread
gaogaotiantian marked this conversation as resolved.
if remove_home:
homesave = os.environ.pop('HOME', None)
try:
stdout, stderr = self._run_pdb([filename], commands, expected_returncode, extra_env)
finally:
if homesave is not None:
Comment thread
iritkatriel marked this conversation as resolved.
os.environ['HOME'] = homesave
return stdout, stderr

def run_pdb_module(self, script, commands):
"""Runs the script code as part of a module"""
Expand Down Expand Up @@ -2904,37 +2920,80 @@ def test_issue26053(self):
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)
Expand All @@ -2949,40 +3008,6 @@ def test_readrc_homedir(self):
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'
Expand Down