I'm trying to build a small interactive shell in Python using the cmd
module. Is there an easy way to allow for multi-word commands?
For example, it's easy to process the hello
command
class FooShell(Cmd):
def do_hello(self, args):
print("Hi")
But what if I wanted something more complicated. Let's say I'm trying to implement an SQL shell and want to write show tables
. The show
command can take multiple targets such as show track_counts
or show bonjour
. If I wanted to process something like this in the cmd module, it looks like I would have to write the following:
class FooShell(Cmd):
def do_show(self, line):
args = line.strip().split(" ")
if args == []:
print("Error: show command requires arguments")
else:
if args[0] == "tables":
pass # logic here
elif args[0] == "bonjour":
pass # logic here
elif args[0] == "track_counts":
pass # logic here
else:
print("{} is not a valid target for the 'show' command".format(args[0]))
print("Valid targets are tables, bonjour, track_counts")
There are a few problems with this approach:
- I have to write the error message myself. As I add additional commands in the if statements, I have to manually update the list of valid commands.
- There is no tab-completion here after the user types
show
- This is just really ugly.
Another way of writing the above would be like this:
class FooShell(Cmd):
def do_show_tables(self, args):
pass
def do_show_bonjour(self, args):
pass
def do_show_track_counts(self, args):
pass
def do_show(self, line):
args = line.strip().split(" ")
if args == []:
print("Error: show command requires arguments")
else:
handlers = {
"tables": self.do_show_tables,
"bonjour": self.do_show_bonjour,
"track_counts": self.do_show_track_counts
}
handler = handlers.get(args[0], None)
if handler:
handler(args[1:])
else:
print("{} is not a valid target for the 'show' command".format(args[0]))
targets = ", ".join([key for key in handlers])
print("Valid targets are: {}".format(targets))
But this still does not give tab completion after the 'show' command. Additionally, it now feels like I'm basically rewriting the core functionality of the cmd
module.
Is there a simpler way to do this? Should I be using another module instead of cmd
?
EDIT: to be clear, I am not actually writing an SQL shell, just using that as an example of how I want multi-word commands to be parsed.