Files
tryton/trytond/protocols/xmlrpc.py
T

178 lines
4.9 KiB
Python
Raw Normal View History

2014-12-02 12:54:01 +01:00
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
2016-02-07 16:46:16 +01:00
import xmlrpclib as client
2010-06-09 19:52:47 +02:00
import datetime
import logging
2009-02-12 18:31:42 +01:00
# convert decimal to float before marshalling:
from decimal import Decimal
2016-03-15 16:57:26 +01:00
from werkzeug.wrappers import Response
from werkzeug.utils import cached_property
from werkzeug.exceptions import BadRequest
from trytond.protocols.wrappers import Request
from trytond.exceptions import TrytonException
logger = logging.getLogger(__name__)
2012-04-01 23:08:15 +02:00
def dump_decimal(self, value, write):
2011-12-22 22:17:08 +01:00
value = {'__class__': 'Decimal',
'decimal': str(value),
}
self.dump_struct(value, write)
2012-04-01 23:08:15 +02:00
2015-03-16 19:28:34 +01:00
def dump_bytes(self, value, write):
2011-09-17 14:43:05 +02:00
self.write = write
2016-02-07 16:46:16 +01:00
value = client.Binary(value)
2011-09-17 14:43:05 +02:00
value.encode(self)
del self.write
2012-04-01 23:08:15 +02:00
2011-12-22 22:17:08 +01:00
def dump_date(self, value, write):
value = {'__class__': 'date',
'year': value.year,
'month': value.month,
'day': value.day,
}
self.dump_struct(value, write)
2012-04-01 23:08:15 +02:00
2012-02-07 16:11:22 +01:00
def dump_time(self, value, write):
value = {'__class__': 'time',
'hour': value.hour,
'minute': value.minute,
'second': value.second,
2014-03-15 10:36:20 +01:00
'microsecond': value.microsecond,
2012-02-07 16:11:22 +01:00
}
self.dump_struct(value, write)
2015-02-09 22:58:56 +01:00
def dump_timedelta(self, value, write):
value = {'__class__': 'timedelta',
'seconds': value.total_seconds(),
}
self.dump_struct(value, write)
2016-02-07 16:46:16 +01:00
client.Marshaller.dispatch[Decimal] = dump_decimal
client.Marshaller.dispatch[type(None)] = \
2014-06-13 19:08:32 +02:00
lambda self, value, write: write("<value><nil/></value>")
2016-02-07 16:46:16 +01:00
client.Marshaller.dispatch[datetime.date] = dump_date
client.Marshaller.dispatch[datetime.time] = dump_time
client.Marshaller.dispatch[datetime.timedelta] = dump_timedelta
if bytes == str:
client.Marshaller.dispatch[bytearray] = dump_bytes
2009-02-12 18:31:42 +01:00
2012-04-01 23:08:15 +02:00
2016-02-07 16:46:16 +01:00
def dump_struct(self, value, write, escape=client.escape):
converted_value = {}
for k, v in value.items():
if type(k) in (int, long):
k = str(int(k))
elif type(k) == float:
k = repr(k)
converted_value[k] = v
return self.dump_struct(converted_value, write, escape=escape)
2016-02-07 16:46:16 +01:00
client.Marshaller.dispatch[dict] = dump_struct
2012-04-01 23:08:15 +02:00
class XMLRPCDecoder(object):
decoders = {}
@classmethod
def register(cls, klass, decoder):
assert klass not in cls.decoders
cls.decoders[klass] = decoder
def __call__(self, dct):
if dct.get('__class__') in self.decoders:
return self.decoders[dct['__class__']](dct)
return dct
XMLRPCDecoder.register('date',
lambda dct: datetime.date(dct['year'], dct['month'], dct['day']))
XMLRPCDecoder.register('time',
lambda dct: datetime.time(dct['hour'], dct['minute'], dct['second'],
dct['microsecond']))
2015-02-09 22:58:56 +01:00
XMLRPCDecoder.register('timedelta',
lambda dct: datetime.timedelta(seconds=dct['seconds']))
XMLRPCDecoder.register('Decimal', lambda dct: Decimal(dct['decimal']))
2011-12-22 22:17:08 +01:00
def end_struct(self, data):
mark = self._marks.pop()
# map structs to Python dictionaries
dct = {}
items = self._stack[mark:]
for i in range(0, len(items), 2):
2016-02-07 16:46:16 +01:00
dct[items[i]] = items[i + 1]
dct = XMLRPCDecoder()(dct)
2011-12-22 22:17:08 +01:00
self._stack[mark:] = [dct]
2010-03-12 17:41:07 +01:00
self._value = 0
2011-12-22 22:17:08 +01:00
2016-02-07 16:46:16 +01:00
client.Unmarshaller.dispatch['struct'] = end_struct
2012-04-01 23:08:15 +02:00
2010-06-09 19:52:47 +02:00
def _end_dateTime(self, data):
2016-02-07 16:46:16 +01:00
value = client.DateTime()
2010-06-09 19:52:47 +02:00
value.decode(data)
2016-02-07 16:46:16 +01:00
value = client._datetime_type(data)
2010-06-09 19:52:47 +02:00
self.append(value)
2016-02-07 16:46:16 +01:00
client.Unmarshaller.dispatch["dateTime.iso8601"] = _end_dateTime
2010-03-12 17:41:07 +01:00
2009-02-12 18:31:42 +01:00
2014-06-07 23:54:44 +02:00
def _end_base64(self, data):
2016-02-07 16:46:16 +01:00
value = client.Binary()
value.decode(data.encode('ascii'))
2015-03-16 19:28:34 +01:00
cast = bytearray if bytes == str else bytes
self.append(cast(value.data))
2014-06-07 23:54:44 +02:00
self._value = 0
2016-02-07 16:46:16 +01:00
if bytes == str:
client.Unmarshaller.dispatch['base64'] = _end_base64
2014-06-07 23:54:44 +02:00
2016-03-15 16:57:26 +01:00
class XMLRequest(Request):
parsed_content_type = 'xml'
2009-02-12 18:31:42 +01:00
2016-03-15 16:57:26 +01:00
@cached_property
def parsed_data(self):
if self.parsed_content_type in self.environ.get('CONTENT_TYPE', ''):
2010-03-23 10:45:02 +01:00
try:
2016-03-15 16:57:26 +01:00
# TODO replace by own loads
return client.loads(self.decoded_data)
except Exception:
raise BadRequest('Unable to read XMl request')
2009-02-12 18:31:42 +01:00
else:
2016-03-15 16:57:26 +01:00
raise BadRequest('Not an XML request')
@property
def method(self):
return self.parsed_data[1]
@property
def params(self):
return self.parsed_data[0]
class XMLProtocol:
content_type = 'xml'
@classmethod
def request(cls, environ):
return XMLRequest(environ)
@classmethod
def response(cls, data, request):
if isinstance(data, TrytonException):
data = client.Fault(data.code, str(data))
elif isinstance(data, Exception):
data = client.Fault(255, str(data))
else:
data = (data,)
return Response(client.dumps(
data, methodresponse=True, allow_none=True),
content_type='text/xml')