Author: cito
Date: Wed Nov 25 07:59:03 2015
New Revision: 623

Log:
Backport decimal_point handling from trunk to 4.x

This fixes some issues with the old implementation and also introduces
the new feature to return money values formatted as string by setting
decimal_point(None), which was not possible before. Everything is still
totally backward compatible as decimal_point('.') is still the default.

Modified:
   branches/4.x/module/TEST_PyGreSQL_classic_connection.py
   branches/4.x/module/TEST_PyGreSQL_classic_dbwrapper.py
   branches/4.x/module/pgmodule.c
   branches/4.x/module/setup.py

Modified: branches/4.x/module/TEST_PyGreSQL_classic_connection.py
==============================================================================
--- branches/4.x/module/TEST_PyGreSQL_classic_connection.py     Wed Nov 25 
07:25:24 2015        (r622)
+++ branches/4.x/module/TEST_PyGreSQL_classic_connection.py     Wed Nov 25 
07:59:03 2015        (r623)
@@ -934,22 +934,49 @@
         # if and only if the decimal point is set appropriately
         # for the current lc_monetary setting
         query("set lc_monetary='en_US.UTF-8'")
+        pg.set_decimal_point(None)
+        try:
+            r = query("select '34.25'::money").getresult()[0][0]
+        finally:
+            pg.set_decimal_point(point)
+        self.assertIsInstance(r, str)
+        self.assertIn(r, (
+            '$34.25', '$ 34.25', '34.25$', '34.25 $', '34.25 Dollar'))
         pg.set_decimal_point('.')
-        r = query("select '34.25'::money").getresult()[0][0]
+        try:
+            r = query("select '34.25'::money").getresult()[0][0]
+        finally:
+            pg.set_decimal_point(point)
         self.assertIsInstance(r, d)
         self.assertEqual(r, d('34.25'))
         pg.set_decimal_point(',')
-        r = query("select '34.25'::money").getresult()[0][0]
+        try:
+            r = query("select '34.25'::money").getresult()[0][0]
+        finally:
+            pg.set_decimal_point(point)
         self.assertNotEqual(r, d('34.25'))
         query("set lc_monetary='de_DE.UTF-8'")
+        pg.set_decimal_point(None)
+        try:
+            r = query("select '34,25'::money").getresult()[0][0]
+        finally:
+            pg.set_decimal_point(point)
+        self.assertIsInstance(r, str)
+        self.assertIn(r, ('34,25€', '34,25 €', '€34,25' '€ 34,25',
+            '34,25 EUR', '34,25 Euro', '34,25 DM'))
         pg.set_decimal_point(',')
-        r = query("select '34,25'::money").getresult()[0][0]
+        try:
+            r = query("select '34,25'::money").getresult()[0][0]
+        finally:
+            pg.set_decimal_point(point)
         self.assertIsInstance(r, d)
         self.assertEqual(r, d('34.25'))
-        pg.set_decimal_point('.')
+        try:
+            pg.set_decimal_point('.')
+        finally:
+            pg.set_decimal_point(point)
         r = query("select '34,25'::money").getresult()[0][0]
         self.assertNotEqual(r, d('34.25'))
-        pg.set_decimal_point(point)
 
     def testSetDecimal(self):
         d = pg.Decimal
@@ -958,11 +985,13 @@
         self.assertIsInstance(r, d)
         self.assertEqual(r, d('3425'))
         pg.set_decimal(long)
-        r = query("select 3425::numeric").getresult()[0][0]
+        try:
+            r = query("select 3425::numeric").getresult()[0][0]
+        finally:
+            pg.set_decimal(d)
         self.assertNotIsInstance(r, d)
         self.assertIsInstance(r, long)
         self.assertEqual(r, 3425L)
-        pg.set_decimal(d)
 
     @unittest.skipUnless(namedtuple, 'Named tuples not available')
     def testSetNamedresult(self):

Modified: branches/4.x/module/TEST_PyGreSQL_classic_dbwrapper.py
==============================================================================
--- branches/4.x/module/TEST_PyGreSQL_classic_dbwrapper.py      Wed Nov 25 
07:25:24 2015        (r622)
+++ branches/4.x/module/TEST_PyGreSQL_classic_dbwrapper.py      Wed Nov 25 
07:59:03 2015        (r623)
@@ -283,9 +283,11 @@
 
     def setUp(self):
         self.db = DB()
-        self.db.query("set lc_monetary='C'")
-        self.db.query('set bytea_output=hex')
-        self.db.query('set standard_conforming_strings=on')
+        query = self.db.query
+        query('set client_encoding=utf8')
+        query('set standard_conforming_strings=on')
+        query('set bytea_output=hex')
+        query("set lc_monetary='C'")
 
     def tearDown(self):
         self.db.close()

Modified: branches/4.x/module/pgmodule.c
==============================================================================
--- branches/4.x/module/pgmodule.c      Wed Nov 25 07:25:24 2015        (r622)
+++ branches/4.x/module/pgmodule.c      Wed Nov 25 07:59:03 2015        (r623)
@@ -119,7 +119,7 @@
 
 static PyObject *decimal = NULL, /* decimal type */
                                *namedresult = NULL; /* function for getting 
named results */
-static char *decimal_point = "."; /* decimal point used in money values */
+static char decimal_point = '.'; /* decimal point used in money values */
 
 
 /* --------------------------------------------------------------------- */
@@ -2170,13 +2170,15 @@
                                                break;
 
                                        case 5:  /* money */
+                                               /* convert to decimal only if 
decimal point is set */
+                                               if (!decimal_point) goto 
default_case;
                                                for (k = 0;
                                                         *s && k < 
sizeof(cashbuf) / sizeof(cashbuf[0]) - 1;
                                                         s++)
                                                {
-                                                       if (isdigit(*s))
+                                                       if (*s >= '0' && *s <= 
'9')
                                                                cashbuf[k++] = 
*s;
-                                                       else if (*s == 
*decimal_point)
+                                                       else if (*s == 
decimal_point)
                                                                cashbuf[k++] = 
'.';
                                                        else if (*s == '(' || 
*s == '-')
                                                                cashbuf[k++] = 
'-';
@@ -2200,6 +2202,7 @@
                                                break;
 
                                        default:
+                                       default_case:
                                                val = PyString_FromString(s);
                                                break;
                                }
@@ -2297,13 +2300,16 @@
                                                break;
 
                                        case 5:  /* money */
+                                               /* convert to decimal only if 
decimal point is set */
+                                               if (!decimal_point) goto 
default_case;
+
                                                for (k = 0;
                                                         *s && k < 
sizeof(cashbuf) / sizeof(cashbuf[0]) - 1;
                                                         s++)
                                                {
-                                                       if (isdigit(*s))
+                                                       if (*s >= '0' && *s <= 
'9')
                                                                cashbuf[k++] = 
*s;
-                                                       else if (*s == 
*decimal_point)
+                                                       else if (*s == 
decimal_point)
                                                                cashbuf[k++] = 
'.';
                                                        else if (*s == '(' || 
*s == '-')
                                                                cashbuf[k++] = 
'-';
@@ -2327,6 +2333,7 @@
                                                break;
 
                                        default:
+                                       default_case:
                                                val = PyString_FromString(s);
                                                break;
                                }
@@ -3701,13 +3708,24 @@
 set_decimal_point(PyObject *self, PyObject * args)
 {
        PyObject *ret = NULL;
-       char *s;
+       char *s = NULL;
 
-       if (PyArg_ParseTuple(args, "s", &s))
-       {
-               decimal_point = s;
+       /* gets arguments */
+       if (PyArg_ParseTuple(args, "z", &s)) {
+               if (!s)
+                       s = "\0";
+               else if (*s && (*(s+1) || !strchr(".,;: '*/_`|", *s)))
+                       s = NULL;
+       }
+
+       if (s) {
+               decimal_point = *s;
                Py_INCREF(Py_None); ret = Py_None;
+       } else {
+               PyErr_SetString(PyExc_TypeError,
+                       "set_decimal_point() expects a decimal mark character");
        }
+
        return ret;
 }
 
@@ -3719,18 +3737,23 @@
 get_decimal_point(PyObject *self, PyObject * args)
 {
        PyObject *ret = NULL;
+       char s[2];
 
        if (PyArg_ParseTuple(args, ""))
        {
-               ret = PyString_FromString(decimal_point);
+               if (decimal_point) {
+                       s[0] = decimal_point; s[1] = '\0';
+                       ret = PyString_FromString(s);
+               } else {
+                       Py_INCREF(Py_None); ret = Py_None;
+               }
        }
        else
        {
                PyErr_SetString(PyExc_TypeError,
-                       " get_decimal_point() takes no parameter");
+                       "get_decimal_point() takes no parameter");
        }
 
-
        return ret;
 }
 

Modified: branches/4.x/module/setup.py
==============================================================================
--- branches/4.x/module/setup.py        Wed Nov 25 07:25:24 2015        (r622)
+++ branches/4.x/module/setup.py        Wed Nov 25 07:59:03 2015        (r623)
@@ -87,7 +87,7 @@
 library_dirs = [get_python_lib(), pg_config('libdir')]
 define_macros = [('PYGRESQL_VERSION', version)]
 undef_macros = []
-extra_compile_args = ['-O2', '-Wall', '-Werror']
+extra_compile_args = ['-O2', '-Wall', '-Werror', '-funsigned-char']
 
 
 class build_pg_ext(build_ext):
_______________________________________________
PyGreSQL mailing list
[email protected]
https://mail.vex.net/mailman/listinfo.cgi/pygresql

Reply via email to