Package turbogears :: Module errorhandling

Source Code for Module turbogears.errorhandling

  1  import sys 
  2  from itertools import izip, islice 
  3  from inspect import getargspec 
  4   
  5  import cherrypy 
  6  from dispatch import generic, NoApplicableMethods, strategy 
  7   
  8  from turbogears.util import inject_args, adapt_call, call_on_stack, has_arg, \ 
  9                              remove_keys, Enum, combine_contexts 
 10  from turbogears.decorator import func_eq 
 11  from turbogears.genericfunctions import MultiorderGenericFunction 
 12   
 13  default = strategy.default 
 14   
 15  [generic(MultiorderGenericFunction)] 
16 -def dispatch_error(controller, tg_source, tg_errors, tg_exceptions, 17 *args, **kw):
18 """Dispatch error. 19 20 Error handler is a function registered via register_handler or if no 21 such decorator was applied, the method triggering the error. 22 23 """
24 25 [dispatch_error.when( 26 "(tg_errors and has_arg(tg_source, 'tg_errors'))", order=3)]
27 -def _register_implicit_errh(controller, tg_source, tg_errors, 28 tg_exceptions, *args, **kw):
29 """Register implicitly declared error handler and re-dispatch. 30 31 Any method declaring tg_errors parameter is considered an implicitly 32 declared error handler. 33 34 """ 35 error_handler(tg_source)(tg_source) 36 return dispatch_error(controller, tg_source, tg_errors, tg_exceptions, 37 *args, **kw)
38 39 [dispatch_error.when( 40 "(tg_exceptions and has_arg(tg_source, 'tg_exceptions'))", order=3)]
41 -def _register_implicit_exch(controller, tg_source, tg_errors, 42 tg_exceptions, *args, **kw):
43 """Register implicitly declared exception handler and re-dispatch. 44 45 Any method declaring tg_exceptions parameter is considered an 46 implicitly declared exception handler. 47 48 """ 49 exception_handler(tg_source)(tg_source) 50 return dispatch_error(controller, tg_source, tg_errors, tg_exceptions, 51 *args, **kw)
52
53 -def dispatch_error_adaptor(func):
54 """Construct a signature isomorphic to dispatch_error. 55 56 The actual handler will receive only arguments explicitly 57 declared, and a possible tg_format parameter. 58 59 """ 60 def adaptor(controller, tg_source, 61 tg_errors, tg_exceptions, *args, **kw): 62 tg_format = kw.pop('tg_format', None) 63 args, kw = inject_args(func, {"tg_source":tg_source, 64 "tg_errors":tg_errors, "tg_exceptions":tg_exceptions}, 65 args, kw, 1) 66 args, kw = adapt_call(func, args, kw, 1) 67 if tg_format is not None: 68 kw['tg_format'] = tg_format 69 return func(controller, *args, **kw)
70 return adaptor 71
72 -def try_call(func, self, *args, **kw):
73 """Call function, catch and dispatch any resulting exception.""" 74 # turbogears.database import here to avoid circular imports 75 from turbogears.database import restart_transaction 76 try: 77 return func(self, *args, **kw) 78 except Exception, e: 79 if isinstance(e, cherrypy.HTTPRedirect) or \ 80 call_on_stack("dispatch_error", 81 {"tg_source":func, "tg_exception":e}, 4): 82 raise 83 84 else: 85 exc_type, exc_value, exc_trace = sys.exc_info() 86 remove_keys(kw, ("tg_source", "tg_errors", "tg_exceptions")) 87 if 'tg_format' in cherrypy.request.params: 88 kw['tg_format'] = 'json' 89 if getattr(cherrypy.request, "in_transaction", None): 90 restart_transaction(1) 91 try: 92 output = dispatch_error(self, func, None, e, *args, **kw) 93 except NoApplicableMethods: 94 raise exc_type, exc_value, exc_trace 95 else: 96 del exc_trace 97 return output
98
99 -def run_with_errors(errors, func, self, *args, **kw):
100 """Branch execution depending on presence of errors.""" 101 if errors: 102 if hasattr(self, "validation_error"): 103 import warnings 104 warnings.warn( 105 "Use decorator error_handler() on per-method base " 106 "rather than defining a validation_error() method.", 107 DeprecationWarning, 2) 108 return self.validation_error(func.__name__, kw, errors) 109 else: 110 remove_keys(kw, ("tg_source", "tg_errors", "tg_exceptions")) 111 if 'tg_format' in cherrypy.request.params: 112 kw['tg_format'] = 'json' 113 try: 114 return dispatch_error(self, func, errors, None, *args, **kw) 115 except NoApplicableMethods: 116 raise NotImplementedError("Method %s.%s() has no applicable " 117 "error handler." % (self.__class__.__name__, func.__name__)) 118 else: 119 return func(self, *args, **kw)
120
121 -def register_handler(handler=None, rules=None):
122 """Register handler as an error handler for decorated method. 123 124 If handler is not given, method is considered it's own error handler. 125 126 rules can be a string containing an arbitrary logical Python expression 127 to be used as dispatch rule allowing multiple error handlers for a 128 single method. 129 130 register_handler decorator is an invariant. 131 132 """ 133 def register(func): 134 when = "func_eq(tg_source, func)" 135 if rules: 136 when += " and (%s)" % rules 137 dispatch_error.when(dispatch_error.parse(when, *combine_contexts( 138 depth=[0, 1])), order=1)(dispatch_error_adaptor(handler or func)) 139 return func
140 return register 141
142 -def bind_rules(pre_rules):
143 """Prepend rules to error handler specialisation.""" 144 def registrant(handler=None, rules=None): 145 when = pre_rules 146 if rules: 147 when += " and (%s)" % rules 148 return register_handler(handler, when)
149 return registrant 150 151 error_handler = bind_rules("tg_errors") 152 exception_handler = bind_rules("tg_exceptions") 153 154 FailsafeSchema = Enum("none", "values", "map_errors", "defaults") 155 156 [generic()]
157 -def dispatch_failsafe(schema, values, errors, source, kw):
158 """Dispatch fail-safe mechanism for failed inputs."""
159 160 [dispatch_failsafe.when(strategy.default)]
161 -def _failsafe_none(schema, values, errors, source, kw):
162 """No fail-safe values.""" 163 return kw
164 165 [dispatch_failsafe.when( 166 "schema is FailsafeSchema.values and isinstance(values, dict) and " 167 "isinstance(errors, dict)")]
168 -def _failsafe_values_dict(schema, values, errors, source, kw):
169 """Map erroneous inputs to values.""" 170 for key in errors: 171 if key in values: 172 kw[key] = values[key] 173 return kw
174 175 [dispatch_failsafe.when( 176 "schema is FailsafeSchema.values and isinstance(errors, dict)")]
177 -def _failsafe_values_atom(schema, values, errors, source, kw):
178 """Map all erroneous inputs to a single value.""" 179 for key in errors: 180 kw[key] = values 181 return kw
182 183 [dispatch_failsafe.when( 184 "schema is FailsafeSchema.map_errors and isinstance(errors, dict)")]
185 -def _failsafe_map_errors(schema, values, errors, source, kw):
186 """Map erroneous inputs to corresponding exceptions.""" 187 kw.update(errors) 188 return kw
189 190 [dispatch_failsafe.when( 191 "schema is FailsafeSchema.defaults and isinstance(errors, dict)")]
192 -def _failsafe_defaults(schema, values, errors, source, kw):
193 """Map erroneous inputs to method defaults.""" 194 argnames, defaultvals = getargspec(source)[::3] 195 defaults = dict(izip(islice(argnames, len(argnames) - len(defaultvals), 196 None), defaultvals)) 197 for key in errors: 198 if key in defaults: 199 kw[key] = defaults[key] 200 return kw
201 202 __all__ = ["dispatch_error", "dispatch_error_adaptor", "try_call", 203 "run_with_errors", "default", "register_handler", "FailsafeSchema", 204 "dispatch_failsafe", "error_handler", "exception_handler"] 205