Package turbogears :: Module errorhandling
[hide private]

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