I’ve always wanted to use an interactive python instance as a calculator for back-of-the-envelope calculations that are to small or specific to warrant a spreadsheet. Simply typing python into a terminal didn’t work very well, however:

  • The python interactive shell is very rudimentary, offering no syntax highlighting or auto complete. Multi-lkne editing is also a very clunky experience.
  • IPhython solves this, but has pretty long startup times.
  • Startup times get even worse if your work requires pandas, numpy, matplotlib & friends. Import times cause some friction, as does typing out imports.
  • It would be nice to have a repository of utility functions like “plot this 2d function” or “import some of my personal data into a pandas DataFrame”.

My solution is to have one IPython instance created at startup inside a tmux session, with a custom init scrip that loads common packages and a custom utils package, taking advantage of the autoreload extension. To stop me from accidentally exiting the session, Ctrl+D is bound to tmux detach inside the session.

This can be very easily achieved with some bash magyxs. The first component is a script that sets up the tmux session:

# create_session.py

tmux new -ds calc ipython -i ~/.bin/scripts/ipython_calc/defaults.py
tmux bind-key -n C-d detach

Passing -d means that the script won’t try attaching to the tmux session. -s specifies calc as the session name, and ipython -i ~/.bin/scripts/ipython_calc/defaults.py the command that is run inside the session. This starts the ipython interactive shell after running defaults.py, which sets up imports:

# defaults.py

import importlib
import math
import matplotlib.pyplot as plt
import numpy as np
import os
import pandas as pd
import sys

from IPython.core import getipython
getipython.get_ipython().run_line_magic("reload_ext", "autoreload")
getipython.get_ipython().run_line_magic("autoreload", "2")

# My own module with shorthands. Installed with
# > pip install -e ~/develop/ipython_utils/
import ipython_utils as iu

To open the calculator, I use a script which creates the calculator session if it doesn’t exist already, and attaches to it in a new terminal window:

# show_calc.py

tmux ls | grep calc || ~/.bin/scripts/ipython_calc/create_session.sh

alacritty -e tmux at -t calc

The final ingredient is to bind this script to a keybinding, for which I use i3:

# i3 configuration file

...
mode "launch" {
    ...
    bindsym c exec --no-startup-id "~/.bin/scripts/ipython_calc/show_calc.sh", mode "default"
    ...

    # back to normal: Enter or Escape or $mod+m
    bindsym Escape mode "default"
    bindsym $mod+m mode "default"
}
...

And that’s it! Pressing Win+m, c opens up a new alacritty window with IPython. The first time after a reboot will take a moment, consecutive times will be instantaneous. I actually run create_session.sh on startup to get rid of that first lag too, but that’s a matter of preference.

A side-benefit that I didn’t anticipate is that history is always consistent and preserved, so it’s relatively easy to go back to previous calculations.