A minimal yet productive Python shell

I love IPython, I really do. However, the software has grown somewhat massively since its very first release and the list of dependencies has become really big.

I've been looking for ways to emulate the same behaviour as IPython without the overloaded environment that must come with it. I particularly hate the fact that the IPython shell takes 2 to 3 seconds to come through even on blazing fast hardware. One of its killer features is to complete code: you load a module, type its name, then a . (dot) and then <TAB> and it automatically complete all functions available within the said module. Neat!

After some research, I've finally put together a nice and clean solution to emulate the same yet basic features, especially the complete one. How? .pythonrc.py!

Well actually the magic occurs thanks to the PYTHONSTARTUP environment variable. If it points to a readable Python file. the Python interpreter reads it before spawning the shell.

In my case, I created the file in my home directory i.e. /home/patrice/.pythonrc.py. There's not much to it as it is plain Python code.

Here's mine:

# $id pythonrc.py 2017-12-11 22:28:57 patrice

# Add auto-completion and a stored history file of commands to your Python
# interactive interpreter. Requires Python 2.0+, readline.
import atexit
import sys
import os

# Let's try first to import readline.
try:
    import readline
except ImportError:
    # Abort now!
    print("Module 'readline' not available!")
else:
    # libedit is a bit messed up
    # and doesn't allow tabs to complete.
    import rlcompleter
    if 'libedit' in readline.__doc__:
        # Bind Ctrl^i to history completion.
        # Bind Ctlr^r to history search.
        readline.parse_and_bind('bind ^I rl_complete')
        readline.parse_and_bind('bind ^R em-inc-search-prev')
    else:
        # Bind Tab to tab completion.
        readline.parse_and_bind('tab: complete')

# Save history to ~/.python_history file.
histpath = os.path.expanduser('~/.python_history')

# Define a function to write history out to file.
def save_history(histpath=histpath):
    readline.write_history_file(histpath)

# Read history file upon shell start.
if os.path.exists(histpath):
    readline.read_history_file(histpath)

# And call `save_history` when exiting.
atexit.register(save_history)

# Anything not deleted (sys and os) will remain in the interpreter session
del atexit, rlcompleter, save_history, histpath

# Modules we always want to have imported in the current session are therefor:
# os, sys, glob and readline

It is no secret that the Python shell relies heavily on GNU readline to interpret commands typed into it. We're just covering some basics here as I want the shell to stay as minimal as possible. Have a look at the documentation if you wish to configure more keystrokes.