0001from formencode.api import FancyValidator, Invalid, Validator
0002import simplejson
0003import cgi
0004from cStringIO import StringIO
0005from paste.util.multidict import MultiDict
0006import xmlrpclib
0007
0008class JSONConverter(FancyValidator):
0009
0010 def _to_python(self, value, state):
0011
0012 try:
0013 return simplejson.loads(value)
0014 except ValueError, e:
0015 raise Invalid('Invalid JSON (%s): %r' % (e, value), value, state)
0016
0017 def _from_python(self, value, state):
0018 return simplejson.dumps(value)
0019
0020class LineConverter(FancyValidator):
0021
0022 if_empty = ()
0023
0024 def _to_python(self, value, state):
0025 value = value.splitlines()
0026 while value and not value[-1]:
0027 value.pop()
0028 return value
0029
0030 def _from_python(self, value, state):
0031 return '\n'.join(value) + '\n'
0032
0033class XMLRPCConverter(FancyValidator):
0034
0035 object_name = None
0036
0037 _marshal = xmlrpclib.Marshaller(allow_none=True)
0038 _marshal_dump = _marshal._Marshaller__dump
0039
0040 def _from_python(self, value, state):
0041 if self.object_name is None:
0042 object_name = 'object'
0043 if getattr(state, 'object', None):
0044 object_name = state.object.__class__.__name__.lower()
0045 else:
0046 object_name = self.object_name
0047 body = self._to_xmlrpc(value, state)
0048 return '<%s>%s</%s>' % (object_name, body, object_name)
0049
0050 def _to_xmlrpc(self, value, state):
0051 out = []
0052 self._marshal_dump(value, out.append)
0053 return ''.join(out)
0054
0055 def _to_python(self, value, state):
0056 value = self._unwrap(value, state)
0057 value = self._wrap_xmlrpc(value, state)
0058 parser, unmarshal = xmlrpclib.getparser()
0059 parser.feed(value)
0060 parser.close()
0061 result = unmarshal.close()[0]
0062 return result
0063
0064 def _unwrap(self, value, state):
0065 start = value.find('>')
0066 if start == -1:
0067 raise Invalid(
0068 "Not valid XML: %r" % value,
0069 value, state)
0070 value = value[start+1:]
0071 end = value.rfind('<')
0072 if end == -1:
0073 raise Invalid(
0074 "Not valid XML: %r" % value,
0075 value, state)
0076 value = value[:end]
0077 return value
0078
0079 def _wrap_xmlrpc(self, value, state):
0080 return (
0081 '<methodResponse><params><param>'
0082 '<value>%s</value>'
0083 '</param></params></methodResponse>' % value)
0084
0085
0086class ToFrom(Validator):
0087 """
0088 Applies one validator when going to_python, another when going
0089 from_python (for non-symmetrical conversion).
0090 """
0091
0092 to_python_validator = None
0093 from_python_validator = None
0094 __unpackargs__ = ('to_python_validator', 'from_python_validator')
0095
0096 def __init__(self, *args, **kw):
0097 Validator.__init__(self, *args, **kw)
0098
0099
0100
0101
0102
0103
0104 if (isinstance(self.to_python_validator, type)
0105 and issubclass(self.to_python_validator, Validator)):
0106 self.to_python_validator = self.to_python_validator()
0107 if (isinstance(self.from_python_validator, type)
0108 and issubclass(self.from_python_validator, Validator)):
0109 self.from_python_validator = self.from_python_validator()
0110
0111 def to_python(self, value, state):
0112 return self.to_python_validator.to_python(value, state)
0113
0114 def from_python(self, value, state):
0115 return self.from_python_validator.from_python(value, state)
0116
0117
0118
0119
0120
0121class SimplePostConverter(FancyValidator):
0122
0123 encoding = None
0124 content_type = None
0125 header_validator = True
0126
0127 def _to_python(self, value, state=None):
0128 headers, body = value
0129 if self.encoding is not None:
0130 body = body.decode(self.encoding)
0131 return body
0132
0133 def _from_python(self, value, state=None):
0134 headers = {}
0135 if self.content_type is not None:
0136 headers['Content-Type'] = self.content_type
0137 if self.encoding:
0138 if headers.get('Content-Type'):
0139 headers['Content-Type'] += '; charset=%s' % self.encoding
0140 if isinstance(value, unicode):
0141 value = value.encode(self.encoding)
0142 return (headers, value)
0143
0144class FormPostConverter(FancyValidator):
0145
0146 header_validator = True
0147 dict = False
0148
0149 def _to_python(self, value, state=None):
0150 headers, body = value
0151 environ = {}
0152 for name, value in headers:
0153 if name.lower() == 'content-type':
0154 name = 'CONTENT_TYPE'
0155 else:
0156 name = 'HTTP_%s' % (name.upper().replace('-', '_'))
0157 environ[name] = value
0158 environ['CONTENT_LENGTH'] = str(len(body))
0159 fs = cgi.FieldStorage(fp=StringIO(body),
0160 environ=environ,
0161 keep_blank_values=1)
0162 if not dict:
0163 return fs
0164 result = MultiDict()
0165 for field in fs.list:
0166 result.add(field.name, field.value)
0167 return result
0168
0169 def _from_python(self, value, state=None):
0170 headers = {
0171 'Content-Type': 'application/x-www-form-urlencoded'}
0172 body = urllib.urlencode(value, doseq=True)
0173 return headers, body
0174
0175class SimplePostIdentity(FancyValidator):
0176
0177 default_encoding = 'utf8'
0178 encoding = None
0179
0180 def _to_python(self, value, state):
0181 if self.encoding and isinstance(value, str):
0182 value = value.decode(self.encoding)
0183 return value
0184
0185 def _from_python(self, value, state):
0186 if not isinstance(value, basestring):
0187 if hasattr(value, '__unicode__'):
0188 value = unicode(value)
0189 else:
0190 value = str(value)
0191 if isinstance(value, unicode):
0192 value = value.encode(
0193 self.encoding or self.default_encoding)
0194 return value
0195
0196def to_python_headers(validator, header_body, state=None):
0197 if getattr(validator, 'header_validator', False):
0198 return validator.to_python(header_body, state)
0199 else:
0200 return validator.to_python(header_body[1], state)
0201
0202def from_python_headers(validator, data, state=None):
0203 if getattr(validator, 'header_validator', False):
0204 return ({}, validator.from_python(data, state))
0205 else:
0206 return validator.from_python(data, state)