Author: cito
Date: Sun Jul 17 11:10:42 2011
New Revision: 430

Log:
Support nan and inf as float values (#39, as suggested by Maxim Yegorushkin).

Modified:
   trunk/module/TEST_PyGreSQL_dbapi20.py
   trunk/module/pgdb.py

Modified: trunk/module/TEST_PyGreSQL_dbapi20.py
==============================================================================
--- trunk/module/TEST_PyGreSQL_dbapi20.py       Thu Jul  7 14:49:17 2011        
(r429)
+++ trunk/module/TEST_PyGreSQL_dbapi20.py       Sun Jul 17 11:10:42 2011        
(r430)
@@ -49,7 +49,7 @@
         con = self._connect()
         curs = myCursor(con)
         ret = curs.execute("select 1 as a, 2 as b")
-        self.assertTrue(ret is curs, 'execute() should return cursor')
+        self.assert_(ret is curs, 'execute() should return cursor')
         self.assertEqual(curs.fetchone(), {'a': 1, 'b': 2})
 
     def test_cursor_iteration(self):
@@ -61,9 +61,9 @@
     def test_fetch_2_rows(self):
         Decimal = pgdb.decimal_type()
         values = ['test', pgdb.Binary('\xff\x52\xb2'),
-            True, 5, 6,
-            5.7, Decimal('234.234234'), Decimal('75.45'),
-            '2008-10-20 15:25:35', 7897234]
+            True, 5, 6, 5.7, Decimal('234.234234'), Decimal('75.45'),
+            '2011-07-17', '15:47:42', '2008-10-20 15:25:35', '15:31:05',
+            7897234]
         table = self.table_prefix + 'booze'
         con = self._connect()
         try:
@@ -77,14 +77,17 @@
                 "floattest float8,"
                 "numerictest numeric,"
                 "moneytest money,"
+                "datetest date,"
+                "timetest time,"
                 "datetimetest timestamp,"
+                "intervaltest interval,"
                 "rowidtest oid)" % table)
             for s in ('numeric', 'monetary', 'time'):
                 cur.execute("set lc_%s to 'C'" % s)
             for i in range(2):
                 cur.execute("insert into %s values ("
                     "%%s,%%s,%%s,%%s,%%s,%%s,%%s,"
-                    "'%%s'::money,%%s,%%s)" % table, values)
+                    "'%%s'::money,%%s,%%s,%%s,%%s,%%s)" % table, values)
             cur.execute("select * from %s" % table)
             rows = cur.fetchall()
             self.assertEqual(len(rows), 2)
@@ -93,26 +96,74 @@
         finally:
             con.close()
 
+    def test_float(self):
+        from math import pi, e
+        try:
+            nan = float('nan')
+        except ValueError: # Python < 2.6
+            nan = 3.0e999 - 1.5e999999
+        try:
+            inf = float('inf')
+        except ValueError: # Python < 2.6
+            inf = 3.0e999 * 1.5e999999
+        try:
+            from math import isnan, isinf
+        except ImportError: # Python < 2.6
+            isnan = lambda x: x != x
+            isinf = lambda x: not isnan(x) and isnan(x * 0)
+        try:
+            from math import isnan, isinf
+        except ImportError: # Python < 2.6
+            isnan = lambda x: x != x
+            isinf = lambda x: not isnan(x) and isnan(x * 0)
+        self.assert_(isnan(nan) and not isinf(nan))
+        self.assert_(isinf(inf) and not isnan(inf))
+        values = [0, 1, 0.03125, -42.53125, nan, inf, -inf]
+        table = self.table_prefix + 'float'
+        con = self._connect()
+        try:
+            cur = con.cursor()
+            cur.execute("create table %s (floattest float)" % table)
+            params = [(val,) for val in values]
+            cur.executemany("insert into %s values(%%s)" % table, params)
+            cur.execute("select * from %s" % table)
+            rows = cur.fetchall()
+            self.assertEqual(len(rows), len(values))
+            rows = [row[0] for row in rows]
+            for inval, outval in zip(values, rows):
+                if isinf(inval):
+                    self.assert_(isinf(outval))
+                    if inval < 0:
+                        self.assert_(outval < 0)
+                    else:
+                        self.assert_(outval > 0)
+                elif isnan(inval):
+                    self.assert_(isnan(outval))
+                else:
+                    self.assertEqual(inval, outval)
+        finally:
+            con.close()
+
     def test_set_decimal_type(self):
         decimal_type = pgdb.decimal_type()
-        self.assertTrue(decimal_type is not None and callable(decimal_type))
+        self.assert_(decimal_type is not None and callable(decimal_type))
         con = self._connect()
         try:
             cur = con.cursor()
-            self.assertTrue(pgdb.decimal_type(int) is int)
+            self.assert_(pgdb.decimal_type(int) is int)
             cur.execute('select 42')
             value = cur.fetchone()[0]
-            self.assertTrue(isinstance(value, int))
+            self.assert_(isinstance(value, int))
             self.assertEqual(value, 42)
-            self.assertTrue(pgdb.decimal_type(float) is float)
+            self.assert_(pgdb.decimal_type(float) is float)
             cur.execute('select 4.25')
             value = cur.fetchone()[0]
-            self.assertTrue(isinstance(value, float))
+            self.assert_(isinstance(value, float))
             self.assertEqual(value, 4.25)
         finally:
             con.close()
             pgdb.decimal_type(decimal_type)
-        self.assertTrue(pgdb.decimal_type() is decimal_type)
+        self.assert_(pgdb.decimal_type() is decimal_type)
 
     def test_nextset(self):
         pass # not implemented

Modified: trunk/module/pgdb.py
==============================================================================
--- trunk/module/pgdb.py        Thu Jul  7 14:49:17 2011        (r429)
+++ trunk/module/pgdb.py        Sun Jul 17 11:10:42 2011        (r430)
@@ -75,6 +75,17 @@
     set_decimal(Decimal)
 except ImportError: # otherwise (Python < 2.4)
     Decimal = float # use float instead of Decimal
+try:
+    from math import isnan, isinf
+except ImportError: # Python < 2.6
+    isnan = lambda x: x != x
+    isinf = lambda x: not isnan(x) and isnan(x * 0)
+try:
+    inf = float('inf')
+    nan = float('nan')
+except ValueError: # Python < 2.6
+    inf = 1.0e999
+    nan = inf * 0
 
 
 ### Module Constants
@@ -113,10 +124,23 @@
     return unescape_bytea(value)
 
 
+def _cast_float(value):
+    try:
+        return float(value)
+    except ValueError:
+        if value == 'NaN':
+            return nan
+        elif value == 'Infinity':
+            return inf
+        elif value == '-Infinity':
+            return -inf
+        raise
+
+
 _cast = {'bool': _cast_bool, 'bytea': _cast_bytea,
     'int2': int, 'int4': int, 'serial': int,
     'int8': long, 'oid': long, 'oid8': long,
-    'float4': float, 'float8': float,
+    'float4': _cast_float, 'float8': _cast_float,
     'numeric': Decimal, 'money': _cast_money}
 
 
@@ -201,8 +225,13 @@
                 val = "E'%s'" % self._cnx.escape_bytea(val)
             else:
                 val = "'%s'" % self._cnx.escape_string(val)
-        elif isinstance(val, (int, long, float)):
+        elif isinstance(val, (int, long)):
             pass
+        elif isinstance(val, float):
+            if isinf(val):
+                return val < 0 and "'-Infinity'" or "'Infinity'"
+            elif isnan(val):
+                return "'NaN'"
         elif val is None:
             val = 'NULL'
         elif isinstance(val, (list, tuple)):
_______________________________________________
PyGreSQL mailing list
[email protected]
http://mailman.vex.net/mailman/listinfo/pygresql

Reply via email to