https://github.com/python/cpython/commit/ee337bea01beb3da6dccfe1b48db9a4c891b05a1
commit: ee337bea01beb3da6dccfe1b48db9a4c891b05a1
branch: main
author: Tian Gao <[email protected]>
committer: gaogaotiantian <[email protected]>
date: 2025-02-19T21:01:04-05:00
summary:

gh-57537: Support breakpoints for zipimport modules on pdb (#130290)

files:
A Misc/NEWS.d/next/Library/2025-02-19-01-29-16.gh-issue-57537.4tdVuK.rst
M Lib/pdb.py
M Lib/test/test_pdb.py

diff --git a/Lib/pdb.py b/Lib/pdb.py
index cf0fa66e2f0c8b..08a941de79ec55 100644
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -1134,6 +1134,7 @@ def do_break(self, arg, temporary=False):
         filename = None
         lineno = None
         cond = None
+        module_globals = None
         comma = arg.find(',')
         if comma > 0:
             # parse stuff after comma: "condition"
@@ -1179,6 +1180,7 @@ def do_break(self, arg, temporary=False):
                     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 @@ def do_break(self, arg, temporary=False):
                     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 @@ def lineinfo(self, identifier):
         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 @@ def checkline(self, filename, lineno):
         # 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
diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py
index fa439c1fe8915c..83753279599f76 100644
--- a/Lib/test/test_pdb.py
+++ b/Lib/test/test_pdb.py
@@ -11,6 +11,7 @@
 import textwrap
 import linecache
 import zipapp
+import zipfile
 
 from contextlib import ExitStack, redirect_stdout
 from io import StringIO
@@ -4207,6 +4208,38 @@ def f(x):
             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
index 00000000000000..40e4094cc5fccf
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-02-19-01-29-16.gh-issue-57537.4tdVuK.rst
@@ -0,0 +1 @@
+Support breakpoints for :mod:`zipimport` modules on :mod:`pdb`

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to