Welcome, guest | Sign In | My Account | Store | Cart

This recipe shows how to use the Cmd object to create a simple OS neutral console. It shows how to use many of the hooks provided by the Cmd object and also documents some errors and omissions in the official cmd documentation,

Python, 91 lines
 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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
## console.py
## Author:   James Thiele
## Date:     27 April 2004
## Version:  1.0
## Location: http://www.eskimo.com/~jet/python/examples/cmd/
## Copyright (c) 2004, James Thiele

import os
import cmd
import readline

class Console(cmd.Cmd):

    def __init__(self):
        cmd.Cmd.__init__(self)
        self.prompt = "=>> "
        self.intro  = "Welcome to console!"  ## defaults to None

    ## Command definitions ##
    def do_hist(self, args):
        """Print a list of commands that have been entered"""
        print self._hist

    def do_exit(self, args):
        """Exits from the console"""
        return -1

    ## Command definitions to support Cmd object functionality ##
    def do_EOF(self, args):
        """Exit on system end of file character"""
        return self.do_exit(args)

    def do_shell(self, args):
        """Pass command to a system shell when line begins with '!'"""
        os.system(args)

    def do_help(self, args):
        """Get help on commands
           'help' or '?' with no arguments prints a list of commands for which help is available
           'help <command>' or '? <command>' gives help on <command>
        """
        ## The only reason to define this method is for the help text in the doc string
        cmd.Cmd.do_help(self, args)

    ## Override methods in Cmd object ##
    def preloop(self):
        """Initialization before prompting user for commands.
           Despite the claims in the Cmd documentaion, Cmd.preloop() is not a stub.
        """
        cmd.Cmd.preloop(self)   ## sets up command completion
        self._hist    = []      ## No history yet
        self._locals  = {}      ## Initialize execution namespace for user
        self._globals = {}

    def postloop(self):
        """Take care of any unfinished business.
           Despite the claims in the Cmd documentaion, Cmd.postloop() is not a stub.
        """
        cmd.Cmd.postloop(self)   ## Clean up command completion
        print "Exiting..."

    def precmd(self, line):
        """ This method is called after the line has been input but before
            it has been interpreted. If you want to modifdy the input line
            before execution (for example, variable substitution) do it here.
        """
        self._hist += [ line.strip() ]
        return line

    def postcmd(self, stop, line):
        """If you want to stop the console, return something that evaluates to true.
           If you want to do some post command processing, do it here.
        """
        return stop

    def emptyline(self):    
        """Do nothing on empty input line"""
        pass

    def default(self, line):       
        """Called on an input line when the command prefix is not recognized.
           In that case we execute the line as Python code.
        """
        try:
            exec(line) in self._locals, self._globals
        except Exception, e:
            print e.__class__, ":", e

if __name__ == '__main__':
        console = Console()
        console . cmdloop() 

This recipe was inspired by Mike Foord's Windows Console recipe. It is similar but not OS dependent by using the Cmd object in the standard cmd module. This console differs from the Windows Console in that it escapes to the OS specific CLI/shell by preceding the command with '!'. It also provides a 'help' facility and supplies command completion when you hit the 'tab' key. In addition you can use command line editing and history keys, which Cmd gives you for free.

In it's simplest form, you use Cmd by subclassing it and adding commands by defining methods with names of the form 'do_xxx()' where 'xxx' is the name of the command you wish to add. In this example the new user commands are 'hist' (history) and 'exit'. 'do_shell()' is needed if you want '!' escapes and 'do_EOF()' if the end of file character needs to be caught.

The documentation for the Cmd object doesn't mention that 'do_help()' will print the doc string of 'do_xxx()' if it can't find 'help_xxx()'. I added a custom 'do_help()' so the user could type 'help help'.

The documentation for the Cmd object claims that 'preloop()' and 'postloop()' are stubs. They aren't. Be very careful when overriding these methods.

4 comments

Dave Moor 17 years, 7 months ago  # | flag

Readline. I am using python 2.3.2, when I run the script I get an error about failing to import readline. Is this a third party lib and is there a windows version of it?

Dave

James Thiele (author) 17 years, 7 months ago  # | flag
James Thiele (author) 17 years, 7 months ago  # | flag

Console without readline. If you don't have readline you can make the following 2 changes to console.py:

Delete the line:

import readline

After the line:

cmd.Cmd.__init__(self)

Add this line:

self.completekey = None
pythonscript 8 years, 8 months ago  # | flag

In Python 3, the preloop and postloop methods are just empty methods.

http://hg.python.org/cpython/file/3.3/Lib/cmd.py