[r7405]: tags / 0.8a4 / turbogears / controllers.py History

Child: [r7406] (diff)

Download this file

controllers.py    162 lines (142 with data), 6.1 kB

  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
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
"""Classes and methods for TurboGears controllers."""
import view
import cherrypy
import logging
import re
import types
import validators as turbogearsvalid
import kid
import formencode
log = logging.getLogger("turbogears.controllers")
unicodechars = re.compile(r"([^\x00-\x9F])")
defaultfmt = cherrypy.config.get("kid.outputformat", "html")
if defaultfmt not in kid.output_methods.keys():
defaultfmt = "html"
def _process_output(tg_format, output, template):
"""Produces final output form from the data returned from a
controller method.
@param tg_format: format of desired output (html or json)
@param output: the output returned by the controller
@param template: HTML template to use
"""
if isinstance(output, dict):
if output.has_key("tg_template"):
template=output.pop("tg_template")
if not tg_format:
if template:
tg_format = defaultfmt
else:
tg_format = "json"
if tg_format == "json":
log.debug("Returning JSON")
cherrypy.response.headerMap["Content-Type"] = "text/javascript"
output["tg_flash"] = get_flash()
output = view.render(output, tg_format, template=template)
# fix the Safari XMLHttpRequest encoding problem
try:
contentType = cherrypy.response.headerMap["Content-Type"]
ua = cherrypy.request.headerMap["User-Agent"]
except KeyError:
return output
if not contentType.startswith("text/"):
return output
ua = view.UserAgent(ua)
if ua.browser == "safari":
if isinstance(output, str):
output = output.decode("utf8")
output = unicodechars.sub(
lambda m: "&#x%x;" % ord(m.group(1)),
output).encode("ascii")
if isinstance(output, unicode):
output = output.encode("utf8")
# Fix for opera browser
if "Opera" in ua.browser and tg_format == "json":
cherrypy.response.headerMap["Content-Type"] = "text/plain"
return output
def expose(html=None, validators=None,
template=None, format=None, content_type="text/html"):
"""TurboGears verson of CherryPy's expose.
In addition to exposing the method to the web, this expose function will
also perform validation of input arguments,
process output through a template, fix Safari's problem with
XMLHttpRequest encodings and provide JSON output on request.
If validators are supplied, incoming arguments will be processed by the
validator assigned to the argument. If validation fails, an attempt
will be made to call validation_error on the object that was
being called. validation_error is given the name of the method that was
called, the arguments that were provided, and a list of Invalid
exceptions.
@param html: reference along the Python path for the HTML template
@type html: string
@param template: reference along the Python path for the template.
for use in place of "html"
@type template: string
@param validators: maps argument names to validator applied to that arg
@type validators: dict or instance of formencode.Schema
@param format: format to output by default
@type format: string
@param content_type: sets the content-type http header
@type content_type: string
"""
import controllers
if template:
html = template
def decorator(func):
def newfunc(self, *args, **kw):
tg_format = kw.pop("tg_format", format)
underscore = kw.pop("_", None)
cherrypy.response.headerMap['Content-Type']= content_type
errors = {}
if validators:
if isinstance(validators, dict):
for field, validator in validators.items():
if field not in kw:
continue
try:
kw[field] = validator.to_python(kw[field])
except turbogearsvalid.Invalid, error:
errors[field] = error
else:
try:
kw = validators.to_python(kw)
except turbogearsvalid.Invalid, error:
errors = error.error_dict
if errors:
if hasattr(self, "validation_error"):
output = self.validation_error(func.func_name, kw, errors)
else:
raise turbogearsvalid.Invalid(str(errors))
else:
output = func(self, *args, **kw)
return controllers._process_output(tg_format, output, html)
newfunc.func_name = func.func_name
newfunc.exposed = True
return newfunc
return decorator
def flash(message):
"""Set a message to be displayed in the browser on next page display"""
cherrypy.response.simpleCookie['tg_flash'] = message
cherrypy.response.simpleCookie['tg_flash']['path'] = '/'
def get_flash():
"""Retrieve the flash message, if one is set. The message is cleared
after retrieval."""
try:
message = cherrypy.request.simpleCookie["tg_flash"].value
cherrypy.response.simpleCookie["tg_flash"] = ""
cherrypy.response.simpleCookie["tg_flash"]['expires'] = 0
cherrypy.response.simpleCookie['tg_flash']['path'] = '/'
except KeyError:
message = None
return message
class Controller(object):
"""Base class for a web application's controller.
As of 0.6, this has no functionality and does not need to be
used directly. This may be a source of future functionality,
but it's mostly here as a base class for Root."""
pass
class Root(Controller):
"""Base class for the root of a web application.
Your web application should have one of these. The root of
your application is used to compute URLs used by your app."""
pass
__all__ = ["expose", "flash", "get_flash", "Root", "Controller"]