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        # @@: Should catch error:
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        #if not self.to_python_validator:
0099        #    raise ValueError(
0100        #        "You must give a value for to_python_validator")
0101        #if not self.from_python_validator:
0102        #    raise ValueError(
0103        #        "You must give a value for from_python_validator")
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## POST request validators
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)