Use the env module to catch errors in the dispatcher.
[wrw.git] / wrw / dispatch.py
1 import sys, traceback
2 import env
3
4 __all__ = ["restart"]
5
6 class restart(Exception):
7     def handle(self, req):
8         pass
9
10 def mangle(result):
11     try:
12         iter(result)
13     except TypeError:
14         pass
15     else:
16         return result
17     return [str(result)]
18
19 class iterproxy(object):
20     # Makes sure iter(real).next() is called immediately, in order to
21     # let generator code run.
22     def __init__(self, real):
23         self.bk = real
24         self.bki = iter(real)
25         self._next = [None]
26         self.next()
27
28     def __iter__(self):
29         return self
30
31     def next(self):
32         if self._next is None:
33             raise StopIteration()
34         ret = self._next[0]
35         try:
36             self._next[:] = [self.bki.next()]
37         except StopIteration:
38             self._next = None
39         return ret
40
41     def close(self):
42         if hasattr(self.bk, "close"):
43             self.bk.close()
44
45 def defaulterror(req, excinfo):
46     import resp
47     traceback.print_exception(*excinfo)
48     raise resp.httperror(500)
49
50 def wraphandler(handler, excinfo):
51     def wrapped(req):
52         return handler(req, excinfo)
53     return wrapped
54
55 errorhandler = env.var(defaulterror)
56
57 def handle(req, startreq, handler):
58     eh = errorhandler.val
59     try:
60         resp = [""]
61         while True:
62             try:
63                 resp = iterproxy(handler(req))
64                 break
65             except restart, i:
66                 handler = i.handle
67             except Exception, i:
68                 if eh is None:
69                     raise
70                 handler = wraphandler(eh, sys.exc_info())
71                 eh = None
72         req.commit(startreq)
73         return resp
74     finally:
75         req.cleanup()