mirror of https://github.com/python/cpython
gh-118500: Add pdb support for zipapp (#118501)
This commit is contained in:
parent
e54b0c8a4a
commit
4e2caf2aa0
|
@ -705,6 +705,9 @@ pdb
|
|||
command line option or :envvar:`PYTHONSAFEPATH` environment variable).
|
||||
(Contributed by Tian Gao and Christian Walther in :gh:`111762`.)
|
||||
|
||||
* :mod:`zipapp` is supported as a debugging target.
|
||||
(Contributed by Tian Gao in :gh:`118501`.)
|
||||
|
||||
queue
|
||||
-----
|
||||
|
||||
|
|
50
Lib/pdb.py
50
Lib/pdb.py
|
@ -120,7 +120,10 @@ def find_function(funcname, filename):
|
|||
try:
|
||||
fp = tokenize.open(filename)
|
||||
except OSError:
|
||||
return None
|
||||
lines = linecache.getlines(filename)
|
||||
if not lines:
|
||||
return None
|
||||
fp = io.StringIO(''.join(lines))
|
||||
funcdef = ""
|
||||
funcstart = None
|
||||
# consumer of this info expects the first line to be 1
|
||||
|
@ -237,6 +240,44 @@ class _ModuleTarget(_ExecutableTarget):
|
|||
)
|
||||
|
||||
|
||||
class _ZipTarget(_ExecutableTarget):
|
||||
def __init__(self, target):
|
||||
import runpy
|
||||
|
||||
self._target = os.path.realpath(target)
|
||||
sys.path.insert(0, self._target)
|
||||
try:
|
||||
_, self._spec, self._code = runpy._get_main_module_details()
|
||||
except ImportError as e:
|
||||
print(f"ImportError: {e}")
|
||||
sys.exit(1)
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
def __repr__(self):
|
||||
return self._target
|
||||
|
||||
@property
|
||||
def filename(self):
|
||||
return self._code.co_filename
|
||||
|
||||
@property
|
||||
def code(self):
|
||||
return self._code
|
||||
|
||||
@property
|
||||
def namespace(self):
|
||||
return dict(
|
||||
__name__='__main__',
|
||||
__file__=os.path.normcase(os.path.abspath(self.filename)),
|
||||
__package__=self._spec.parent,
|
||||
__loader__=self._spec.loader,
|
||||
__spec__=self._spec,
|
||||
__builtins__=__builtins__,
|
||||
)
|
||||
|
||||
|
||||
class _PdbInteractiveConsole(code.InteractiveConsole):
|
||||
def __init__(self, ns, message):
|
||||
self._message = message
|
||||
|
@ -1076,7 +1117,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):
|
|||
if f:
|
||||
fname = f
|
||||
item = parts[1]
|
||||
answer = find_function(item, fname)
|
||||
answer = find_function(item, self.canonic(fname))
|
||||
return answer or failed
|
||||
|
||||
def checkline(self, filename, lineno):
|
||||
|
@ -2282,7 +2323,10 @@ def main():
|
|||
if not opts.args:
|
||||
parser.error("no module or script to run")
|
||||
file = opts.args.pop(0)
|
||||
target = _ScriptTarget(file)
|
||||
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
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import unittest
|
|||
import subprocess
|
||||
import textwrap
|
||||
import linecache
|
||||
import zipapp
|
||||
|
||||
from contextlib import ExitStack, redirect_stdout
|
||||
from io import StringIO
|
||||
|
@ -3532,6 +3533,30 @@ def bœr():
|
|||
if filename.endswith(".py"):
|
||||
self._run_pdb([os.path.join(script_dir, filename)], 'q')
|
||||
|
||||
def test_zipapp(self):
|
||||
with os_helper.temp_dir() as temp_dir:
|
||||
os.mkdir(os.path.join(temp_dir, 'source'))
|
||||
script = textwrap.dedent(
|
||||
"""
|
||||
def f(x):
|
||||
return x + 1
|
||||
f(21 + 21)
|
||||
"""
|
||||
)
|
||||
with open(os.path.join(temp_dir, 'source', '__main__.py'), 'w') as f:
|
||||
f.write(script)
|
||||
zipapp.create_archive(os.path.join(temp_dir, 'source'),
|
||||
os.path.join(temp_dir, 'zipapp.pyz'))
|
||||
stdout, _ = self._run_pdb([os.path.join(temp_dir, 'zipapp.pyz')], '\n'.join([
|
||||
'b f',
|
||||
'c',
|
||||
'p x',
|
||||
'q'
|
||||
]))
|
||||
self.assertIn('42', stdout)
|
||||
self.assertIn('return x + 1', stdout)
|
||||
|
||||
|
||||
class ChecklineTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
linecache.clearcache() # Pdb.checkline() uses linecache.getline()
|
||||
|
|
|
@ -226,7 +226,7 @@ class PyclbrTest(TestCase):
|
|||
cm(
|
||||
'pdb',
|
||||
# pyclbr does not handle elegantly `typing` or properties
|
||||
ignore=('Union', '_ModuleTarget', '_ScriptTarget'),
|
||||
ignore=('Union', '_ModuleTarget', '_ScriptTarget', '_ZipTarget'),
|
||||
)
|
||||
cm('pydoc', ignore=('input', 'output',)) # properties
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Add :mod:`pdb` support for zipapps
|
Loading…
Reference in New Issue