pupy/pupy/pupylib/PythonCompleter.py

107 lines
2.7 KiB
Python

import __builtin__
__all__ = ["PythonCompleter"]
class PythonCompleter:
def __init__(self, local_ns=None, global_ns=None):
if local_ns is not None:
self.local_ns=local_ns
else:
self.local_ns={}
if global_ns is not None:
self.global_ns=global_ns
else:
self.global_ns={}
def complete(self, text, state):
if state == 0:
if "." in text:
self.matches = self.attr_matches(text)
else:
self.matches = self.var_matches(text)
try:
return self.matches[state]
except IndexError:
return None
def _callable_postfix(self, val, word):
if hasattr(val, '__call__'):
word = word + "("
return word
def var_matches(self, text):
import re
m = re.match(r"(\w*)", text)
if not m:
return []
words=[x for x in self.local_ns.iterkeys() if x.startswith(m.group(1))]
if "__builtins__" in words:
words.remove("__builtins__")
return words
def attr_matches(self, text):
"""Compute matches when text contains a dot.
Assuming the text is of the form NAME.NAME....[NAME], and is
evaluatable in self.namespace, it will be evaluated and its attributes
(as revealed by dir()) are used as possible completions. (For class
instances, class members are also considered.)
WARNING: this can still invoke arbitrary C code, if an object
with a __getattr__ hook is evaluated.
"""
import re
bsw="[a-zA-Z0-9_\\(\\)\\[\\]\"']"
m = re.match(r"(\w+(\.\w+)*)\.(\w*)".replace(r"\w",bsw), text)
if not m:
return []
expr, attr = m.group(1, 3)
try:
try:
thisobject = eval(expr, self.global_ns, self.local_ns)
except NameError as e:
"""
print str(e)
try:
exec "import %s"%expr in global_ns, self.local_ns
thisobject = eval(expr, global_ns, self.local_ns)
except ImportError:
pass
"""
except Exception as e:
return []
# get the content of the object, except __builtins__
words = dir(thisobject)
if "__builtins__" in words:
words.remove("__builtins__")
if hasattr(thisobject, '__class__'):
words.append('__class__')
words.extend(get_class_members(thisobject.__class__))
words=[x for x in words if not x.startswith("__")]
matches = []
n = len(attr)
for word in words:
if word[:n] == attr and hasattr(thisobject, word):
val = getattr(thisobject, word)
word = self._callable_postfix(val, "%s.%s" % (expr, word))
matches.append(word)
return matches
def get_class_members(klass):
ret = dir(klass)
if hasattr(klass,'__bases__'):
for base in klass.__bases__:
ret = ret + get_class_members(base)
return ret
if __name__=="__main__":
import code
import readline
readline.set_completer(PythonCompleter().complete)
readline.parse_and_bind('tab: complete')
code.interact()