You want to ship an application that end users will run on their own computer. However, you don't want to use a GUI toolkit such as Tkinter, PyQt, PyGTk, or whatever.
If your application's GUI needs can be met by a web application, you can write the application using Quixote and ship a package containing the necessary Python and PTL files to the user. When the user runs the application, run Quixote using a pure-Python HTTP server that listens to a local port and point a web browser instance at this local port.
Using the Python standard library
Lucio Torre wrote a QuixoteHTTPServer on top of the CGIHTTPServer that's part of the Python standard library.
The code is available from his quixote-users post.
import os, time import webbrowser from quixote.server import medusa_http if __name__ == '__main__': s = medusa_http.Server('quixote.demo', port=4241) pid = os.fork() if pid == 0: # Open web browser in child so we can delay a bit time.sleep(2) webbrowser.open('http://localhost:4241/') os._exit(0) else: # In parent, run the HTTP server s.run()
import os, time import webbrowser from quixote.server import twisted_http if __name__ == '__main__': s = twisted_http.Server('quixote.demo', port=4241) pid = os.fork() if pid == 0: # Open web browser in child so we can delay a bit time.sleep(2) webbrowser.open('http://localhost:4241/') os._exit(0) else: # In parent, run the HTTP server s.run()
The most difficult part of this implementation is figuring out when the HTTP server can be safely shut down. If the user just closes their browser, the HTTP server stays running, consuming resources on the user's machine for no purpose.
The easiest solution is to implement a "Quit" or "Shut down" link that simply does a sys.exit().
XXX How would you implement a shutdown after 30 minutes of inactivity?
I would run a timer in a separate thread which is being reset at each request. This is what I am doing when building standalone applications based on SimplHTTPServer shipped with Python.
My apps do have an exit link which perform a os._exit() because my apps run in separate threads rather than in separate processes (for Windows compatibility).
However, this solution might require some ugly hacks when applied to medusa or twisted...