/usr/lib/python2.7/dist-packages/pylons/decorators/__init__.py is in python-pylons 1.0.1-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | """Pylons Decorators
Common decorators intended for use in controllers. Additional
decorators for use with controllers are in the
:mod:`~pylons.decorators.cache`, :mod:`~pylons.decorators.rest` and
:mod:`~pylons.decorators.secure` modules.
"""
import logging
import warnings
import formencode
import simplejson
from decorator import decorator
from formencode import api, htmlfill, variabledecode
from pylons.decorators.util import get_pylons
from pylons.i18n import _ as pylons_gettext
__all__ = ['jsonify', 'validate']
log = logging.getLogger(__name__)
class JSONEncoder(simplejson.JSONEncoder):
def default(self, obj):
encoder = getattr(obj, '__json__', None)
if encoder is not None:
return encoder()
return super(JSONEncoder, self).default(obj)
@decorator
def jsonify(func, *args, **kwargs):
"""Action decorator that formats output for JSON
Given a function that will return content, this decorator will turn
the result into JSON, with a content-type of 'application/json' and
output it.
"""
pylons = get_pylons(args)
pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8'
data = func(*args, **kwargs)
if isinstance(data, (list, tuple)):
msg = "JSON responses with Array envelopes are susceptible to " \
"cross-site data leak attacks, see " \
"http://wiki.pylonshq.com/display/pylonsfaq/Warnings"
warnings.warn(msg, Warning, 2)
log.warning(msg)
log.debug("Returning JSON wrapped action output")
return simplejson.dumps(data, cls=JSONEncoder, encoding='utf-8')
def validate(schema=None, validators=None, form=None, variable_decode=False,
dict_char='.', list_char='-', post_only=True, state=None,
on_get=False, **htmlfill_kwargs):
"""Validate input either for a FormEncode schema, or individual
validators
Given a form schema or dict of validators, validate will attempt to
validate the schema or validator list.
If validation was successful, the valid result dict will be saved
as ``self.form_result``. Otherwise, the action will be re-run as if
it was a GET, and the output will be filled by FormEncode's
htmlfill to fill in the form field errors.
``schema``
Refers to a FormEncode Schema object to use during validation.
``form``
Method used to display the form, which will be used to get the
HTML representation of the form for error filling.
``variable_decode``
Boolean to indicate whether FormEncode's variable decode
function should be run on the form input before validation.
``dict_char``
Passed through to FormEncode. Toggles the form field naming
scheme used to determine what is used to represent a dict. This
option is only applicable when used with variable_decode=True.
``list_char``
Passed through to FormEncode. Toggles the form field naming
scheme used to determine what is used to represent a list. This
option is only applicable when used with variable_decode=True.
``post_only``
Boolean that indicates whether or not GET (query) variables
should be included during validation.
.. warning::
``post_only`` applies to *where* the arguments to be
validated come from. It does *not* restrict the form to
only working with post, merely only checking POST vars.
``state``
Passed through to FormEncode for use in validators that utilize
a state object.
``on_get``
Whether to validate on GET requests. By default only POST
requests are validated.
Example::
class SomeController(BaseController):
def create(self, id):
return render('/myform.mako')
@validate(schema=model.forms.myshema(), form='create')
def update(self, id):
# Do something with self.form_result
pass
"""
if state is None:
state = PylonsFormEncodeState
def wrapper(func, self, *args, **kwargs):
"""Decorator Wrapper function"""
request = self._py_object.request
errors = {}
# Skip the validation if on_get is False and its a GET
if not on_get and request.environ['REQUEST_METHOD'] == 'GET':
return func(self, *args, **kwargs)
# If they want post args only, use just the post args
if post_only:
params = request.POST
else:
params = request.params
params = params.mixed()
if variable_decode:
log.debug("Running variable_decode on params")
decoded = variabledecode.variable_decode(params, dict_char,
list_char)
else:
decoded = params
if schema:
log.debug("Validating against a schema")
try:
self.form_result = schema.to_python(decoded, state)
except formencode.Invalid, e:
errors = e.unpack_errors(variable_decode, dict_char, list_char)
if validators:
log.debug("Validating against provided validators")
if isinstance(validators, dict):
if not hasattr(self, 'form_result'):
self.form_result = {}
for field, validator in validators.iteritems():
try:
self.form_result[field] = \
validator.to_python(decoded.get(field), state)
except formencode.Invalid, error:
errors[field] = error
if errors:
log.debug("Errors found in validation, parsing form with htmlfill "
"for errors")
request.environ['REQUEST_METHOD'] = 'GET'
self._py_object.tmpl_context.form_errors = errors
# If there's no form supplied, just continue with the current
# function call.
if not form:
return func(self, *args, **kwargs)
request.environ['pylons.routes_dict']['action'] = form
response = self._dispatch_call()
# If the form_content is an exception response, return it
if hasattr(response, '_exception'):
return response
htmlfill_kwargs2 = htmlfill_kwargs.copy()
htmlfill_kwargs2.setdefault('encoding', request.charset)
return htmlfill.render(response, defaults=params, errors=errors,
**htmlfill_kwargs2)
return func(self, *args, **kwargs)
return decorator(wrapper)
def pylons_formencode_gettext(value):
"""Translates a string ``value`` using pylons gettext first and if
that fails, formencode gettext.
This allows to "merge" localized error messages from built-in
FormEncode's validators with application-specific validators.
"""
trans = pylons_gettext(value)
if trans == value:
# translation failed, try formencode
trans = api._stdtrans(value)
return trans
class PylonsFormEncodeState(object):
"""A ``state`` for FormEncode validate API that includes smart
``_`` hook.
The FormEncode library used by validate() decorator has some
provision for localizing error messages. In particular, it looks
for attribute ``_`` in the application-specific state object that
gets passed to every ``.to_python()`` call. If it is found, the
``_`` is assumed to be a gettext-like function and is called to
localize error messages.
One complication is that FormEncode ships with localized error
messages for standard validators so the user may want to re-use
them instead of gathering and translating everything from scratch.
To allow this, we pass as ``_`` a function which looks up
translation both in application and formencode message catalogs.
"""
_ = staticmethod(pylons_formencode_gettext)
|