]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-139289: Lazy import rlcompleter to fix the refleak (#139305)
authorTian Gao <gaogaotiantian@hotmail.com>
Fri, 26 Sep 2025 14:17:02 +0000 (22:17 +0800)
committerGitHub <noreply@github.com>
Fri, 26 Sep 2025 14:17:02 +0000 (22:17 +0800)
Lib/pdb.py
Lib/test/test_pyclbr.py
Misc/NEWS.d/next/Library/2025-09-24-14-17-34.gh-issue-139289.Vmk25k.rst [new file with mode: 0644]

index fd48882e28fe7cb7d3e1e8e8ecac2a4bd7cd2a4c..f695a39332e461772f55cea21866e69d66b77864 100644 (file)
@@ -364,14 +364,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
@@ -1100,6 +1092,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
@@ -1196,7 +1213,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.f_locals)
         while (match := completer.complete(text, state)) is not None:
             matches.append(match)
             state += 1
@@ -1211,7 +1228,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):
             return
 
         try:
-            completer = self.RlCompleter(ns)
+            completer = self.rlcompleter(ns)
             old_completer = readline.get_completer()
             readline.set_completer(completer.complete)
             yield
index bce68e6cd7a57e1f78e4fdfd69ebcb0e35adf142..79ef178f3807f410dbb961585104031f278672e1 100644 (file)
@@ -250,7 +250,7 @@ class PyclbrTest(TestCase):
                 'pdb',
                 # pyclbr does not handle elegantly `typing` or properties
                 ignore=('Union', '_ModuleTarget', '_ScriptTarget', '_ZipTarget', 'curframe_locals',
-                        '_InteractState'),
+                        '_InteractState', '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 (file)
index 0000000..0416261
--- /dev/null
@@ -0,0 +1 @@
+Do a real lazy-import on :mod:`rlcompleter` in :mod:`pdb` and restore the existing completer after importing :mod:`rlcompleter`.