Pattern for foo tool <-> API <-> shell|GUI
Steven Bethard
steven.bethard at gmail.com
Sun Mar 25 10:44:34 EDT 2007
Anastasios Hatzis wrote:
> I'm working on a tool which is totally command-line based and consisting of
> multiple scripts. The user can execute a Python script in the shell, this
> script does some basic verification before delegating a call into my tool's
> package and depending on some arguments and options provided in the
> command-line, e.g.
> $python generate.py myproject --force --verbose
> the tool processes whatever necessary. There are multiple command handlers
> available in this package which are responsible for different tasks and
> depending of the script that has been executed one or more of these command
> handlers are fired to do their work ;)
Side note: you might find argparse (http://argparse.python-hosting.com/)
makes this a bit easier if you have positional arguments or sub-commands::
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('name')
>>> parser.add_argument('--force', action='store_true')
>>> parser.add_argument('--verbose', action='store_true')
>>> parser.parse_args(['my_project', '--force', '--verbose'])
Namespace(force=True, name='my_project', verbose=True)
>>> parser = argparse.ArgumentParser()
>>> subparsers = parser.add_subparsers()
>>> cmd1_parser = subparsers.add_parser('cmd1')
>>> cmd1_parser.add_argument('--foo')
>>> cmd2_parser = subparsers.add_parser('cmd2')
>>> cmd2_parser.add_argument('bar')
>>> parser.parse_args(['cmd1', '--foo', 'X'])
Namespace(foo='X')
>>> parser.parse_args(['cmd2', 'Y'])
Namespace(bar='Y')
> And I don't think that this is very trivial (at least not for my programming
> skill level). In the given example "generate.py" (above) the following
> scenario is pretty likely:
>
> (1) User works with UML tool and clicks in some dialog a "generate" button
> (2) UML tool triggers this event an calls a magic generate() method of my tool
> (via the API I provide for this purpose), like my generate.py script would do
> same way
> (3) Somewhen with-in this generate process my tool may need to get some
> information from the user in order to continue (it is in the nature of the
> features that I can't avoid this need of interaction in any case).
So you're imagining an API something like::
def generate(name,
force=False,
verbose=False,
handler=command_line_handler):
...
choice = handler.prompt_user(question_text, user_choices)
...
where the command-line handler might look something like::
class CommandLineHandler(object):
...
def prompt_user(self, question_text, user_choices):
while True:
choice = raw_input(question_text)
if choice in user_choices:
return choice
print 'invalid choice, choose from %s' % choices
and the GUI client would implement the equivalent thing with dialogs?
That seems basically reasonable to me, though you should be clear in the
documentation of generate() -- and any other methods that accept handler
objects -- exactly what methods the handler must provide.
You also may find that "prompt_user" is a bit too generic -- e.g. a file
chooser dialog looks a lot different from a color chooser dialog -- so
you may need to split this up into "prompt_user_file",
"prompt_user_color", etc. so that handler's don't have to introspect the
question text to know what to do...
STeVe
More information about the Python-list
mailing list