Package turbogears :: Module controllers
[hide private]

Source Code for Module turbogears.controllers

  1  """Classes and methods for TurboGears controllers.""" 
  2   
  3  import logging 
  4  import re 
  5  import urllib 
  6  import types 
  7  from itertools import izip 
  8  from dispatch import generic, strategy, functions 
  9  from inspect import isclass 
 10  import cherrypy 
 11  from cherrypy import request, response 
 12  import turbogears.util as tg_util 
 13  from turbogears import view, database, errorhandling, config 
 14  from turbogears.decorator import weak_signature_decorator 
 15  from turbogears.validators import Invalid 
 16  from turbogears.errorhandling import error_handler, exception_handler 
 17   
 18   
 19  log = logging.getLogger("turbogears.controllers") 
 20   
 21  unicodechars = re.compile(r"([^\x00-\x7F])") 
 22   
 23  if config.get("session_filter.on", None) == True: 
 24      if config.get("session_filter.storage_type", None) == "PostgreSQL": 
 25          import psycopg2 
 26          config.update( 
 27                  {'session_filter.get_db': psycopg2.connect( 
 28                      psycopg2.get('sessions.postgres.dsn')) 
 29                      }) 
 30      # support for mysql/sqlite/etc here 
 31   
 32   
33 -def _process_output(output, template, format, content_type, 34 mapping, fragment=False):
35 """Produce final output form from data returned from a controller method. 36 37 See the expose() arguments for more info since they are the same. 38 39 """ 40 if isinstance(output, dict): 41 from turbogears.widgets import js_location 42 43 css = tg_util.setlike() 44 js = dict(izip(js_location, iter(tg_util.setlike, None))) 45 include_widgets = {} 46 include_widgets_lst = config.get("tg.include_widgets", []) 47 48 if config.get("tg.mochikit_all", False): 49 include_widgets_lst.insert(0, 'turbogears.mochikit') 50 51 for i in include_widgets_lst: 52 widget = tg_util.load_class(i) 53 if isclass(widget): 54 widget = widget() 55 include_widgets["tg_%s" % i.split(".")[-1]] = widget 56 for script in widget.retrieve_javascript(): 57 if hasattr(script, "location"): 58 js[script.location].add(script) 59 else: 60 js[js_location.head].add(script) 61 css.add_all(widget.retrieve_css()) 62 63 for value in output.itervalues(): 64 if hasattr(value, "retrieve_css"): 65 retrieve = getattr(value, "retrieve_css") 66 if callable(retrieve): 67 css.add_all(value.retrieve_css()) 68 if hasattr(value, "retrieve_javascript"): 69 retrieve = getattr(value, "retrieve_javascript") 70 if callable(retrieve): 71 for script in value.retrieve_javascript(): 72 if hasattr(script, "location"): 73 js[script.location].add(script) 74 else: 75 js[js_location.head].add(script) 76 output.update(include_widgets) 77 output["tg_css"] = css 78 #output.update([("tg_js_%s" % str(l), js[l]) for l in js_location]) 79 for l in iter(js_location): 80 output["tg_js_%s" % str(l)] = js[l] 81 82 tg_flash = _get_flash() 83 if not tg_flash == None: 84 output["tg_flash"] = tg_flash 85 output = view.render(output, template=template, format=format, 86 mapping=mapping, content_type=content_type, 87 fragment=fragment) 88 else: 89 if content_type: 90 response.headers["Content-Type"] = content_type 91 92 # fix the Safari XMLHttpRequest encoding problem 93 try: 94 contentType = response.headers["Content-Type"] 95 ua = request.headers["User-Agent"] 96 except KeyError: 97 return output 98 if not contentType.startswith("text/"): 99 return output 100 ua = view.UserAgent(ua) 101 enc = tg_util.get_template_encoding_default() 102 if ua.browser == "safari": 103 if isinstance(output, str): 104 output = output.decode(enc) 105 elif isinstance(output, types.GeneratorType): 106 output = "".join(output) 107 108 output = unicodechars.sub( 109 lambda m: "&#x%x;" % ord(m.group(1)), output).encode("ascii") 110 111 if isinstance(output, unicode): 112 output = output.encode(enc) 113 return output
114 115
116 -class BadFormatError(Exception):
117 """Output-format exception."""
118 119
120 -def validate(form=None, validators=None, 121 failsafe_schema=errorhandling.FailsafeSchema.none, 122 failsafe_values=None, state_factory=None):
123 """Validate input. 124 125 @param form: a form instance that must be passed throught the validation 126 process... you must give a the same form instance as the one that will 127 be used to post data on the controller you are putting the validate 128 decorator on. 129 @type form: a form instance 130 131 @param validators: individual validators to use for parameters. 132 If you use a schema for validation then the schema instance must 133 be the sole argument. 134 If you use simple validators, then you must pass a dictionary with 135 each value name to validate as a key of the dictionary and the validator 136 instance (eg: tg.validators.Int() for integer) as the value. 137 @type validators: dictionary or schema instance 138 139 @param failsafe_schema: a schema for handling failsafe values. 140 The default is 'none', but you can also use 'values', 'map_errors', 141 or 'defaults' to map erroneous inputs to values, corresponding exceptions 142 or method defaults. 143 @type failsafe_schema: errorhandling.FailsafeSchema 144 145 @param failsafe_values: replacements for erroneous inputs. You can either 146 define replacements for every parameter, or a single replacement value 147 for all parameters. This is only used when failsafe_schema is 'values'. 148 @type failsafe_values: a dictionary or a single value 149 150 @param state_factory: If this is None, the initial state for validation 151 is set to None, otherwise this must be a callable that returns the initial 152 state to be used for validation. 153 @type state_factory: callable or None 154 155 """ 156 def entangle(func): 157 if callable(form) and not hasattr(form, "validate"): 158 init_form = lambda self: form(self) 159 else: 160 init_form = lambda self: form 161 162 def validate(func, *args, **kw): 163 # do not validate a second time if already validated 164 if hasattr(request, 'validation_state'): 165 return func(*args, **kw) 166 167 form = init_form(args and args[0] or kw["self"]) 168 args, kw = tg_util.to_kw(func, args, kw) 169 170 errors = {} 171 if state_factory is not None: 172 state = state_factory() 173 else: 174 state = None 175 176 if form: 177 value = kw.copy() 178 try: 179 kw.update(form.validate(value, state)) 180 except Invalid, e: 181 errors = e.unpack_errors() 182 request.validation_exception = e 183 request.validated_form = form 184 185 if validators: 186 if isinstance(validators, dict): 187 for field, validator in validators.iteritems(): 188 try: 189 kw[field] = validator.to_python( 190 kw.get(field, None), state) 191 except Invalid, error: 192 errors[field] = error 193 else: 194 try: 195 value = kw.copy() 196 kw.update(validators.to_python(value, state)) 197 except Invalid, e: 198 errors = e.unpack_errors() 199 request.validation_exception = e 200 request.validation_errors = errors 201 request.input_values = kw.copy() 202 request.validation_state = state 203 204 if errors: 205 kw = errorhandling.dispatch_failsafe(failsafe_schema, 206 failsafe_values, errors, func, kw) 207 args, kw = tg_util.from_kw(func, args, kw) 208 return errorhandling.run_with_errors(errors, func, *args, **kw)
209 210 return validate 211 return weak_signature_decorator(entangle) 212 213
214 -class CustomDispatch(functions.GenericFunction):
215
216 - def combine(self, cases):
217 strict = [strategy.ordered_signatures, strategy.safe_methods] 218 cases = strategy.separate_qualifiers( 219 cases, 220 primary = strict, 221 ) 222 primary = strategy.method_chain(cases.get('primary', [])) 223 if type(primary) != types.FunctionType: 224 for i in primary: 225 for y in i: 226 return y[1] 227 return primary
228 229
230 -def _add_rule(_expose, found_default, as_format, accept_format, template, 231 rulefunc):
232 if as_format == "default": 233 if found_default: 234 colon = template.find(":") 235 if colon == -1: 236 as_format = template 237 else: 238 as_format = template[:colon] 239 else: 240 found_default = True 241 ruleparts = [] 242 ruleparts.append('kw.get("tg_format", "default") == "%s"' 243 % as_format) 244 if accept_format: 245 ruleparts.append('(accept == "%s" and kw.get("tg_format", ' 246 '"default") == "default")' % accept_format) 247 rule = " or ".join(ruleparts) 248 log.debug("Generated rule %s", rule) 249 _expose.when(rule)(rulefunc) 250 251 return found_default
252 253
254 -def _build_rules(func):
255 [generic(CustomDispatch)] 256 def _expose(func, accept, allow_json, *args, **kw): 257 pass
258 259 if func._allow_json: 260 log.debug("Adding allow_json rule: " 261 'allow_json and ' 262 '(kw.get("tg_format", None) == "json" or accept ' 263 '=="text/javascript"