]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-57537: Support breakpoints for zipimport modules on pdb (#130290)
authorTian Gao <gaogaotiantian@hotmail.com>
Thu, 20 Feb 2025 02:01:04 +0000 (21:01 -0500)
committerGitHub <noreply@github.com>
Thu, 20 Feb 2025 02:01:04 +0000 (21:01 -0500)
Lib/pdb.py
Lib/test/test_pdb.py
Misc/NEWS.d/next/Library/2025-02-19-01-29-16.gh-issue-57537.4tdVuK.rst [new file with mode: 0644]

index cf0fa66e2f0c8b6a8ccd4a1f8cb4e192674b38ed..08a941de79ec55d290c48bfc2b77ee35d963bebd 100644 (file)
@@ -1134,6 +1134,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):
         filename = None
         lineno = None
         cond = None
+        module_globals = None
         comma = arg.find(',')
         if comma > 0:
             # parse stuff after comma: "condition"
@@ -1179,6 +1180,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):
                     funcname = code.co_name
                     lineno = find_first_executable_line(code)
                     filename = code.co_filename
+                    module_globals = func.__globals__
                 except:
                     # last thing to try
                     (ok, filename, ln) = self.lineinfo(arg)
@@ -1190,8 +1192,9 @@ class Pdb(bdb.Bdb, cmd.Cmd):
                     lineno = int(ln)
         if not filename:
             filename = self.defaultFile()
+        filename = self.canonic(filename)
         # Check for reasonable breakpoint
-        line = self.checkline(filename, lineno)
+        line = self.checkline(filename, lineno, module_globals)
         if line:
             # now set the break point
             err = self.set_break(filename, line, temporary, cond, funcname)
@@ -1258,7 +1261,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):
         answer = find_function(item, self.canonic(fname))
         return answer or failed
 
-    def checkline(self, filename, lineno):
+    def checkline(self, filename, lineno, module_globals=None):
         """Check whether specified line seems to be executable.
 
         Return `lineno` if it is, 0 if not (e.g. a docstring, comment, blank
@@ -1267,8 +1270,9 @@ class Pdb(bdb.Bdb, cmd.Cmd):
         # this method should be callable before starting debugging, so default
         # to "no globals" if there is no current frame
         frame = getattr(self, 'curframe', None)
-        globs = frame.f_globals if frame else None
-        line = linecache.getline(filename, lineno, globs)
+        if module_globals is None:
+            module_globals = frame.f_globals if frame else None
+        line = linecache.getline(filename, lineno, module_globals)
         if not line:
             self.message('End of file')
             return 0
index fa439c1fe8915c8c2e2aa3c6a93b65b87598ddb7..83753279599f76db84ca65ec19ecbdf6a41d6753 100644 (file)
@@ -11,6 +11,7 @@ import subprocess
 import textwrap
 import linecache
 import zipapp
+import zipfile
 
 from contextlib import ExitStack, redirect_stdout
 from io import StringIO
@@ -4207,6 +4208,38 @@ def bœr():
             self.assertIn('42', stdout)
             self.assertIn('return x + 1', stdout)
 
+    def test_zipimport(self):
+        with os_helper.temp_dir() as temp_dir:
+            os.mkdir(os.path.join(temp_dir, 'source'))
+            zipmodule = textwrap.dedent(
+                """
+                def bar():
+                    pass
+                """
+            )
+            script = textwrap.dedent(
+                f"""
+                import sys; sys.path.insert(0, {repr(os.path.join(temp_dir, 'zipmodule.zip'))})
+                import foo
+                foo.bar()
+                """
+            )
+
+            with zipfile.ZipFile(os.path.join(temp_dir, 'zipmodule.zip'), 'w') as zf:
+                zf.writestr('foo.py', zipmodule)
+            with open(os.path.join(temp_dir, 'script.py'), 'w') as f:
+                f.write(script)
+
+            stdout, _ = self._run_pdb([os.path.join(temp_dir, 'script.py')], '\n'.join([
+                'n',
+                'n',
+                'b foo.bar',
+                'c',
+                'p f"break in {$_frame.f_code.co_name}"',
+                'q'
+            ]))
+            self.assertIn('break in bar', stdout)
+
 
 class ChecklineTests(unittest.TestCase):
     def setUp(self):
diff --git a/Misc/NEWS.d/next/Library/2025-02-19-01-29-16.gh-issue-57537.4tdVuK.rst b/Misc/NEWS.d/next/Library/2025-02-19-01-29-16.gh-issue-57537.4tdVuK.rst
new file mode 100644 (file)
index 0000000..40e4094
--- /dev/null
@@ -0,0 +1 @@
+Support breakpoints for :mod:`zipimport` modules on :mod:`pdb`