Problem exiting application in Windows Console.

A

Ant

Hi all,

I'm putting together a simple help module for my applications, using
html files stored in the application directory somewhere. Basically it
sets up a basic web server, and then uses the webbrowser module to
display it in the users browser. I have it set up to call sys.exit(0)
if the url quit.html is called, but for some reason (on Windows XP via
the cmd.exe shell) python won't let me have the console back. I get the
System Exit stack trace OK:

Exiting...
----------------------------------------
Exception happened during processing of request from ('127.0.0.1',
3615)
Traceback (most recent call last):
....
File "C:\Documents and Settings\aroy\My Do...
sys.exit(0)
SystemExit: 0
----------------------------------------


However, at this point instead of getting back to a command prompt, I
get an unresponsive console. Hitting CTRL-Break gets me the command
prompt back, but I would have expected to get back the command prompt
as soon as the sys.exit(0) had completed.

Here's the code:

import webbrowser, os, sys
from threading import Thread
from BaseHTTPServer import HTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler

class HelpHTTPRequestHandler(SimpleHTTPRequestHandler):
def do_GET(self):
print "PATH: ", self.path
if self.path.endswith("quit.html"):
print "Exiting..."
sys.exit(0)
else:
return SimpleHTTPRequestHandler.do_GET(self)

def help(base_dir, server_class=HTTPServer,
handler_class=HelpHTTPRequestHandler):
os.chdir(base_dir)
server_address = ('', 8000)
httpd = server_class(server_address, handler_class)
server_thread = Thread(target=httpd.serve_forever)
server_thread.start()

webbrowser.open("http://localhost:8000/index.html")

print "Hit CTRL-Break or CTRL-C to exit server"

def main():
current_dir = os.path.split(sys.argv[0])[0]
help(current_dir)

if __name__ == "__main__":
main()
 
A

Ant

Ant wrote:
....
However, at this point instead of getting back to a command prompt, I
get an unresponsive console. Hitting CTRL-Break gets me the command
prompt back, but I would have expected to get back the command prompt
as soon as the sys.exit(0) had completed. ....
class HelpHTTPRequestHandler(SimpleHTTPRequestHandler):
def do_GET(self):
print "PATH: ", self.path
if self.path.endswith("quit.html"):
print "Exiting..."
sys.exit(0)
else:
return SimpleHTTPRequestHandler.do_GET(self)

def help(base_dir, server_class=HTTPServer,
handler_class=HelpHTTPRequestHandler):
....

OK, I've narrowed the problem back to the way HTTPServer (actually its
TCPServer parent) handles exceptions thrown by the process_request
method by catching them all, and then calling a handle_error method.
There doesn't seem to be a way of getting at the exception thrown
however - does anyone know how I can get this information?

The default handle_error method in the TCPServer uses the traceback
module to print the stacktrace, but I can't find anything in that
module to get the actual exception object (or string) - is there an
alternative trick?

Incidentally, this seems to me to be a pretty drastic try: except:
block, catching *everything* and then (essentially) discarding the
exception. Wouldn't it be better to either catch only the exceptions
that are expected (presumably IO errors, Socket exceptions, HTTP error
code exceptions etc), and let others pass through, or alternatively
pass the exception through to the handle_error() method since this is
where it should be dealt with?

Thanks.
 
A

Ant

Ant wrote:
....
OK, I've narrowed the problem back to the way HTTPServer (actually its
TCPServer parent) handles exceptions thrown by the process_request
method by catching them all, and then calling a handle_error method.
There doesn't seem to be a way of getting at the exception thrown
however - does anyone know how I can get this information?

Hmm. Lonely topic ;-)

I've found a way to solve the problem, by creating a subclass of
HTTPServer which overrides the handle_error method:

class HelpServer(HTTPServer):
def handle_error(self, request, client_address):
exception_line = inspect.trace()[-1][-2][0]
if "sys.exit" in exception_line:
print "Trying to exit again!"
sys.exit(0)
else:
HTTPServer.handle_error(self, request, client_address)

This seems a really nasty hack though - any ideas for a cleaner way to
do it?
 
S

Steve Holden

Ant said:
Ant wrote:
....
OK, I've narrowed the problem back to the way HTTPServer (actually its
TCPServer parent) handles exceptions thrown by the process_request
method by catching them all, and then calling a handle_error method.
There doesn't seem to be a way of getting at the exception thrown
however - does anyone know how I can get this information?

Hmm. Lonely topic ;-)

I've found a way to solve the problem, by creating a subclass of
HTTPServer which overrides the handle_error method:

class HelpServer(HTTPServer):
def handle_error(self, request, client_address):
exception_line = inspect.trace()[-1][-2][0]
if "sys.exit" in exception_line:
print "Trying to exit again!"
sys.exit(0)
else:
HTTPServer.handle_error(self, request, client_address)

This seems a really nasty hack though - any ideas for a cleaner way to
do it?
First of all, five hour response time is a high expectation, you must be
a Platinum customer :)

Secondly, while a try/except catching all exceptions *is* unusual it's
justifiable in a server context (though some logging and/or analysis
certainly wouldn't go amiss).

Thirdly your "ugly hack" *could* be replaced by something cleaner with
more analysis of the trace structure, but given how infrequently this
code is going to run and the low probability that anything else will
trigger the hook I'd be happy with it as it is. But that's just me ...

regards
Steve
 
M

Matimus

This seems a really nasty hack though - any ideas for a cleaner way to

You could overload handle_request instead. I think that makes more
sense anyway because you don't want to handle a SystemExit exception as
an error, you want to exit. Of course this only deals with catching the
exception, there may be a better method of shutting down and exiting
the server (other than sys.exit that is).

class HelpServer(HTTPServer):
def handle_request(self):
try:
request, client_address = self.get_request()
except socket.error:
return
if self.verify_request(request, client_address):
try:
self.process_request(request, client_address)
except SystemExit:
raise SystemExit
except:
self.handle_error(request, client_address)
self.close_request(request)
 
G

Gabriel Genellina

At Wednesday 8/11/2006 09:10, Ant wrote:

[getting a stack trace for SystemExit instead of a clean exit]
class HelpHTTPRequestHandler(SimpleHTTPRequestHandler):
def do_GET(self):
print "PATH: ", self.path
if self.path.endswith("quit.html"):
print "Exiting..."
sys.exit(0)
else:
return SimpleHTTPRequestHandler.do_GET(self)

def help(base_dir, server_class=HTTPServer,
handler_class=HelpHTTPRequestHandler):
os.chdir(base_dir)
server_address = ('', 8000)
httpd = server_class(server_address, handler_class)
server_thread = Thread(target=httpd.serve_forever)
server_thread.start()

webbrowser.open("http://localhost:8000/index.html")

print "Hit CTRL-Break or CTRL-C to exit server"

Replace serve_forever with your own loop checking an exit flag, and
set the flag in your "quit.html" handler instead of sys.exit(0)


--
Gabriel Genellina
Softlab SRL

__________________________________________________
Correo Yahoo!
Espacio para todos tus mensajes, antivirus y antispam ¡gratis!
¡Abrí tu cuenta ya! - http://correo.yahoo.com.ar
 
A

Ant

Steve Holden wrote:
....
First of all, five hour response time is a high expectation, you must be
a Platinum customer :)

I'm in the last week of my current job - start a new one on Monday, and
so I haven't got a great deal to do at the moment. Five hours is a
lifetime when you're staring at a newsgroup waiting for it to change
;-)
Secondly, while a try/except catching all exceptions *is* unusual it's
justifiable in a server context (though some logging and/or analysis
certainly wouldn't go amiss).

True. And I'd expected that the exception ought to be passed to the
handle_error method so that something could be done with it there. This
morning however I discovered that Guido's been in his time machine
since yesterday and provided the very useful sys.exc_info() function
for this very purpose!
Thirdly your "ugly hack" *could* be replaced by something cleaner with
more analysis of the trace structure, but given how infrequently this
code is going to run and the low probability that anything else will
trigger the hook I'd be happy with it as it is. But that's just me ...

The sys.exc_info() was what I was looking for it turns out, I can get
the exception type from that instead of trying to parse the stack
trace.

However:

Gabriel Genellina wrote:
....
Replace serve_forever with your own loop checking an exit flag, and
set the flag in your "quit.html" handler instead of sys.exit(0)

This is the approach I decided to go for. I found that RequestHandler
objects have a reference to its server that I can use to control the
server.

Thanks for the input chaps!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top