views:

881

answers:

3

When an object has hundreds of methods, tab completion is hard to use. More often than not the interesting methods are the ones defined or overridden by the inspected object's class and not its base classes.

How can I get IPython to group its tab completion possibilities so the methods and properties defined in the inspected object's class come first, followed by those in base classes?

It looks like the undocumented inspect.classify_class_attrs(cls) function along with inspect.getmro(cls) give me most of the information I need (these were originally written to implement python's help(object) feature).

By default readline displays completions alphabetically, but the function used to display completions can be replaced with ctypes or the readline module included with Python 2.6 and above. I've overridden readline's completions display and it works great.

Now all I need is a method to merge per-class information (from inspect.* per above) with per-instance information, sort the results by method resolution order, pretty print and paginate.

For extra credit, it would be great to store the chosen autocompletion, and display the most popular choices first next time autocomplete is attempted on the same object.

+1  A: 

I don't think this can be accomplished easily. There's no mechanism in Ipython to perform it in any case.

Initially I had thought you could modify Ipython's source to change the order (eg by changing the dir2() function in genutils.py). However it looks like readline alphabetically sorts the completions you pass to it, so this won't work (at least not without a lot more effort), though you could perhaps exclude methods on the base class completely.

Brian
+1  A: 

It looks like I can use readline.set_completion_display_matches_hook([function]) (new in Python 2.6) to display the results. The completer would return a list of possibilities as usual, but would also store the results of inspect.classify_class_attrs(cls) where applicable. The completion_display_matches_hook would have to hold a reference to the completer to retrieve the most recent list of completions plus the classification information I am looking for because only receives a list of match names in its arguments. Then the hook displays the list of completions in a pleasing way.

joeforker
+3  A: 

Since I am not using Python 2.6 or 3.0 yet and don't have readline.set_completion_display_matches_hook(), I can use ctypes to set completion_display_func like so:

from ctypes import *

rl = cdll.LoadLibrary('libreadline.so')

def completion_display_func(matches, num_matches, max_length):
    print "Hello from Python"
    for i in range(num_matches):
        print matches[i]

COMPLETION_DISPLAY_FUNC = CFUNCTYPE(None, POINTER(c_char_p), c_int, c_int)
hook = COMPLETION_DISPLAY_FUNC(completion_display_func)
ptr = c_void_p.in_dll(rl, 'rl_completion_display_matches_hook')
ptr.value = cast(hook, c_void_p).value

Now, when I press 'tab' to complete, my own function prints the list of completions. So that answers the question 'how do I change the way readline displays completions'.

joeforker