2

I'm running some code with a sys.exit() call at the end. Without the sys.exit() line, the self.response works just fine and renders the template. But when I call sys.exit(), the page returns blank. It's almost like sys.exit() is interrupting the template mid-render. Why is it doing this?

page = 'index.html'
template_values = {}
path = os.path.join(os.path.dirname(__file__), page)
self.response.out.write(template.render(path, template_values))
sys.exit()

EDIT I've solved my problem by using "return" instead of "sys.exit()"

zakdances
  • 22,285
  • 32
  • 102
  • 173
  • 1
    I suspect Python's [internal] buffering is biting the response here -- a flush should do the trick. See also: http://stackoverflow.com/questions/107705/python-output-buffering (It would be nice to see an answer on why one approach [say without `sys.exit`] "works" while the other does not; what is the difference in Python termination?) –  Oct 08 '11 at 01:26
  • 1
    You should never call sys.exit on App Engine. – Nick Johnson Oct 10 '11 at 00:55

4 Answers4

6

Remove the sys.exit().

If you're basing it on the wording in http://code.google.com/appengine/docs/python/runtime.html#Responses (which has since been reworded), pretend for the moment that the use of "exit" in the first two sentences means "completes" or "finishes".

Dave W. Smith
  • 24,318
  • 4
  • 40
  • 46
1

As others have already given good solutions, I'll try to explain why this happens.

The SystemExit exception raised by sys.exit() differs from other exceptions in one particullar way. If it isn't caught, sys.excepthook isn't called. Instead, after printing the message contained within it and extracting the exit reason, Python shuts down (Py_Finalize) and calls the ANSI/C function exit() which terminates the process.

A solution is to either let the process end normally (see other answers) or to flush the streams.

yak
  • 8,851
  • 2
  • 29
  • 23
0

Alternatively, you can catch SystemExit and return normally:

def main():
 try:
   ...
 except SystemExit, e:
   # return normally for exit() or exit(0). Otherwise, reraise.
   if e.args and e.args[0]:
     raise

Expanding slightly:

The reason it doesn't work is that your Python script isn't being run like a "normal" CGI — there's an exception-catching wrapper, among other things, and sys.exit() is implemented by raising an exception (which doesn't subclass Exception() so it doesn't get caught by default).

I consider this a bug in GAE; you might want to file a bug report. (OTOH, you really shouldn't be using sys.exit() within GAE, since then it's unclear whether your main() function is re-runnable.)

tc.
  • 33,468
  • 5
  • 78
  • 96
  • It's not a bug, because you shouldn't be calling exit from App Engine in the first place. – Nick Johnson Oct 10 '11 at 00:56
  • @NickJohnson: If it is specifically *App Engine* that causes this failure (i.e. if `if __name__ == "__main__": sys.stdout.write("Status: 200 OK\nContent-Type:text/plain\n\nGoodbye, Cruel World"); sys.exit();` fails), then it is an App Engine bug because App Engine is supposed to give you a CGI-like environment. However, it might actually be a property of the web framework, which would probably not be a bug. – tc. Oct 13 '11 at 13:58
0

Try flushing the buffer before the sys.exit call:

page = 'index.html'
template_values = {}
path = os.path.join(os.path.dirname(__file__), page)
self.response.out.write(template.render(path, template_values))
self.response.out.flush()
sys.exit()
chown
  • 51,908
  • 16
  • 134
  • 170