Issue 5062: Rlcompleter.Completer does not use dir magic method (original) (raw)

The documentation at http://docs.python.org/library/rlcompleter.html claims that

Completer.complete(text, state)¶

Return the state*th completion for *text.

If called for text that doesn’t include a period character ('.'), it will complete from names currently defined in main, builtin and keywords (as defined by the keyword module).

If called for a dotted name, it will try to evaluate anything without obvious side-effects (functions will not be evaluated, but it can generate calls to getattr()) up to the last part, and find matches for the rest via the dir() function. Any exception raised during the evaluation of the expression is caught, silenced and None is returned.

In other words, it claims to use dir(obj) as part of the tab completion process. This is not true (using Python 2.6.1 on OS X):

class B(object): ... def dir(self): return dir(u"") #Makes B objects look like strings ... b = B() dir(b) ['add', 'class', 'contains', 'delattr', 'doc', 'eq', 'format', 'ge', 'getattribute', 'getitem', 'getnewargs', 'getslice', 'gt', 'hash', 'init', 'le', 'len', 'lt', 'mod', 'mul', 'ne', 'new', 'reduce', 'reduce_ex', 'repr', 'rmod', 'rmul', 'setattr', 'sizeof', 'str', 'subclasshook', '_formatter_field_name_split', '_formatter_parser', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'islower', 'isnumeric', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill'] c = rlcompleter.Completer() c.complete("b.", 0) #Notice that it does NOT return add u'b.class(' c.matches #Notice that this list is completely different from the list given by dir(b) [u'b.class(', u'b.delattr(', u'b.doc', u'b.format(', u'b.getattribute(', u'b.hash(', u'b.init(', u'b.new(', u'b.reduce(', u'b.reduce_ex(', u'b.repr(', u'b.setattr(', u'b.sizeof(', u'b.str(', u'b.subclasshook(', u'b.class(', u'b.class(', u'b.delattr(', u'b.dict', u'b.dir(', u'b.doc', u'b.format(', u'b.getattribute(', u'b.hash(', u'b.init(', u'b.module', u'b.new(', u'b.reduce(', u'b.reduce_ex(', u'b.repr(', u'b.setattr(', u'b.sizeof(', u'b.str(', u'b.subclasshook(', u'b.weakref', u'b.class(', u'b.delattr(', u'b.doc', u'b.format(', u'b.getattribute(', u'b.hash(', u'b.init(', u'b.new(', u'b.reduce(', u'b.reduce_ex(', u'b.repr(', u'b.setattr(', u'b.sizeof(', u'b.str(', u'b.subclasshook(']

Suggested course of action:

See http://mail.python.org/pipermail/python-dev/2009-January/thread.html#85471

This is not a bug in rlcompleter; dir is returning bogus items, and rlcompleter checks whether there exist actually an attribute with such name.

Defining getattr (or getattribute) and a matching dir works fine:

class B(object): ... def dir(self): ... return dir(object) + ["xa","xb","xc"] ... def getattr(self, name): ... if name in ["xa","xb","xc"]: ... return None ... raise AttributeError, name ... b = B() import rlcompleter c = rlcompleter.Completer() c.complete("b.", 0) 'b.class(' c.matches ['b.class(', 'b.delattr(', 'b.doc', 'b.format(', 'b.getattribute(', ... 'b.xa', 'b.xb', 'b.xc', 'b.class(', 'b.class(', ...] c.complete("b.x", 0) 'b.xa' c.matches ['b.xa', 'b.xb', 'b.xc']

Now, looking at this I saw there is a bug in rlcompleter, as it may return many duplicate items:

c.complete("b.__c", 0) 'b.class(' c.matches ['b.class(', 'b.class(', 'b.class(', 'b.class(']

The attached patch fixes that.