Switching between cmd.CMD instances

J

Josh English

I have a program with several cmd.Cmd instances. I am trying to figure out what the best way to organize them should be.

I've got my BossCmd, SubmissionCmd, and StoryCmd objects.

The BossCmd object can start either of the other two, and this module allows the user switch back and forth between them. Exiting either of the sub-command objects returns back to the BossCmd.

I have defined both a do_done and do_exit method on the sub-commands.

Is it possible to flag BossCmd so when either of the other two process do_exit, the BossCmd will also exit?

Josh
 
J

Jason Swails

I have a program with several cmd.Cmd instances. I am trying to figure out
what the best way to organize them should be.

I've got my BossCmd, SubmissionCmd, and StoryCmd objects.

The BossCmd object can start either of the other two, and this module
allows the user switch back and forth between them. Exiting either of the
sub-command objects returns back to the BossCmd.

I have defined both a do_done and do_exit method on the sub-commands.

Is it possible to flag BossCmd so when either of the other two process
do_exit, the BossCmd will also exit?

I have an app that also has a number of cmd.Cmd subclasses to implement
different interpreter layers. I haven't needed to implement what you're
talking about here (exiting one interpreter just drops you down to a
lower-level interpreter). However, it's definitely possible. You can have
your SubmissionCmd and StoryCmd take a "master" (BossCmd) object in its
__init__ method and store the BossCmd as an instance attribute.
From there, you can implement a method interface in which the child Cmd
subclasses can call to indicate to BossCmd that do_exit has been called and
it should quit after the child's cmdloop returns. So something like this:

class SubmissionCmd(cmd.Cmd):
# your stuff
def __init__(self, master):
cmd.Cmd.__init__(self, *your_args)
self.master = master

def do_exit(self, line):
self.master.child_has_exited()

class BossCmd(cmd.Cmd):
# your stuff
def child_has_exited(self):
self.exit_on_return = True # this should be set False in __init__

def do_submit(self, line):
subcmd = SubmissionCmd(self)
subcmd.cmdloop()
if self.exit_on_return: return True

Untested and incomplete, but you get the idea.

HTH,
Jason
 
J

Josh English

From there, you can implement a method interface in which the child Cmd subclasses can call to indicate to BossCmd that do_exit has been called and it should quit after the child's cmdloop returns.  So something like this:

Hey, yeah. My previous responses didn't show up, or are delayed, or something.

Thank you, yes. This advice helped and rooting around the source code I realized that the Cmd.cmdqueue attribute is the easy way out:

import cmd

class BossCmd(cmd.Cmd):
def __init__(self):
cmd.Cmd.__init__(self)
self.prompt = 'Boss>'
self.exit_called_from_minion = False
self.minions = {}

def add_minion(self, name, cmder):
self.minions[name] = cmder

def do_exit(self, line):
return True

def postloop(self):
print "I mean it. I'm done"

def postcmd(self, stop, line):
# check if minion called for exit
if self.exit_called_from_minion:
stop = True
return stop

def do_submission(self, line):
if line:
self.minions['submission'].onecmd(line)
else:
self.minions['submission'].cmdloop()

def do_story(self, line):
if line:
self.minions['story'].onecmd(line)
else:
self.minions['story'].cmdloop()

class SubmissionCmd(cmd.Cmd):
def __init__(self, master = None):
cmd.Cmd.__init__(self)
self.prompt = 'Submission>'
self.master = master
if self.master:
self.master.add_minion('submission', self)

def do_done(self, line):
return True

def do_exit(self, line):
self.master.exit_called_from_minion = True
return True

def do_story(self, line):
if line:
self.master.minions['story'].onecmd(line)
else:
self.master.cmdqueue.append('story {}'.format(line))
return True


class StoryCmd(cmd.Cmd):
def __init__(self, master=None):
cmd.Cmd.__init__(self)
self.prompt = 'Story>'
self.master=master
if self.master:
self.master.add_minion('story', self)

def do_done(self, line):
return True

def do_exit(self, line):
elf.master.exit_called_from_minion = True
return True

def do_submission(self, line):
if line:
self.master.minions['submission'].onecmd(line)
else:
self.master.cmdqueue.append('submission {}'.format(line))
return True

Boss = BossCmd()
Sub = SubmissionCmd(Boss)
Story = StoryCmd(Boss)

Boss.cmdloop()
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,736
Latest member
zacharyharris

Latest Threads

Top