Skip to content

Commit ee337be

Browse files
gh-57537: Support breakpoints for zipimport modules on pdb (#130290)
1 parent c718c6b commit ee337be

File tree

3 files changed

+42
-4
lines changed

3 files changed

+42
-4
lines changed

Lib/pdb.py

+8-4
Original file line numberDiff line numberDiff line change
@@ -1134,6 +1134,7 @@ def do_break(self, arg, temporary=False):
11341134
filename = None
11351135
lineno = None
11361136
cond = None
1137+
module_globals = None
11371138
comma = arg.find(',')
11381139
if comma > 0:
11391140
# parse stuff after comma: "condition"
@@ -1179,6 +1180,7 @@ def do_break(self, arg, temporary=False):
11791180
funcname = code.co_name
11801181
lineno = find_first_executable_line(code)
11811182
filename = code.co_filename
1183+
module_globals = func.__globals__
11821184
except:
11831185
# last thing to try
11841186
(ok, filename, ln) = self.lineinfo(arg)
@@ -1190,8 +1192,9 @@ def do_break(self, arg, temporary=False):
11901192
lineno = int(ln)
11911193
if not filename:
11921194
filename = self.defaultFile()
1195+
filename = self.canonic(filename)
11931196
# Check for reasonable breakpoint
1194-
line = self.checkline(filename, lineno)
1197+
line = self.checkline(filename, lineno, module_globals)
11951198
if line:
11961199
# now set the break point
11971200
err = self.set_break(filename, line, temporary, cond, funcname)
@@ -1258,7 +1261,7 @@ def lineinfo(self, identifier):
12581261
answer = find_function(item, self.canonic(fname))
12591262
return answer or failed
12601263

1261-
def checkline(self, filename, lineno):
1264+
def checkline(self, filename, lineno, module_globals=None):
12621265
"""Check whether specified line seems to be executable.
12631266
12641267
Return `lineno` if it is, 0 if not (e.g. a docstring, comment, blank
@@ -1267,8 +1270,9 @@ def checkline(self, filename, lineno):
12671270
# this method should be callable before starting debugging, so default
12681271
# to "no globals" if there is no current frame
12691272
frame = getattr(self, 'curframe', None)
1270-
globs = frame.f_globals if frame else None
1271-
line = linecache.getline(filename, lineno, globs)
1273+
if module_globals is None:
1274+
module_globals = frame.f_globals if frame else None
1275+
line = linecache.getline(filename, lineno, module_globals)
12721276
if not line:
12731277
self.message('End of file')
12741278
return 0

Lib/test/test_pdb.py

+33
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import textwrap
1212
import linecache
1313
import zipapp
14+
import zipfile
1415

1516
from contextlib import ExitStack, redirect_stdout
1617
from io import StringIO
@@ -4207,6 +4208,38 @@ def f(x):
42074208
self.assertIn('42', stdout)
42084209
self.assertIn('return x + 1', stdout)
42094210

4211+
def test_zipimport(self):
4212+
with os_helper.temp_dir() as temp_dir:
4213+
os.mkdir(os.path.join(temp_dir, 'source'))
4214+
zipmodule = textwrap.dedent(
4215+
"""
4216+
def bar():
4217+
pass
4218+
"""
4219+
)
4220+
script = textwrap.dedent(
4221+
f"""
4222+
import sys; sys.path.insert(0, {repr(os.path.join(temp_dir, 'zipmodule.zip'))})
4223+
import foo
4224+
foo.bar()
4225+
"""
4226+
)
4227+
4228+
with zipfile.ZipFile(os.path.join(temp_dir, 'zipmodule.zip'), 'w') as zf:
4229+
zf.writestr('foo.py', zipmodule)
4230+
with open(os.path.join(temp_dir, 'script.py'), 'w') as f:
4231+
f.write(script)
4232+
4233+
stdout, _ = self._run_pdb([os.path.join(temp_dir, 'script.py')], '\n'.join([
4234+
'n',
4235+
'n',
4236+
'b foo.bar',
4237+
'c',
4238+
'p f"break in {$_frame.f_code.co_name}"',
4239+
'q'
4240+
]))
4241+
self.assertIn('break in bar', stdout)
4242+
42104243

42114244
class ChecklineTests(unittest.TestCase):
42124245
def setUp(self):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Support breakpoints for :mod:`zipimport` modules on :mod:`pdb`

0 commit comments

Comments
 (0)