    #!/usr/bin/env python

    """DebugAppServer

    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.

    Also, exceptions are not caught and gracefully handled with an HTML error
    page. Instead, the exceptions rise uncaught which allows the debugger to
    trap them so you can inspect the program.

    To use, simply run "python Launch.py DebugAppServer" using whatever debugging
    environment you prefer.

    Caveats:

    This app server supports the AutoReload feature but not for Python's standard
    modules or WebKit or WebKit's dependencies (MiscUtils, WebUtils and TaskKit).
    Even with that limitation, auto-reload is still useful because if you modify
    any module in your site, the auto-reload will happen. Note that the app server
    *will* restart when the aformentioned modules are modified, but the modules
    won't actually be reloaded.

    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.

    Tested on:
        - WingIDE on Windows, http://wingware.com/
        - PythonWin
        - JEdit with the JPyDbg plugin, on Windows
    """

    import ThreadedAppServer, ImportSpy, Profiler
    import sys

    # 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 want the Python debugger to trap the exceptions, not WebKit
    ThreadedAppServer.doesRunHandleExceptions = False

    class DebugAppServer(OriginalThreadedAppServer):
        """Sigle-threaded AppServer for debugging purposes.

        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.

        """

        ## Init ##

        excludePrefixes = ('WebKit', 'MiscUtils', 'WebUtils',  'TaskKit')

        def __init__(self, path=None):
            """Initialize DebugAppServer."""
            # 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):
            """Return default configuration."""
            # 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:
                OriginalThreadedAppServer.config(self)
                self.setSetting('StartServerThreads', 0)
                self.setSetting('MaxServerThreads', 0)
                self.setSetting('MinServerThreads', 0)
            return self._config

        ## Overridden methods ##

        def mainloop(self):
            """Main loop for Windows.

            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.

            """
            self.initThread()
            try:
                OriginalThreadedAppServer.mainloop(self)
            finally:
                self.delThread()

        def createApplication(self):
            """Create and return an application object. Invoked by __init__."""
            return DebugApplication(server=self)

        def restart(self):
            # The normal restart technique is to exit the application
            # with a special exit code and let an exta-process script
            # start the app server up again. That works poorly for a
            # debugging environment which is attached to a particular process.
            Profiler.reset()
            self.initiateShutdown()
            self._closeThread.join()
            sys.stdout.flush()
            sys.stderr.flush()
            ImportSpy.modloader.delModules(includePythonModules=False,
                excludePrefixes=self.excludePrefixes)
            ImportSpy.reset()
            raise ThreadedAppServer.RestartAppServerError

    from Application import Application
    from WebKit.Transaction import Transaction
    class DebugApplication(Application):

        ## Overridden methods ##

        # Don't handle exceptions gracefully because we want
        # them to rise uncaught so the debugger will kick in.

        # @@ 2005-07-15 CE: This works well for exceptions within responding to a request,
        # but for problems during importing a servlet, the exception gets printed to
        # console and the debugger does not kick in.

        def handleException(self):
            """Handle exception.

            This should only be used in cases where there is no transaction object,
            for example if an exception occurs when attempting to save a session
            to disk.

            """
            raise

        def handleExceptionInTransaction(self, excInfo, transaction):
            """Handle exception with info.

            Raises exception `excInfo` (as returned by ``sys.exc_info()``)
            that was generated by `transaction`.

            """
            raise

    class DummyRequestQueue:
        """This is a dummy replacement for the request queue.

        It merely executes handlers as soon as they are "pushed".

        """

        ## Overridden methods ##

        def put(self, handler):
            handler.handleRequest()
            handler.close()

    ## Globals ##

    # 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
    def runMainLoopInThread():
        return 0
    ThreadedAppServer.runMainLoopInThread = runMainLoopInThread