Using Readline-Type Features with Apple's Python on OS X 10.5

Edward Moy, an Apple engineer, helped us realize that Mac OSX uses libEdit, rather that GNU readline.

The functionality is basically the same, but the "names" of the functions are different. So you have to use different commands to map keyboard events to the functions. If you try to bind to the GNU readline function names, either it won't work (no readline behavior) or it might crash. Ouch.

I cobbled up two patches for IPython that check to see if the Python is bound to Leopard's libEdit, and if so, to avoid GNU readline bindings, and (as a special case) bind the TAB key to the readline completer function.

This is a great start, but it may not be entirely satisfactory. However, it seems to work well enough for many IPython users.

These patches were applied to the IPython subversion trunk, and I believe that they made it into the 0.82 release.

NOTE: THESE PATCHES EFFECTIVELY DISABLE READLINE COMMANDS IN YOUR .ipythonrc -- YOU WILL NEED TO ADD ANY READLINE KEYBOARD CONFIGURATIONS TO YOUR .editrc instead.

 man editrc 

Patch 1

   1 --- IPython/rlineimpl.py        2007-10-30 17:34:13.000000000 -0600
   2 +++ IPython/rlineimpl.py        2007-10-31 10:54:23.000000000 -0600
   3 @@ -29,6 +29,16 @@
   4          print "Failed GetOutputFile"
   5          have_readline = False
   6 
   7 +uses_libedit = False
   8 +if sys.platform == 'darwin' and have_readline:
   9 +    import commands
  10 +    (status, result) = commands.getstatusoutput( "otool -L %s | grep libedit" % _rl.__file__ )
  11 +    if status == 0 and len(result) > 0:
  12 +        # we are bound to libedit - new in Leopard
  13 +        _rl.parse_and_bind("bind ^I rl_complete")
  14 +        print "Leopard libedit detected."
  15 +        uses_libedit = True
  16 +
  17  # the clear_history() function was only introduced in Python 2.4 and is
  18  # actually optional in the readline API, so we must explicitly check for its
  19  # existence.  Some known platforms actually don't have it.  This thread:

Patch 2

   1 --- IPython/iplib.py.orig       2007-10-31 13:01:11.000000000 -0600
   2 +++ IPython/iplib.py    2007-10-31 13:12:05.000000000 -0600
   3 @@ -1325,7 +1325,10 @@
   4              if inputrc_name is None:
   5                  home_dir = get_home_dir()
   6                  if home_dir is not None:
   7 -                    inputrc_name = os.path.join(home_dir,'.inputrc')
   8 +                    inputrc_name = '.inputrc'
   9 +                    if readline.uses_libedit:
  10 +                        inputrc_name = '.editrc'
  11 +                    inputrc_name = os.path.join(home_dir, inputrc_name)
  12              if os.path.isfile(inputrc_name):
  13                  try:
  14                      readline.read_init_file(inputrc_name)
  15 @@ -1340,8 +1343,9 @@
  16              self.set_completer()
  17 
  18              # Configure readline according to user's prefs
  19 -            for rlcommand in self.rc.readline_parse_and_bind:
  20 -                readline.parse_and_bind(rlcommand)
  21 +            if not readline.uses_libedit:
  22 +                for rlcommand in self.rc.readline_parse_and_bind:
  23 +                       readline.parse_and_bind(rlcommand)
  24 
  25              # remove some chars from the delimiters list
  26              delims = readline.get_completer_delims()

InstallationOSXLeopard/LeopardPythonReadline (last edited 2008-01-15 18:35:23 by EdwardReam)