Return to Home Page
      Blog     Consulting     Seminars     Calendar     Books     CD-ROMS     Newsletter     About     FAQ      Search
 

12-20-03 Browser as Desktop UI

I began giving seminars before I knew much about web technology. I knew enough to put up an HTML form that could be printed and faxed, and this seemed to work. People were comfortable faxing credit-card numbers, but secure servers still required pricey proprietary technology (it was only a few years ago that public domain versions of these became legal, because of patent expirations). Web programming meant CGI, and I didn't understand that at the time (even when I did tackle it, my first programs were in C++, and a compiled language is not conducive to web-style rapid development). It was a solution that worked, and any solution that works tends to persist far longer than you might plan or desire (there's a maxim in there somewhere).

As a result we've ended up with piles of paper information. Your best customers are the ones that have already bought from you, and I have been looking for better ways to get the word out when I give a seminar. One obvious way to do this is get all these names and addresses entered in so that we can send out postcards and messages announcing events.

The question is: what technology to use? My Dad will be doing the data entry; he works on Windows and is reasonably comfortable with any program that has a straightforward user interface. So I could use FileMaker Pro (something I've had a little experience with in the past, but I don't remember much about it now).

More important is ease/rapidity of development, as well as control — the ability to do anything that I want. For example, I think I'll want to automatically zip files and upload them to my server, which Dad doesn't know how to do. But it's possible I may want to do something that I can't imagine right now and that may be out of the purview of FileMaker (or possible, but requiring writing an external DLL and linking to it, etc.). I want something I can get working fast, but that doesn't limit me or require a herculean effort to add any feature I want.

Naturally, my first choice for this is Python, but then I have the problem of deciding what GUI to use. Python has GUIs; too many of them, in fact (PythonCard is very promising), and none that are second nature to me , so I don't have a sense of how long that would take. Besides, a full-blown GUI is overkill. All I need is simple forms and buttons. Like HTML. Yes, that would be ideal, if I could just lay out forms in HTML and use a web browser as the GUI.

I know that Python has the webbrowser module that starts up an instance of the browser of choice on the user's machine, opening the URL of your choice. I also know that the SimpleHTTPServer module allows you to create a little web server. All I need to do is start up both and get them talking to each other.

The default location of the SimpleHTTPServer is 127.0.0.1:8000. To make the connection, I start the browser at that URL, then start the SimpleHTTPServer, which delivers the forms containing the database information, and handles requests (although SimpleHTTPServer handles requests only in the form of GETs, other Python server libraries are more sophisticated — but also more complex, and I'm just trying to get away with "the simplest thing that could possibly work" here).

I had to poke around a little to see where the GET information ended up inside the send_head() method that's overridden in the class derived from SimpleHTTPServer. It's encoded in the path variable, but this information is easily extracted using the Python cgi module. You end up with a dictionary of key-value pairs taken directly from the HTML form.

The buttons in the HTML form all have NAME="Command" and VALUE tags that indicate the button's function. The VALUE appears in the CGI dictionary object associated with the key "Command", so all you have to do is see what the command is and act on that.

I started out with the dumbdbm database, but then discovered (through the act of programming) that it would be easier just to use shelve and store objects. Both approaches look like a dictionary, where the record key is the dictionary key. I keep track of the next available key within the database itself, using the special record 'nextKey' (shelve allows you to mix record types with impunity). Each record has an initial field which is a boolean indicating whether the record is valid or not. In order to delete records it seemed simpler to turn off this flag, rather than using the del keyword and actually removing the entry (because then you have the problem of traversing past the 'empty spot', since its index is taken up. I would have used an iterator, but Python's iterators only move one way). The only drawback to this approach is that record zero has become a special case, but the solution to that may become obvious as time passes, or it may also become clear that it's unimportant.

Shutting down the program is an interesting challenge. First, there's no "stop" command that I know of for the server. If you use sys.exit() the exception will be caught by the server (who's job is, after all, to keep running no matter what). os._exit(0) exits "cleanly" (without producing error messages), but if you call it within the send_head() function then the browser gives a disturbing message. I solved the problem using a Timer, with the following line:

threading.Timer(1, lambda: os._exit(0)).start()

send_head() completes and returns a page telling the user the program has shut down, then the timer shuts down the server. But before this happens, the program performs a couple of different backups: a conversion to CSV (comma- separated values) format using the csv module, and a zip of the data files using the zipfile module. I will probably add a separate button that will upload the files to an off-site repository using ftp. Notice that the vastness of the Python standard library toolset is one of the reasons you can create complex programs so quickly.

Here's the final program, which took me a couple of days to write (which was primarily spent figuring out the issues; obviously you can adapt what I have here to your own purposes in a few minutes).

The program initializes the database with dummy data to give you something to look at. You only need Python installed to run it, and all you have to do is either double-click on the program file, or run

python FlatFiler.py

This now provides a simple GUI suitable for many different kinds of applications (and the simplicity of the GUI is limited only by your knowledge of HTML).

Note that everything is in a single program file. A benefit to this approach is the ease of upgrades, and that's something I anticipate doing. This way, I can email a single Python file to Dad and teach him to drag and drop it out of the email on top of the old file, click "yes" to overwrite, and then we're upgraded.

Of course, you could easily adapt this system to using a regular DBMS like MySQL, since there are Python adapters for MySQL, and MySQL runs as a standalone program on a desktop. Or you could just as easily use this system as an interface to a non-database program.

The initial version of the program combined model and controller, which I knew was poor practice but it seemed reasonable because there was so little code necessary to control the model — why not just code it directly into the controller code? (The same thinking is the slippery slope to many Visual-Basic style messes.) I discovered, however, that a new SimpleHTTPRequestHandler is instantiated every single time that a request comes in, so there wasn't any way to store persistent values there, so in the end I was forced to separate the model and the controller. However, this cleaned up the code, making the implementation simpler and much easier to debug. In addition, changing the implementation of the database becomes easier because it is nicely hidden within the DataBase class.

    Links I Read
Cafe Au Lait
Artima
Daily Python URL
Martin Fowler
Joel on Software
Paul Graham
Cringely
Search     Home     Web Log     Articles     Calendar     Books     CD-ROMS     Seminars     Services     Newsletter     About     Contact     Site Feedback     Site Design     Server Maintenance     Powered by Zope
©2003 MindView, Inc.