Skip to content

Commit ab82422

Browse files
Issue #25011: rlcomplete now omits private and special attribute names unless
the prefix starts with underscores.
1 parent 8ace8e9 commit ab82422

4 files changed

Lines changed: 51 additions & 10 deletions

File tree

Doc/whatsnew/3.6.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,14 @@ operator
103103
(Contributed by Joe Jevnik in :issue:`24379`.)
104104

105105

106+
rlcomplete
107+
----------
108+
109+
Private and special attribute names now are omitted unless the prefix starts
110+
with underscores. A space or a colon can be added after completed keyword.
111+
(Contributed by Serhiy Storchaka in :issue:`25011` and :issue:`25209`.)
112+
113+
106114
Optimizations
107115
=============
108116

Lib/rlcompleter.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -142,20 +142,35 @@ def attr_matches(self, text):
142142
return []
143143

144144
# get the content of the object, except __builtins__
145-
words = dir(thisobject)
146-
if "__builtins__" in words:
147-
words.remove("__builtins__")
145+
words = set(dir(thisobject))
146+
words.discard("__builtins__")
148147

149148
if hasattr(thisobject, '__class__'):
150-
words.append('__class__')
151-
words.extend(get_class_members(thisobject.__class__))
149+
words.add('__class__')
150+
words.update(get_class_members(thisobject.__class__))
152151
matches = []
153152
n = len(attr)
154-
for word in words:
155-
if word[:n] == attr and hasattr(thisobject, word):
156-
val = getattr(thisobject, word)
157-
word = self._callable_postfix(val, "%s.%s" % (expr, word))
158-
matches.append(word)
153+
if attr == '':
154+
noprefix = '_'
155+
elif attr == '_':
156+
noprefix = '__'
157+
else:
158+
noprefix = None
159+
while True:
160+
for word in words:
161+
if (word[:n] == attr and
162+
not (noprefix and word[:n+1] == noprefix) and
163+
hasattr(thisobject, word)):
164+
val = getattr(thisobject, word)
165+
word = self._callable_postfix(val, "%s.%s" % (expr, word))
166+
matches.append(word)
167+
if matches or not noprefix:
168+
break
169+
if noprefix == '_':
170+
noprefix = '__'
171+
else:
172+
noprefix = None
173+
matches.sort()
159174
return matches
160175

161176
def get_class_members(klass):

Lib/test/test_rlcompleter.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
class CompleteMe:
66
""" Trivial class used in testing rlcompleter.Completer. """
77
spam = 1
8+
_ham = 2
89

910

1011
class TestRlcompleter(unittest.TestCase):
@@ -51,11 +52,25 @@ def test_attr_matches(self):
5152
['str.{}('.format(x) for x in dir(str)
5253
if x.startswith('s')])
5354
self.assertEqual(self.stdcompleter.attr_matches('tuple.foospamegg'), [])
55+
expected = sorted({'None.%s%s' % (x, '(' if x != '__doc__' else '')
56+
for x in dir(None)})
57+
self.assertEqual(self.stdcompleter.attr_matches('None.'), expected)
58+
self.assertEqual(self.stdcompleter.attr_matches('None._'), expected)
59+
self.assertEqual(self.stdcompleter.attr_matches('None.__'), expected)
5460

5561
# test with a customized namespace
5662
self.assertEqual(self.completer.attr_matches('CompleteMe.sp'),
5763
['CompleteMe.spam'])
5864
self.assertEqual(self.completer.attr_matches('Completeme.egg'), [])
65+
self.assertEqual(self.completer.attr_matches('CompleteMe.'),
66+
['CompleteMe.mro(', 'CompleteMe.spam'])
67+
self.assertEqual(self.completer.attr_matches('CompleteMe._'),
68+
['CompleteMe._ham'])
69+
matches = self.completer.attr_matches('CompleteMe.__')
70+
for x in matches:
71+
self.assertTrue(x.startswith('CompleteMe.__'), x)
72+
self.assertIn('CompleteMe.__name__', matches)
73+
self.assertIn('CompleteMe.__new__(', matches)
5974

6075
CompleteMe.me = CompleteMe
6176
self.assertEqual(self.completer.attr_matches('CompleteMe.me.me.sp'),

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ Core and Builtins
2727
Library
2828
-------
2929

30+
- Issue #25011: rlcomplete now omits private and special attribute names unless
31+
the prefix starts with underscores.
32+
3033
- Issue #25209: rlcomplete now can add a space or a colon after completed keyword.
3134

3235
- Issue #22241: timezone.utc name is now plain 'UTC', not 'UTC-00:00'.

0 commit comments

Comments
 (0)