Separate IPython profiles for interactive use

Posted by Simon Walker on Sun 18 January 2015

I used to have two simple shell aliases for IPython:

alias ipy=ipython
alias pylab='ipython --pylab'

These were separated for a couple of reasons:

The pylab mode of IPython was deprecated, for good reason. It "infects" the global namespace with all matplotlib and numpy functions. It breaks two entries in the famous "Zen of Python":

  • Explicit is better than implicit.
  • Namespaces are one honking great idea -- let's do more of those!

From a practicality perspective it also is much slower to start up. This is annoying when I quickly want to plot something.

I then remembered the IPython profile functionality. A separate profile, and hence separate configuration and startup procedure for each profile. I customized my configuration for each profile in basically the same way: I turned off the startup banner - I've seen it enough times now! - and configured the log format. In the "pylab" form I set c.InteractiveShellApp.pylab = 'auto' to enable the interactive plotting, with a backend chosen for me, and set c.TerminalInteractiveShell.autocall = 2. This last one may be a bit controversial, so I'll explain a bit further.

autocall

This setting (sometimes) removes the need for parentheses when running python code. For example:

def stuff(value):
    print(value + 5)

stuff(5)   # Normal python
stuff 5    # Valid with autocall = 1 or 2, see below

def more_stuff():
    print('Hi there')

more_stuff()   # Normal python
more_stuff     # Exception in all but autocall = 2

This setting has three options: 0 to disable the feature, 1 to enable it in a "smart" sense, and 2 where it's enabled always. The main difference between 1 and 2 is when a "bare" function is called, e.g. more_stuff in the example above, without parentheses. With autocall = 2 the function is called rather than merely returned.

Starting up with seaborn

I am a fan of the seaborn visualisation package, for the styles and extra features. In the pylab profile I set this up to automatically import seaborn and silently fail if it's not found. This code can be found in this file. I'll explain it here.

The code:

from __future__ import print_function

try:
    print('Loading seaborn...', end=' ')
    import seaborn as sns
except ImportError:
    print('Cannot load seaborn')
else:
    print('Done')

I start by importing print_function from __future__ to ensure python 2/3 compatibility. Next in a try/except block I try importing seaborn, under the sns prefix which I'm accustomed to. Should an import error occur (such as I have not got the package installed in the current conda environment) I tell the user. The print functions are called such with ... end='') to ensure the status message is all on one line, purely for aesthetics.

Current configuration

My current configuration can be read for