Conspicuous Compiler
Conspicuous Compiler

Reputation: 6469

How can I add a command to the Python interactive shell?

I'm trying to save myself just a few keystrokes for a command I type fairly regularly in Python.

In my python startup script, I define a function called load which is similar to import, but adds some functionality. It takes a single string:

def load(s):
  # Do some stuff
  return something

In order to call this function I have to type

>>> load('something')

I would rather be able to simply type:

>>> load something

I am running Python with readline support, so I know there exists some programmability there, but I don't know if this sort of thing is possible using it.

I attempted to get around this by using the InteractivConsole and creating an instance of it in my startup file, like so:

import code, re, traceback

class LoadingInteractiveConsole(code.InteractiveConsole):
  def raw_input(self, prompt = ""):
    s = raw_input(prompt)
    match = re.match('^load\s+(.+)', s)
    if match:
      module = match.group(1)
      try:
        load(module)
        print "Loaded " + module
      except ImportError:
        traceback.print_exc()
      return ''
    else:
      return s

console = LoadingInteractiveConsole()
console.interact("")

This works with the caveat that I have to hit Ctrl-D twice to exit the python interpreter: once to get out of my custom console, once to get out of the real one.

Is there a way to do this without writing a custom C program and embedding the interpreter into it?

Edit

Out of channel, I had the suggestion of appending this to the end of my startup file:

import sys
sys.exit()

It works well enough, but I'm still interested in alternative solutions.

Upvotes: 2

Views: 2837

Answers (4)

Markus Hirsimäki
Markus Hirsimäki

Reputation: 695

Here is an example of adding custom commands to the interactive interpreter

import sys
import os
import pprint

def SyntaxErrorToCommand(exc_type, exc_value, exc_traceback):
    if (command := getattr(exc_value, "text", "").strip("\n")) == "!pwd":
        print(os.getcwd())
    elif command == "!ls":
        print("\n".join(os.listdir(os.getcwd())))
    elif command == "!pp":
        dphook = lambda value: pprint.pprint(value) if value is not None else None
        sys.displayhook = sys.__displayhook__ if sys.displayhook == dphook else dphook
    else:
        sys.__excepthook__(exc_type, exc_value, exc_traceback)

sys.excepthook = SyntaxErrorToCommand

After this you can use !pp to toggle prettyprinting or !pwd to print current working directory

>>> !pwd
file1.txt
file2.txt
myimage.png

If you add the code to sitecustomize such as /usr/lib/python3.13/sitecustomize.py it will be loaded automatically in all sessions and virtual environments.

Upvotes: 0

Conspicuous Compiler
Conspicuous Compiler

Reputation: 6469

Hate to answer my own question, but there hasn't been an answer that works for all the versions of Python I use. Aside from the solution I posted in my question edit (which is what I'm now using), here's another:

Edit .bashrc to contain the following lines:

alias python3='python3 ~/py/shellreplace.py'
alias python='python ~/py/shellreplace.py'
alias python27='python27 ~/py/shellreplace.py'

Then simply move all of the LoadingInteractiveConsole code into the file ~/py/shellreplace.py Once the script finishes executing, python will cease executing, and the improved interactive session will be seamless.

Upvotes: 0

mmmmmm
mmmmmm

Reputation: 32616

You could try ipython - which gives a python shell which does allow many things including automatic parentheses which gives you the function call as you requested.

Upvotes: 7

mcpeterson
mcpeterson

Reputation: 5134

I think you want the cmd module.

See a tutorial here: http://wiki.python.org/moin/CmdModule

Upvotes: 0

Related Questions