diff options
author | Tian Gao <gaogaotiantian@hotmail.com> | 2024-05-02 20:53:27 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-02 20:53:27 (GMT) |
commit | 4e2caf2aa046bf80e87e9b858837bb527459a034 (patch) | |
tree | b6908dbcd22d55e1f7a40dbaab8e4fd0016e5d07 | |
parent | e54b0c8a4ad6c6e958245eb3ea4ecc47e0f97ff0 (diff) | |
download | cpython-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.rst | 3 | ||||
-rwxr-xr-x | Lib/pdb.py | 50 | ||||
-rw-r--r-- | Lib/test/test_pdb.py | 25 | ||||
-rw-r--r-- | Lib/test/test_pyclbr.py | 2 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2024-05-02-04-27-12.gh-issue-118500.pBGGtQ.rst | 1 |
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 ----- @@ -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 |