Date: Thu Jul 14 12:52:08 2005
New Revision: 2726
Added DebugAppServer, a single-threaded app server
that makes it possible to debug servlets using a standard Python
debugger. I've tested it on Windows only, using both PythonWin
and JEdit with the JPyDbg plugin.
--- Webware/trunk/WebKit/AppServer.py (original)
+++ Webware/trunk/WebKit/AppServer.py Thu Jul 14 12:52:08 2005
@@ -97,7 +97,7 @@
self._closeEvent = Event()
- self._closeThread = Thread(target=self.closeThread)
+ self._closeThread = Thread(target=self.closeThread, name="CloseThread")
--- (empty file)
+++ Webware/trunk/WebKit/DebugAppServer.py Thu Jul 14 12:52:08 2005
@@ -0,0 +1,85 @@
+DebugAppServer executes all requests within the main thread, allowing
+servlets to be easily debugged using any Python debugger. The drawback is
+that only one request can be processed at a time using this approach.
+Currently the session sweeper is still run within a separate thread, and
+a "close thread" is started up by the AppServer base class, but neither
+of these two extra threads should pose any problems debugging servlets.
+To use, simply run "python Launch.py DebugAppServer" using whatever debugging
+environment you prefer. On Windows, I have tested using both PythonWin
+and JEdit with the JPyDbg plugin.
+import sys, traceback
+# We are going to replace ThreadedAppServer with our own class,
+# so we need to save a reference to the original class.
+OriginalThreadedAppServer = ThreadedAppServer.ThreadedAppServer
+ We are piggybacking on 99% of the code in ThreadedAppServer. Our
+ trick is to replace the request queue with a dummy object
+ that executes requests immediately instead of pushing them onto
+ a queue to be handled by other threads.
+ def __init__(self, path=None):
+ # Initialize the base class
+ OriginalThreadedAppServer.__init__(self, path)
+ # Replace the request queue with a dummy object that merely
+ # runs request handlers as soon as they are "pushed"
+ self._requestQueue = DummyRequestQueue()
+ def config(self):
+ # Force ThreadedAppServer to create an empty thread pool by hacking
+ # the settings to zero. This is not strictly necessary to do.
+ if self._config is None:
+ self.setSetting('StartServerThreads', 0)
+ self.setSetting('MaxServerThreads', 0)
+ self.setSetting('MinServerThreads', 0)
+ return self._config
+ def mainloop(self):
+ This is needed for COM support on Windows, because special
+ thread initialization is required on any thread that runs
+ servlets, in this case the main thread itself.
+ This is a dummy replacement for the request queue. It merely
+ executes handlers as soon as they are "pushed".
+ def put(self, handler):
+# Replace ThreadedAppServer class in the ThreadedAppServer module with our
+# DebugAppServer. This seems like an awful hack, but it works and
+# requires less code duplication than other approaches I could think of, and
+# required a very minimal amount of modification to ThreadedAppServer.py.
+ThreadedAppServer.ThreadedAppServer = DebugAppServer
+# Grab the main function from ThreadedAppServer -- it has been "tricked"
+# into using DebugAppServer instead.
+main = ThreadedAppServer.main
+# Replace Tweak ThreadedAppServer so that it never runs the main loop in a thread
+ return 0
+ThreadedAppServer.runMainLoopInThread = runMainLoopInThread
--- Webware/trunk/WebKit/Docs/RelNotes-X.Y.html (original)
+++ Webware/trunk/WebKit/Docs/RelNotes-X.Y.html Thu Jul 14 12:52:08 2005
@@ -73,6 +73,12 @@
of session IDs that are sent via means other than cookies or
URL parameters. (An example would be via an XML-RPC parameter.)
See the docstring for more details.
+ <li> Added DebugAppServer, a single-threaded app server
+ that makes it possible to debug servlets using a standard Python
+ debugger. I've tested it on Windows only, using both PythonWin
+ and JEdit with the JPyDbg plugin. See WebKit/DebugAppServer.py for
--- Webware/trunk/WebKit/ThreadedAppServer.py (original)
+++ Webware/trunk/WebKit/ThreadedAppServer.py Thu Jul 14 12:52:08 2005
@@ -760,6 +760,15 @@
+# Determines whether the main look should run in another thread.
+# On NT, we run the mainloop in a different thread because
+# it's not safe for Ctrl-C to be caught while
+# manipulating the queues. It's not safe on Linux
+# either, but there, it appears that Ctrl-C will
+# trigger an exception in ANY thread, so this fix
+# doesn't help.
+ return os.name == 'nt'
@@ -779,14 +788,7 @@
server = None
server = ThreadedAppServer(workDir)
- # On NT, run mainloop in a different thread because
- # it's not safe for Ctrl-C to be caught while
- # manipulating the queues. It's not safe on Linux
- # either, but there, it appears that Ctrl-C will
- # trigger an exception in ANY thread, so this fix
- # doesn't help.
- if os.name == 'nt':
+ if runMainLoopInThread():
# catch the exception raised by sys.exit so
# that we can re-call it in the main thread.