Changeset 616 for trunk


Ignore:
Timestamp:
Nov 23, 2015, 7:42:03 PM (4 years ago)
Author:
cito
Message:

Allow money values to be returned as string

If set_decimal_point() is called with None or , then money values
will not be returned as Decimal, but as strings from the database,
including the currency and other formatting. Maybe this should one
day become the default setting.

Location:
trunk/module
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/module/TEST_PyGreSQL_classic_connection.py

    r615 r616  
    11401140    def testGetDecimalPoint(self):
    11411141        point = pg.get_decimal_point()
     1142        # error if a parameter is passed
     1143        self.assertRaises(TypeError, pg.get_decimal_point, point)
    11421144        self.assertIsInstance(point, str)
    1143         self.assertEqual(point, '.')
     1145        self.assertEqual(point, '.')  # the default setting
    11441146        pg.set_decimal_point(',')
    11451147        try:
     
    11531155        d = pg.Decimal
    11541156        point = pg.get_decimal_point()
    1155         query = self.c.query
    1156         # check that money values can be interpreted correctly
    1157         # if and only if the decimal point is set appropriately
    1158         # for the current lc_monetary setting
     1157        self.assertRaises(TypeError, pg.set_decimal_point)
     1158        # error if decimal point is not a string
     1159        self.assertRaises(TypeError, pg.set_decimal_point, 0)
     1160        # error if more than one decimal point passed
     1161        self.assertRaises(TypeError, pg.set_decimal_point, '.', ',')
     1162        self.assertRaises(TypeError, pg.set_decimal_point, '.,')
     1163        # error if decimal point is not a punctuation character
     1164        self.assertRaises(TypeError, pg.set_decimal_point, '0')
     1165        query = self.c.query
     1166        # check that money values are interpreted as decimal values
     1167        # only if decimal_point is set, and that the result is correct
     1168        # only if it is set suitable for the current lc_monetary setting
     1169        select_money = "select '34.25'::money"
     1170        proper_money = d(34.25)
     1171        bad_money = d(3425)
     1172        en_locales = 'en', 'en_US', 'en_US.utf8', 'en_US.UTF-8'
     1173        en_money = '$34.25', '$ 34.25', '34.25$', '34.25 $', '34.25 Dollar'
     1174        de_locales = 'de', 'de_DE', 'de_DE.utf8', 'de_DE.UTF-8'
     1175        de_money = ('34,25€', '34,25 €', '€34,25' '€ 34,25',
     1176            '34,25 EUR', '34,25 Euro', '34,25 DM')
    11591177        # first try with English localization (using the point)
    1160         for lc in 'en', 'en_US', 'en_US.utf8', 'en_US.UTF-8':
     1178        for lc in en_locales:
    11611179            try:
    11621180                query("set lc_monetary='%s'" % lc)
     
    11681186            self.SkipTest("cannot set English money locale")
    11691187        try:
    1170             r = query("select '34.25'::money")
     1188            r = query(select_money)
    11711189        except pg.ProgrammingError:
    11721190            # this can happen if the currency signs cannot be
    11731191            # converted using the encoding of the test database
    11741192            self.skipTest('database does not support money')
     1193        pg.set_decimal_point(None)
     1194        try:
     1195            r = r.getresult()[0][0]
     1196        finally:
     1197            pg.set_decimal_point(point)
     1198        self.assertIsInstance(r, str)
     1199        self.assertIn(r, en_money)
     1200        r = query(select_money)
    11751201        pg.set_decimal_point('.')
    11761202        try:
     
    11791205            pg.set_decimal_point(point)
    11801206        self.assertIsInstance(r, d)
    1181         self.assertEqual(r, d('34.25'))
    1182         r = query("select '34.25'::money")
     1207        self.assertEqual(r, proper_money)
     1208        r = query(select_money)
    11831209        pg.set_decimal_point(',')
    11841210        try:
     
    11861212        finally:
    11871213            pg.set_decimal_point(point)
    1188         self.assertNotEqual(r, d('34.25'))
     1214        self.assertIsInstance(r, d)
     1215        self.assertEqual(r, bad_money)
     1216        r = query(select_money)
     1217        pg.set_decimal_point('!')
     1218        try:
     1219            r = r.getresult()[0][0]
     1220        finally:
     1221            pg.set_decimal_point(point)
     1222        self.assertIsInstance(r, d)
     1223        self.assertEqual(r, bad_money)
    11891224        # then try with German localization (using the comma)
    1190         for lc in 'de', 'de_DE', 'de_DE.utf8', 'de_DE.UTF-8':
     1225        for lc in de_locales:
    11911226            try:
    11921227                query("set lc_monetary='%s'" % lc)
     
    11971232        else:
    11981233            self.SkipTest("cannot set German money locale")
    1199         try:
    1200             r = query("select '34,25'::money")
    1201         except pg.ProgrammingError:
    1202             self.skipTest('database does not support money')
     1234        r = query(select_money)
     1235        pg.set_decimal_point(None)
     1236        try:
     1237            r = r.getresult()[0][0]
     1238        finally:
     1239            pg.set_decimal_point(point)
     1240        self.assertIsInstance(r, str)
     1241        self.assertIn(r, de_money)
     1242        r = query(select_money)
    12031243        pg.set_decimal_point(',')
    12041244        try:
     
    12071247            pg.set_decimal_point(point)
    12081248        self.assertIsInstance(r, d)
    1209         self.assertEqual(r, d('34.25'))
    1210         r = query("select '34,25'::money")
     1249        self.assertEqual(r, proper_money)
     1250        r = query(select_money)
    12111251        pg.set_decimal_point('.')
    12121252        try:
     
    12141254        finally:
    12151255            pg.set_decimal_point(point)
    1216         self.assertNotEqual(r, d('34.25'))
     1256        self.assertEqual(r, bad_money)
     1257        r = query(select_money)
     1258        pg.set_decimal_point('!')
     1259        try:
     1260            r = r.getresult()[0][0]
     1261        finally:
     1262            pg.set_decimal_point(point)
     1263        self.assertEqual(r, bad_money)
    12171264
    12181265    def testSetDecimal(self):
  • trunk/module/pgmodule.c

    r614 r616  
    109109static PyObject *decimal = NULL, /* decimal type */
    110110                                *namedresult = NULL; /* function for getting named results */
    111 static char *decimal_point = "."; /* decimal point used in money values */
     111static char decimal_point = '.'; /* decimal point used in money values */
    112112
    113113static int pg_encoding_utf8 = 0;
     
    32843284
    32853285                                        case 5:  /* money */
     3286                                                /* convert to decimal only if decimal point is set */
     3287                                                if (!decimal_point) goto default_case;
    32863288                                                for (k = 0;
    32873289                                                         *s && k < sizeof(cashbuf) / sizeof(cashbuf[0]) - 1;
     
    32903292                                                        if (isdigit((int)*s))
    32913293                                                                cashbuf[k++] = *s;
    3292                                                         else if (*s == *decimal_point)
     3294                                                        else if (*s == decimal_point)
    32933295                                                                cashbuf[k++] = '.';
    32943296                                                        else if (*s == '(' || *s == '-')
     
    33183320
    33193321                                        default:
     3322                                        default_case:
    33203323#if IS_PY3
    33213324                                                if (encoding == pg_encoding_utf8)
     
    34323435                                                break;
    34333436
    3434                                         case 5:  /* money */
     3437                                        case 5:  /* pgmoney */
     3438                                                /* convert to decimal only if decimal point is set */
     3439                                                if (!decimal_point) goto default_case;
     3440
    34353441                                                for (k = 0;
    34363442                                                         *s && k < sizeof(cashbuf) / sizeof(cashbuf[0]) - 1;
     
    34393445                                                        if (isdigit((int)*s))
    34403446                                                                cashbuf[k++] = *s;
    3441                                                         else if (*s == *decimal_point)
     3447                                                        else if (*s == decimal_point)
    34423448                                                                cashbuf[k++] = '.';
    34433449                                                        else if (*s == '(' || *s == '-')
     
    34673473
    34683474                                        default:
     3475                                        default_case:
    34693476                                                val = PyStr_FromString(s);
    34703477                                                break;
     
    37903797{
    37913798        PyObject *ret = NULL;
    3792         char *s;
    3793 
    3794         if (PyArg_ParseTuple(args, "s", &s))
    3795         {
    3796                 decimal_point = s;
     3799        char *s = NULL;
     3800
     3801        /* gets arguments */
     3802        if (PyArg_ParseTuple(args, "z", &s)) {
     3803                if (!s)
     3804                        s = "\0";
     3805                else if (*s && (*(s+1) || !ispunct(*s)))
     3806                        s = NULL;
     3807        }
     3808
     3809        if (s) {
     3810                decimal_point = *s;
    37973811                Py_INCREF(Py_None); ret = Py_None;
    3798         }
     3812        } else {
     3813                PyErr_SetString(PyExc_TypeError,
     3814                        "set_decimal_point() takes a punctuation character");
     3815        }
     3816
    37993817        return ret;
    38003818}
     
    38083826{
    38093827        PyObject *ret = NULL;
     3828        char s[2];
    38103829
    38113830        if (PyArg_ParseTuple(args, ""))
    38123831        {
    3813                 ret = PyStr_FromString(decimal_point);
     3832                if (decimal_point) {
     3833                        s[0] = decimal_point; s[1] = '\0';
     3834                        ret = PyStr_FromString(s);
     3835                } else {
     3836                        Py_INCREF(Py_None); ret = Py_None;
     3837                }
    38143838        }
    38153839        else
    38163840        {
    38173841                PyErr_SetString(PyExc_TypeError,
    3818                         " get_decimal_point() takes no parameter");
    3819         }
    3820 
     3842                        "get_decimal_point() takes no parameter");
     3843        }
    38213844
    38223845        return ret;
Note: See TracChangeset for help on using the changeset viewer.