Package qm :: Package external :: Package DocumentTemplate :: Module DT_Try
[hide private]
[frames] | no frames]

Source Code for Module qm.external.DocumentTemplate.DT_Try

  1  ############################################################################## 
  2  # 
  3  # Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved. 
  4  # 
  5  # This software is subject to the provisions of the Zope Public License, 
  6  # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution. 
  7  # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED 
  8  # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
  9  # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS 
 10  # FOR A PARTICULAR PURPOSE 
 11  # 
 12  ############################################################################## 
 13   
 14  import  sys, traceback 
 15  from cStringIO import StringIO 
 16  from DT_Util import ParseError, parse_params, render_blocks 
 17  from DT_Util import namespace, InstanceDict 
 18  from DT_Return import DTReturn 
 19   
20 -class Try:
21 """Zope DTML Exception handling 22 23 usage: 24 25 <!--#try--> 26 <!--#except SomeError AnotherError--> 27 <!--#except YetAnotherError--> 28 <!--#except--> 29 <!--#else--> 30 <!--#/try--> 31 32 or: 33 34 <!--#try--> 35 <!--#finally--> 36 <!--#/try--> 37 38 The DTML try tag functions quite like Python's try command. 39 40 The contents of the try tag are rendered. If an exception is raised, 41 then control switches to the except blocks. The first except block to 42 match the type of the error raised is rendered. If an except block has 43 no name then it matches all raised errors. 44 45 The try tag understands class-based exceptions, as well as string-based 46 exceptions. Note: the 'raise' tag raises string-based exceptions. 47 48 Inside the except blocks information about the error is available via 49 three variables. 50 51 'error_type' -- This variable is the name of the exception caught. 52 53 'error_value' -- This is the caught exception's value. 54 55 'error_tb' -- This is a traceback for the caught exception. 56 57 The optional else block is rendered when no exception occurs in the 58 try block. Exceptions in the else block are not handled by the preceding 59 except blocks. 60 61 The try..finally form specifies a `cleanup` block, to be rendered even 62 when an exception occurs. Note that any rendered result is discarded if 63 an exception occurs in either the try or finally blocks. The finally block 64 is only of any use if you need to clean up something that will not be 65 cleaned up by the transaction abort code. 66 67 The finally block will always be called, wether there was an exception in 68 the try block or not, or wether or not you used a return tag in the try 69 block. Note that any output of the finally block is discarded if you use a 70 return tag in the try block. 71 72 If an exception occurs in the try block, and an exception occurs in the 73 finally block, or you use the return tag in that block, any information 74 about that first exception is lost. No information about the first 75 exception is available in the finally block. Also, if you use a return tag 76 in the try block, and an exception occurs in the finally block or you use 77 a return tag there as well, the result returned in the try block will be 78 lost. 79 80 Original version by Jordan B. Baker. 81 82 Try..finally and try..else implementation by Martijn Pieters. 83 """ 84 85 name = 'try' 86 blockContinuations = 'except', 'else', 'finally' 87 finallyBlock=None 88 elseBlock=None 89
90 - def __init__(self, blocks):
91 tname, args, section = blocks[0] 92 93 self.args = parse_params(args) 94 self.section = section.blocks 95 96 97 # Find out if this is a try..finally type 98 if len(blocks) == 2 and blocks[1][0] == 'finally': 99 self.finallyBlock = blocks[1][2].blocks 100 101 # This is a try [except]* [else] block. 102 else: 103 # store handlers as tuples (name,block) 104 self.handlers = [] 105 defaultHandlerFound = 0 106 107 for tname,nargs,nsection in blocks[1:]: 108 if tname == 'else': 109 if not self.elseBlock is None: 110 raise ParseError, ( 111 'No more than one else block is allowed', 112 self.name) 113 self.elseBlock = nsection.blocks 114 115 elif tname == 'finally': 116 raise ParseError, ( 117 'A try..finally combination cannot contain ' 118 'any other else, except or finally blocks', 119 self.name) 120 121 else: 122 if not self.elseBlock is None: 123 raise ParseError, ( 124 'The else block should be the last block ' 125 'in a try tag', self.name) 126 127 for errname in nargs.split(): 128 self.handlers.append((errname,nsection.blocks)) 129 if nargs.strip()=='': 130 if defaultHandlerFound: 131 raise ParseError, ( 132 'Only one default exception handler ' 133 'is allowed', self.name) 134 else: 135 defaultHandlerFound = 1 136 self.handlers.append(('',nsection.blocks))
137
138 - def render(self, md):
139 if (self.finallyBlock is None): 140 return self.render_try_except(md) 141 else: 142 return self.render_try_finally(md)
143
144 - def render_try_except(self, md):
145 result = '' 146 147 # first we try to render the first block 148 try: 149 result = render_blocks(self.section, md) 150 except DTReturn: 151 raise 152 except: 153 # but an error occurs.. save the info. 154 t,v = sys.exc_info()[:2] 155 if type(t)==type(''): 156 errname = t 157 else: 158 errname = t.__name__ 159 160 handler = self.find_handler(t) 161 162 if handler is None: 163 # we didn't find a handler, so reraise the error 164 raise 165 166 # found the handler block, now render it 167 try: 168 f=StringIO() 169 traceback.print_exc(100,f) 170 error_tb=f.getvalue() 171 ns = namespace(md, error_type=errname, error_value=v, 172 error_tb=error_tb)[0] 173 md._push(InstanceDict(ns,md)) 174 return render_blocks(handler, md) 175 finally: 176 md._pop(1) 177 178 else: 179 # No errors have occured, render the optional else block 180 if (self.elseBlock is None): 181 return result 182 else: 183 return result + render_blocks(self.elseBlock, md)
184
185 - def render_try_finally(self, md):
186 result = '' 187 # first try to render the first block 188 try: 189 result = render_blocks(self.section, md) 190 # Then handle finally block 191 finally: 192 result = result + render_blocks(self.finallyBlock, md) 193 return result
194
195 - def find_handler(self,exception):
196 "recursively search for a handler for a given exception" 197 if type(exception)==type(''): 198 for e,h in self.handlers: 199 if exception==e or e=='': 200 return h 201 else: 202 return None 203 for e,h in self.handlers: 204 if e==exception.__name__ or e=='' or self.match_base(exception,e): 205 return h 206 return None
207
208 - def match_base(self,exception,name):
209 for base in exception.__bases__: 210 if base.__name__==name or self.match_base(base,name): 211 return 1 212 return None
213 214 __call__ = render
215