Update of /usr/cvs/Public/pygresql/module
In directory druid.net:/tmp/cvs-serv7343

Modified Files:
        TEST_PyGreSQL_dbapi20.py pgdb.py 
Log Message:
Modernized pgdb module code a bit (we now require Python 2.3). Improvements and 
tests for pgdbType.
To see the diffs for this commit:
   
http://www.druid.net/pygresql/viewcvs.cgi/cvs/pygresql/module/TEST_PyGreSQL_dbapi20.py.diff?r1=1.8&r2=1.9

Index: TEST_PyGreSQL_dbapi20.py
===================================================================
RCS file: /usr/cvs/Public/pygresql/module/TEST_PyGreSQL_dbapi20.py,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- TEST_PyGreSQL_dbapi20.py    31 Oct 2008 17:13:50 -0000      1.8
+++ TEST_PyGreSQL_dbapi20.py    1 Nov 2008 13:04:07 -0000       1.9
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# $Id: TEST_PyGreSQL_dbapi20.py,v 1.8 2008/10/31 17:13:50 cito Exp $
+# $Id: TEST_PyGreSQL_dbapi20.py,v 1.9 2008/11/01 13:04:07 cito Exp $
 
 import dbapi20
 import unittest
@@ -84,10 +84,32 @@
             con.close()
 
     def test_nextset(self):
-        pass
+        pass # not implemented
 
     def test_setoutputsize(self):
-        pass
+        pass # not implemented
+
+    def test_pgdb_type(self):
+        self.assertEqual(pgdb.STRING, pgdb.STRING)
+        self.assertNotEqual(pgdb.STRING, pgdb.INTEGER)
+        self.assertNotEqual(pgdb.STRING, pgdb.BOOL)
+        self.assertNotEqual(pgdb.BOOL, pgdb.INTEGER)
+        self.assertEqual(pgdb.INTEGER, pgdb.INTEGER)
+        self.assertNotEqual(pgdb.INTEGER, pgdb.NUMBER)
+        self.assertEqual('char', pgdb.STRING)
+        self.assertEqual('varchar', pgdb.STRING)
+        self.assertEqual('text', pgdb.STRING)
+        self.assertNotEqual('numeric', pgdb.STRING)
+        self.assertEqual('numeric', pgdb.NUMERIC)
+        self.assertEqual('numeric', pgdb.NUMBER)
+        self.assertEqual('int4', pgdb.NUMBER)
+        self.assertNotEqual('int4', pgdb.NUMERIC)
+        self.assert_('char' in pgdb.STRING)
+        self.assert_(pgdb.NUMERIC <= pgdb.NUMBER)
+        self.assert_(pgdb.NUMBER >= pgdb.INTEGER)
+        self.assert_(pgdb.TIME <= pgdb.DATETIME)
+        self.assert_(pgdb.DATETIME >= pgdb.DATE)
+
 
 if __name__ == '__main__':
     unittest.main()

   
http://www.druid.net/pygresql/viewcvs.cgi/cvs/pygresql/module/pgdb.py.diff?r1=1.41&r2=1.42

Index: pgdb.py
===================================================================
RCS file: /usr/cvs/Public/pygresql/module/pgdb.py,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -r1.41 -r1.42
--- pgdb.py     1 Nov 2008 11:29:46 -0000       1.41
+++ pgdb.py     1 Nov 2008 13:04:07 -0000       1.42
@@ -4,7 +4,7 @@
 #
 # Written by D'Arcy J.M. Cain
 #
-# $Id: pgdb.py,v 1.41 2008/11/01 11:29:46 cito Exp $
+# $Id: pgdb.py,v 1.42 2008/11/01 13:04:07 cito Exp $
 #
 
 """pgdb - DB-API 2.0 compliant module for PygreSQL.
@@ -66,6 +66,10 @@
 from _pg import *
 import types
 import time
+try:
+       frozenset
+except NameError: # Python < 2.4
+       from sets import ImmutableSet as frozenset
 try: # use mx.DateTime module if available
        from mx.DateTime import DateTime, \
                TimeDelta, DateTimeType
@@ -109,13 +113,12 @@
        'numeric': Decimal, 'money': _cast_money}
 
 
-class pgdbTypeCache:
+class pgdbTypeCache(dict):
        """Cache for database types."""
 
        def __init__(self, cnx):
                """Initialize type cache for connection."""
                self._src = cnx.source()
-               self._cache = {}
 
        def typecast(typ, value):
                """Cast value to database type."""
@@ -133,7 +136,7 @@
        def getdescr(self, oid):
                """Get name of database type with given oid."""
                try:
-                       return self._cache[oid]
+                       return self[oid]
                except:
                        self._src.execute(
                                "SELECT typname, typlen "
@@ -143,27 +146,30 @@
                        # It will have to be prepended by the caller.
                        res = (res[0], None, int(res[1]),
                                None, None, None)
-                       self._cache[oid] = res
+                       self[oid] = res
                        return res
 
 
 class _quoteitem(dict):
+       """Dictionary with auto quoting of its items."""
+
        def __getitem__(self, key):
                return _quote(super(_quoteitem, self).__getitem__(key))
 
 
 def _quote(x):
+       """Quote value depending on its type."""
        if isinstance(x, DateTimeType):
                x = str(x)
        elif isinstance(x, unicode):
                x = x.encode( 'utf-8' )
-       if isinstance(x, types.StringType):
+       if isinstance(x, str):
                x = "'%s'" % str(x).replace("\\", "\\\\").replace("'", "''")
-       elif isinstance(x, (types.IntType, types.LongType, types.FloatType)):
+       elif isinstance(x, (int, long, float)):
                pass
        elif x is None:
                x = 'NULL'
-       elif isinstance(x, (types.ListType, types.TupleType)):
+       elif isinstance(x, (list, tuple)):
                x = '(%s)' % ','.join(map(lambda x: str(_quote(x)), x))
        elif Decimal is not float and isinstance(x, Decimal):
                pass
@@ -175,6 +181,11 @@
 
 
 def _quoteparams(s, params):
+       """Quote parameters.
+
+       This function works for both mappings and sequences.
+
+       """
        if hasattr(params, 'has_key'):
                params = _quoteitem(params)
        else:
@@ -184,7 +195,7 @@
 
 ### Cursor Object
 
-class pgdbCursor:
+class pgdbCursor(object):
        """Cursor Object."""
 
        def __init__(self, dbcnx):
@@ -197,7 +208,7 @@
                self.arraysize = 1
                self.lastrowid = None
 
-       def row_factory(self, row):
+       def row_factory(row):
                """You can overwrite this with a custom row factory
                        e.g. a dict_factory
 
@@ -209,8 +220,8 @@
                                        return d
                        cursor = myCursor(cnx)
                """
-
                return row
+       row_factory = staticmethod(row_factory)
 
        def close(self):
                self._src.close()
@@ -226,8 +237,8 @@
                # The parameters may also be specified as list of
                # tuples to e.g. insert multiple rows in a single
                # operation, but this kind of usage is deprecated:
-               if params and isinstance(params, types.ListType) \
-                               and isinstance(params[0], types.TupleType):
+               if (params and isinstance(params, list)
+                               and isinstance(params[0], tuple)):
                        self.executemany(operation, params)
                else:
                        # not a list of tuples
@@ -300,30 +311,31 @@
                if keep == 1:
                        self.arraysize = size
                try:
-                       res = self._src.fetch(size)
+                       result = self._src.fetch(size)
                except Error, e:
                        raise DatabaseError(str(e))
-               result = []
-               for r in res:
-                       row = []
-                       for desc, val in zip(self.description, r):
-                               row.append(self._type_cache.typecast(desc[1], 
val))
-                       result.append(self.row_factory(row))
-               return result
+               row_factory = self.row_factory
+               typecast = self._type_cache.typecast
+               coltypes = [desc[1] for desc in self.description]
+               return [row_factory([typecast(*args)
+                       for args in zip(coltypes, row)]) for row in result]
 
-       def nextset(self):
+       def nextset():
                raise NotSupportedError("nextset() is not supported")
+       nextset = staticmethod(nextset)
 
-       def setinputsizes(self, sizes):
+       def setinputsizes(sizes):
                pass
+       setinputsizes = staticmethod(setinputsizes)
 
-       def setoutputsize(self, size, col=0):
+       def setoutputsize(size, col=0):
                pass
+       setoutputsize = staticmethod(setoutputsize)
 
 
 ### Connection Objects
 
-class pgdbCnx:
+class pgdbCnx(object):
        """Connection Object."""
 
        def __init__(self, cnx):
@@ -429,7 +441,7 @@
 
 ### Types Handling
 
-class pgdbType:
+class pgdbType(frozenset):
        """Type class for a couple of PostgreSQL data types.
 
        PostgreSQL is object-oriented: types are dynamic.
@@ -437,46 +449,53 @@
 
        """
 
-       def __init__(self, *values):
-               self.values = values
+       def __new__(cls, values):
+               # for Python >= 2.4
+               if isinstance(values, basestring):
+                       values = values.split()
+               return super(pgdbType, cls).__new__(cls, values)
+
+       def __init__(self, values):
+               # for Python < 2.4
+               if isinstance(values, basestring):
+                       values = values.split()
+               super(pgdbType, self).__init__(values)
+
+       def __eq__(self, other):
+               if isinstance(other, basestring):
+                       return other in self
+               else:
+                       return super(pgdbType, self).__eq__(other)
 
-       def __cmp__(self, other):
-               if other in self.values:
-                       return 0
-               if other < self.values:
-                       return 1
+       def __ne__(self, other):
+               if isinstance(other, basestring):
+                       return other not in self
                else:
-                       return -1
+                       return super(pgdbType, self).__ne__(other)
 
 
 # Mandatory type objects defined by DB-API 2 specs:
 
-STRING = pgdbType('char', 'bpchar', 'name', 'text', 'varchar', 'bool')
-BINARY = pgdbType() # BLOB support is pg specific
-NUMBER = pgdbType('int2', 'int4', 'serial', 'int8',
-       'float4', 'float8', 'numeric', 'money')
-# this may be problematic as type are quite different ... I hope it won't hurt
-DATETIME = pgdbType('date', 'time', 'timetz',
-       'timestamp', 'timestamptz', 'datetime', 'abstime'
-       'interval', 'tinterval', 'timespan', 'reltime')
-# OIDs are used for everything (types, tables, BLOBs, rows, ...). This may 
cause
-# confusion, but we are unable to find out what exactly is behind the OID (at
-# least not easily enough). Should this be undefined as BLOBs ?
-ROWID = pgdbType('oid', 'oid8')
+STRING = pgdbType('char bpchar name text varchar')
+BINARY = pgdbType('bytea')
+NUMBER = pgdbType('int2 int4 serial int8 float4 float8 numeric money')
+DATETIME = pgdbType('date time timetz timestamp timestamptz datetime abstime'
+       ' interval tinterval timespan reltime')
+ROWID = pgdbType('oid oid8')
 
 
 # Additional type objects (more specific):
 
 BOOL = pgdbType('bool')
-INTEGER = pgdbType('int2', 'int4', 'serial')
+INTEGER = pgdbType('int2 int4 serial')
 LONG = pgdbType('int8')
-FLOAT = pgdbType('float4', 'float8')
+FLOAT = pgdbType('float4 float8')
 NUMERIC = pgdbType('numeric')
 MONEY = pgdbType('money')
 DATE = pgdbType('date')
-TIME = pgdbType('time', 'timetz')
-TIMESTAMP = pgdbType('timestamp', 'timestamptz', 'datetime', 'abstime')
-INTERVAL = pgdbType('interval', 'tinterval', 'timespan', 'reltime')
+TIME = pgdbType('time timetz')
+TIMESTAMP = pgdbType('timestamp timestamptz datetime abstime')
+INTERVAL = pgdbType('interval tinterval timespan reltime')
 
 
 # Mandatory type helpers defined by DB-API 2 specs:
@@ -491,16 +510,16 @@
        return DateTime(year, month, day, hour, minute, second)
 
 def DateFromTicks(ticks):
-       return apply(Date, time.localtime(ticks)[:3])
+       return Date(*time.localtime(ticks)[:3])
 
 def TimeFromTicks(ticks):
-       return apply(Time, time.localtime(ticks)[3:6])
+       return Time(*time.localtime(ticks)[3:6])
 
 def TimestampFromTicks(ticks):
-       return apply(Timestamp, time.localtime(ticks)[:6])
+       return Timestamp(*time.localtime(ticks)[:6])
 
-def Binary(str):
-       return str
+def Binary(value):
+       return value
 
 
 # If run as script, print some information:

_______________________________________________
PyGreSQL mailing list
[email protected]
http://mailman.vex.net/mailman/listinfo/pygresql

Reply via email to