From: Tian Gao Date: Fri, 26 Sep 2025 14:50:33 +0000 (+0800) Subject: [3.13] gh-139289: Lazy import rlcompleter to fix the refleak (GH-139305) (#139357) X-Git-Tag: v3.13.8~32 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=773a7c05ff0c2cc9076140d9cd767e94f7f29018;p=thirdparty%2FPython%2Fcpython.git [3.13] gh-139289: Lazy import rlcompleter to fix the refleak (GH-139305) (#139357) (cherry picked from commit 8288f3693f50058ad9b9fe04e01f5dad902d8bad) --- diff --git a/Lib/pdb.py b/Lib/pdb.py index 41735f4e249f..a990d60fe1c2 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -332,14 +332,6 @@ class Pdb(bdb.Bdb, cmd.Cmd): 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 @@ -918,6 +910,31 @@ class Pdb(bdb.Bdb, cmd.Cmd): # Generic completion functions. Individual complete_foo methods can be # assigned below to one of these functions. + @property + def rlcompleter(self): + """Return the `Completer` class from `rlcompleter`, while avoiding the + side effects of changing the completer from `import rlcompleter`. + + This is a compromise between GH-138860 and GH-139289. If GH-139289 is + fixed, then we don't need this and we can just `import rlcompleter` in + `Pdb.__init__`. + """ + if not hasattr(self, "_rlcompleter"): + try: + import readline + except ImportError: + # readline is not available, just get the Completer + from rlcompleter import Completer + self._rlcompleter = Completer + else: + # importing rlcompleter could have side effect of changing + # the current completer, we need to restore it + prev_completer = readline.get_completer() + from rlcompleter import Completer + self._rlcompleter = Completer + readline.set_completer(prev_completer) + return self._rlcompleter + def completenames(self, text, line, begidx, endidx): # Overwrite completenames() of cmd so for the command completion, # if no current command matches, check for expressions as well @@ -996,7 +1013,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): state = 0 matches = [] - completer = self.RlCompleter(self.curframe.f_globals | self.curframe.f_locals) + completer = self.rlcompleter(self.curframe.f_globals | self.curframe_locals) while (match := completer.complete(text, state)) is not None: matches.append(match) state += 1 diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py index a65705aaf53a..01f43ac1068d 100644 --- a/Lib/test/test_pyclbr.py +++ b/Lib/test/test_pyclbr.py @@ -225,7 +225,7 @@ class PyclbrTest(TestCase, ExtraAssertions): cm( 'pdb', # pyclbr does not handle elegantly `typing` or properties - ignore=('Union', '_ModuleTarget', '_ScriptTarget', '_ZipTarget'), + ignore=('Union', '_ModuleTarget', '_ScriptTarget', '_ZipTarget', 'rlcompleter'), ) cm('pydoc', ignore=('input', 'output',)) # properties diff --git a/Misc/NEWS.d/next/Library/2025-09-24-14-17-34.gh-issue-139289.Vmk25k.rst b/Misc/NEWS.d/next/Library/2025-09-24-14-17-34.gh-issue-139289.Vmk25k.rst new file mode 100644 index 000000000000..04162619cf21 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-09-24-14-17-34.gh-issue-139289.Vmk25k.rst @@ -0,0 +1 @@ +Do a real lazy-import on :mod:`rlcompleter` in :mod:`pdb` and restore the existing completer after importing :mod:`rlcompleter`.