Skip to main content

Emacs 26, Mojave, elpy, readline

I first started having problems with macOS readline and macports Python a year or two ago. Initially, it was bugs in resetting the tty to a sane configuration when a Python REPL exited. That seems to have been solved, but I'm now encountering readline problems with Python 3.7, GNU Emacs 26.1, and elpy. These notes describe what seems to be a solution, at least for the time being.

I typically install Python versions like this via macports:

sudo port install python37
sudo port install py37-pip
sudo port install py37-virtualenv
sudo port install py37-virtualenvwrapper

Subsequently, I'll use the Python through virtual environments, such as:

mkvirtualenv -p python3.7 py37

With Python versions 3.5 or earlier, it is necessary to use gnureadline to work around problems in the macports readline which uses libedit. This can be done by installing py-gnureadline with macports and configuring it as the readline via $PYTHONSTARTUP. Both the REPL and elpy work fine with this configuration.

With Python 3.6+, gnureadline works properly with the REPL, but elpy has problems with it, preventing inferior Python processes from working properly with Emacs.

Workaround

This is how I resolved the elpy problem.

At this point in the process, there is a ~/.virtualenvs/py37/lib/python3.7/readline.so, which is a symbolic link to /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/lib-dynload/readline.cpython-37m-darwin.so. This is the libedit readline.

Use easy_install to (not pip) install gnureadline.

sudo easy_install gnureadline

This installs gnureadline in ~/.virtualenvs/py37/lib/python3.7/gnureadline-6.3.8-py3.7-macosx-10.12-x86_64.egg.

Once installed, gnureadline is functional, at least in $PYTHONSTARTUP and in ordinary python code. elpy also works when editing python code. However, elpy fails when sending code to a python process. One can test this by first starting an Emacs via Emacs -Q and then running the command M-x run-python. When I did this, I received warnings like the following:

Warning (python): Your ‘python-shell-interpreter’ doesn’t seem to support readline,
yet ‘python-shell-completion-native-enable’ was t and "python" is not part of the 
‘python-shell-completion-native-disabled-interpreters’ list.  Native completions
have been disabled locally.

The failure, I think, is due to path precedence problems in sys.path which cause the libedit readline to be used instead of gnureadline. In any event, I found a workaround.

The final setp in the workaround is taken from here, which renames the libedit readline so that it can't be found.

cd /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/lib-dynload
sudo mv readline.cpython-37m-darwin.so  mv readline.cpython-37m-darwin.so.bak

The solution leads me to believe that, somewhere in elpy, is code that loads gnureadline if it cant find readline.

Regardless, with the rename, python inferior processes work correctly. And, fortunately, my $PYTHONSTARTUP continues to work properly as well.