ActiveState Code

Recipe 438813: An editable buffer for the Python shell (similar to '\e' on sql prompts)


I hacked up this useful wrapper around the python command line shell to allow editing of the last typed in lines of code in an external editor.

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# Python Console with an editable buffer.
import os
from tempfile import mkstemp
from code import InteractiveConsole

EDITOR = os.environ.get('EDITOR', 'vim')
EDIT_CMD = '\e'

class EditableBufferInteractiveConsole(InteractiveConsole):
    def __init__(self, *args):
        self.last_buffer = [] # This holds the last executed statement
        InteractiveConsole.__init__(self, *args)

    def runsource(self, source, *args):
        self.last_buffer = [ source ]
        return InteractiveConsole.runsource(self, source, *args)

    def raw_input(self, *args):
        line = InteractiveConsole.raw_input(self, *args)
        if line == EDIT_CMD:
            fd, tmpfl = mkstemp()
            os.write(fd, '\n'.join(self.last_buffer))
            os.close(fd)
            os.system('%s %s' % (EDITOR, tmpfl))
            line = open(tmpfl).read()
            os.unlink(tmpfl)
            tmpfl = ''
        return line

c = EditableBufferInteractiveConsole()
c.write("""
Starting the editable interactive console.
Edit command is '%s'.

""" % EDIT_CMD)
c.interact(banner='')

Discussion

When working in the python command shell, I often end up writing more than 10+ lines of indented code before making a stupid typo. This got irritating enough for me to do something about it. So, here's an 'Interactive Console with an editable buffer'. Hope that people find it useful. To load it up automatically put it in your python startup file [ http://docs.python.org/tut/node4.html#SECTION004240000000000000000 ].

Notes: a) This code works with python 2.3 only due to it's use of tempfile.msktemp(). Maybe somebody could modify it to work with other python versions. b) The editor is selected using the EDITOR environment variable and defaults to 'vim' if it has not been defined. c) The command to invoke the editor is '\e' by default. It may be customized by changing the 'EDIT_CMD' variable.

Comments

  1. 1. At 9:08 a.m. on 5 aug 2005, Bill Mill said:

    Use ipython. Get ipython at http://ipython.scipy.org .

  2. 2. At 1:59 p.m. on 5 jan 2006, Karl Waedt said:

    Editing multiple lines. Works fine, even with gvim.exe. However, for editing multiple lines like:

    print 1
    def f( x ):
        return x + 2
    

    a small extension is required before 'return line'. Only the last line entered via the editor is returned by raw_input(). The other lines are handed over to InteractiveConsole.push(), e.g.

    def raw_input(self, *args):
        line = InteractiveConsole.raw_input(self, *args)
        if line == EDIT_CMD:
            ...
            lines = line.split( '\n' )
            for i in range(len(lines) - 1): self.push( lines[i] )
            line = lines[-1]
        return line
    
  3. 3. At 3:19 p.m. on 23 may 2007, Nathaniel Whiteinge said:

    Python file extension. Awesome tip! This brings the standard Python shell to 90% of IPython's functionality (for me).

    If you change the following line, the temporary file will have a .py file extension which might be helpful::

    fd, tmpfl = mkstemp('.py')
    
  4. 4. At 4:08 p.m. on 15 may 2008, Nathaniel Whiteinge said:

    Make namespace available to the sub-shell. If you add kwargs to __init__ you can easily pass the local namespace to the InteractiveConsole.

    def __init__(self, *args, **kwargs):
        ...
        InteractiveConsole.__init__(self, *args, **kwargs)
    

    then

    c = EditableBufferInteractiveConsole(locals=locals())
    

Sign in to comment