Pattern for foo tool <-> API <-> shell|GUI

Anastasios Hatzis ah at hatzis.de
Sat Mar 24 12:31:36 EDT 2007


I'm looking for a pattern where different client implementations can use the 
same commands of some fictive tool ("foo") by accessing some kind of API. 
Actually I have the need for such pattern for my own tool 
(http://openswarm.sourceforge.net). I already started restructuring my code 
to separate the actual command implementations from the command-line scripts 
(which is optparser-based now) and have some ideas how to proceed. But 
probably there is already a good pattern used for Python-based tools.

In the case that some of you are interested into this topic and my recent 
thoughts, you may want to have a look at the description below. Any comments 
are very much appreciated. Hopefully this list is a good place for discussing 
a pattern, otherwise I would be okay to move this to another place. Thank 
you.

Here we go:
The tool package itself provides several commands, although not important for 
the pattern itself, here some examples: modifying user-specific preferences, 
creating and changing project settings files, project-related 
code-generation, or combinations of such commands ... later also commands for 
transformation between several XML formats etc. The classes which implement 
these commands are currently in multiple modules, each having a class named
CmdHandler.

I have some Python scripts (each having a ScriptHandler classes), for use via 
command-line. Each ScriptHandler class is responsible to add all related 
command-line options and process those provided by the user (based on 
optparse library from Python standard lib). The script then calls the 
corresponding command and provide the verified options as parameters.

Due to the nature of the tool under specific conditions the following results 
may come during command execution:
* successful execution, no interaction
* critical error, execution cancelled
* user interaction needed (e.g. prompt user to approve replace existing 
directory (yes/no), prompt user to provide an alternative option)

Command-line interactions work simply with raw_input().

So far this works. Nevertheless, there are some other aspects that could be 
improved, but this is another topic: The tool uses custom exceptions (e.g. 
for critical errors) and logging features (based on logging from Python 
standard lib). Currently no automated tests, but I have to add.

For the next step I plan to support not only my own command-line scripts, but 
also a GUI to access the commands, as well as 3rd-party products (themselves 
command-line scripts or GUIs, such as foo plugins for any 3rd-party-tools). As 
far as I see, these clients need to implement a handler that:
(1) Collecting all required parameters and optional parameters from a user
(2) Provide these parameters for a particular call to command API
(3) Provides some kind of hooks that are called back from the API on specific 
events, e.g. Question with user-choice; Information with user-input
(4) Provide a logging handler object from the tool logging 
class or a sub-class of that in the case that a client-specific logging object 
should be triggered on each debug, message, warning etc.

(1) is very client-specific, e.g. in a GUI via dialogs.

(2) Each command provides a signature for all required/optional parameters. 
They are all verified from the command itself, although a client could do 
some verification at the first place.

(3) Example use-case: a command needs to know if the user wants the command to 
proceed with a particular action, e.g. "Do you want to delete bar.txt?" 
with "Yes", "No" and "Cancel" choice. So the client's handler object (which 
is provided as first parameter to each command) implements client-specific 
features to show the user this question (e.g. pop-up dialog with question and 
three buttons), receive the user input (clicking one of the buttons) and pass 
this choice back to the foo API. Alternatively some kind of text information 
could be required, as in raw_input(), so actually this probably would be two 
different interaction features to be implemented.

(4) The foo API also provides a logging class. The client needs to initialize 
such an object and provide it as member of the handler object provided to the 
API. I wonder if some clients may have own logging features and want to 
include all log messages from foo tool to the own logs. In this case a client 
could its own sub-class of the foo logging class and extending it with 
callbacks to its (client-)native logging object.

What do you think about this?

Best regards,
Anastasios



More information about the Python-list mailing list