From 0415e46c73f1150dff178bfee803f433dfe6aaae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 12 Mar 2010 17:41:07 +0100 Subject: [PATCH] Don't allow to use float in Numeric fields The goal is to prevent to introduce float errors in Numeric fields. There is a trick for external protocols like XML-RPC and JSON-RPC where the string representation is stored in the Float object and will be used to convert it into Decimal. --- CHANGELOG | 1 + trytond/backend/fields.py | 4 +++- trytond/protocols/datatype.py | 18 ++++++++++++++++++ trytond/protocols/jsonrpc.py | 3 ++- trytond/protocols/xmlrpc.py | 6 ++++++ 5 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 trytond/protocols/datatype.py diff --git a/CHANGELOG b/CHANGELOG index 3b0d7d0acf..f44a8ea7f7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Don't allow to use float in Numeric fields * set/get function on Fields take a list of ids * New interface for Function/Property fields Take a Field as first argument instead of many separate arguments diff --git a/trytond/backend/fields.py b/trytond/backend/fields.py index 57239e0a4a..032c32cd21 100644 --- a/trytond/backend/fields.py +++ b/trytond/backend/fields.py @@ -79,8 +79,10 @@ class Numeric(Float): def sql_format(value): if not value: value = Decimal('0.0') - if isinstance(value, (int, long, float)): + if isinstance(value, (int, long)): value = Decimal(repr(value)) + if isinstance(value, float) and hasattr(value, 'decimal'): + value = Decimal(value.decimal) assert isinstance(value, Decimal) return value diff --git a/trytond/protocols/datatype.py b/trytond/protocols/datatype.py new file mode 100644 index 0000000000..de49e973fc --- /dev/null +++ b/trytond/protocols/datatype.py @@ -0,0 +1,18 @@ +#This file is part of Tryton. The COPYRIGHT file at the top level of +#this repository contains the full copyright notices and license terms. + +class Float(float): + + def __init__(self, value): + super(Float, self).__init__() + self.__decimal = value + + @property + def decimal(self): + return self.__decimal + + def __repr__(self): + return self.decimal + + def __str__(self): + return self.decimal diff --git a/trytond/protocols/jsonrpc.py b/trytond/protocols/jsonrpc.py index bff602b9f3..61a2892691 100644 --- a/trytond/protocols/jsonrpc.py +++ b/trytond/protocols/jsonrpc.py @@ -3,6 +3,7 @@ from trytond.protocols.sslsocket import SSLSocket from trytond.protocols.dispatcher import dispatch from trytond.config import CONFIG +from trytond.protocols.datatype import Float import SimpleXMLRPCServer import SimpleHTTPServer import SocketServer @@ -77,7 +78,7 @@ class SimpleJSONRPCDispatcher(SimpleXMLRPCServer.SimpleXMLRPCDispatcher): existing method through subclassing is the prefered means of changing method dispatch behavior. """ - rawreq = json.loads(data, object_hook=object_hook) + rawreq = json.loads(data, object_hook=object_hook, parse_float=Float) req_id = rawreq.get('id', 0) method = rawreq['method'] diff --git a/trytond/protocols/xmlrpc.py b/trytond/protocols/xmlrpc.py index 02bd7c6655..1617263f16 100644 --- a/trytond/protocols/xmlrpc.py +++ b/trytond/protocols/xmlrpc.py @@ -3,6 +3,7 @@ from trytond.protocols.sslsocket import SSLSocket from trytond.protocols.dispatcher import dispatch from trytond.config import CONFIG +from trytond.protocols.datatype import Float import SimpleXMLRPCServer import SocketServer import xmlrpclib @@ -21,6 +22,11 @@ xmlrpclib.Marshaller.dispatch[Decimal] = \ xmlrpclib.Marshaller.dispatch[type(None)] = \ lambda self, value, write: self.dump_bool(bool(value), write) +def _end_double(self, data): + self.append(Float(data)) + self._value = 0 +xmlrpclib.Unmarshaller.dispatch["double"] = _end_double + class GenericXMLRPCRequestHandler: