Emacs and Python

Tuesday October 7, 2014

A short talk at the DC Python meetup group, introducing Emacs through demonstration of fun and useful features. Original source and notes are up on github. Thanks to Eddie Welker for hosting the event and putting up video!

This is a screen you see when you start up Emacs. There's a tutorial and a manual and it's all very user-friendly.

M-x tetris

Tetris is included in base Emacs. But Emacs is also a text editor. Editing text is important.

So why Emacs?

C-x C-c

In addition to editing text, you probably need or want to send computers commands via text. It may be convenient or necessary to be productive in a pure text environment. So it is a desirable characteristic of a text editor that it be as capable in text mode as graphical mode. There are two serious contenders: Vim and Emacs.

There are further reasons to prefer a keyboard-based interface, but at a minimum we need an editor that can be used over ssh.

got bash
alias got
grep -o '\w*grep' ~/.bashrc | sort | uniq -c

I use bash, and I have it customized a little bit, which makes it nicer.

If you're competent in a shell like bash, you know some keyboard shortcuts. Defaults like Ctrl + a (C-a) to go to the beginning of a line are very useful. These are Emacs keybindings. They're the readline defaults. They're ubiquitous.

Keyboard shortcuts that work in bash, Emacs, and many other places:

Emacs does require effort to learn, but you already know a lot of its keybindings, or should, and they can be used in many places.

fg

If you want, the many places you use Emacs can be all inside Emacs. Here I'm just finishing an email.

C-c C-c
C-x C-c
got emacs

Emacs can run client-server. I use this way of running Emacs to get a lot of the benefits that you get with screen or tmux. I don't lose anything if a network connection dies, for example. It's also faster to start up the Emacs client.

e
M-x shell
got emacs

You can also run a shell inside Emacs, and it works much the same as outside. A contrast with tmux is that you don't have to switch modes to access the scrollback. For example, in an Emacs shell, M-r will search the command history, and C-r will search back through the buffer (as it does throughout Emacs).

eg &
C-x b shell
got emacs

I can start a graphical Emacs from here in the shell inside console Emacs, and you can see that now both clients are connected to the same Emacs daemon.

Notice how similar the interface is whether at a console or in a GUI window.

C-x C-f hello.el
C-M-f
C-x C-e

Emacs achieves its extensibility by essentially being a Lisp interpreter. (It's Emacs Lisp.) I'm just showing a tiny cosmetic interface tweak here, but all the packages and fun features I use work because Emacs is a programmable environment.

A related point is that base Emacs includes a lot, and you can manage in base Emacs, but you probably won't want to. You can think of Emacs as a kit for making an editor. The advantage is that you can make any sort of editor you want. The disadvantage is that there's some assembly required.

Emacs gets so much better with customized settings that there are several whole projects which are just collections of Emacs configuration. Prelude is probably the biggest; Graphene is another one. I tried Prelude and eventually got tired of turning things off more than I was turning them on, but things like Prelude are great for finding out about functionality, and could be a great way to get into Emacs. There are also blogs that post about Emacs, and of course everybody has their configuration files on github too.

Let's take a look at editing with Emacs, using a DC Python project as an example. We notice that there are some problems at the end of the README, so maybe we can fix it up a little.

git clone git@github.com:ajschumacher/dcpython-django.git django

To work on the project, we'll clone my fork of the repo and open up the README.rst. It opens up in reStructuredText mode.

Before we get to the numbered lists, we notice some whitespace problems: tabs and trailing whitespace.

So we make a branch to do some work on. (The git-in-Emacs interface is magit.) Then we can mark-whole-buffer and untabify. Tabs are changed to spaces. Then delete-trailing-whitespace. Good.

We can make a quick commit with this change very quickly.

Down at the bottom, it looks like markdown in reStructuredText. We need to fix the back-ticks and the numbered lists.

In reStructuredText, you need double back-ticks. Select the region, query-replace with M-%, enter "`" and "``", and if feeling confident, use "!" to replace all.

Oops, one command isn't back-ticked that should be. Nice chance to show expand-region and wrap-region. All good - commit.

The numbered lists aren't hard to fix in this case, but let's show some more features. We'll make a macro, starting it with C-x (. Then C-s for 1 to go to the start of a numbering region. C-a for the start of the line. Set mark with C-<space>. Do a regular expression search for a blank line ("^$") with C-M-s. Previous line with C-p. Number the lines with a rectangle command, C-x r N. Next line to clear the numbering, and finish the macro with C-x ). Then we can run it again with C-x e, and again with just e.

This isn't really done, so let's go back to the first "1." and select it, then invoke a multiple-cursors command to select them all and clean up. Presto!

Commit, push, pull request!

Now to Python. I use elpy (on github) with flycheck and jedi. Also IPython. And YASnippet. Etc. I'll demo some things.

C-x C-f tset/tset.py

Using a toy Python project of mine, we can see how flycheck will tell you when you're violating PEP 8 ("E302 expected 2 blank lines, found 1", etc.). If I add in import os without using it, that'll get shown too. And it catches syntax errors like x= as well.

(point after "at")
C-c C-e

One fun feature of elpy is that it can use jedi to find symbols that are semantically the same and edit them at the same time. Neat!

C-c C-t

It's very convenient to run tests.

C-c C-z
np <shift>-<tab>
np.random. <tab>

It's easy to run interactive python. I'll show snippets here too. And you get auto-completion. Nice.

C-x o
M-<
C-o C-o C-o
print 'hello'
C-<space> C-a
C-c C-c

It's easy to send code from the editor to the REPL. It was a little weird to me at first that it didn't echo in the REPL, but it's generally fine this way. If you want you can copy and paste explicitly, or make a macro to do the same.

import os
os
C-c C-d
.

In the editor, you can get docstring help with C-c C-d, and there's also the popular drop-down method of showing available things.

fork
C-c C-d

And of course help on functions themselves.

C-x 1
C-x C-j
(navigate to scikit-learn/sklearn/tests/test_naive_bayes.py)
M-1
M-g M-g 332 (point on 'MultinomialNB')
M-. (until 'object')
M-* (back)

To demonstrate navigating some more serious hierarchies, I've got a clone of the scikit-learn source. I'll go to the Naive Bayes tests using dired, a standard mode. There are a lot of lines here. I have a custom binding to show and hide line numbers. Let's go to line 332, where MultinomialNB is getting tested. If I put point on that symbol, elpy let's me use M-. to jump to the definition. I can go several definitions up, and then use M-* to jump back to where I started. This is pretty neat.

nyan-mode
nyan-start-animation

I started with Tetris, and I want to finish with something fun too. If you want to, you can install and use nyan-mode. Totally up to you.

C-x b *twittering-edit*

And here's that tweet I promised earlier.

Thank you!


All my configuration is in my .emacs.d. It's subject to change. This demo is as of 7716de4, with some keystrokes shown above as they usually are rather than how I have them bound.


For even more completeness, here are other ways of doing Python in Emacs:


Thanks to local Emacs users Jenna Colazzi and Rami Chowdhurry, and to the broader Emacs community who are super friendly and produce excellent resources: