https://github.com/python/cpython/commit/c8624cd36746b17d8f991cde63705e9419e940de
commit: c8624cd36746b17d8f991cde63705e9419e940de
branch: main
author: Tian Gao <[email protected]>
committer: gaogaotiantian <[email protected]>
date: 2025-09-24T11:46:05+08:00
summary:
gh-138860: Lazy import rlcompleter in pdb to avoid deadlock in subprocess
(#139185)
files:
A Misc/NEWS.d/next/Library/2025-09-20-17-50-31.gh-issue-138860.Y9JXap.rst
M Lib/pdb.py
M Lib/test/test_pdb.py
diff --git a/Lib/pdb.py b/Lib/pdb.py
index a783583a2b1c38..fd48882e28fe7c 100644
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -100,7 +100,6 @@
import _pyrepl.utils
from contextlib import ExitStack, closing, contextmanager
-from rlcompleter import Completer
from types import CodeType
from warnings import deprecated
@@ -364,6 +363,15 @@ def __init__(self, completekey='tab', stdin=None,
stdout=None, skip=None,
readline.set_completer_delims(' \t\n`@#%^&*()=+[{]}\\|;:\'",<>?')
except ImportError:
pass
+
+ # GH-138860
+ # We need to lazy-import rlcompleter to avoid deadlock
+ # We cannot import it during self.complete* methods because importing
+ # rlcompleter for the first time will overwrite readline's completer
+ # So we import it here and save the Completer class
+ from rlcompleter import Completer
+ self.RlCompleter = Completer
+
self.allow_kbdint = False
self.nosigint = nosigint
# Consider these characters as part of the command so when the users
type
@@ -1186,10 +1194,9 @@ def completedefault(self, text, line, begidx, endidx):
conv_vars =
self.curframe.f_globals.get('__pdb_convenience_variables', {})
return [f"${name}" for name in conv_vars if
name.startswith(text[1:])]
- # Use rlcompleter to do the completion
state = 0
matches = []
- completer = Completer(self.curframe.f_globals | self.curframe.f_locals)
+ completer = self.RlCompleter(self.curframe.f_globals |
self.curframe.f_locals)
while (match := completer.complete(text, state)) is not None:
matches.append(match)
state += 1
@@ -1204,8 +1211,8 @@ def _enable_rlcompleter(self, ns):
return
try:
+ completer = self.RlCompleter(ns)
old_completer = readline.get_completer()
- completer = Completer(ns)
readline.set_completer(completer.complete)
yield
finally:
diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py
index 6b74e21ad73d1a..9a7d855003551a 100644
--- a/Lib/test/test_pdb.py
+++ b/Lib/test/test_pdb.py
@@ -4688,6 +4688,28 @@ def foo():
stdout, _ = self._run_script(script, commands)
self.assertIn("42", stdout)
+ def test_readline_not_imported(self):
+ """GH-138860
+ Directly or indirectly importing readline might deadlock a subprocess
+ if it's launched with process_group=0 or preexec_fn=setpgrp
+
+ It's also a pattern that readline is never imported with just import
pdb.
+
+ This test is to ensure that readline is not imported for import pdb.
+ It's possible that we have a good reason to do that in the future.
+ """
+
+ script = textwrap.dedent("""
+ import sys
+ import pdb
+ if "readline" in sys.modules:
+ print("readline imported")
+ """)
+ commands = ""
+ stdout, stderr = self._run_script(script, commands)
+ self.assertNotIn("readline imported", stdout)
+ self.assertEqual(stderr, "")
+
@support.force_colorized_test_class
class PdbTestColorize(unittest.TestCase):
diff --git
a/Misc/NEWS.d/next/Library/2025-09-20-17-50-31.gh-issue-138860.Y9JXap.rst
b/Misc/NEWS.d/next/Library/2025-09-20-17-50-31.gh-issue-138860.Y9JXap.rst
new file mode 100644
index 00000000000000..0903eb71ae4346
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-09-20-17-50-31.gh-issue-138860.Y9JXap.rst
@@ -0,0 +1 @@
+Lazy import :mod:`rlcompleter` in :mod:`pdb` to avoid deadlock in subprocess.
_______________________________________________
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]