Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 27 additions & 10 deletions Lib/pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,14 +364,6 @@ def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None,
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
Expand Down Expand Up @@ -1100,6 +1092,31 @@ def set_convenience_variable(self, frame, name, value):
# 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
Expand Down Expand Up @@ -1196,7 +1213,7 @@ def completedefault(self, text, line, begidx, endidx):

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
Expand All @@ -1211,7 +1228,7 @@ def _enable_rlcompleter(self, ns):
return

try:
completer = self.RlCompleter(ns)
completer = self.rlcompleter(ns)
old_completer = readline.get_completer()
readline.set_completer(completer.complete)
yield
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_pyclbr.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ def test_others(self):
'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

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Do a real lazy-import on :mod:`rlcompleter` in :mod:`pdb` and restore the existing completer after importing :mod:`rlcompleter`.
Loading