21

Several months ago, I wrote a blog post detailing how to achieve tab-completion in the standard Python interactive interpreter--a feature I once thought only available in IPython. I've found it tremendously handy given that I sometimes have to switch to the standard interpreter due to IPython unicode issues.

Recently I've done some work in OS X. To my discontent, the script doesn't seem to work for OS X's Terminal application. I'm hoping some of you with experience in OS X might be able to help me trouble-shoot it so it can work in Terminal, as well.

I am reproducing the code below

import atexit
import os.path

try:
    import readline
except ImportError:
    pass
else:
    import rlcompleter

    class IrlCompleter(rlcompleter.Completer):
        """
        This class enables a "tab" insertion if there's no text for
        completion.

        The default "tab" is four spaces. You can initialize with '\t' as
        the tab if you wish to use a genuine tab.

        """

        def __init__(self, tab='    '):
            self.tab = tab
            rlcompleter.Completer.__init__(self)


        def complete(self, text, state):
            if text == '':
                readline.insert_text(self.tab)
                return None
            else:
                return rlcompleter.Completer.complete(self,text,state)


    #you could change this line to bind another key instead tab.
    readline.parse_and_bind('tab: complete')
    readline.set_completer(IrlCompleter('\t').complete)


# Restore our command-line history, and save it when Python exits.
history_path = os.path.expanduser('~/.pyhistory')
if os.path.isfile(history_path):
    readline.read_history_file(history_path)
atexit.register(lambda x=history_path: readline.write_history_file(x))

Note that I have slightly edited it from the version on my blog post so that the IrlCompleter is initialized with a true tab, which seems to be what is output by the Tab key in Terminal.

gotgenes
  • 38,661
  • 28
  • 100
  • 128

7 Answers7

56

This should work under Leopard's python:

import rlcompleter
import readline
readline.parse_and_bind ("bind ^I rl_complete")

Whereas this one does not:

import readline, rlcompleter
readline.parse_and_bind("tab: complete")

Save it in ~/.pythonrc.py and execute in .bash_profile

export PYTHONSTARTUP=$HOME/.pythonrc.py
B0rG
  • 1,215
  • 12
  • 13
  • works for me! Now, can you get it to work with `readline.set_completer()`? – ʞɔıu Jun 12 '09 at 15:55
  • strange... can you tell me what's your Python version? mine is Python 2.5.1 (r251:54863, Feb 6 2009, 19:02:12) [GCC 4.0.1 (Apple Inc. build 5465)] on darwin – B0rG Jun 12 '09 at 16:32
  • yeah, now it works, it was missing import rlcompleter, sorry for making such fuss ;-) cheers. – B0rG Jun 12 '09 at 21:09
  • 1
    And you can use readline.parse_and_bind ("bind ^[ rl_complete") if you want to bind completion to esc. Which I have bound to caps lock using double-command. That little bit of distance I now save when completing is amazing! (And I use TextMate, which uses esc as the complete key). – Matthew Schinckel Jul 25 '09 at 05:50
  • I tried this implementation and I have a problem that a key "b" stops working in Python 3, though it well in Python2. – schatten Apr 28 '15 at 02:21
  • It's 2017 and this is still the way to get this to work on macOS. Thank you! – ephsmith Oct 14 '17 at 15:23
11

here is a full cross platform version of loading tab completion for Windows/OS X/Linux in one shot:

#Code  UUID = '9301d536-860d-11de-81c8-0023dfaa9e40'
import sys
try:
        import readline
except ImportError:
        try:
                import pyreadline as readline
        # throw open a browser if we fail both readline and pyreadline
        except ImportError:
                import webbrowser
                webbrowser.open("http://ipython.scipy.org/moin/PyReadline/Intro#line-36")
                # throw open a browser
        #pass
else:
        import rlcompleter
        if(sys.platform == 'darwin'):
                readline.parse_and_bind ("bind ^I rl_complete")
        else:
                readline.parse_and_bind("tab: complete")

From http://www.farmckon.net/?p=181

FarMcKon
  • 161
  • 1
  • 5
  • ``readline.parse_and_bind ("bind ^I rl_complete")`` and ``readline.parse_and_bind("tab: complete")`` don't seem to conflict, so the ``else`` can be simplified down a bit. – Gregg Lind Dec 19 '11 at 22:35
8

To avoid having to use more GPL code, Apple doesn't include a real readline. Instead it uses the BSD-licensed libedit, which is only mostly-readline-compatible. Build your own Python (or use Fink or MacPorts) if you want completion.

vasi
  • 1,026
  • 7
  • 6
  • It seems that there are no Python with TabCompletion in Macports: % port variants python26 % gives only darwin, universal and ucs4 packages. -- How can you install Python with tab completion by MacPorts? – Léo Léopold Hertz 준영 Jun 12 '09 at 15:49
  • @Masi, tab completion isn't a port variant, it's something you configure after-the-fact. See http://docs.python.org/library/rlcompleter.html – mpontillo Sep 24 '11 at 20:11
1

If after trying the above, it still doesn't work, then try to execute in the shell:

sudo easy_install readline

Then, create ~/.profile file with the content:

export PYTHONSTARTUP=$HOME/.pythonrc.py

and a ~/.pythonrc.py file with the content:

try:
    import readline
except:
    print ("Module readline is not available.")
else:
    import rlcompleter
    readline.parse_and_bind("tab: complete")

Thanks to Steven Bamford for the easy_install tip, and Nicolas for the file content.

Gilad Beeri
  • 306
  • 3
  • 5
1

This works for me on both Linux bash and OS X 10.4

import readline
import rlcompleter
readline.parse_and_bind('tab: complete')
Van Gale
  • 43,536
  • 9
  • 71
  • 81
  • I've noticed this works in my copy of Python3.0 on Leopard (OS X 10.5), which I compiled against readline 6. It doesn't seem to work for me with the copy of Python2.5 that shipped with the OS. – Jarret Hardie Mar 23 '09 at 23:34
  • +1 Because I didn't know about this short way of doing things though! – Jarret Hardie Mar 23 '09 at 23:39
  • As Jarrett said, this doesn't work on OS X 10.5 with the included Python 2.5. – gotgenes Mar 24 '09 at 21:27
  • 1
    Ok that's too bad. I also realized later that this doesn't help with the "initial tab" problem, which is the reason for your more complex code. – Van Gale Mar 24 '09 at 22:41
  • @Van Gale: What is the name of the file where I should put the code? I know that you can use .pythonrc by the module user, but I am not sure whether it is the right way or not. – Léo Léopold Hertz 준영 Jun 12 '09 at 15:55
  • @Masi: On Linux it is .pythonstartup in your home directory. Unfortunately my Mac hard disk crashed a few weeks ago so I can't verify whether it's the same there. – Van Gale Jun 12 '09 at 17:26
0

The documented way to tell libedit (the Mac OS semi-readline) from the real one is: if "libedit" in readline.doc: pass # Mac case else: pass # GNU readline case

0

After crashing into many issues dealing with Python (2 and 3) on FreeBSD, I finally got a proper extension to work using libedit directly as the completer for Python.

The basic issue with libedit/readline is that Python's completion and input was heavily bent towards GNU readline... Sadly, this is actually not a particularly good interface. It requires a giant number of globals in C and does not work well on an "instance" basis.

Solution:

https://github.com/mark-nicholson/python-editline

This is a true separate python extension which directly links to libedit using the actual "libedit" interface -- not the readline glue on the side.

I have tested it pretty thoroughly on Ubuntu, FreeBSD, OpenBSD, NetBSD and MacOS -- results are posted in the readme. The c-code is very clean and has virtually no platform dependent bits -- unlike the readline.c module in Python.

Notes: It works on Python3 > 3.2. It is NOT a drop-in replacement for 'import readline' in other scripts, but those scripts can be adjusted easily. It can co-exist with readline.so -- there is code for a sitecustomize.py file which enables the selection. It can use a distribution 'libedit.so', a custom built one or libedit built into the extension itself.

mjn
  • 403
  • 5
  • 7