From 08f2c2c19a2f66eaf3c243bd1db7ace82f0e1286 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ga=C3=ABtan=20de=20Menten?= Date: Sun, 28 Feb 2010 20:39:49 +0000 Subject: [PATCH] support scale argument for the C implementation of the decimal processor --- lib/sqlalchemy/cextension/processors.c | 19 ++++++++---- lib/sqlalchemy/processors.py | 41 +++++++++++--------------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/lib/sqlalchemy/cextension/processors.c b/lib/sqlalchemy/cextension/processors.c index d2d3980904..6e33027194 100644 --- a/lib/sqlalchemy/cextension/processors.c +++ b/lib/sqlalchemy/cextension/processors.c @@ -143,6 +143,7 @@ typedef struct { typedef struct { PyObject_HEAD PyObject *type; + PyObject *format; } DecimalResultProcessor; @@ -158,7 +159,7 @@ UnicodeResultProcessor_init(UnicodeResultProcessor *self, PyObject *args, PyObject *encoding, *errors = NULL; static char *kwlist[] = {"encoding", "errors", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "S|S:init", kwlist, + if (!PyArg_ParseTupleAndKeywords(args, kwds, "S|S:__init__", kwlist, &encoding, &errors)) return -1; @@ -252,30 +253,38 @@ static int DecimalResultProcessor_init(DecimalResultProcessor *self, PyObject *args, PyObject *kwds) { - PyObject *type; + PyObject *type, *format; - if (!PyArg_ParseTuple(args, "O", &type)) + if (!PyArg_ParseTuple(args, "OS", &type, &format)) return -1; Py_INCREF(type); self->type = type; + Py_INCREF(format); + self->format = format; + return 0; } static PyObject * DecimalResultProcessor_process(DecimalResultProcessor *self, PyObject *value) { - PyObject *str, *result; + PyObject *str, *result, *args; if (value == Py_None) Py_RETURN_NONE; if (PyFloat_CheckExact(value)) { /* Decimal does not accept float values directly */ - str = PyObject_Str(value); + args = PyTuple_Pack(1, value); + if (args == NULL) + return NULL; + + str = PyString_Format(self->format, args); if (str == NULL) return NULL; + result = PyObject_CallFunctionObjArgs(self->type, str, NULL); Py_DECREF(str); return result; diff --git a/lib/sqlalchemy/processors.py b/lib/sqlalchemy/processors.py index 04fa5054ab..c99ca4c6f5 100644 --- a/lib/sqlalchemy/processors.py +++ b/lib/sqlalchemy/processors.py @@ -4,7 +4,8 @@ # This module is part of SQLAlchemy and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php -"""defines generic type conversion functions, as used in result processors. +"""defines generic type conversion functions, as used in bind and result +processors. They all share one common characteristic: None is passed through unchanged. @@ -39,9 +40,13 @@ try: else: return UnicodeResultProcessor(encoding).process - # TODO: add scale argument - #def to_decimal_processor_factory(target_class): - # return DecimalResultProcessor(target_class).process + def to_decimal_processor_factory(target_class, scale=10): + # Note that the scale argument is not taken into account for integer + # values in the C implementation while it is in the Python one. + # For example, the Python implementation might return + # Decimal('5.00000') whereas the C implementation will + # return Decimal('5'). These are equivalent of course. + return DecimalResultProcessor(target_class, "%%.%df" % scale).process except ImportError: def to_unicode_processor_factory(encoding, errors=None): @@ -54,18 +59,18 @@ except ImportError: # decoder returns a tuple: (value, len). Simply dropping the # len part is safe: it is done that way in the normal # 'xx'.decode(encoding) code path. - # cfr python-source/Python/codecs.c:PyCodec_Decode return decoder(value, errors)[0] return process - # TODO: add scale argument - #def to_decimal_processor_factory(target_class): - # def process(value): - # if value is None: - # return None - # else: - # return target_class(str(value)) - # return process + def to_decimal_processor_factory(target_class, scale=10): + fstring = "%%.%df" % scale + + def process(value): + if value is None: + return None + else: + return target_class(fstring % value) + return process def to_float(value): if value is None: @@ -94,13 +99,3 @@ except ImportError: str_to_time = str_to_datetime_processor_factory(TIME_RE, datetime.time) str_to_date = str_to_datetime_processor_factory(DATE_RE, datetime.date) - -def to_decimal_processor_factory(target_class, scale=10): - fstring = "%%.%df" % scale - - def process(value): - if value is None: - return None - else: - return target_class(fstring % value) - return process -- 2.47.3