Skip to content

Commit 773a7c0

Browse files
[3.13] pythongh-139289: Lazy import rlcompleter to fix the refleak (pythonGH-139305) (python#139357)
(cherry picked from commit 8288f36)
1 parent 606022c commit 773a7c0

File tree

3 files changed

+28
-10
lines changed

3 files changed

+28
-10
lines changed

Lib/pdb.py

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -332,14 +332,6 @@ def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None,
332332
except ImportError:
333333
pass
334334

335-
# GH-138860
336-
# We need to lazy-import rlcompleter to avoid deadlock
337-
# We cannot import it during self.complete* methods because importing
338-
# rlcompleter for the first time will overwrite readline's completer
339-
# So we import it here and save the Completer class
340-
from rlcompleter import Completer
341-
self.RlCompleter = Completer
342-
343335
self.allow_kbdint = False
344336
self.nosigint = nosigint
345337
# Consider these characters as part of the command so when the users type
@@ -918,6 +910,31 @@ def set_convenience_variable(self, frame, name, value):
918910
# Generic completion functions. Individual complete_foo methods can be
919911
# assigned below to one of these functions.
920912

913+
@property
914+
def rlcompleter(self):
915+
"""Return the `Completer` class from `rlcompleter`, while avoiding the
916+
side effects of changing the completer from `import rlcompleter`.
917+
918+
This is a compromise between GH-138860 and GH-139289. If GH-139289 is
919+
fixed, then we don't need this and we can just `import rlcompleter` in
920+
`Pdb.__init__`.
921+
"""
922+
if not hasattr(self, "_rlcompleter"):
923+
try:
924+
import readline
925+
except ImportError:
926+
# readline is not available, just get the Completer
927+
from rlcompleter import Completer
928+
self._rlcompleter = Completer
929+
else:
930+
# importing rlcompleter could have side effect of changing
931+
# the current completer, we need to restore it
932+
prev_completer = readline.get_completer()
933+
from rlcompleter import Completer
934+
self._rlcompleter = Completer
935+
readline.set_completer(prev_completer)
936+
return self._rlcompleter
937+
921938
def completenames(self, text, line, begidx, endidx):
922939
# Overwrite completenames() of cmd so for the command completion,
923940
# if no current command matches, check for expressions as well
@@ -996,7 +1013,7 @@ def completedefault(self, text, line, begidx, endidx):
9961013

9971014
state = 0
9981015
matches = []
999-
completer = self.RlCompleter(self.curframe.f_globals | self.curframe.f_locals)
1016+
completer = self.rlcompleter(self.curframe.f_globals | self.curframe_locals)
10001017
while (match := completer.complete(text, state)) is not None:
10011018
matches.append(match)
10021019
state += 1

Lib/test/test_pyclbr.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ def test_others(self):
225225
cm(
226226
'pdb',
227227
# pyclbr does not handle elegantly `typing` or properties
228-
ignore=('Union', '_ModuleTarget', '_ScriptTarget', '_ZipTarget'),
228+
ignore=('Union', '_ModuleTarget', '_ScriptTarget', '_ZipTarget', 'rlcompleter'),
229229
)
230230
cm('pydoc', ignore=('input', 'output',)) # properties
231231

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Do a real lazy-import on :mod:`rlcompleter` in :mod:`pdb` and restore the existing completer after importing :mod:`rlcompleter`.

0 commit comments

Comments
 (0)