Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4e2caf2

Browse files
gh-118500: Add pdb support for zipapp (#118501)
1 parent e54b0c8 commit 4e2caf2

File tree

5 files changed

+77
-4
lines changed

5 files changed

+77
-4
lines changed

Doc/whatsnew/3.13.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,9 @@ pdb
705705
command line option or :envvar:`PYTHONSAFEPATH` environment variable).
706706
(Contributed by Tian Gao and Christian Walther in :gh:`111762`.)
707707

708+
* :mod:`zipapp` is supported as a debugging target.
709+
(Contributed by Tian Gao in :gh:`118501`.)
710+
708711
queue
709712
-----
710713

Lib/pdb.py

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,10 @@ def find_function(funcname, filename):
120120
try:
121121
fp = tokenize.open(filename)
122122
except OSError:
123-
return None
123+
lines = linecache.getlines(filename)
124+
if not lines:
125+
return None
126+
fp = io.StringIO(''.join(lines))
124127
funcdef = ""
125128
funcstart = None
126129
# consumer of this info expects the first line to be 1
@@ -237,6 +240,44 @@ def namespace(self):
237240
)
238241

239242

243+
class _ZipTarget(_ExecutableTarget):
244+
def __init__(self, target):
245+
import runpy
246+
247+
self._target = os.path.realpath(target)
248+
sys.path.insert(0, self._target)
249+
try:
250+
_, self._spec, self._code = runpy._get_main_module_details()
251+
except ImportError as e:
252+
print(f"ImportError: {e}")
253+
sys.exit(1)
254+
except Exception:
255+
traceback.print_exc()
256+
sys.exit(1)
257+
258+
def __repr__(self):
259+
return self._target
260+
261+
@property
262+
def filename(self):
263+
return self._code.co_filename
264+
265+
@property
266+
def code(self):
267+
return self._code
268+
269+
@property
270+
def namespace(self):
271+
return dict(
272+
__name__='__main__',
273+
__file__=os.path.normcase(os.path.abspath(self.filename)),
274+
__package__=self._spec.parent,
275+
__loader__=self._spec.loader,
276+
__spec__=self._spec,
277+
__builtins__=__builtins__,
278+
)
279+
280+
240281
class _PdbInteractiveConsole(code.InteractiveConsole):
241282
def __init__(self, ns, message):
242283
self._message = message
@@ -1076,7 +1117,7 @@ def lineinfo(self, identifier):
10761117
if f:
10771118
fname = f
10781119
item = parts[1]
1079-
answer = find_function(item, fname)
1120+
answer = find_function(item, self.canonic(fname))
10801121
return answer or failed
10811122

10821123
def checkline(self, filename, lineno):
@@ -2282,7 +2323,10 @@ def main():
22822323
if not opts.args:
22832324
parser.error("no module or script to run")
22842325
file = opts.args.pop(0)
2285-
target = _ScriptTarget(file)
2326+
if file.endswith('.pyz'):
2327+
target = _ZipTarget(file)
2328+
else:
2329+
target = _ScriptTarget(file)
22862330

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

Lib/test/test_pdb.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import subprocess
1111
import textwrap
1212
import linecache
13+
import zipapp
1314

1415
from contextlib import ExitStack, redirect_stdout
1516
from io import StringIO
@@ -3532,6 +3533,30 @@ def test_non_utf8_encoding(self):
35323533
if filename.endswith(".py"):
35333534
self._run_pdb([os.path.join(script_dir, filename)], 'q')
35343535

3536+
def test_zipapp(self):
3537+
with os_helper.temp_dir() as temp_dir:
3538+
os.mkdir(os.path.join(temp_dir, 'source'))
3539+
script = textwrap.dedent(
3540+
"""
3541+
def f(x):
3542+
return x + 1
3543+
f(21 + 21)
3544+
"""
3545+
)
3546+
with open(os.path.join(temp_dir, 'source', '__main__.py'), 'w') as f:
3547+
f.write(script)
3548+
zipapp.create_archive(os.path.join(temp_dir, 'source'),
3549+
os.path.join(temp_dir, 'zipapp.pyz'))
3550+
stdout, _ = self._run_pdb([os.path.join(temp_dir, 'zipapp.pyz')], '\n'.join([
3551+
'b f',
3552+
'c',
3553+
'p x',
3554+
'q'
3555+
]))
3556+
self.assertIn('42', stdout)
3557+
self.assertIn('return x + 1', stdout)
3558+
3559+
35353560
class ChecklineTests(unittest.TestCase):
35363561
def setUp(self):
35373562
linecache.clearcache() # Pdb.checkline() uses linecache.getline()

Lib/test/test_pyclbr.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ def test_others(self):
226226
cm(
227227
'pdb',
228228
# pyclbr does not handle elegantly `typing` or properties
229-
ignore=('Union', '_ModuleTarget', '_ScriptTarget'),
229+
ignore=('Union', '_ModuleTarget', '_ScriptTarget', '_ZipTarget'),
230230
)
231231
cm('pydoc', ignore=('input', 'output',)) # properties
232232

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add :mod:`pdb` support for zipapps

0 commit comments

Comments
 (0)