1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 import string, sys, traceback
87 from cStringIO import StringIO
88 from DT_Util import ParseError, parse_params, render_blocks
89 from DT_Util import namespace, InstanceDict
90 from DT_Return import DTReturn
91
93 """Zope DTML Exception handling
94
95 usage:
96
97 <!--#try-->
98 <!--#except SomeError AnotherError-->
99 <!--#except YetAnotherError-->
100 <!--#except-->
101 <!--#else-->
102 <!--#/try-->
103
104 or:
105
106 <!--#try-->
107 <!--#finally-->
108 <!--#/try-->
109
110 The DTML try tag functions quite like Python's try command.
111
112 The contents of the try tag are rendered. If an exception is raised,
113 then control switches to the except blocks. The first except block to
114 match the type of the error raised is rendered. If an except block has
115 no name then it matches all raised errors.
116
117 The try tag understands class-based exceptions, as well as string-based
118 exceptions. Note: the 'raise' tag raises string-based exceptions.
119
120 Inside the except blocks information about the error is available via
121 three variables.
122
123 'error_type' -- This variable is the name of the exception caught.
124
125 'error_value' -- This is the caught exception's value.
126
127 'error_tb' -- This is a traceback for the caught exception.
128
129 The optional else block is rendered when no exception occurs in the
130 try block. Exceptions in the else block are not handled by the preceding
131 except blocks.
132
133 The try..finally form specifies a `cleanup` block, to be rendered even
134 when an exception occurs. Note that any rendered result is discarded if
135 an exception occurs in either the try or finally blocks. The finally block
136 is only of any use if you need to clean up something that will not be
137 cleaned up by the transaction abort code.
138
139 The finally block will always be called, wether there was an exception in
140 the try block or not, or wether or not you used a return tag in the try
141 block. Note that any output of the finally block is discarded if you use a
142 return tag in the try block.
143
144 If an exception occurs in the try block, and an exception occurs in the
145 finally block, or you use the return tag in that block, any information
146 about that first exception is lost. No information about the first
147 exception is available in the finally block. Also, if you use a return tag
148 in the try block, and an exception occurs in the finally block or you use
149 a return tag there as well, the result returned in the try block will be
150 lost.
151
152 Original version by Jordan B. Baker.
153
154 Try..finally and try..else implementation by Martijn Pieters.
155 """
156
157 name = 'try'
158 blockContinuations = 'except', 'else', 'finally'
159 finallyBlock=None
160 elseBlock=None
161
163 tname, args, section = blocks[0]
164
165 self.args = parse_params(args)
166 self.section = section.blocks
167
168
169
170 if len(blocks) == 2 and blocks[1][0] == 'finally':
171 self.finallyBlock = blocks[1][2].blocks
172
173
174 else:
175
176 self.handlers = []
177 defaultHandlerFound = 0
178
179 for tname,nargs,nsection in blocks[1:]:
180 if tname == 'else':
181 if not self.elseBlock is None:
182 raise ParseError, (
183 'No more than one else block is allowed',
184 self.name)
185 self.elseBlock = nsection.blocks
186
187 elif tname == 'finally':
188 raise ParseError, (
189 'A try..finally combination cannot contain '
190 'any other else, except or finally blocks',
191 self.name)
192
193 else:
194 if not self.elseBlock is None:
195 raise ParseError, (
196 'The else block should be the last block '
197 'in a try tag', self.name)
198
199 for errname in string.split(nargs):
200 self.handlers.append((errname,nsection.blocks))
201 if string.strip(nargs)=='':
202 if defaultHandlerFound:
203 raise ParseError, (
204 'Only one default exception handler '
205 'is allowed', self.name)
206 else:
207 defaultHandlerFound = 1
208 self.handlers.append(('',nsection.blocks))
209
215
217 result = ''
218
219
220 try:
221 result = render_blocks(self.section, md)
222 except DTReturn:
223 raise
224 except:
225
226 t,v = sys.exc_info()[:2]
227 if type(t)==type(''):
228 errname = t
229 else:
230 errname = t.__name__
231
232 handler = self.find_handler(t)
233
234 if handler is None:
235
236 raise
237
238
239 try:
240 f=StringIO()
241 traceback.print_exc(100,f)
242 error_tb=f.getvalue()
243 ns = namespace(md, error_type=errname, error_value=v,
244 error_tb=error_tb)[0]
245 md._push(InstanceDict(ns,md))
246 return render_blocks(handler, md)
247 finally:
248 md._pop(1)
249
250 else:
251
252 if (self.elseBlock is None):
253 return result
254 else:
255 return result + render_blocks(self.elseBlock, md)
256
266
268 "recursively search for a handler for a given exception"
269 if type(exception)==type(''):
270 for e,h in self.handlers:
271 if exception==e or e=='':
272 return h
273 else:
274 return None
275 for e,h in self.handlers:
276 if e==exception.__name__ or e=='' or self.match_base(exception,e):
277 return h
278 return None
279
285
286 __call__ = render
287