Python Code completion in Emacs — at last!
I’ve been coding Python in Emacs for years now, and for the most part it’s been a satisfactory experience. After experimenting with various python modes and utilities, I’ve had a pretty good environment that marries Emacs editing to syntax highlighting, real-time error highlighting, the ipython shell, linting tools like pylint and pep8, and various other goodies. But the one hole, the one sore spot in the whole works, was code completion. Something even idle can do out-of-the-box was simply beyond my ability to get functional in Emacs.
I’d tried just about every solution the internet could offer: PyMacs, company-mode, anything-mode, ipython completion, standard autocomplete-mode. Everything I tried either gave unacceptable results (like autocomplete-mode, which just scans the current buffer for completion information), or just flat-out didn’t work no matter how many tutorials I followed.
Here lately I’ve been trying to work a lot more on my Pythoning, so I decided to see if the state of the art has caught up with this need. Echo base, I’ve found it. Repeat: I’ve found it.
Jedi is a generic python code-completion tool, designed to be integrated into whatever editor you like. The Jedi.el emacs package is used to connect jedi to Emacs. After a look at the screenshots for jedi.el I was sold; this setup looked darned nice and I needed it. Unfortunately, as I’ve learned from experience, these things are never straightforward to install and get working. After reading through the jedi.el documentation and a couple blog posts, I found it was not so hard after all. In fact, I’ve so far managed to get it going on both my main Ubuntu (13.04) system and my Arch Linux test system.
Keeping this as simple as possible, here’s what I did to install jedi and get it working with Emacs.
- I’m using Linux (Ubuntu or Arch, so far)
- Using Emacs 24.3
- I’ve added the marmalade repository to my Emacs package list.
- I’ve got python-virtualenv installed.
- My Emacs is set up to use python-mode whenever I open a .py file.
Step one: install jedi.el
- Launch Emacs (if for some bizarre reason it’s ever not running on your system) and do “M-x package-list-packages”
- Search for, and install, the “jedi” package. If you don’t see it, double check that you’ve correctly set up your package archives with marmalade.
Step two: configure your .emacs
- Add, at a minimum, these two lines to your .emacs file:
(autoload 'jedi:setup "jedi" nil t) (add-hook 'python-mode-hook 'jedi:setup)
- If you want the default keyboard shortcuts, add this line:
(setq jedi:setup-keys t)
- If you want it to complete on the “.” (so that, when you type some object or module name and a “.” it gives you all the possible attributes/submodules/methods/etc), add this line:
(setq jedi:complete-on-dot t)
- Save your .emacs file. Exit Emacs.
- No, really, exit Emacs. Just doing “M-x eval-buffer” doesn’t cut it for some reason.
- I know, I know, but you can exit Emacs for just a minute or two. Maybe have a second computer nearby that you can run Emacs on while you do this.
Step three: configure jedi’s virtualenv
One cool thing about the way jedi.el works is that it creates its own Python virtualenv to operate in, so that you don’t have to go to the trouble of installing jedi in your main system environment. This is nice since there aren’t packages in most distro’s repositories for jedi (yet). Package.el doesn’t set this up for you, though, so you have to do this:
- Browse to the folder containing jedi.el. It’s probably in ~/.emacs.d/elpa/jedi-(someversionnumber). If not, it’s wherever package.el downloads packages on your system.
- Note there’s a “Makefile” in this directory.
- Run “make requirements”. This will create a virtual environment in the plugin’s folder with jedi and all its dependencies.
Step four: Check.it.out.
- Relaunch Emacs. There, that wasn’t so bad was it?
- Open a new file with a .py extension, so as to trigger Python mode.
- Try importing some standard module like “os”. You should right away see some auto completion as you type.
- Try typing “os.” and notice you get a pop-up with the contents of the “os” module.
- Now type “os.path”. Put your cursor somewhere on the word “path” and do “M-x jedi:show-doc” (or, if you loaded the default keys, C-c d). You should have a buffer pop up with the documentation for os.path.
Pretty awesome stuff, right???
Things I’m still working through
So far the only issue I’m having with Jedi is that it wants to complete using Python2 on my Ubuntu system (which makes sense, as it’s the default Python on 13.04). On the Arch system, where Python3 is default, it completes for Python3. It’d be nice if I could figure out a simple way to switch this easily, since I often need to work in both environments.
Otherwise, I’m pretty pleased with Jedi so far. Makes we want to write more code!