Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
hugovk committed Oct 15, 2024
2 parents 299d020 + 7453b8f commit 37e533a
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 9 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ body:
label: "CPython versions tested on:"
multiple: true
options:
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3.13"
- "3.14"
- "CPython main branch"
validations:
required: true
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/crash.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ body:
label: "CPython versions tested on:"
multiple: true
options:
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3.13"
- "3.14"
- "CPython main branch"
validations:
required: true
Expand Down
8 changes: 8 additions & 0 deletions Lib/bdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,14 @@ def set_break(self, filename, lineno, temporary=False, cond=None,
return 'Line %s:%d does not exist' % (filename, lineno)
self._add_to_breaks(filename, lineno)
bp = Breakpoint(filename, lineno, temporary, cond, funcname)
# After we set a new breakpoint, we need to search through all frames
# and set f_trace to trace_dispatch if there could be a breakpoint in
# that frame.
frame = self.enterframe
while frame:
if self.break_anywhere(frame):
frame.f_trace = self.trace_dispatch
frame = frame.f_back
return None

def _load_breaks(self):
Expand Down
30 changes: 24 additions & 6 deletions Lib/pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
import inspect
import textwrap
import tokenize
import itertools
import traceback
import linecache
import _colorize
Expand Down Expand Up @@ -2433,30 +2434,47 @@ def main():
parser.add_argument('-c', '--command', action='append', default=[], metavar='command', dest='commands',
help='pdb commands to execute as if given in a .pdbrc file')
parser.add_argument('-m', metavar='module', dest='module')
parser.add_argument('args', nargs='*',
help="when -m is not specified, the first arg is the script to debug")

if len(sys.argv) == 1:
# If no arguments were given (python -m pdb), print the whole help message.
# Without this check, argparse would only complain about missing required arguments.
parser.print_help()
sys.exit(2)

opts = parser.parse_args()
opts, args = parser.parse_known_args()

if opts.module:
# If a module is being debugged, we consider the arguments after "-m module" to
# be potential arguments to the module itself. We need to parse the arguments
# before "-m" to check if there is any invalid argument.
# e.g. "python -m pdb -m foo --spam" means passing "--spam" to "foo"
# "python -m pdb --spam -m foo" means passing "--spam" to "pdb" and is invalid
idx = sys.argv.index('-m')
args_to_pdb = sys.argv[1:idx]
# This will raise an error if there are invalid arguments
parser.parse_args(args_to_pdb)
else:
# If a script is being debugged, then pdb expects the script name as the first argument.
# Anything before the script is considered an argument to pdb itself, which would
# be invalid because it's not parsed by argparse.
invalid_args = list(itertools.takewhile(lambda a: a.startswith('-'), args))
if invalid_args:
parser.error(f"unrecognized arguments: {' '.join(invalid_args)}")
sys.exit(2)

if opts.module:
file = opts.module
target = _ModuleTarget(file)
else:
if not opts.args:
if not args:
parser.error("no module or script to run")
file = opts.args.pop(0)
file = args.pop(0)
if file.endswith('.pyz'):
target = _ZipTarget(file)
else:
target = _ScriptTarget(file)

sys.argv[:] = [file] + opts.args # Hide "pdb.py" and pdb options from argument list
sys.argv[:] = [file] + args # Hide "pdb.py" and pdb options from argument list

# Note on saving/restoring sys.argv: it's a good idea when sys.argv was
# modified by the script being debugged. It's a bad idea when it was
Expand Down
51 changes: 50 additions & 1 deletion Lib/test/test_pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -3089,6 +3089,7 @@ def _run_pdb(self, pdb_args, commands,
def run_pdb_script(self, script, commands,
expected_returncode=0,
extra_env=None,
script_args=None,
pdbrc=None,
remove_home=False):
"""Run 'script' lines with pdb and the pdb 'commands'."""
Expand All @@ -3106,7 +3107,9 @@ def run_pdb_script(self, script, commands,
if remove_home:
homesave = os.environ.pop('HOME', None)
try:
stdout, stderr = self._run_pdb([filename], commands, expected_returncode, extra_env)
if script_args is None:
script_args = []
stdout, stderr = self._run_pdb([filename] + script_args, commands, expected_returncode, extra_env)
finally:
if homesave is not None:
os.environ['HOME'] = homesave
Expand Down Expand Up @@ -3393,6 +3396,36 @@ def test_issue26053(self):
self.assertRegex(res, "Restarting .* with arguments:\na b c")
self.assertRegex(res, "Restarting .* with arguments:\nd e f")

def test_issue58956(self):
# Set a breakpoint in a function that already exists on the call stack
# should enable the trace function for the frame.
script = """
import bar
def foo():
ret = bar.bar()
pass
foo()
"""
commands = """
b bar.bar
c
b main.py:5
c
p ret
quit
"""
bar = """
def bar():
return 42
"""
with open('bar.py', 'w') as f:
f.write(textwrap.dedent(bar))
self.addCleanup(os_helper.unlink, 'bar.py')
stdout, stderr = self.run_pdb_script(script, commands)
lines = stdout.splitlines()
self.assertIn('-> pass', lines)
self.assertIn('(Pdb) 42', lines)

def test_step_into_botframe(self):
# gh-125422
# pdb should not be able to step into the botframe (bdb.py)
Expand Down Expand Up @@ -3559,6 +3592,22 @@ def test_run_module_with_args(self):
stdout, _ = self._run_pdb(["-m", "calendar", "1"], commands)
self.assertIn("December", stdout)

stdout, _ = self._run_pdb(["-m", "calendar", "--type", "text"], commands)
self.assertIn("December", stdout)

def test_run_script_with_args(self):
script = """
import sys
print(sys.argv[1:])
"""
commands = """
continue
quit
"""

stdout, stderr = self.run_pdb_script(script, commands, script_args=["--bar", "foo"])
self.assertIn("['--bar', 'foo']", stdout)

def test_breakpoint(self):
script = """
if __name__ == '__main__':
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed a bug in :mod:`pdb` where sometimes the breakpoint won't trigger if it was set on a function which is already in the call stack.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed a bug in :mod:`pdb` where arguments starting with ``-`` can't be passed to the debugged script.

0 comments on commit 37e533a

Please sign in to comment.