summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTian Gao <gaogaotiantian@hotmail.com>2024-05-02 20:53:27 (GMT)
committerGitHub <noreply@github.com>2024-05-02 20:53:27 (GMT)
commit4e2caf2aa046bf80e87e9b858837bb527459a034 (patch)
treeb6908dbcd22d55e1f7a40dbaab8e4fd0016e5d07
parente54b0c8a4ad6c6e958245eb3ea4ecc47e0f97ff0 (diff)
downloadcpython-4e2caf2aa046bf80e87e9b858837bb527459a034.zip
cpython-4e2caf2aa046bf80e87e9b858837bb527459a034.tar.gz
cpython-4e2caf2aa046bf80e87e9b858837bb527459a034.tar.bz2
gh-118500: Add pdb support for zipapp (#118501)
-rw-r--r--Doc/whatsnew/3.13.rst3
-rwxr-xr-xLib/pdb.py50
-rw-r--r--Lib/test/test_pdb.py25
-rw-r--r--Lib/test/test_pyclbr.py2
-rw-r--r--Misc/NEWS.d/next/Library/2024-05-02-04-27-12.gh-issue-118500.pBGGtQ.rst1
5 files changed, 77 insertions, 4 deletions
diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst
index fbf2f4c..d59c4ee 100644
--- a/Doc/whatsnew/3.13.rst
+++ b/Doc/whatsnew/3.13.rst
@@ -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
-----
diff --git a/Lib/pdb.py b/Lib/pdb.py
index fa2e1ec..bb669a0 100755
--- a/Lib/pdb.py
+++ b/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
diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py
index 5635d17..a3d2dda 100644
--- a/Lib/test/test_pdb.py
+++ b/Lib/test/test_pdb.py
@@ -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()
diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py
index c7c5419..46206ac 100644
--- a/Lib/test/test_pyclbr.py
+++ b/Lib/test/test_pyclbr.py
@@ -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
diff --git a/Misc/NEWS.d/next/Library/2024-05-02-04-27-12.gh-issue-118500.pBGGtQ.rst b/Misc/NEWS.d/next/Library/2024-05-02-04-27-12.gh-issue-118500.pBGGtQ.rst
new file mode 100644
index 0000000..62c7b5f
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-05-02-04-27-12.gh-issue-118500.pBGGtQ.rst
@@ -0,0 +1 @@
+Add :mod:`pdb` support for zipapps