X Tutup
Skip to content

Commit 64771cd

Browse files
more autocomplete reformatting
1 parent 3ee8696 commit 64771cd

File tree

1 file changed

+182
-148
lines changed

1 file changed

+182
-148
lines changed

bpython/autocomplete.py

Lines changed: 182 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -57,147 +57,6 @@
5757
"oct", "hex", "index", "coerce", "enter", "exit"]]
5858

5959

60-
def attr_complete(text, namespace=None, mode=SIMPLE):
61-
"""Return list of matches """
62-
if namespace is None:
63-
namespace = __main__.__dict__
64-
65-
assert '.' in text
66-
67-
for i in range(1, len(text) + 1):
68-
if text[-i] == '[':
69-
i -= 1
70-
break
71-
methodtext = text[-i:]
72-
matches = [''.join([text[:-i], m]) for m in
73-
attr_matches(methodtext, namespace, mode)]
74-
75-
# unless the first character is a _ filter out all attributes starting with a _
76-
if not text.split('.')[-1].startswith('_'):
77-
matches = [match for match in matches
78-
if not match.split('.')[-1].startswith('_')]
79-
return matches
80-
81-
82-
class SafeEvalFailed(Exception):
83-
"""If this object is returned, safe_eval failed"""
84-
# Because every normal Python value is a possible return value of safe_eval
85-
86-
def safe_eval(expr, namespace):
87-
"""Not all that safe, just catches some errors"""
88-
if expr.isdigit():
89-
# Special case: float literal, using attrs here will result in
90-
# a SyntaxError
91-
return SafeEvalFailed
92-
try:
93-
obj = eval(expr, namespace)
94-
return obj
95-
except (NameError,) as e:
96-
# If debugging safe_eval, raise this!
97-
# raise e
98-
return SafeEvalFailed
99-
100-
def attr_matches(text, namespace, autocomplete_mode):
101-
"""Taken from rlcompleter.py and bent to my will.
102-
"""
103-
104-
# Gna, Py 2.6's rlcompleter searches for __call__ inside the
105-
# instance instead of the type, so we monkeypatch to prevent
106-
# side-effects (__getattr__/__getattribute__)
107-
m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text)
108-
if not m:
109-
return []
110-
111-
expr, attr = m.group(1, 3)
112-
obj = safe_eval(expr, namespace)
113-
if obj is SafeEvalFailed:
114-
return []
115-
with inspection.AttrCleaner(obj):
116-
matches = attr_lookup(obj, expr, attr, autocomplete_mode)
117-
return matches
118-
119-
def attr_lookup(obj, expr, attr, autocomplete_mode):
120-
"""Second half of original attr_matches method factored out so it can
121-
be wrapped in a safe try/finally block in case anything bad happens to
122-
restore the original __getattribute__ method."""
123-
words = dir(obj)
124-
if hasattr(obj, '__class__'):
125-
words.append('__class__')
126-
words = words + rlcompleter.get_class_members(obj.__class__)
127-
if has_abc and not isinstance(obj.__class__, abc.ABCMeta):
128-
try:
129-
words.remove('__abstractmethods__')
130-
except ValueError:
131-
pass
132-
133-
matches = []
134-
n = len(attr)
135-
for word in words:
136-
if method_match(word, n, attr, autocomplete_mode) and word != "__builtins__":
137-
matches.append("%s.%s" % (expr, word))
138-
return matches
139-
140-
def _callable_postfix(value, word):
141-
"""rlcompleter's _callable_postfix done right."""
142-
with inspection.AttrCleaner(value):
143-
if inspection.is_callable(value):
144-
word += '('
145-
return word
146-
147-
def global_matches(text, namespace, autocomplete_mode):
148-
"""Compute matches when text is a simple name.
149-
Return a list of all keywords, built-in functions and names currently
150-
defined in self.namespace that match.
151-
"""
152-
153-
hash = {}
154-
n = len(text)
155-
import keyword
156-
for word in keyword.kwlist:
157-
if method_match(word, n, text, autocomplete_mode):
158-
hash[word] = 1
159-
for nspace in [__builtin__.__dict__, namespace]:
160-
for word, val in nspace.items():
161-
if method_match(word, len(text), text, autocomplete_mode) and word != "__builtins__":
162-
hash[_callable_postfix(val, word)] = 1
163-
matches = hash.keys()
164-
matches.sort()
165-
return matches
166-
167-
#TODO use method_match everywhere instead of startswith to implement other completion modes
168-
# will also need to rewrite checking mode so cseq replace doesn't happen in frontends
169-
def method_match(word, size, text, autocomplete_mode):
170-
if autocomplete_mode == SIMPLE:
171-
return word[:size] == text
172-
elif autocomplete_mode == SUBSTRING:
173-
s = r'.*%s.*' % text
174-
return re.search(s, word)
175-
else:
176-
s = r'.*%s.*' % '.*'.join(list(text))
177-
return re.search(s, word)
178-
179-
def filename_matches(cs):
180-
matches = []
181-
username = cs.split(os.path.sep, 1)[0]
182-
user_dir = os.path.expanduser(username)
183-
for filename in glob(os.path.expanduser(cs + '*')):
184-
if os.path.isdir(filename):
185-
filename += os.path.sep
186-
if cs.startswith('~'):
187-
filename = username + filename[len(user_dir):]
188-
matches.append(filename)
189-
return matches
190-
191-
def last_part_of_filename(filename):
192-
filename.rstrip(os.sep).rsplit(os.sep)[-1]
193-
if os.sep in filename[:-1]:
194-
return filename[filename.rindex(os.sep, 0, -1)+1:]
195-
else:
196-
return filename
197-
198-
def after_last_dot(name):
199-
return name.rstrip('.').rsplit('.')[-1]
200-
20160
def get_completer(cursor_offset, current_line, locals_, argspec, full_code, mode, complete_magic_methods):
20261
"""Returns a list of matches and a class for what kind of completion is happening
20362
@@ -233,7 +92,6 @@ def get_completer(cursor_offset, current_line, locals_, argspec, full_code, mode
23392
return None, None
23493
return sorted(set(current_word_matches)), AttrCompletion
23594

236-
23795
class BaseCompletionType(object):
23896
"""Describes different completion types"""
23997
def matches(cls, cursor_offset, line, **kwargs):
@@ -271,7 +129,9 @@ class ImportCompletion(BaseCompletionType):
271129
def matches(cls, cursor_offset, current_line, **kwargs):
272130
return importcompletion.complete(cursor_offset, current_line)
273131
locate = staticmethod(lineparts.current_word)
274-
format = staticmethod(after_last_dot)
132+
@classmethod
133+
def format(cls, name):
134+
return name.rstrip('.').rsplit('.')[-1]
275135

276136
class FilenameCompletion(BaseCompletionType):
277137
shown_before_tab = False
@@ -280,20 +140,59 @@ def matches(cls, cursor_offset, current_line, **kwargs):
280140
cs = lineparts.current_string(cursor_offset, current_line)
281141
if cs is None:
282142
return None
283-
return filename_matches(cs[2])
143+
start, end, text = cs
144+
matches = []
145+
username = text.split(os.path.sep, 1)[0]
146+
user_dir = os.path.expanduser(username)
147+
for filename in glob(os.path.expanduser(text + '*')):
148+
if os.path.isdir(filename):
149+
filename += os.path.sep
150+
if text.startswith('~'):
151+
filename = username + filename[len(user_dir):]
152+
matches.append(filename)
153+
return matches
154+
284155
locate = staticmethod(lineparts.current_string)
285-
format = staticmethod(last_part_of_filename)
156+
@classmethod
157+
def format(cls, filename):
158+
filename.rstrip(os.sep).rsplit(os.sep)[-1]
159+
if os.sep in filename[:-1]:
160+
return filename[filename.rindex(os.sep, 0, -1)+1:]
161+
else:
162+
return filename
286163

287164
class AttrCompletion(BaseCompletionType):
288165
@classmethod
289166
def matches(cls, cursor_offset, line, locals_, mode, **kwargs):
290167
r = cls.locate(cursor_offset, line)
291168
if r is None:
292169
return None
293-
cw = r[2]
294-
return attr_complete(cw, namespace=locals_, mode=mode)
170+
text = r[2]
171+
172+
if locals_ is None:
173+
locals_ = __main__.__dict__
174+
175+
assert '.' in text
176+
177+
for i in range(1, len(text) + 1):
178+
if text[-i] == '[':
179+
i -= 1
180+
break
181+
methodtext = text[-i:]
182+
matches = [''.join([text[:-i], m]) for m in
183+
attr_matches(methodtext, locals_, mode)]
184+
185+
#TODO add open paren for methods via _callable_prefix (or decide not to)
186+
# unless the first character is a _ filter out all attributes starting with a _
187+
if not text.split('.')[-1].startswith('_'):
188+
matches = [match for match in matches
189+
if not match.split('.')[-1].startswith('_')]
190+
return matches
191+
295192
locate = staticmethod(lineparts.current_dotted_attribute)
296-
format = staticmethod(after_last_dot)
193+
@classmethod
194+
def format(cls, name):
195+
return name.rstrip('.').rsplit('.')[-1]
297196

298197
class DictKeyCompletion(BaseCompletionType):
299198
locate = staticmethod(lineparts.current_dict_key)
@@ -354,3 +253,138 @@ def matches(cls, cursor_offset, line, argspec, **kwargs):
354253
if name.startswith(word))
355254
return matches
356255
locate = staticmethod(lineparts.current_word)
256+
257+
class MagicMethodCompletion(BaseCompletionType):
258+
locate = staticmethod(lineparts.current_method_definition_name)
259+
@classmethod
260+
def matches(cls, cursor_offset, line, full_code, **kwargs):
261+
r = cls.locate(cursor_offset, line)
262+
if r is None:
263+
return None
264+
if 'class' not in full_code:
265+
return None
266+
start, end, word = r
267+
return [name for name in MAGIC_METHODS if name.startswith(word)]
268+
269+
class GlobalCompletion(BaseCompletionType):
270+
@classmethod
271+
def matches(cls, cursor_offset, line, locals_, mode, **kwargs):
272+
"""Compute matches when text is a simple name.
273+
Return a list of all keywords, built-in functions and names currently
274+
defined in self.namespace that match.
275+
"""
276+
r = cls.locate(cursor_offset, line)
277+
if r is None:
278+
return None
279+
start, end, text = r
280+
281+
hash = {}
282+
n = len(text)
283+
import keyword
284+
for word in keyword.kwlist:
285+
if method_match(word, n, text, mode):
286+
hash[word] = 1
287+
for nspace in [__builtin__.__dict__, locals_]:
288+
for word, val in nspace.items():
289+
if method_match(word, len(text), text, mode) and word != "__builtins__":
290+
hash[_callable_postfix(val, word)] = 1
291+
matches = hash.keys()
292+
matches.sort()
293+
return matches
294+
295+
locate = staticmethod(lineparts.current_single_word)
296+
297+
class ParameterNameCompletion(BaseCompletionType):
298+
@classmethod
299+
def matches(cls, cursor_offset, line, argspec, **kwargs):
300+
if not argspec:
301+
return None
302+
r = cls.locate(cursor_offset, line)
303+
if r is None:
304+
return None
305+
start, end, word = r
306+
if argspec:
307+
matches = [name + '=' for name in argspec[1][0]
308+
if isinstance(name, basestring) and name.startswith(word)]
309+
if py3:
310+
matches.extend(name + '=' for name in argspec[1][4]
311+
if name.startswith(word))
312+
return matches
313+
locate = staticmethod(lineparts.current_word)
314+
315+
class SafeEvalFailed(Exception):
316+
"""If this object is returned, safe_eval failed"""
317+
# Because every normal Python value is a possible return value of safe_eval
318+
319+
def safe_eval(expr, namespace):
320+
"""Not all that safe, just catches some errors"""
321+
if expr.isdigit():
322+
# Special case: float literal, using attrs here will result in
323+
# a SyntaxError
324+
return SafeEvalFailed
325+
try:
326+
obj = eval(expr, namespace)
327+
return obj
328+
except (NameError,) as e:
329+
# If debugging safe_eval, raise this!
330+
# raise e
331+
return SafeEvalFailed
332+
333+
def attr_matches(text, namespace, autocomplete_mode):
334+
"""Taken from rlcompleter.py and bent to my will.
335+
"""
336+
337+
# Gna, Py 2.6's rlcompleter searches for __call__ inside the
338+
# instance instead of the type, so we monkeypatch to prevent
339+
# side-effects (__getattr__/__getattribute__)
340+
m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text)
341+
if not m:
342+
return []
343+
344+
expr, attr = m.group(1, 3)
345+
obj = safe_eval(expr, namespace)
346+
if obj is SafeEvalFailed:
347+
return []
348+
with inspection.AttrCleaner(obj):
349+
matches = attr_lookup(obj, expr, attr, autocomplete_mode)
350+
return matches
351+
352+
def attr_lookup(obj, expr, attr, autocomplete_mode):
353+
"""Second half of original attr_matches method factored out so it can
354+
be wrapped in a safe try/finally block in case anything bad happens to
355+
restore the original __getattribute__ method."""
356+
words = dir(obj)
357+
if hasattr(obj, '__class__'):
358+
words.append('__class__')
359+
words = words + rlcompleter.get_class_members(obj.__class__)
360+
if has_abc and not isinstance(obj.__class__, abc.ABCMeta):
361+
try:
362+
words.remove('__abstractmethods__')
363+
except ValueError:
364+
pass
365+
366+
matches = []
367+
n = len(attr)
368+
for word in words:
369+
if method_match(word, n, attr, autocomplete_mode) and word != "__builtins__":
370+
matches.append("%s.%s" % (expr, word))
371+
return matches
372+
373+
def _callable_postfix(value, word):
374+
"""rlcompleter's _callable_postfix done right."""
375+
with inspection.AttrCleaner(value):
376+
if inspection.is_callable(value):
377+
word += '('
378+
return word
379+
380+
#TODO use method_match everywhere instead of startswith to implement other completion modes
381+
# will also need to rewrite checking mode so cseq replace doesn't happen in frontends
382+
def method_match(word, size, text, autocomplete_mode):
383+
if autocomplete_mode == SIMPLE:
384+
return word[:size] == text
385+
elif autocomplete_mode == SUBSTRING:
386+
s = r'.*%s.*' % text
387+
return re.search(s, word)
388+
else:
389+
s = r'.*%s.*' % '.*'.join(list(text))
390+
return re.search(s, word)

0 commit comments

Comments
 (0)
X Tutup