PK¼hç6âip,j0j0DBUtils/SteadyDB.py"""SteadyDB - hardened DB-API 2 connections. Implements steady connections to a database based on an arbitrary DB-API 2 compliant database interface module. The connections are transparently reopened when they are closed or the database connection has been lost or when they are used more often than an optional usage limit. Database cursors are transparently reopened as well when the execution of a database operation cannot be performed due to a lost connection. Only if the connection is lost after the execution, when rows are already fetched from the database, this will give an error and the cursor will not be reopened automatically, because there is no reliable way to recover the state of the cursor in such a situation. A typical situation where database connections are lost is when the database server or an intervening firewall is shutdown and restarted for maintenance reasons. In such a case, all database connections would become unusable, even though the database service may be already available again. The "hardened" connections provided by this module will make the database connections immediately available again. This approach results in a steady database connection that can be used by PooledDB or PersistentDB to create pooled or persistent connections to a database in a threaded environment such as the application server of "Webware for Python." Note, however, that the connections themselves may not be thread-safe (depending on the used DB-API module). For the Python DB-API 2 specification, see: http://www.python.org/peps/pep-0249.html For information on Webware for Python, see: http://www.webwareforpython.org Usage: You can use the connection constructor connect() in the same way as you would use the connection constructor of a DB-API 2 module if you specify the DB-API 2 module to be used as the first parameter, or alternatively you can specify an arbitrary constructor function returning new DB-API 2 compliant connection objects as the first parameter. Passing just a function allows implementing failover mechanisms and load balancing strategies. You may also specify a usage limit as the second parameter (set it to 0 if you prefer unlimited usage), and an optional list of commands that may serve to prepare the session as a third parameter. When the connection to the database is lost or has been used too often, it will be transparently reset in most situations, without further notice. import pgdb # import used DB-API 2 module from DBUtils.SteadyDB import connect db = connect(pgdb, 10000, ["set datestyle to german"], host=..., database=..., user=..., ...) ... cursor = db.cursor() ... cursor.execute('select ...') result = cursor.fetchall() ... cursor.close() ... db.close() Ideas for improvement: * Alternatively to the maximum number of uses, implement a maximum time to live for connections. * Optionally log usage and loss of connection. Copyright, credits and license: * Contributed as supplement for Webware for Python and PyGreSQL by Christoph Zwerschke in September 2005 * Allowing creator functions as first parameter as in SQLAlchemy suggested by Ezio Vernacotola in December 2006 Licensed under the Open Software License version 2.1. """ __version__ = '0.9.4' __revision__ = "$Rev: 6696 $" __date__ = "$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $" import sys def connect(creator, maxusage=0, setsession=None, *args, **kwargs): """A tough version of the connection constructor of a DB-API 2 module. creator: either an arbitrary function returning new DB-API 2 compliant connection objects or a DB-API 2 compliant database module maxusage: maximum usage limit for the underlying DB-API 2 connection (number of database operations, 0 or False means unlimited usage) callproc(), execute() and executemany() count as one operation When the limit is reached, the connection is automatically reset. setsession: an optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to german", "set time zone mez"] args, kwargs: the parameters that shall be passed to the creator function or the connection constructor of the DB-API 2 module """ return SteadyDBConnection(creator, maxusage, setsession, *args, **kwargs) class SteadyDBConnection: """A "tough" version of DB-API 2 connections.""" _closed = True def __init__(self, creator, maxusage=0, setsession=None, *args, **kwargs): """"Create a "tough" DB-API 2 connection.""" try: self._creator = creator.connect self._dbapi = creator except AttributeError: self._creator = creator try: self._dbapi = sys.modules[creator.__module__] if self._dbapi.connect != creator: raise AttributeError except (AttributeError, KeyError): self._dbapi = None if not callable(self._creator): raise TypeError("%r is not a connection provider." % (creator,)) self._maxusage = maxusage self._setsession_sql = setsession self._args, self._kwargs = args, kwargs self._closeable = 1 self._store(self._create()) def _create(self): """Create a new connection using the creator function.""" con = self._creator(*self._args, **self._kwargs) try: try: if self._dbapi.connect != self._creator: raise AttributeError except AttributeError: try: self._dbapi = sys.modules[con.__module__] if not callable(self._dbapi.connect): raise AttributeError except (AttributeError, KeyError): raise TypeError("Cannot determine DB-API 2 module.") self._setsession(con) except Exception, error: # the database module could not be determined # or the session could not be prepared try: # close the connection first con.close() except Exception: pass raise error # reraise the original error again return con def _setsession(self, con=None): """Execute the SQL commands for session preparation.""" if con is None: con = self._con if self._setsession_sql: cursor = con.cursor() for sql in self._setsession_sql: cursor.execute(sql) cursor.close() def _store(self, con): """Store a database connection for subsequent use.""" self._con = con self._closed = False self._usage = 0 def _close(self): """Close the tough connection. You can always close a tough connection with this method and it will not complain if you close it more than once. """ if not self._closed: try: self._con.close() except Exception: pass self._closed = True def dbapi(self): """Return the underlying DB-API 2 module of the connection.""" return self._dbapi def threadsafety(self): """Return the thread safety level of the connection.""" try: return self._dbapi.threadsafety except AttributeError: return 0 def close(self): """Close the tough connection. You are allowed to close a tough connection by default and it will not complain if you close it more than once. You can disallow closing connections by setting the _closeable attribute to 0 or False. In this case, closing a connection will be silently ignored. """ if self._closeable: self._close() def commit(self): """Commit any pending transaction.""" self._con.commit() def rollback(self): """Rollback pending transaction.""" self._con.rollback() def _cursor(self, *args, **kwargs): """A "tough" version of the method cursor().""" # The args and kwargs are not part of the standard, # but some database modules seem to use these. try: if self._maxusage: if self._usage >= self._maxusage: # the connection was used too often raise self._dbapi.OperationalError cursor = self._con.cursor(*args, **kwargs) # try to get a cursor except (self._dbapi.OperationalError, self._dbapi.InternalError), error: # error in getting cursor try: # try to reopen the connection con2 = self._create() except Exception: pass else: try: # and try one more time to get a cursor cursor = con2.cursor(*args, **kwargs) except Exception: pass else: self._close() self._store(con2) return cursor try: con2.close() except Exception: pass raise error # reraise the original error again return cursor def cursor(self, *args, **kwargs): """Return a new Cursor Object using the connection.""" return SteadyDBCursor(self, *args, **kwargs) def __del__(self): """Delete the steady connection.""" self._close() # make sure the connection is closed class SteadyDBCursor: """A "tough" version of DB-API 2 cursors.""" _closed = True def __init__(self, con, *args, **kwargs): """"Create a "tough" DB-API 2 cursor.""" self._con = con self._args, self._kwargs = args, kwargs self._clearsizes() self._cursor = con._cursor(*args, **kwargs) self._closed = False def setinputsizes(self, sizes): """Store input sizes in case cursor needs to be reopened.""" self._inputsize = sizes def setoutputsize(self, size, column=None): """Store output sizes in case cursor needs to be reopened.""" if self._outputsize is None or column is None: self._outputsize = [(column, size)] else: self._outputsize.append(column, size) def _clearsizes(self): """Clear stored input sizes.""" self._inputsize = self._outputsize = None def _setsizes(self, cursor=None): """Set stored input and output sizes for cursor execution.""" if cursor is None: cursor = self._cursor if self._inputsize is not None: cursor.setinputsizes(self._inputsize) if self._outputsize is not None: for column, size in self._outputsize: if column is None: cursor.setoutputsize(size) else: cursor.setoutputsize(size, column) def close(self): """Close the tough cursor. It will not complain if you close it more than once. """ if not self._closed: try: self._cursor.close() except Exception: pass self._closed = True def _get_tough_method(self, name): """Return a "tough" version of the method.""" def tough_method(*args, **kwargs): execute = name.startswith('execute') try: if self._con._maxusage: if self._con._usage >= self._con._maxusage: # the connection was used too often raise self._con._dbapi.OperationalError if execute: self._setsizes() method = getattr(self._cursor, name) result = method(*args, **kwargs) # try to execute if execute: self._clearsizes() except (self._con._dbapi.OperationalError, self._con._dbapi.InternalError), error: # execution error try: cursor2 = self._con._cursor( *self._args, **self._kwargs) # open new cursor except Exception: pass else: try: # and try one more time to execute if execute: self._setsizes(cursor2) method = getattr(cursor2, name) result = method(*args, **kwargs) if execute: self._clearsizes() except Exception: pass else: self.close() self._cursor = cursor2 self._con._usage += 1 return result try: cursor2.close() except Exception: pass try: # try to reopen the connection con2 = self._con._create() except Exception: pass else: try: cursor2 = con2.cursor( *self._args, **self._kwargs) # open new cursor except Exception: pass else: try: # try one more time to execute if execute: self._setsizes(cursor2) method2 = getattr(cursor2, name) result = method2(*args, **kwargs) if execute: self._clearsizes() except Exception: pass else: self.close() self._con._close() self._con._store(con2) self._cursor = cursor2 self._con._usage += 1 return result try: cursor2.close() except Exception: pass try: con2.close() except Exception: pass raise error # reraise the original error again else: self._con._usage += 1 return result return tough_method def __getattr__(self, name): """Inherit methods and attributes of underlying cursor.""" if name.startswith('execute') or name.startswith('call'): # make execution methods "tough" return self._get_tough_method(name) else: return getattr(self._cursor, name) def __del__(self): """Delete the steady cursor.""" self.close() # make sure the cursor is closed PK@M58"g£:’G’GDBUtils/PooledDB.pyo;ò õÇFc@sÚdZdZdZdZdklZdklZdefd„ƒYZ de fd „ƒYZ d e fd „ƒYZ d e fd „ƒYZ dfd„ƒYZ dfd„ƒYZdfd„ƒYZdfd„ƒYZdS(s!PooledDB - pooling for DB-API 2 connections. Implements a pool of steady, thread-safe cached connections to a database which are transparently reused, using an arbitrary DB-API 2 compliant database interface module. This should result in a speedup for persistent applications such as the application server of "Webware for Python," without loss of robustness. Robustness is provided by using "hardened" SteadyDB connections. Even if the underlying database is restarted and all connections are lost, they will be automatically and transparently reopened. Measures are taken to make the pool of connections thread-safe. If the underlying DB-API module is thread-safe at the connection level, the requested connections may be shared with other threads by default, but you can also request dedicated connections in case you need them. For the Python DB-API 2 specification, see: http://www.python.org/peps/pep-0249.html For information on Webware for Python, see: http://www.webwareforpython.org Usage: First you need to set up the database connection pool by creating an instance of PooledDB, passing the following parameters: creator: either an arbitrary function returning new DB-API 2 connection objects or a DB-API 2 compliant database module mincached: the initial number of idle connections in the pool (the default of 0 means no connections are made at startup) maxcached: the maximum number of idle connections in the pool (the default value of 0 means unlimited pool size) maxshared: maximum number of shared connections allowed (the default value of 0 means all connections are dedicated) When this maximum number is reached, connections are shared if they have been requested as shareable. maxconnections: maximum number of connections generally allowed (the default value of 0 means any number of connections) blocking: determines behavior when exceeding the maximum (the default of 0 or False means report an error; otherwise block and wait until the number of connections decreases) maxusage: maximum number of reuses of a single connection (the default of 0 or False means unlimited reuse) When this maximum usage number of the connection is reached, the connection is automatically reset (closed and reopened). setsession: an optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to german", ...] The creator function or the connect function of the DB-API 2 compliant database module specified as the creator will receive any additional parameters such as the host, database, user, password etc. You may choose some or all of these parameters in your own creator function, allowing for sophisticated failover and load-balancing mechanisms. For instance, if you are using pgdb as your DB-API 2 database module and want a pool of at least five connections to your local database 'mydb': import pgdb # import used DB-API 2 module from DBUtils.PooledDB import PooledDB pool = PooledDB(pgdb, 5, database='mydb') Once you have set up the connection pool you can request database connections from that pool: db = pool.connection() You can use these connections just as if they were ordinary DB-API 2 connections. Actually what you get is the hardened SteadyDB version of the underlying DB-API 2 connection. Please note that the connection may be shared with other threads by default if you set a non-zero maxshared parameter and the DB-API 2 module allows this. If you want to have a dedicated connection, use: db = pool.connection(0) If you don't need it any more, you should immediately return it to the pool with db.close(). You can get another connection in the same way. Warning: In a threaded environment, never do the following: pool.connection().cursor().execute(...) This would release the connection too early for reuse which may be fatal if the connections are not thread-safe. Make sure that the connection object stays alive as long as you are using it, like that: db = pool.connection() cur = db.cursor() cur.execute(...) res = cur.fetchone() cur.close() # or del cur db.close() # or del db Ideas for improvement: * Add thread for monitoring and restarting bad or expired connections (similar to DBConnectionPool/ResourcePool by Warren Smith). * Optionally log usage, bad connections and exceeding of limits. Copyright, credits and license: * Contributed as supplement for Webware for Python and PyGreSQL by Christoph Zwerschke in September 2005 * Based on the code of DBPool, contributed to Webware for Python by Dan Green in December 2000 Licensed under the Open Software License version 2.1. s0.9.4s $Rev: 6696 $s5$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $(s Condition(sconnects PooledDBErrorcBstZdZRS(sGeneral PooledDB error.(s__name__s __module__s__doc__(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys PooledDBError~s sInvalidConnectioncBstZdZRS(sDatabase connection is invalid.(s__name__s __module__s__doc__(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysInvalidConnections sNotSupportedErrorcBstZdZRS(s(DB-API module not supported by PooledDB.(s__name__s __module__s__doc__(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysNotSupportedError„s sTooManyConnectionscBstZdZRS(s*Too many database connections were opened.(s__name__s __module__s__doc__(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysTooManyConnections‡s sPooledDBcBsetZdZdddddded„Zd„Zdd„Zd„Zd„Zd„Z d „Z RS( s•Pool for DB-API 2 connections. After you have created the connection pool, you can use connection() to get pooled, steady DB-API 2 connections. ic OsÔy |i} WnPtj oDy!t|iƒodpd} Wq`tj o d} q`XnX| otdƒ‚n||_| | f\|_ |_ ||_ ||_|o$||jo |}n||_n d|_| djo|o||_g|_n d|_|o;||jo |}n||jo |}n||_n d|_g|_d|_tƒ|_| od„}||i_ngi} t |ƒD]} | |i"dƒƒq°~ dS(sASet up the DB-API 2 connection pool. creator: either an arbitrary function returning new DB-API 2 connection objects or a DB-API 2 compliant database module mincached: initial number of idle connections in the pool (0 means no connections are made at startup) maxcached: maximum number of idle connections in the pool (0 means unlimited pool size) maxshared: maximum number of shared connections (0 means all connections are dedicated) When this maximum number is reached, connections are shared if they have been requested as shareable. maxconnections: maximum number of connections generally allowed (0 means an arbitrary number of connections) blocking: determines behavior when exceeding the maximum (0 or False means report an error; otherwise block and wait until the number of connections decreases) maxusage: maximum number of reuses of a single connection (0 or False means unlimited reuse) When this maximum usage number of the connection is reached, the connection is automatically reset (closed and reopened). setsession: optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to ...", "set time zone ..."] args, kwargs: the parameters that shall be passed to the creator function or the connection constructor of the DB-API 2 module iis#Database module is not thread-safe.icCs t‚dS(N(sTooManyConnections(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pyswait×sN(#screators threadsafetysAttributeErrorscallablesconnectsNotSupportedErrorsselfs_creatorsargsskwargss_argss_kwargssmaxusages _maxusages setsessions _setsessions maxcacheds mincacheds _maxcacheds maxshareds _maxshareds _shared_cachesmaxconnectionss_maxconnectionss _idle_caches _connectionss Conditions _conditionsblockingswaitsappends_[1]srangesis connection(sselfscreators mincacheds maxcacheds maxsharedsmaxconnectionssblockingsmaxusages setsessionsargsskwargssis_[1]s threadsafetyswait((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys__init__“sJ !                    cCs)t|i|i|i|i|iŽSdS(s+Get a steady, unpooled DB-API 2 connection.N(sconnectsselfs_creators _maxusages _setsessions_argss_kwargs(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pyssteady_connectionÝs icCsë|o|io(|iiƒz÷x:|i o|io|i|ijo|iiƒq$Wt |iƒ|ijoWy|i i dƒ}Wnt j o|iƒ}nXt|ƒ}|id7_n*|iiƒ|ii dƒ}|iƒ|ii|ƒ|iiƒWd|iiƒXt||ƒ}n«|iiƒzŒx/|io|i|ijo|iiƒqLWy|i i dƒ}Wnt j o|iƒ}nXt||ƒ}|id7_Wd|iiƒX|SdS(s²"Get a steady, cached DB-API 2 connection from the pool. If shareable is set and the underlying DB-API 2 allows it, then the connection may be shared with other threads. iiN(s shareablesselfs _maxshareds _conditionsacquires _shared_caches_maxconnectionss _connectionsswaitslens _idle_cachespopscons IndexErrorssteady_connectionsSharedDBConnectionssortssharesappendsnotifysreleasesPooledSharedDBConnectionsPooledDedicatedDBConnection(sselfs shareablescon((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys connectionâsH (    cCs‹|iiƒzM|iƒ|i}| o.y|ii|ƒWqYtj oqYXnWd|ii ƒX| o|i |iƒndS(s7Decrease the share of a connection in the shared cache.N( sselfs _conditionsacquiresconsunsharesshareds _shared_cachesremoves ValueErrorsreleasescache(sselfsconsshared((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysunshares    cCs¨|iiƒz†|i pt|iƒ|ijo8y|iƒWntj onX|ii |ƒn |i ƒ|i d8_ |ii ƒWd|ii ƒXdS(s4Put a dedicated connection back into the idle cache.iN(sselfs _conditionsacquires _maxcachedslens _idle_cachesconsrollbacks Exceptionsappendscloses _connectionssnotifysrelease(sselfscon((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pyscache"s $ cCs²|iiƒzx4|io)|iidƒiƒ|id8_qW|io>x;|io,|iidƒi iƒ|id8_qTWn|ii ƒWd|ii ƒXdS(s"Close all connections in the pool.iiN( sselfs _conditionsacquires _idle_cachespopscloses _connectionss _maxshareds _shared_cachescons notifyAllsrelease(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysclose7s    cCs"t|dƒo|iƒndS(sDelete the pool.s _connectionsN(shasattrsselfsclose(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys__del__Fs( s__name__s __module__s__doc__sNones__init__ssteady_connections connectionsunsharescachescloses__del__(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysPooledDB‹s J  0   sPooledDedicatedDBConnectioncBs2tZdZd„Zd„Zd„Zd„ZRS(s7Auxiliary proxy class for pooled dedicated connections.cCs4|iƒ otdƒ‚n||_||_dS(s€Create a pooled dedicated connection. pool: the corresponding PooledDB instance con: the underlying SteadyDB connection s#Database module is not thread-safe.N(scons threadsafetysNotSupportedErrorspoolsselfs_pools_con(sselfspoolscon((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys__init__Qs  cCs.|io |ii|iƒt|_ndS(s&Close the pooled dedicated connection.N(sselfs_cons_poolscachesNone(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysclose]s cCs(|iot|i|ƒSnt‚dS(sProxy all members of the class.N(sselfs_consgetattrsnamesInvalidConnection(sselfsname((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys __getattr__es cCs|iƒdS(sDelete the pooled connection.N(sselfsclose(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys__del__ls(s__name__s __module__s__doc__s__init__scloses __getattr__s__del__(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysPooledDedicatedDBConnectionNs   sSharedDBConnectioncBs2tZdZd„Zd„Zd„Zd„ZRS(s'Auxiliary class for shared connections.cCs||_d|_dS(sJCreate a shared connection. con: the underlying SteadyDB connection iN(sconsselfsshared(sselfscon((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys__init__ts cCs|i|iSdS(s-Compare how often the connections are shared.N(sselfssharedsother(sselfsother((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys__cmp__}scCs|id7_dS(s&Increase the share of this connection.iN(sselfsshared(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pyssharescCs|id8_dS(s&Decrease the share of this connection.iN(sselfsshared(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysunshare…s(s__name__s __module__s__doc__s__init__s__cmp__ssharesunshare(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysSharedDBConnectionqs   sPooledSharedDBConnectioncBs2tZdZd„Zd„Zd„Zd„ZRS(s4Auxiliary proxy class for pooled shared connections.cCsL|i}|iƒdj otdƒ‚n||_||_||_dS(s|Create a pooled shared connection. pool: the corresponding PooledDB instance con: the underlying SharedDBConnection is'Database connection is not thread-safe.N( s shared_conscons threadsafetysNotSupportedErrorspoolsselfs_pools _shared_cons_con(sselfspools shared_conscon((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys__init__s   cCs5|io'|ii|iƒt|_|_ndS(s#Close the pooled shared connection.N(sselfs_cons_poolsunshares _shared_consNone(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysclose›s cCs(|iot|i|ƒSnt‚dS(sProxy all members of the class.N(sselfs_consgetattrsnamesInvalidConnection(sselfsname((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys __getattr__£s cCs|iƒdS(sDelete the pooled connection.N(sselfsclose(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys__del__ªs(s__name__s __module__s__doc__s__init__scloses __getattr__s__del__(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysPooledSharedDBConnectionŠs    N(s__doc__s __version__s __revision__s__date__s threadings ConditionsDBUtils.SteadyDBsconnects Exceptions PooledDBErrorsInvalidConnectionsNotSupportedErrorsTooManyConnectionssPooledDBsPooledDedicatedDBConnectionsSharedDBConnectionsPooledSharedDBConnection( s PooledDBErrors __revision__sNotSupportedErrorsPooledDBs__date__sTooManyConnectionssSharedDBConnectionsconnectsInvalidConnections __version__sPooledSharedDBConnections ConditionsPooledDedicatedDBConnection((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys?ss  Ã#PK¼hç6êuøi33DBUtils/SimplePooledPg.py"""SimplePooledPg - a very simple classic PyGreSQL connection pool. Implements a pool of threadsafe cached connections to a PostgreSQL database which are transparently reused, using the classic (not DB-API 2 compliant) PyGreSQL pg API. This should result in a speedup for persistent applications such as the "Webware for Python" AppServer. For more information on PostgreSQL, see: http://www.postgresql.org For more information on PyGreSQL, see: http://www.pygresql.org For more information on Webware for Python, see: http://www.webwareforpython.org Measures are taken to make the pool of connections threadsafe regardless of the fact that the PyGreSQL pg module itself is not threadsafe at the connection level. Connections will never be shared between threads, so you can safely use transactions. Usage: The idea behind SimplePooledPg is that it's completely transparent. After you have established your connection pool, stating the number of connections to be cached in the pool and the connection parameters, e.g. from DBUtils.SimplePooledPg import PooledPg dbpool = PooledPg(5, host=..., database=..., user=..., ...) you can demand database connections from that pool, db = dbpool.connection() and use them just as if they were ordinary PyGreSQL pg API connections. It's really just a proxy class. db.close() will return the connection to the pool, it will not actually close it. This is so your existing code works nicely. Ideas for improvement: * Do not create the maximum number of connections on startup already, but only a certain number and the rest on demand. * Detect and transparently reset "bad" connections. The PyGreSQL pg API provides a status attribute and a reset() method for that. * Connections should have some sort of "maximum usage limit" after which they should be automatically closed and reopened. * Prefer or enforce thread affinity for the connections. Please note that these and other ideas have been already implemented in in PooledPg, a more sophisticated version of SimplePooledPg. You might also consider using PersistentPg instead for thread-affine persistent PyGreSQL connections. SimplePooledPg may still serve as a very simple reference and example implementation for developers. Copyright, credits and license: * Contributed as supplement for Webware for Python and PyGreSQL by Christoph Zwerschke in September 2005 * Based on the code of DBPool, contributed to Webware for Python by Dan Green in December 2000 Licensed under the Open Software License version 2.1. """ __version__ = '0.9.4' __revision__ = "$Rev: 6696 $" __date__ = "$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $" from pg import DB as PgConnection class PooledPgConnection: """A proxy class for pooled PostgreSQL connections. You don't normally deal with this class directly, but use PooledPg to get new connections. """ def __init__(self, pool, con): self._con = con self._pool = pool def close(self): """Close the pooled connection.""" # Instead of actually closing the connection, # return it to the pool so it can be reused. if self._con is not None: self._pool.cache(self._con) self._con = None def __getattr__(self, name): # All other members are the same. return getattr(self._con, name) def __del__(self): self.close() class PooledPg: """A very simple PostgreSQL connection pool. After you have created the connection pool, you can get connections using getConnection(). """ def __init__(self, maxconnections, *args, **kwargs): """Set up the PostgreSQL connection pool. maxconnections: the number of connections cached in the pool args, kwargs: the parameters that shall be used to establish the PostgreSQL connections using pg.connect() """ # Since there is no connection level safety, we # build the pool using the synchronized queue class # that implements all the required locking semantics. from Queue import Queue self._queue = Queue(maxconnections) # Establish all database connections (it would be better to # only establish a part of them now, and the rest on demand). for i in range(maxconnections): self.cache(PgConnection(*args, **kwargs)) def cache(self, con): """"Add or return a connection to the pool.""" self._queue.put(con) def connection(self): """"Get a connection from the pool.""" return PooledPgConnection(self, self._queue.get()) PK¼hç6ú}ÆI  DBUtils/PooledPg.py"""PooledPg - pooling for classic PyGreSQL connections. Implements a pool of steady, thread-safe cached connections to a PostgreSQL database which are transparently reused, using the classic (not DB-API 2 compliant) PyGreSQL API. This should result in a speedup for persistent applications such as the application server of "Webware for Python," without loss of robustness. Robustness is provided by using "hardened" SteadyPg connections. Even if the underlying database is restarted and all connections are lost, they will be automatically and transparently reopened. Measures are taken to make the pool of connections thread-safe regardless of the fact that the classic PyGreSQL pg module itself is not thread-safe at the connection level. For more information on PostgreSQL, see: http://www.postgresql.org For more information on PyGreSQL, see: http://www.pygresql.org For more information on Webware for Python, see: http://www.webwareforpython.org Usage: First you need to set up the database connection pool by creating an instance of PooledPg, passing the following parameters: mincached: the initial number of connections in the pool (the default of 0 means no connections are made at startup) maxcached: the maximum number of connections in the pool (the default value of 0 means unlimited pool size) maxconnections: maximum number of connections generally allowed (the default value of 0 means any number of connections) blocking: determines behavior when exceeding the maximum (the default of 0 or False means report an error; otherwise block and wait until the number of connections decreases) maxusage: maximum number of reuses of a single connection (the default of 0 or False means unlimited reuse) When this maximum usage number of the connection is reached, the connection is automatically reset (closed and reopened). setsession: an optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to german", ...] Additionally, you have to pass the parameters for the actual PostgreSQL connection which are passed via PyGreSQL, such as the names of the host, database, user, password etc. For instance, if you want a pool of at least five connections to your local database 'mydb': from DBUtils.PooledPg import PooledPg pool = PooledPg(5, dbname='mydb') Once you have set up the connection pool you can request database connections from that pool: db = pool.connection() You can use these connections just as if they were ordinary classic PyGreSQL API connections. Actually what you get is a proxy class for the hardened SteadyPg version of the connection. The connection will not be shared with other threads. If you don't need it any more, you should immediately return it to the pool with db.close(). You can get another connection in the same way or with db.reopen(). Warning: In a threaded environment, never do the following: res = pool.connection().query(...).getresult() This would release the connection too early for reuse which may be fatal because the connections are not thread-safe. Make sure that the connection object stays alive as long as you are using it, like that: db = pool.connection() res = db.query(...).getresult() db.close() # or del db Ideas for improvement: * Add thread for monitoring and restarting bad or expired connections (similar to DBConnectionPool/ResourcePool by Warren Smith). * Optionally log usage, bad connections and exceeding of limits. Copyright, credits and license: * Contributed as supplement for Webware for Python and PyGreSQL by Christoph Zwerschke in September 2005 * Based on the code of DBPool, contributed to Webware for Python by Dan Green in December 2000 Licensed under the Open Software License version 2.1. """ __version__ = '0.9.4' __revision__ = "$Rev: 6696 $" __date__ = "$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $" from Queue import Queue, Empty, Full from DBUtils.SteadyPg import SteadyPgConnection class PooledPgError(Exception): """General PooledPg error.""" class InvalidConnection(PooledPgError): """Database connection is invalid.""" class TooManyConnections(PooledPgError): """Too many database connections were opened.""" class PooledPg: """Pool for classic PyGreSQL connections. After you have created the connection pool, you can use connection() to get pooled, steady PostgreSQL connections. """ def __init__(self, mincached=0, maxcached=0, maxconnections=0, blocking=0, maxusage=0, setsession=None, *args, **kwargs): """Set up the PostgreSQL connection pool. mincached: initial number of connections in the pool (0 means no connections are made at startup) maxcached: maximum number of connections in the pool (0 means unlimited pool size) maxconnections: maximum number of connections generally allowed (0 means an arbitrary number of connections) blocking: determines behavior when exceeding the maximum (0 or False means report an error; otherwise block and wait until the number of connections decreases) maxusage: maximum number of reuses of a single connection (0 or False means unlimited reuse) When this maximum usage number of the connection is reached, the connection is automatically reset (closed and reopened). setsession: optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to ...", "set time zone ..."] args, kwargs: the parameters that shall be used to establish the PostgreSQL connections using class PyGreSQL pg.DB() """ self._args, self._kwargs = args, kwargs self._maxusage = maxusage self._setsession = setsession if maxcached: if maxcached < mincached: maxcached = mincached if maxconnections: if maxconnections < maxcached: maxconnections = maxcached # Create semaphore for number of allowed connections generally: from threading import Semaphore self._connections = Semaphore(maxconnections) self._blocking = blocking else: self._connections = None self._cache = Queue(maxcached) # the actual connection pool # Establish an initial number of database connections: [self.connection() for i in range(mincached)] def steady_connection(self): """Get a steady, unpooled PostgreSQL connection.""" return SteadyPgConnection(self._maxusage, self._setsession, *self._args, **self._kwargs) def connection(self): """"Get a steady, cached PostgreSQL connection from the pool.""" if self._connections: if not self._connections.acquire(self._blocking): raise TooManyConnections try: con = self._cache.get(0) except Empty: con = self.steady_connection() return PooledPgConnection(self, con) def cache(self, con): """Put a connection back into the pool cache.""" try: self._cache.put(con, 0) except Full: con.close() if self._connections: self._connections.release() def close(self): """Close all connections in the pool.""" while 1: try: self._cache.get(0).close() if self._connections: self._connections.release() except Empty: break def __del__(self): """Delete the pool.""" self.close() # Auxiliary class for pooled connections class PooledPgConnection: """Proxy class for pooled PostgreSQL connections.""" def __init__(self, pool, con): """Create a pooled DB-API 2 connection. pool: the corresponding PooledPg instance con: the underlying SteadyPg connection """ self._pool = pool self._con = con def close(self): """Close the pooled connection.""" # Instead of actually closing the connection, # return it to the pool so it can be reused. if self._con: self._pool.cache(self._con) self._con = None def reopen(self): """Reopen the pooled connection.""" # If the connection is already back in the pool, # get another connection from the pool, # otherwise reopen the unerlying connection. if self._con: self._con.reopen() else: self._con = self._pool.connection() def __getattr__(self, name): """Proxy all members of the class.""" if self._con: return getattr(self._con, name) else: raise InvalidConnection def __del__(self): """Delete the pooled connection.""" self.close() PK=M58Ólæ¾%¾%DBUtils/SimplePooledDB.pyo;ò õÇFc@sndZdZdZdZdefd„ƒYZdefd„ƒYZdfd „ƒYZd fd „ƒYZd S( s, SimplePooledDB - a very simple DB-API 2 database connection pool. Implements a pool of threadsafe cached DB-API 2 connections to a database which are transparently reused. This should result in a speedup for persistent applications such as the "Webware for Python" AppServer. For more information on the DB-API 2, see: http://www.python.org/peps/pep-0249.html For more information on Webware for Python, see: http://www.webwareforpython.org Measures are taken to make the pool of connections threadsafe regardless of whether the DB-API 2 module used is threadsafe on the connection level (threadsafety > 1) or not. It must only be threadsafe on the module level (threadsafety = 1). If the DB-API 2 module is threadsafe, the connections will be shared between threads (keep this in mind if you use transactions). Usage: The idea behind SimplePooledDB is that it's completely transparent. After you have established your connection pool, stating the DB-API 2 module to be used, the number of connections to be cached in the pool and the connection parameters, e.g. import pgdb # import used DB-API 2 module from DBUtils.SimplePooledDB import PooledDB dbpool = PooledDB(pgdb, 5, host=..., database=..., user=..., ...) you can demand database connections from that pool, db = dbpool.connection() and use them just as if they were ordinary DB-API 2 connections. It's really just a proxy class. db.close() will return the connection to the pool, it will not actually close it. This is so your existing code works nicely. Ideas for improvement: * Do not create the maximum number of connections on startup already, but only a certain number and the rest on demand. * Detect and transparently reset "bad" connections. * Connections should have some sort of maximum usage limit after which they should be automatically closed and reopened. * Prefer or enforce thread-affinity for the connections, allowing for both sharable and non-sharable connections. Please note that these and other ideas have been already implemented in in PooledDB, a more sophisticated version of SimplePooledDB. You might also consider using PersistentDB instead for thread-affine persistent database connections. SimplePooledDB may still serve as a very simple reference and example implementation for developers. Copyright, credits and license: * Contributed as MiscUtils/DBPool for Webware for Python by Dan Green, December 2000 * Thread safety bug found by Tom Schwaller * Fixes by Geoff Talvola (thread safety in _threadsafe_getConnection()) * Clean up by Chuck Esterbrook * Fix unthreadsafe functions which were leaking, Jay Love * Eli Green's webware-discuss comments were lifted for additional docs * Clean-up and detailed commenting, rename and move to DBUtils by Christoph Zwerschke in September 2005 Licensed under the Open Software License version 2.1. s0.9.4s $Rev: 6696 $s5$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $s PooledDBErrorcBstZdZRS(sGeneral PooledDB error.(s__name__s __module__s__doc__(((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys PooledDBErrorQs sNotSupportedErrorcBstZdZRS(s(DB-API module not supported by PooledDB.(s__name__s __module__s__doc__(((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pysNotSupportedErrorTs sPooledDBConnectioncBs2tZdZd„Zd„Zd„Zd„ZRS(sA proxy class for pooled database connections. You don't normally deal with this class directly, but use PooledDB to get new connections. cCs||_||_dS(N(sconsselfs_conspools_pool(sselfspoolscon((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys__init__`s cCs4|itj o |ii|iƒt|_ndS(sClose the pooled connection.N(sselfs_consNones_poolsreturnConnection(sself((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pysclosedscCst|i|ƒSdS(N(sgetattrsselfs_consname(sselfsname((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys __getattr__lscCs|iƒdS(N(sselfsclose(sself((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys__del__ps(s__name__s __module__s__doc__s__init__scloses __getattr__s__del__(((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pysPooledDBConnectionXs    sPooledDBcBsMtZdZd„Zd„Zd„Zd„Zd„Zd„Zd„Z RS(sˆA very simple database connection pool. After you have created the connection pool, you can get connections using getConnection(). c Os=y |i}Wntj o t}nX|djotdƒ‚nÄ|djoDdkl}||ƒ|_|i |_ |i |_ |i |_ns|ddfjoSdkl}|ƒ|_d|_g|_|i|_ |i|_ |i|_n tdƒ‚x-t|ƒD]}|i |i||ŽƒqWd S( s Set up the database connection pool. dbapi: the DB-API 2 compliant module you want to use maxconnections: the number of connections cached in the pool args, kwargs: the parameters that shall be used to establish the database connections using connect() is8Database module does not support any level of threading.i(sQueueii(sLocks7Database module threading support cannot be determined.N(sdbapis threadsafetys ExceptionsNonesNotSupportedErrorsQueuesmaxconnectionssselfs_queues_unthreadsafe_get_connections connections_unthreadsafe_add_connections addConnections_unthreadsafe_return_connectionsreturnConnections threadingsLocks_locks_nextConnections _connectionss_threadsafe_get_connections_threadsafe_add_connections_threadsafe_return_connectionsrangesisconnectsargsskwargs( sselfsdbapismaxconnectionssargsskwargssisLocksQueues threadsafety((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys__init__|s2               cCst||iiƒƒSdS(s "Get a connection from the pool.N(sPooledDBConnectionsselfs_queuesget(sself((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys_unthreadsafe_get_connection®scCs|ii|ƒdS(s"Add a connection to the pool.N(sselfs_queuesputscon(sselfscon((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys_unthreadsafe_add_connection²scCs|i|ƒdS(s"Return a connection to the pool. In this case, the connections need to be put back into the queue after they have been used. This is done automatically when the connection is closed and should never be called explicitly outside of this module. N(sselfs_unthreadsafe_add_connectionscon(sselfscon((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys_unthreadsafe_return_connection¶scCs||iiƒzZ|i}t||i|ƒ}|d7}|t|iƒjo d}n||_|SWd|ii ƒXdS(s "Get a connection from the pool.iiN( sselfs_locksacquires_nextConnectionsnextsPooledDBConnections _connectionssconslensrelease(sselfsconsnext((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys_threadsafe_get_connectionÆs     cCs|ii|ƒdS(s"Add a connection to the pool.N(sselfs _connectionssappendscon(sselfscon((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys_threadsafe_add_connectionÔscCsdS(s‰Return a connection to the pool. In this case, the connections always stay in the pool, so there is no need to do anything here. N((sselfscon((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys_threadsafe_return_connectionØs( s__name__s __module__s__doc__s__init__s_unthreadsafe_get_connections_unthreadsafe_add_connections_unthreadsafe_return_connections_threadsafe_get_connections_threadsafe_add_connections_threadsafe_return_connection(((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pysPooledDBts  2     N( s__doc__s __version__s __revision__s__date__s Exceptions PooledDBErrorsNotSupportedErrorsPooledDBConnectionsPooledDB(s PooledDBErrors __revision__sNotSupportedErrorsPooledDBs__date__sPooledDBConnections __version__((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys?JsPK¼hç6ËØ©½½DBUtils/__init__.py# DBUtils package __all__ = [ 'SimplePooledPg', 'SteadyPg', 'PooledPg', 'PersistentPg', 'SimplePooledDB', 'SteadyDB', 'PooledDB', 'PersistentDB' ] def InstallInWebKit(appServer): pass PK¼hç6yÓ~ÎÍÍDBUtils/SimplePooledDB.py"""SimplePooledDB - a very simple DB-API 2 database connection pool. Implements a pool of threadsafe cached DB-API 2 connections to a database which are transparently reused. This should result in a speedup for persistent applications such as the "Webware for Python" AppServer. For more information on the DB-API 2, see: http://www.python.org/peps/pep-0249.html For more information on Webware for Python, see: http://www.webwareforpython.org Measures are taken to make the pool of connections threadsafe regardless of whether the DB-API 2 module used is threadsafe on the connection level (threadsafety > 1) or not. It must only be threadsafe on the module level (threadsafety = 1). If the DB-API 2 module is threadsafe, the connections will be shared between threads (keep this in mind if you use transactions). Usage: The idea behind SimplePooledDB is that it's completely transparent. After you have established your connection pool, stating the DB-API 2 module to be used, the number of connections to be cached in the pool and the connection parameters, e.g. import pgdb # import used DB-API 2 module from DBUtils.SimplePooledDB import PooledDB dbpool = PooledDB(pgdb, 5, host=..., database=..., user=..., ...) you can demand database connections from that pool, db = dbpool.connection() and use them just as if they were ordinary DB-API 2 connections. It's really just a proxy class. db.close() will return the connection to the pool, it will not actually close it. This is so your existing code works nicely. Ideas for improvement: * Do not create the maximum number of connections on startup already, but only a certain number and the rest on demand. * Detect and transparently reset "bad" connections. * Connections should have some sort of maximum usage limit after which they should be automatically closed and reopened. * Prefer or enforce thread-affinity for the connections, allowing for both sharable and non-sharable connections. Please note that these and other ideas have been already implemented in in PooledDB, a more sophisticated version of SimplePooledDB. You might also consider using PersistentDB instead for thread-affine persistent database connections. SimplePooledDB may still serve as a very simple reference and example implementation for developers. Copyright, credits and license: * Contributed as MiscUtils/DBPool for Webware for Python by Dan Green, December 2000 * Thread safety bug found by Tom Schwaller * Fixes by Geoff Talvola (thread safety in _threadsafe_getConnection()) * Clean up by Chuck Esterbrook * Fix unthreadsafe functions which were leaking, Jay Love * Eli Green's webware-discuss comments were lifted for additional docs * Clean-up and detailed commenting, rename and move to DBUtils by Christoph Zwerschke in September 2005 Licensed under the Open Software License version 2.1. """ __version__ = '0.9.4' __revision__ = "$Rev: 6696 $" __date__ = "$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $" class PooledDBError(Exception): """General PooledDB error.""" class NotSupportedError(PooledDBError): """DB-API module not supported by PooledDB.""" class PooledDBConnection: """A proxy class for pooled database connections. You don't normally deal with this class directly, but use PooledDB to get new connections. """ def __init__(self, pool, con): self._con = con self._pool = pool def close(self): """Close the pooled connection.""" # Instead of actually closing the connection, # return it to the pool so it can be reused. if self._con is not None: self._pool.returnConnection(self._con) self._con = None def __getattr__(self, name): # All other members are the same. return getattr(self._con, name) def __del__(self): self.close() class PooledDB: """A very simple database connection pool. After you have created the connection pool, you can get connections using getConnection(). """ def __init__(self, dbapi, maxconnections, *args, **kwargs): """Set up the database connection pool. dbapi: the DB-API 2 compliant module you want to use maxconnections: the number of connections cached in the pool args, kwargs: the parameters that shall be used to establish the database connections using connect() """ try: threadsafety = dbapi.threadsafety except Exception: threadsafety = None if threadsafety == 0: raise NotSupportedError( "Database module does not support any level of threading.") elif threadsafety == 1: # If there is no connection level safety, build # the pool using the synchronized queue class # that implements all the required locking semantics. from Queue import Queue self._queue = Queue(maxconnections) # create the queue self.connection = self._unthreadsafe_get_connection self.addConnection = self._unthreadsafe_add_connection self.returnConnection = self._unthreadsafe_return_connection elif threadsafety in (2, 3): # If there is connection level safety, implement the # pool with an ordinary list used as a circular buffer. # We only need a minimum of locking in this case. from threading import Lock self._lock = Lock() # create a lock object to be used later self._nextConnection = 0 # index of the next connection to be used self._connections = [] # the list of connections self.connection = self._threadsafe_get_connection self.addConnection = self._threadsafe_add_connection self.returnConnection = self._threadsafe_return_connection else: raise NotSupportedError( "Database module threading support cannot be determined.") # Establish all database connections (it would be better to # only establish a part of them now, and the rest on demand). for i in range(maxconnections): self.addConnection(dbapi.connect(*args, **kwargs)) # The following functions are used with DB-API 2 modules # that do not have connection level threadsafety, like PyGreSQL. # However, the module must be threadsafe at the module level. # Note: threadsafe/unthreadsafe refers to the DB-API 2 module, # not to this class which should be threadsafe in any case. def _unthreadsafe_get_connection(self): """"Get a connection from the pool.""" return PooledDBConnection(self, self._queue.get()) def _unthreadsafe_add_connection(self, con): """"Add a connection to the pool.""" self._queue.put(con) def _unthreadsafe_return_connection(self, con): """"Return a connection to the pool. In this case, the connections need to be put back into the queue after they have been used. This is done automatically when the connection is closed and should never be called explicitly outside of this module. """ self._unthreadsafe_add_connection(con) # The following functions are used with DB-API 2 modules # that are threadsafe at the connection level, like psycopg. # Note: In this case, connections are shared between threads. # This may lead to problems if you use transactions. def _threadsafe_get_connection(self): """"Get a connection from the pool.""" self._lock.acquire() try: next = self._nextConnection con = PooledDBConnection(self, self._connections[next]) next += 1 if next >= len(self._connections): next = 0 self._nextConnection = next return con finally: self._lock.release() def _threadsafe_add_connection(self, con): """"Add a connection to the pool.""" self._connections.append(con) def _threadsafe_return_connection(self, con): """Return a connection to the pool. In this case, the connections always stay in the pool, so there is no need to do anything here. """ pass PK9M58Çòó$º/º/DBUtils/PersistentDB.pyc;ò õÇFc@sÝdZdZdZdZdklZdefd„ƒYZdefd„ƒYZd fd „ƒYZ yd k l Z Wnae j oUd k l Z lZlZd efd„ƒYZd„Zdefd„ƒYZ nXdS(sPersistentDB - persistent DB-API 2 connections. Implements steady, thread-affine persistent connections to a database based on an arbitrary DB-API 2 compliant database interface module. This should result in a speedup for persistent applications such as the application server of "Webware for Python," without loss of robustness. Robustness is provided by using "hardened" SteadyDB connections. Even if the underlying database is restarted and all connections are lost, they will be automatically and transparently reopened. Measures are taken to make the database connections thread-affine. This means the same thread always uses the same cached connection, and no other thread will use it. So even if the underlying DB-API module is not thread-safe at the connection level this will be no problem here. For best performance, the application server should keep threads persistent. For this, you have to set MinServerThreads = MaxServerThreads in Webware. For the Python DB-API 2 specification, see: http://www.python.org/peps/pep-0249.html For information on Webware for Python, see: http://www.webwareforpython.org Usage: First you need to set up a generator for your kind of database connections by creating an instance of PersistentDB, passing the following parameters: creator: either an arbitrary function returning new DB-API 2 connection objects or a DB-API 2 compliant database module maxusage: the maximum number of reuses of a single connection (the default of 0 or False means unlimited reuse) Whenever the limit is reached, the connection will be reset. setsession: an optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to german", ...]. The creator function or the connect function of the DB-API 2 compliant database module specified as the creator will receive any additional parameters such as the host, database, user, password etc. You may choose some or all of these parameters in your own creator function, allowing for sophisticated failover and load-balancing mechanisms. For instance, if you are using pgdb as your DB-API 2 database module and want every connection to your local database 'mydb' to be reused 1000 times: import pgdb # import used DB-API 2 module from DBUtils.PersistentDB import PersistentDB persist = PersistentDB(pgdb, 1000, database='mydb') Once you have set up the generator with these parameters, you can request database connections of that kind: db = persist.connection() You can use these connections just as if they were ordinary DB-API 2 connections. Actually what you get is the hardened SteadyDB version of the underlying DB-API 2 connection. Closing a persistent connection with db.close() will be silently ignored since it would be reopened at the next usage anyway and contrary to the intent of having persistent connections. Instead, the connection will be automatically closed when the thread dies. You can change this behavior be setting persist._closeable to True. Requirements: Minimum requirement: Python 2.2. Recommended: Python 2.4.3. Ideas for improvement: * Add thread for monitoring and restarting bad or expired connections (similar to DBConnectionPool/ResourcePool by Warren Smith). * Optionally log usage, bad connections and exceeding of limits. Copyright, credits and license: * Contributed as supplement for Webware for Python and PyGreSQL by Christoph Zwerschke in September 2005 * Based on an idea presented on the Webware developer mailing list by Geoffrey Talvola in July 2005 Licensed under the Open Software License version 2.1. s0.9.4s $Rev: 6696 $s5$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $(sconnectsPersistentDBErrorcBstZdZRS(sGeneral PersistentDB error.(s__name__s __module__s__doc__(((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentDB.pysPersistentDBErrorcs sNotSupportedErrorcBstZdZRS(s,DB-API module not supported by PersistentDB.(s__name__s __module__s__doc__(((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentDB.pysNotSupportedErrorfs s PersistentDBcBs2tZdZded„Zd„Zdd„ZRS(s¬Generator for persistent DB-API 2 connections. After you have created the connection pool, you can use connection() to get thread-affine, steady DB-API 2 connections. icOsÄy |i}WnPtj oDy!t|iƒodpd}Wq`tj o d}q`XnX| otdƒ‚n||_||_ ||_ ||f\|_|_d|_tƒ|_dS(söSet up the persistent DB-API 2 connection generator. creator: either an arbitrary function returning new DB-API 2 connection objects or a DB-API 2 compliant database module maxusage: maximum number of reuses of a single connection (number of database operations, 0 or False means unlimited) Whenever the limit is reached, the connection will be reset. setsession: optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to ...", "set time zone ..."] args, kwargs: the parameters that shall be passed to the creator function or the connection constructor of the DB-API 2 module Set the _closeable attribute to True or 1 to allow closing connections. By default, this will be silently ignored. iis#Database module is not thread-safe.N(screators threadsafetysAttributeErrorscallablesconnectsNotSupportedErrorsselfs_creatorsmaxusages _maxusages setsessions _setsessionsargsskwargss_argss_kwargss _closeableslocalsthread(sselfscreatorsmaxusages setsessionsargsskwargss threadsafety((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentDB.pys__init__rs  !    cCs)t|i|i|i|i|iŽSdS(s1Get a steady, non-persistent DB-API 2 connection.N(sconnectsselfs_creators _maxusages _setsessions_argss_kwargs(sself((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentDB.pyssteady_connection”s cCspy|ii}WnUtj oI|iƒ}|iƒ otdƒ‚n|i|_||i_nX|SdS(såGet a steady, persistent DB-API 2 connection. The shareable parameter exists only for compatibility with the PooledDB connection method. In reality, persistent connections are of course never shared with other threads. s#Database module is not thread-safe.N( sselfsthreads connectionsconsAttributeErrorssteady_connections threadsafetysNotSupportedErrors _closeable(sselfs shareablescon((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentDB.pys connection™s  (s__name__s __module__s__doc__sNones__init__ssteady_connections connection(((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentDB.pys PersistentDBjs " (slocal(s currentThreads enumeratesRLocks _localbasecBs tZdddfZd„ZRS(Ns _local__keys _local__argss _local__lockcOsÈti|ƒ}ddtt|ƒƒf}ti|d|ƒti|d||fƒti|dt ƒƒ|p|o|i ti jot dƒ‚nti |dƒ}|tƒi|<|SdS(Ns _local__keys thread.local.s _local__argss _local__locks*Initialization arguments are not supporteds__dict__(sobjects__new__sclssselfsstrsidskeys __setattr__sargsskwargssRLocks__init__s TypeErrors__getattribute__sds currentThreads__dict__(sclssargsskwargssselfsdskey((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentDB.pys__new__²s!(s__name__s __module__s __slots__s__new__(((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentDB.pys _localbase°scCsÆti|dƒ}tƒii|ƒ}|tjo{h}|tƒi| 1) or not. It must only be threadsafe on the module level (threadsafety = 1). If the DB-API 2 module is threadsafe, the connections will be shared between threads (keep this in mind if you use transactions). Usage: The idea behind SimplePooledDB is that it's completely transparent. After you have established your connection pool, stating the DB-API 2 module to be used, the number of connections to be cached in the pool and the connection parameters, e.g. import pgdb # import used DB-API 2 module from DBUtils.SimplePooledDB import PooledDB dbpool = PooledDB(pgdb, 5, host=..., database=..., user=..., ...) you can demand database connections from that pool, db = dbpool.connection() and use them just as if they were ordinary DB-API 2 connections. It's really just a proxy class. db.close() will return the connection to the pool, it will not actually close it. This is so your existing code works nicely. Ideas for improvement: * Do not create the maximum number of connections on startup already, but only a certain number and the rest on demand. * Detect and transparently reset "bad" connections. * Connections should have some sort of maximum usage limit after which they should be automatically closed and reopened. * Prefer or enforce thread-affinity for the connections, allowing for both sharable and non-sharable connections. Please note that these and other ideas have been already implemented in in PooledDB, a more sophisticated version of SimplePooledDB. You might also consider using PersistentDB instead for thread-affine persistent database connections. SimplePooledDB may still serve as a very simple reference and example implementation for developers. Copyright, credits and license: * Contributed as MiscUtils/DBPool for Webware for Python by Dan Green, December 2000 * Thread safety bug found by Tom Schwaller * Fixes by Geoff Talvola (thread safety in _threadsafe_getConnection()) * Clean up by Chuck Esterbrook * Fix unthreadsafe functions which were leaking, Jay Love * Eli Green's webware-discuss comments were lifted for additional docs * Clean-up and detailed commenting, rename and move to DBUtils by Christoph Zwerschke in September 2005 Licensed under the Open Software License version 2.1. s0.9.4s $Rev: 6696 $s5$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $s PooledDBErrorcBstZdZRS(sGeneral PooledDB error.(s__name__s __module__s__doc__(((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys PooledDBErrorQs sNotSupportedErrorcBstZdZRS(s(DB-API module not supported by PooledDB.(s__name__s __module__s__doc__(((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pysNotSupportedErrorTs sPooledDBConnectioncBs2tZdZd„Zd„Zd„Zd„ZRS(sA proxy class for pooled database connections. You don't normally deal with this class directly, but use PooledDB to get new connections. cCs||_||_dS(N(sconsselfs_conspools_pool(sselfspoolscon((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys__init__`s cCs4|itj o |ii|iƒt|_ndS(sClose the pooled connection.N(sselfs_consNones_poolsreturnConnection(sself((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pysclosedscCst|i|ƒSdS(N(sgetattrsselfs_consname(sselfsname((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys __getattr__lscCs|iƒdS(N(sselfsclose(sself((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys__del__ps(s__name__s __module__s__doc__s__init__scloses __getattr__s__del__(((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pysPooledDBConnectionXs    sPooledDBcBsMtZdZd„Zd„Zd„Zd„Zd„Zd„Zd„Z RS(sˆA very simple database connection pool. After you have created the connection pool, you can get connections using getConnection(). c Os=y |i}Wntj o t}nX|djotdƒ‚nÄ|djoDdkl}||ƒ|_|i |_ |i |_ |i |_ns|ddfjoSdkl}|ƒ|_d|_g|_|i|_ |i|_ |i|_n tdƒ‚x-t|ƒD]}|i |i||ŽƒqWd S( s Set up the database connection pool. dbapi: the DB-API 2 compliant module you want to use maxconnections: the number of connections cached in the pool args, kwargs: the parameters that shall be used to establish the database connections using connect() is8Database module does not support any level of threading.i(sQueueii(sLocks7Database module threading support cannot be determined.N(sdbapis threadsafetys ExceptionsNonesNotSupportedErrorsQueuesmaxconnectionssselfs_queues_unthreadsafe_get_connections connections_unthreadsafe_add_connections addConnections_unthreadsafe_return_connectionsreturnConnections threadingsLocks_locks_nextConnections _connectionss_threadsafe_get_connections_threadsafe_add_connections_threadsafe_return_connectionsrangesisconnectsargsskwargs( sselfsdbapismaxconnectionssargsskwargssisLocksQueues threadsafety((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys__init__|s2               cCst||iiƒƒSdS(s "Get a connection from the pool.N(sPooledDBConnectionsselfs_queuesget(sself((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys_unthreadsafe_get_connection®scCs|ii|ƒdS(s"Add a connection to the pool.N(sselfs_queuesputscon(sselfscon((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys_unthreadsafe_add_connection²scCs|i|ƒdS(s"Return a connection to the pool. In this case, the connections need to be put back into the queue after they have been used. This is done automatically when the connection is closed and should never be called explicitly outside of this module. N(sselfs_unthreadsafe_add_connectionscon(sselfscon((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys_unthreadsafe_return_connection¶scCs||iiƒzZ|i}t||i|ƒ}|d7}|t|iƒjo d}n||_|SWd|ii ƒXdS(s "Get a connection from the pool.iiN( sselfs_locksacquires_nextConnectionsnextsPooledDBConnections _connectionssconslensrelease(sselfsconsnext((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys_threadsafe_get_connectionÆs     cCs|ii|ƒdS(s"Add a connection to the pool.N(sselfs _connectionssappendscon(sselfscon((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys_threadsafe_add_connectionÔscCsdS(s‰Return a connection to the pool. In this case, the connections always stay in the pool, so there is no need to do anything here. N((sselfscon((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys_threadsafe_return_connectionØs( s__name__s __module__s__doc__s__init__s_unthreadsafe_get_connections_unthreadsafe_add_connections_unthreadsafe_return_connections_threadsafe_get_connections_threadsafe_add_connections_threadsafe_return_connection(((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pysPooledDBts  2     N( s__doc__s __version__s __revision__s__date__s Exceptions PooledDBErrorsNotSupportedErrorsPooledDBConnectionsPooledDB(s PooledDBErrors __revision__sNotSupportedErrorsPooledDBs__date__sPooledDBConnections __version__((s:build/bdist.darwin-8.0.1-x86/egg/DBUtils/SimplePooledDB.pys?JsPK¼hç6Œ-àšÄ7Ä7DBUtils/PooledDB.py"""PooledDB - pooling for DB-API 2 connections. Implements a pool of steady, thread-safe cached connections to a database which are transparently reused, using an arbitrary DB-API 2 compliant database interface module. This should result in a speedup for persistent applications such as the application server of "Webware for Python," without loss of robustness. Robustness is provided by using "hardened" SteadyDB connections. Even if the underlying database is restarted and all connections are lost, they will be automatically and transparently reopened. Measures are taken to make the pool of connections thread-safe. If the underlying DB-API module is thread-safe at the connection level, the requested connections may be shared with other threads by default, but you can also request dedicated connections in case you need them. For the Python DB-API 2 specification, see: http://www.python.org/peps/pep-0249.html For information on Webware for Python, see: http://www.webwareforpython.org Usage: First you need to set up the database connection pool by creating an instance of PooledDB, passing the following parameters: creator: either an arbitrary function returning new DB-API 2 connection objects or a DB-API 2 compliant database module mincached: the initial number of idle connections in the pool (the default of 0 means no connections are made at startup) maxcached: the maximum number of idle connections in the pool (the default value of 0 means unlimited pool size) maxshared: maximum number of shared connections allowed (the default value of 0 means all connections are dedicated) When this maximum number is reached, connections are shared if they have been requested as shareable. maxconnections: maximum number of connections generally allowed (the default value of 0 means any number of connections) blocking: determines behavior when exceeding the maximum (the default of 0 or False means report an error; otherwise block and wait until the number of connections decreases) maxusage: maximum number of reuses of a single connection (the default of 0 or False means unlimited reuse) When this maximum usage number of the connection is reached, the connection is automatically reset (closed and reopened). setsession: an optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to german", ...] The creator function or the connect function of the DB-API 2 compliant database module specified as the creator will receive any additional parameters such as the host, database, user, password etc. You may choose some or all of these parameters in your own creator function, allowing for sophisticated failover and load-balancing mechanisms. For instance, if you are using pgdb as your DB-API 2 database module and want a pool of at least five connections to your local database 'mydb': import pgdb # import used DB-API 2 module from DBUtils.PooledDB import PooledDB pool = PooledDB(pgdb, 5, database='mydb') Once you have set up the connection pool you can request database connections from that pool: db = pool.connection() You can use these connections just as if they were ordinary DB-API 2 connections. Actually what you get is the hardened SteadyDB version of the underlying DB-API 2 connection. Please note that the connection may be shared with other threads by default if you set a non-zero maxshared parameter and the DB-API 2 module allows this. If you want to have a dedicated connection, use: db = pool.connection(0) If you don't need it any more, you should immediately return it to the pool with db.close(). You can get another connection in the same way. Warning: In a threaded environment, never do the following: pool.connection().cursor().execute(...) This would release the connection too early for reuse which may be fatal if the connections are not thread-safe. Make sure that the connection object stays alive as long as you are using it, like that: db = pool.connection() cur = db.cursor() cur.execute(...) res = cur.fetchone() cur.close() # or del cur db.close() # or del db Ideas for improvement: * Add thread for monitoring and restarting bad or expired connections (similar to DBConnectionPool/ResourcePool by Warren Smith). * Optionally log usage, bad connections and exceeding of limits. Copyright, credits and license: * Contributed as supplement for Webware for Python and PyGreSQL by Christoph Zwerschke in September 2005 * Based on the code of DBPool, contributed to Webware for Python by Dan Green in December 2000 Licensed under the Open Software License version 2.1. """ __version__ = '0.9.4' __revision__ = "$Rev: 6696 $" __date__ = "$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $" from threading import Condition from DBUtils.SteadyDB import connect class PooledDBError(Exception): """General PooledDB error.""" class InvalidConnection(PooledDBError): """Database connection is invalid.""" class NotSupportedError(PooledDBError): """DB-API module not supported by PooledDB.""" class TooManyConnections(PooledDBError): """Too many database connections were opened.""" class PooledDB: """Pool for DB-API 2 connections. After you have created the connection pool, you can use connection() to get pooled, steady DB-API 2 connections. """ def __init__(self, creator, mincached=0, maxcached=0, maxshared=0, maxconnections=0, blocking=0, maxusage=0, setsession=None, *args, **kwargs): """Set up the DB-API 2 connection pool. creator: either an arbitrary function returning new DB-API 2 connection objects or a DB-API 2 compliant database module mincached: initial number of idle connections in the pool (0 means no connections are made at startup) maxcached: maximum number of idle connections in the pool (0 means unlimited pool size) maxshared: maximum number of shared connections (0 means all connections are dedicated) When this maximum number is reached, connections are shared if they have been requested as shareable. maxconnections: maximum number of connections generally allowed (0 means an arbitrary number of connections) blocking: determines behavior when exceeding the maximum (0 or False means report an error; otherwise block and wait until the number of connections decreases) maxusage: maximum number of reuses of a single connection (0 or False means unlimited reuse) When this maximum usage number of the connection is reached, the connection is automatically reset (closed and reopened). setsession: optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to ...", "set time zone ..."] args, kwargs: the parameters that shall be passed to the creator function or the connection constructor of the DB-API 2 module """ try: threadsafety = creator.threadsafety except AttributeError: try: threadsafety = callable(creator.connect) and 0 or 2 except AttributeError: threadsafety = 2 if not threadsafety: raise NotSupportedError("Database module is not thread-safe.") self._creator = creator self._args, self._kwargs = args, kwargs self._maxusage = maxusage self._setsession = setsession if maxcached: if maxcached < mincached: maxcached = mincached self._maxcached = maxcached else: self._maxcached = 0 if threadsafety > 1 and maxshared: self._maxshared = maxshared self._shared_cache = [] # the cache for shared connections else: self._maxshared = 0 if maxconnections: if maxconnections < maxcached: maxconnections = maxcached if maxconnections < maxshared: maxconnections = maxshared self._maxconnections = maxconnections else: self._maxconnections = 0 self._idle_cache = [] # the actual pool of idle connections self._connections = 0 self._condition = Condition() if not blocking: def wait(): raise TooManyConnections self._condition.wait = wait # Establish an initial number of idle database connections: [self.connection(0) for i in range(mincached)] def steady_connection(self): """Get a steady, unpooled DB-API 2 connection.""" return connect(self._creator, self._maxusage, self._setsession, *self._args, **self._kwargs) def connection(self, shareable=1): """"Get a steady, cached DB-API 2 connection from the pool. If shareable is set and the underlying DB-API 2 allows it, then the connection may be shared with other threads. """ if shareable and self._maxshared: self._condition.acquire() try: while not self._shared_cache and self._maxconnections \ and self._connections >= self._maxconnections: self._condition.wait() if len(self._shared_cache) < self._maxshared: # shared cache is not full, get a dedicated connection try: # first try to get it from the idle cache con = self._idle_cache.pop(0) except IndexError: # else get a fresh connection con = self.steady_connection() con = SharedDBConnection(con) self._connections += 1 else: # shared cache full or no more connections allowed self._shared_cache.sort() # least shared connection first con = self._shared_cache.pop(0) # get it con.share() # increase share of this connection # put the connection (back) into the shared cache self._shared_cache.append(con) self._condition.notify() finally: self._condition.release() con = PooledSharedDBConnection(self, con) else: # try to get a dedicated connection self._condition.acquire() try: while self._maxconnections \ and self._connections >= self._maxconnections: self._condition.wait() # connection limit not reached, get a dedicated connection try: # first try to get it from the idle cache con = self._idle_cache.pop(0) except IndexError: # else get a fresh connection con = self.steady_connection() con = PooledDedicatedDBConnection(self, con) self._connections += 1 finally: self._condition.release() return con def unshare(self, con): """Decrease the share of a connection in the shared cache.""" self._condition.acquire() try: con.unshare() shared = con.shared if not shared: # connection is idle, try: # so try to remove it self._shared_cache.remove(con) # from shared cache except ValueError: pass # pool has already been closed finally: self._condition.release() if not shared: # connection has become idle, self.cache(con.con) # so add it to the idle cache def cache(self, con): """Put a dedicated connection back into the idle cache.""" self._condition.acquire() try: if not self._maxcached or len(self._idle_cache) < self._maxcached: # the idle cache is not full, so put it there, but try: # before returning the connection back to the pool, con.rollback() # perform a rollback # in order to prevent uncommited actions from being # unintentionally commited by some other thread except Exception: # if an error occurs (no transaction, not supported) pass # then it will be silently ignored self._idle_cache.append(con) # append it to the idle cache else: # if the idle cache is already full, con.close() # then close the connection self._connections -= 1 self._condition.notify() finally: self._condition.release() def close(self): """Close all connections in the pool.""" self._condition.acquire() try: while self._idle_cache: # close all idle connections self._idle_cache.pop(0).close() self._connections -= 1 if self._maxshared: # close all shared connections while self._shared_cache: self._shared_cache.pop(0).con.close() self._connections -= 1 self._condition.notifyAll() finally: self._condition.release() def __del__(self): """Delete the pool.""" if hasattr(self, '_connections'): self.close() # Auxiliary classes for pooled connections class PooledDedicatedDBConnection: """Auxiliary proxy class for pooled dedicated connections.""" def __init__(self, pool, con): """Create a pooled dedicated connection. pool: the corresponding PooledDB instance con: the underlying SteadyDB connection """ if not con.threadsafety(): raise NotSupportedError("Database module is not thread-safe.") self._pool = pool self._con = con def close(self): """Close the pooled dedicated connection.""" # Instead of actually closing the connection, # return it to the pool for future reuse. if self._con: self._pool.cache(self._con) self._con = None def __getattr__(self, name): """Proxy all members of the class.""" if self._con: return getattr(self._con, name) else: raise InvalidConnection def __del__(self): """Delete the pooled connection.""" self.close() class SharedDBConnection: """Auxiliary class for shared connections.""" def __init__(self, con): """Create a shared connection. con: the underlying SteadyDB connection """ self.con = con self.shared = 1 def __cmp__(self, other): """Compare how often the connections are shared.""" return self.shared - other.shared def share(self): """Increase the share of this connection.""" self.shared += 1 def unshare(self): """Decrease the share of this connection.""" self.shared -= 1 class PooledSharedDBConnection: """Auxiliary proxy class for pooled shared connections.""" def __init__(self, pool, shared_con): """Create a pooled shared connection. pool: the corresponding PooledDB instance con: the underlying SharedDBConnection """ con = shared_con.con if not con.threadsafety() > 1: raise NotSupportedError("Database connection is not thread-safe.") self._pool = pool self._shared_con = shared_con self._con = con def close(self): """Close the pooled shared connection.""" # Instead of actually closing the connection, # unshare it and/or return it to the pool. if self._con: self._pool.unshare(self._shared_con) self._shared_con = self._con = None def __getattr__(self, name): """Proxy all members of the class.""" if self._con: return getattr(self._con, name) else: raise InvalidConnection def __del__(self): """Delete the pooled connection.""" self.close() PK¼hç6²­ÿRRDBUtils/PersistentPg.py"""PersistentPg - persistent classic PyGreSQL connections. Implements steady, thread-affine persistent connections to a PostgreSQL database using the classic (not DB-API 2 compliant) PyGreSQL API. This should result in a speedup for persistent applications such as the application server of "Webware for Python," without loss of robustness. Robustness is provided by using "hardened" SteadyPg connections. Even if the underlying database is restarted and all connections are lost, they will be automatically and transparently reopened. Measures are taken to make the database connections thread-affine. This means the same thread always uses the same cached connection, and no other thread will use it. So the fact that the classic PyGreSQL pg module is not thread-safe at the connection level is no problem here. For best performance, the application server should keep threads persistent. For this, you have to set MinServerThreads = MaxServerThreads in Webware. For more information on PostgreSQL, see: http://www.postgresql.org For more information on PyGreSQL, see: http://www.pygresql.org For more information on Webware for Python, see: http://www.webwareforpython.org Usage: First you need to set up a generator for your kind of database connections by creating an instance of PersistentPg, passing the following parameters: maxusage: the maximum number of reuses of a single connection (the default of 0 or False means unlimited reuse) When this maximum usage number of the connection is reached, the connection is automatically reset (closed and reopened). setsession: An optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to german", ...] Additionally, you have to pass the parameters for the actual PostgreSQL connection which are passed via PyGreSQL, such as the names of the host, database, user, password etc. For instance, if you want every connection to your local database 'mydb' to be reused 1000 times: from DBUtils.PersistentPg import PersistentPg persist = PersistentPg(5, dbname='mydb') Once you have set up the generator with these parameters, you can request database connections of that kind: db = persist.connection() You can use these connections just as if they were ordinary classic PyGreSQL API connections. Actually what you get is the hardened SteadyPg version of a classic PyGreSQL connection. Closing a persistent connection with db.close() will be silently ignored since it would be reopened at the next usage anyway and contrary to the intent of having persistent connections. Instead, the connection will be automatically closed when the thread dies. You can change this behavior be setting persist._closeable to True. Requirements: Minimum requirement: Python 2.2 and PyGreSQL 3.4. Recommended: Python 2.4.3 and PyGreSQL 3.8. Ideas for improvement: * Add thread for monitoring and restarting bad or expired connections (similar to DBConnectionPool/ResourcePool by Warren Smith). * Optionally log usage, bad connections and exceeding of limits. Copyright, credits and license: * Contributed as supplement for Webware for Python and PyGreSQL by Christoph Zwerschke in September 2005 * Based on an idea presented on the Webware developer mailing list by Geoffrey Talvola in July 2005 Licensed under the Open Software License version 2.1. """ __version__ = '0.9.4' __revision__ = "$Rev: 6696 $" __date__ = "$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $" from DBUtils.SteadyPg import SteadyPgConnection class PersistentPg: """Generator for persistent classic PyGreSQL connections. After you have created the connection pool, you can use connection() to get thread-affine, steady PostgreSQL connections. """ def __init__(self, maxusage=0, setsession=None, *args, **kwargs): """Set up the persistent PostgreSQL connection generator. maxusage: maximum number of reuses of a single connection (0 or False means unlimited reuse) When this maximum usage number of the connection is reached, the connection is automatically reset (closed and reopened). setsession: optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to ...", "set time zone ..."] args, kwargs: the parameters that shall be used to establish the PostgreSQL connections using class PyGreSQL pg.DB() Set the _closeable attribute to True or 1 to allow closing connections. By default, this will be silently ignored. """ self._maxusage = maxusage self._setsession = setsession self._args, self._kwargs = args, kwargs self._closeable = 0 self.thread = local() def steady_connection(self): """Get a steady, non-persistent PyGreSQL connection.""" return SteadyPgConnection( self._maxusage, self._setsession, *self._args, **self._kwargs) def connection(self): """Get a steady, persistent PyGreSQL connection.""" try: con = self.thread.connection except AttributeError: con = self.steady_connection() con._closeable = self._closeable self.thread.connection = con return con try: # import a class for representing thread-local objects from threading import local except ImportError: # for Python < 2.4, use the following simple implementation from threading import currentThread, enumerate, RLock class _localbase(object): __slots__ = '_local__key', '_local__args', '_local__lock' def __new__(cls, *args, **kwargs): self = object.__new__(cls) key = '_local__key', 'thread.local.' + str(id(self)) object.__setattr__(self, '_local__key', key) object.__setattr__(self, '_local__args', (args, kwargs)) object.__setattr__(self, '_local__lock', RLock()) if args or kwargs and (cls.__init__ is object.__init__): raise TypeError("Initialization arguments are not supported") d = object.__getattribute__(self, '__dict__') currentThread().__dict__[key] = d return self def _patch(self): key = object.__getattribute__(self, '_local__key') d = currentThread().__dict__.get(key) if d is None: d = {} currentThread().__dict__[key] = d object.__setattr__(self, '__dict__', d) cls = type(self) if cls.__init__ is not object.__init__: args, kwargs = object.__getattribute__(self, '_local__args') cls.__init__(self, *args, **kwargs) else: object.__setattr__(self, '__dict__', d) class local(_localbase): def __getattribute__(self, name): lock = object.__getattribute__(self, '_local__lock') lock.acquire() try: _patch(self) return object.__getattribute__(self, name) finally: lock.release() def __setattr__(self, name, value): lock = object.__getattribute__(self, '_local__lock') lock.acquire() try: _patch(self) return object.__setattr__(self, name, value) finally: lock.release() def __delattr__(self, name): lock = object.__getattribute__(self, '_local__lock') lock.acquire() try: _patch(self) return object.__delattr__(self, name) finally: lock.release() def __del__(): threading_enumerate = enumerate __getattribute__ = object.__getattribute__ def __del__(self): try: key = __getattribute__(self, '_local__key') threads = list(threading_enumerate()) except Exception: return for thread in threads: try: __dict__ = thread.__dict__ except AttributeError: continue if key in __dict__: try: del __dict__[key] except KeyError: pass return __del__ __del__ = __del__() PK=M58ú5éê€,€,DBUtils/PooledPg.pyo;ò õÇFc@sªdZdZdZdZdklZlZlZdklZde fd„ƒYZ de fd „ƒYZ d e fd „ƒYZ d fd „ƒYZ dfd„ƒYZdS(sÄPooledPg - pooling for classic PyGreSQL connections. Implements a pool of steady, thread-safe cached connections to a PostgreSQL database which are transparently reused, using the classic (not DB-API 2 compliant) PyGreSQL API. This should result in a speedup for persistent applications such as the application server of "Webware for Python," without loss of robustness. Robustness is provided by using "hardened" SteadyPg connections. Even if the underlying database is restarted and all connections are lost, they will be automatically and transparently reopened. Measures are taken to make the pool of connections thread-safe regardless of the fact that the classic PyGreSQL pg module itself is not thread-safe at the connection level. For more information on PostgreSQL, see: http://www.postgresql.org For more information on PyGreSQL, see: http://www.pygresql.org For more information on Webware for Python, see: http://www.webwareforpython.org Usage: First you need to set up the database connection pool by creating an instance of PooledPg, passing the following parameters: mincached: the initial number of connections in the pool (the default of 0 means no connections are made at startup) maxcached: the maximum number of connections in the pool (the default value of 0 means unlimited pool size) maxconnections: maximum number of connections generally allowed (the default value of 0 means any number of connections) blocking: determines behavior when exceeding the maximum (the default of 0 or False means report an error; otherwise block and wait until the number of connections decreases) maxusage: maximum number of reuses of a single connection (the default of 0 or False means unlimited reuse) When this maximum usage number of the connection is reached, the connection is automatically reset (closed and reopened). setsession: an optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to german", ...] Additionally, you have to pass the parameters for the actual PostgreSQL connection which are passed via PyGreSQL, such as the names of the host, database, user, password etc. For instance, if you want a pool of at least five connections to your local database 'mydb': from DBUtils.PooledPg import PooledPg pool = PooledPg(5, dbname='mydb') Once you have set up the connection pool you can request database connections from that pool: db = pool.connection() You can use these connections just as if they were ordinary classic PyGreSQL API connections. Actually what you get is a proxy class for the hardened SteadyPg version of the connection. The connection will not be shared with other threads. If you don't need it any more, you should immediately return it to the pool with db.close(). You can get another connection in the same way or with db.reopen(). Warning: In a threaded environment, never do the following: res = pool.connection().query(...).getresult() This would release the connection too early for reuse which may be fatal because the connections are not thread-safe. Make sure that the connection object stays alive as long as you are using it, like that: db = pool.connection() res = db.query(...).getresult() db.close() # or del db Ideas for improvement: * Add thread for monitoring and restarting bad or expired connections (similar to DBConnectionPool/ResourcePool by Warren Smith). * Optionally log usage, bad connections and exceeding of limits. Copyright, credits and license: * Contributed as supplement for Webware for Python and PyGreSQL by Christoph Zwerschke in September 2005 * Based on the code of DBPool, contributed to Webware for Python by Dan Green in December 2000 Licensed under the Open Software License version 2.1. s0.9.4s $Rev: 6696 $s5$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $(sQueuesEmptysFull(sSteadyPgConnections PooledPgErrorcBstZdZRS(sGeneral PooledPg error.(s__name__s __module__s__doc__(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledPg.pys PooledPgErrorns sInvalidConnectioncBstZdZRS(sDatabase connection is invalid.(s__name__s __module__s__doc__(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledPg.pysInvalidConnectionqs sTooManyConnectionscBstZdZRS(s*Too many database connections were opened.(s__name__s __module__s__doc__(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledPg.pysTooManyConnectionsts sPooledPgcBsVtZdZddddded„Zd„Zd„Zd„Zd„Zd„Z RS(sŸPool for classic PyGreSQL connections. After you have created the connection pool, you can use connection() to get pooled, steady PostgreSQL connections. ic Osà||f\|_|_||_||_|o||jo |}qLn|o@||jo |}ndk l } | |ƒ|_||_n t|_t|ƒ|_gi} t|ƒD]} | |iƒƒq¿~ dS(séSet up the PostgreSQL connection pool. mincached: initial number of connections in the pool (0 means no connections are made at startup) maxcached: maximum number of connections in the pool (0 means unlimited pool size) maxconnections: maximum number of connections generally allowed (0 means an arbitrary number of connections) blocking: determines behavior when exceeding the maximum (0 or False means report an error; otherwise block and wait until the number of connections decreases) maxusage: maximum number of reuses of a single connection (0 or False means unlimited reuse) When this maximum usage number of the connection is reached, the connection is automatically reset (closed and reopened). setsession: optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to ...", "set time zone ..."] args, kwargs: the parameters that shall be used to establish the PostgreSQL connections using class PyGreSQL pg.DB() (s SemaphoreN(sargsskwargssselfs_argss_kwargssmaxusages _maxusages setsessions _setsessions maxcacheds mincachedsmaxconnectionss threadings Semaphores _connectionssblockings _blockingsNonesQueues_cachesappends_[1]srangesis connection( sselfs mincacheds maxcachedsmaxconnectionssblockingsmaxusages setsessionsargsskwargssis_[1]s Semaphore((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledPg.pys__init__€s         cCs#t|i|i|i|iŽSdS(s-Get a steady, unpooled PostgreSQL connection.N(sSteadyPgConnectionsselfs _maxusages _setsessions_argss_kwargs(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledPg.pyssteady_connection­scCsx|io%|ii|iƒ o t‚q/ny|iidƒ}Wntj o|i ƒ}nXt ||ƒSdS(s:"Get a steady, cached PostgreSQL connection from the pool.iN( sselfs _connectionssacquires _blockingsTooManyConnectionss_cachesgetsconsEmptyssteady_connectionsPooledPgConnection(sselfscon((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledPg.pys connection²s cCsVy|ii|dƒWntj o|iƒnX|io|iiƒndS(s*Put a connection back into the pool cache.iN(sselfs_cachesputsconsFullscloses _connectionssrelease(sselfscon((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledPg.pyscache½s cCs_xXnoPy5|iidƒiƒ|io|iiƒnWqtj oPqXq WdS(s"Close all connections in the pool.iiN(sselfs_cachesgetscloses _connectionssreleasesEmpty(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledPg.pyscloseÆs cCs|iƒdS(sDelete the pool.N(sselfsclose(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledPg.pys__del__Ðs( s__name__s __module__s__doc__sNones__init__ssteady_connections connectionscachescloses__del__(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledPg.pysPooledPgxs -  sPooledPgConnectioncBs;tZdZd„Zd„Zd„Zd„Zd„ZRS(s.Proxy class for pooled PostgreSQL connections.cCs||_||_dS(sCreate a pooled DB-API 2 connection. pool: the corresponding PooledPg instance con: the underlying SteadyPg connection N(spoolsselfs_poolscons_con(sselfspoolscon((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledPg.pys__init__Ús cCs.|io |ii|iƒt|_ndS(sClose the pooled connection.N(sselfs_cons_poolscachesNone(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledPg.pyscloseäs cCs1|io|iiƒn|iiƒ|_dS(sReopen the pooled connection.N(sselfs_consreopens_pools connection(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledPg.pysreopenìs cCs(|iot|i|ƒSnt‚dS(sProxy all members of the class.N(sselfs_consgetattrsnamesInvalidConnection(sselfsname((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledPg.pys __getattr__ös cCs|iƒdS(sDelete the pooled connection.N(sselfsclose(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledPg.pys__del__ýs(s__name__s __module__s__doc__s__init__sclosesreopens __getattr__s__del__(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledPg.pysPooledPgConnection×s   N(s__doc__s __version__s __revision__s__date__sQueuesEmptysFullsDBUtils.SteadyPgsSteadyPgConnections Exceptions PooledPgErrorsInvalidConnectionsTooManyConnectionssPooledPgsPooledPgConnection( sQueues __revision__sPooledPgConnections__date__sTooManyConnectionssPooledPgsFulls PooledPgErrorsSteadyPgConnectionsInvalidConnections __version__sEmpty((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledPg.pys?cs _PK4M581RK??DBUtils/SteadyDB.pyc;ò õÇFc@sZdZdZdZdZdkZded„Zdfd„ƒYZd fd „ƒYZdS( s¡ SteadyDB - hardened DB-API 2 connections. Implements steady connections to a database based on an arbitrary DB-API 2 compliant database interface module. The connections are transparently reopened when they are closed or the database connection has been lost or when they are used more often than an optional usage limit. Database cursors are transparently reopened as well when the execution of a database operation cannot be performed due to a lost connection. Only if the connection is lost after the execution, when rows are already fetched from the database, this will give an error and the cursor will not be reopened automatically, because there is no reliable way to recover the state of the cursor in such a situation. A typical situation where database connections are lost is when the database server or an intervening firewall is shutdown and restarted for maintenance reasons. In such a case, all database connections would become unusable, even though the database service may be already available again. The "hardened" connections provided by this module will make the database connections immediately available again. This approach results in a steady database connection that can be used by PooledDB or PersistentDB to create pooled or persistent connections to a database in a threaded environment such as the application server of "Webware for Python." Note, however, that the connections themselves may not be thread-safe (depending on the used DB-API module). For the Python DB-API 2 specification, see: http://www.python.org/peps/pep-0249.html For information on Webware for Python, see: http://www.webwareforpython.org Usage: You can use the connection constructor connect() in the same way as you would use the connection constructor of a DB-API 2 module if you specify the DB-API 2 module to be used as the first parameter, or alternatively you can specify an arbitrary constructor function returning new DB-API 2 compliant connection objects as the first parameter. Passing just a function allows implementing failover mechanisms and load balancing strategies. You may also specify a usage limit as the second parameter (set it to 0 if you prefer unlimited usage), and an optional list of commands that may serve to prepare the session as a third parameter. When the connection to the database is lost or has been used too often, it will be transparently reset in most situations, without further notice. import pgdb # import used DB-API 2 module from DBUtils.SteadyDB import connect db = connect(pgdb, 10000, ["set datestyle to german"], host=..., database=..., user=..., ...) ... cursor = db.cursor() ... cursor.execute('select ...') result = cursor.fetchall() ... cursor.close() ... db.close() Ideas for improvement: * Alternatively to the maximum number of uses, implement a maximum time to live for connections. * Optionally log usage and loss of connection. Copyright, credits and license: * Contributed as supplement for Webware for Python and PyGreSQL by Christoph Zwerschke in September 2005 * Allowing creator functions as first parameter as in SQLAlchemy suggested by Ezio Vernacotola in December 2006 Licensed under the Open Software License version 2.1. s0.9.4s $Rev: 6696 $s5$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $NicOst|||||ŽSdS(sêA tough version of the connection constructor of a DB-API 2 module. creator: either an arbitrary function returning new DB-API 2 compliant connection objects or a DB-API 2 compliant database module maxusage: maximum usage limit for the underlying DB-API 2 connection (number of database operations, 0 or False means unlimited usage) callproc(), execute() and executemany() count as one operation When the limit is reached, the connection is automatically reset. setsession: an optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to german", "set time zone mez"] args, kwargs: the parameters that shall be passed to the creator function or the connection constructor of the DB-API 2 module N(sSteadyDBConnectionscreatorsmaxusages setsessionsargsskwargs(screatorsmaxusages setsessionsargsskwargs((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pysconnect`ssSteadyDBConnectioncBs’tZdZeZded„Zd„Zed„Zd„Z d„Z d„Z d„Z d „Z d „Zd „Zd „Zd „Zd„ZRS(s*A "tough" version of DB-API 2 connections.icOsy|i|_||_Wnutj oi||_y4ti|i|_|ii|jo t‚nWq‘tt fj ot |_q‘XnXt |iƒ ot d|fƒ‚n||_||_||f\|_|_d|_|i|iƒƒdS(s&"Create a "tough" DB-API 2 connection.s %r is not a connection provider.iN(screatorsconnectsselfs_creators_dbapisAttributeErrorssyssmoduless __module__sKeyErrorsNonescallables TypeErrorsmaxusages _maxusages setsessions_setsession_sqlsargsskwargss_argss_kwargss _closeables_stores_create(sselfscreatorsmaxusages setsessionsargsskwargs((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pys__init__ws&      cCs |i|i|iŽ}y¨y$|ii|ijo t‚nWnptj ody5ti |i |_t |iiƒ o t‚nWq²tt fj ot dƒ‚q²XnX|i|ƒWn?tj o3}y|iƒWntj onX|‚nX|SdS(s3Create a new connection using the creator function.s!Cannot determine DB-API 2 module.N(sselfs_creators_argss_kwargsscons_dbapisconnectsAttributeErrorssyssmoduless __module__scallablesKeyErrors TypeErrors _setsessions Exceptionserrorsclose(sselfserrorscon((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pys_createŒs* cCsc|tjo |i}n|io;|iƒ}x|iD]}|i|ƒq:W|iƒndS(s1Execute the SQL commands for session preparation.N( sconsNonesselfs_cons_setsession_sqlscursorssqlsexecutesclose(sselfsconscursorssql((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pys _setsession¥s     cCs||_t|_d|_dS(s/Store a database connection for subsequent use.iN(sconsselfs_consFalses_closeds_usage(sselfscon((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pys_store¯s  cCsC|i o4y|iiƒWntj onXt|_ndS(s–Close the tough connection. You can always close a tough connection with this method and it will not complain if you close it more than once. N(sselfs_closeds_conscloses ExceptionsTrue(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pys_closeµs cCs |iSdS(s8Return the underlying DB-API 2 module of the connection.N(sselfs_dbapi(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pysdbapiÃscCs,y|iiSWntj o dSnXdS(s1Return the thread safety level of the connection.iN(sselfs_dbapis threadsafetysAttributeError(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pys threadsafetyÇs cCs|io|iƒndS(s0Close the tough connection. You are allowed to close a tough connection by default and it will not complain if you close it more than once. You can disallow closing connections by setting the _closeable attribute to 0 or False. In this case, closing a connection will be silently ignored. N(sselfs _closeables_close(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pyscloseÎs  cCs|iiƒdS(sCommit any pending transaction.N(sselfs_conscommit(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pyscommitÜscCs|iiƒdS(sRollback pending transaction.N(sselfs_consrollback(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pysrollbackàscOsyJ|io'|i|ijo|ii‚q4n|ii||Ž}Wn¾|ii|ii fj o }y|i ƒ}Wnt j onmXy|i||Ž}Wnt j onX|iƒ|i|ƒ|Sy|iƒWnt j onX|‚nX|SdS(s)A "tough" version of the method cursor().N(sselfs _maxusages_usages_dbapisOperationalErrors_conscursorsargsskwargss InternalErrorserrors_createscon2s Exceptions_closes_storesclose(sselfsargsskwargsscon2scursorserror((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pys_cursoräs0 "   cOst|||ŽSdS(s0Return a new Cursor Object using the connection.N(sSteadyDBCursorsselfsargsskwargs(sselfsargsskwargs((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pyscursorscCs|iƒdS(sDelete the steady connection.N(sselfs_close(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pys__del__s(s__name__s __module__s__doc__sTrues_closedsNones__init__s_creates _setsessions_stores_closesdbapis threadsafetysclosescommitsrollbacks_cursorscursors__del__(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pysSteadyDBConnectionrs          sSteadyDBCursorcBsktZdZeZd„Zd„Zed„Zd„Z ed„Z d„Z d„Z d„Z d „ZRS( s&A "tough" version of DB-API 2 cursors.cOsM||_||f\|_|_|iƒ|i||Ž|_t |_ dS(s""Create a "tough" DB-API 2 cursor.N( sconsselfs_consargsskwargss_argss_kwargss _clearsizess_cursorsFalses_closed(sselfsconsargsskwargs((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pys__init__s   cCs ||_dS(s6Store input sizes in case cursor needs to be reopened.N(ssizessselfs _inputsize(sselfssizes((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pys setinputsizesscCsJ|itjp |tjo||fg|_n|ii||ƒdS(s7Store output sizes in case cursor needs to be reopened.N(sselfs _outputsizesNonescolumnssizesappend(sselfssizescolumn((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pys setoutputsizescCst|_|_dS(sClear stored input sizes.N(sNonesselfs _inputsizes _outputsize(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pys _clearsizes%scCsž|tjo |i}n|itj o|i|iƒn|itj oLxI|iD]:\}}|tjo|i |ƒqX|i ||ƒqXWndS(s7Set stored input and output sizes for cursor execution.N( scursorsNonesselfs_cursors _inputsizes setinputsizess _outputsizescolumnssizes setoutputsize(sselfscursorscolumnssize((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pys _setsizes)s    cCsC|i o4y|iiƒWntj onXt|_ndS(sSClose the tough cursor. It will not complain if you close it more than once. N(sselfs_closeds_cursorscloses ExceptionsTrue(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pysclose6s cs‡‡d†}|SdS(s'Return a "tough" version of the method.c s ˆidƒ}yŒˆiio0ˆiiˆiijoˆiii‚qOn|oˆi ƒnt ˆi ˆƒ}|||Ž}|oˆiƒnWnhˆiiiˆiiifj oD}yˆii ˆiˆiŽ}Wntj on´XyO|oˆi |ƒnt |ˆƒ}|||Ž}|oˆiƒnWntj on+Xˆiƒ|ˆ_ ˆiid7_|Sy|iƒWntj onXyˆiiƒ}Wntj on'Xy|iˆiˆiŽ}Wntj onÑXyO|oˆi |ƒnt |ˆƒ}|||Ž}|oˆiƒnWntj onHXˆiƒˆiiƒˆii|ƒ|ˆ_ ˆiid7_|Sy|iƒWntj onXy|iƒWntj onX|‚nXˆiid7_|SdS(Nsexecutei(snames startswithsexecutesselfs_cons _maxusages_usages_dbapisOperationalErrors _setsizessgetattrs_cursorsmethodsargsskwargssresults _clearsizess InternalErrorserrors_argss_kwargsscursor2s Exceptionscloses_createscon2scursorsmethod2s_closes_store( sargsskwargssexecuteserrorsmethod2scursor2scon2sresultsmethod(snamesself(s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pys tough_methodEs† (      N(s tough_method(sselfsnames tough_method((sselfsnames4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pys_get_tough_methodCsNcCsE|idƒp |idƒo|i|ƒSnt|i|ƒSdS(s4Inherit methods and attributes of underlying cursor.sexecutescallN(snames startswithsselfs_get_tough_methodsgetattrs_cursor(sselfsname((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pys __getattr__•s cCs|iƒdS(sDelete the steady cursor.N(sselfsclose(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pys__del__s(s__name__s __module__s__doc__sTrues_closeds__init__s setinputsizessNones setoutputsizes _clearsizess _setsizesscloses_get_tough_methods __getattr__s__del__(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pysSteadyDBCursor s      R ( s__doc__s __version__s __revision__s__date__ssyssNonesconnectsSteadyDBConnectionsSteadyDBCursor(ssyss __revision__s__date__sconnects __version__sSteadyDBCursorsSteadyDBConnection((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/SteadyDB.pys?Vs ›PK¼hç6*Çc·DBUtils/SteadyPg.py"""SteadyPg - hardened classic PyGreSQL connections. Implements steady connections to a PostgreSQL database using the classic (not DB-API 2 compliant) PyGreSQL API. The connections are transparently reopened when they are closed or the database connection has been lost or when they are used more often than an optional usage limit. A typical situation where database connections are lost is when the database server or an intervening firewall is shutdown and restarted for maintenance reasons. In such a case, all database connections would become unusuable, even though the database service may be already available again. The "hardened" connections provided by this module will make the database connections immediately available again. This results in a steady PostgreSQL connection that can be used by PooledPg or PersistentPg to create pooled or persistent connections to a PostgreSQL database in a threaded environment such as the application server of "Webware for Python." Note, however, that the connections themselves are not thread-safe. For more information on PostgreSQL, see: http://www.postgresql.org For more information on PyGreSQL, see: http://www.pygresql.org For more information on Webware for Python, see: http://www.webwareforpython.org Usage: You can use the class SteadyPgConnection in the same way as you would use the class DB from the classic PyGreSQL API module db. The only difference is that you may specify a usage limit as the first paramenter when you open a connection (set it to 0 if you prefer unlimited usage), and an optional list of commands that may serve to prepare the session as the second parameter. When the connection to the PostgreSQL database is lost or has been used too often, it will be automatically reset, without further notice. from DBUtils.SteadyPg import SteadyPgConnection db = SteadyPgConnection(10000, ["set datestyle to german"], host=..., dbname=..., user=..., ...) ... result = db.query('...') ... db.close() Ideas for improvement: * Alternatively to the maximum number of uses, implement a maximum time to live for connections. * Optionally log usage and loss of connection. Copyright, credits and license: * Contributed as supplement for Webware for Python and PyGreSQL by Christoph Zwerschke in September 2005 Licensed under the Open Software License version 2.1. """ __version__ = '0.9.4' __revision__ = "$Rev: 6696 $" __date__ = "$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $" from pg import DB as PgConnection class SteadyPgConnection: """Class representing steady connections to a PostgreSQL database. Underlying the connection is a classic PyGreSQL pg API database connection which is reset if the connection is lost or used too often. Thus the resulting connection is steadier ("tough and self-healing"). If you want the connection to be persistent in a threaded environment, then you should not deal with this class directly, but use either the PooledPg module or the PersistentPg module to get the connections. """ _closed = True def __init__(self, maxusage=0, setsession=None, *args, **kwargs): """Create a "tough" PostgreSQL connection. maxusage: maximum usage limit for the underlying PyGreSQL connection (number of uses, 0 or False means unlimited usage) When this limit is reached, the connection is automatically reset. setsession: optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to ...", "set time zone ..."] args, kwargs: the parameters that shall be used to establish the PostgreSQL connections with PyGreSQL using pg.DB() """ self._maxusage = maxusage self._setsession_sql = setsession self._closeable = 1 self._con = PgConnection(*args, **kwargs) self._closed = False self._setsession() self._usage = 0 def _setsession(self): """Execute the SQL commands for session preparation.""" if self._setsession_sql: for sql in self._setsession_sql: self._con.query(sql) def _close(self): """Close the tough connection. You can always close a tough connection with this method and it will not complain if you close it more than once. """ if not self._closed: try: self._con.close() except Exception: pass self._closed = True def close(self): """Close the tough connection. You are allowed to close a tough connection by default and it will not complain if you close it more than once. You can disallow closing connections by setting the _closeable attribute to 0 or False. In this case, closing a connection will be silently ignored. """ if self._closeable: self._close() def reopen(self): """Reopen the tough connection. It will not complain if the connection cannot be reopened. """ try: self._con.reopen() except Exception: pass else: self._closed = False self._setsession() self._usage = 0 def reset(self): """Reset the tough connection. If a reset is not possible, tries to reopen the connection. It will not complain if the connection is already closed. """ try: self._con.reset() self._setsession() self._usage = 0 except Exception: self.reopen() def _get_tough_method(self, method): """Return a "tough" version of a connection class method. The tough version checks whether the connection is bad (lost) and automatically and transparently tries to reset the connection if this is the case (for instance, the database has been restarted). """ def tough_method(*args, **kwargs): try: # check whether connection status is bad if not self._con.db.status: raise AttributeError if self._maxusage: # or connection used too often if self._usage >= self._maxusage: raise AttributeError except Exception: self.reset() # then reset the connection try: result = method(*args, **kwargs) # try connection method except Exception: # error in query if self._con.db.status: # if it was not a connection problem raise # then propagate the error else: # otherwise self.reset() # reset the connection result = method(*args, **kwargs) # and try one more time self._usage += 1 return result return tough_method def __getattr__(self, name): """Inherit the members of the standard connection class. Some methods are made "tougher" than in the standard version. """ attr = getattr(self._con, name) if name in ('query', 'get', 'insert', 'update', 'delete') \ or name.startswith('get_'): attr = self._get_tough_method(attr) return attr def __del__(self): """Delete the steady connection.""" self._close() # make sure the connection is closed PK@M58êŒõp)p)DBUtils/PersistentPg.pyo;ò õÇFc@s±dZdZdZdZdklZdfd„ƒYZydklZWnae j oUdkl Z l Z l Z d e fd „ƒYZd „Zd efd „ƒYZnXdS(s# PersistentPg - persistent classic PyGreSQL connections. Implements steady, thread-affine persistent connections to a PostgreSQL database using the classic (not DB-API 2 compliant) PyGreSQL API. This should result in a speedup for persistent applications such as the application server of "Webware for Python," without loss of robustness. Robustness is provided by using "hardened" SteadyPg connections. Even if the underlying database is restarted and all connections are lost, they will be automatically and transparently reopened. Measures are taken to make the database connections thread-affine. This means the same thread always uses the same cached connection, and no other thread will use it. So the fact that the classic PyGreSQL pg module is not thread-safe at the connection level is no problem here. For best performance, the application server should keep threads persistent. For this, you have to set MinServerThreads = MaxServerThreads in Webware. For more information on PostgreSQL, see: http://www.postgresql.org For more information on PyGreSQL, see: http://www.pygresql.org For more information on Webware for Python, see: http://www.webwareforpython.org Usage: First you need to set up a generator for your kind of database connections by creating an instance of PersistentPg, passing the following parameters: maxusage: the maximum number of reuses of a single connection (the default of 0 or False means unlimited reuse) When this maximum usage number of the connection is reached, the connection is automatically reset (closed and reopened). setsession: An optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to german", ...] Additionally, you have to pass the parameters for the actual PostgreSQL connection which are passed via PyGreSQL, such as the names of the host, database, user, password etc. For instance, if you want every connection to your local database 'mydb' to be reused 1000 times: from DBUtils.PersistentPg import PersistentPg persist = PersistentPg(5, dbname='mydb') Once you have set up the generator with these parameters, you can request database connections of that kind: db = persist.connection() You can use these connections just as if they were ordinary classic PyGreSQL API connections. Actually what you get is the hardened SteadyPg version of a classic PyGreSQL connection. Closing a persistent connection with db.close() will be silently ignored since it would be reopened at the next usage anyway and contrary to the intent of having persistent connections. Instead, the connection will be automatically closed when the thread dies. You can change this behavior be setting persist._closeable to True. Requirements: Minimum requirement: Python 2.2 and PyGreSQL 3.4. Recommended: Python 2.4.3 and PyGreSQL 3.8. Ideas for improvement: * Add thread for monitoring and restarting bad or expired connections (similar to DBConnectionPool/ResourcePool by Warren Smith). * Optionally log usage, bad connections and exceeding of limits. Copyright, credits and license: * Contributed as supplement for Webware for Python and PyGreSQL by Christoph Zwerschke in September 2005 * Based on an idea presented on the Webware developer mailing list by Geoffrey Talvola in July 2005 Licensed under the Open Software License version 2.1. s0.9.4s $Rev: 6696 $s5$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $(sSteadyPgConnections PersistentPgcBs/tZdZded„Zd„Zd„ZRS(s¶Generator for persistent classic PyGreSQL connections. After you have created the connection pool, you can use connection() to get thread-affine, steady PostgreSQL connections. icOsC||_||_||f\|_|_d|_ t ƒ|_ dS(s˜Set up the persistent PostgreSQL connection generator. maxusage: maximum number of reuses of a single connection (0 or False means unlimited reuse) When this maximum usage number of the connection is reached, the connection is automatically reset (closed and reopened). setsession: optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to ...", "set time zone ..."] args, kwargs: the parameters that shall be used to establish the PostgreSQL connections using class PyGreSQL pg.DB() Set the _closeable attribute to True or 1 to allow closing connections. By default, this will be silently ignored. iN( smaxusagesselfs _maxusages setsessions _setsessionsargsskwargss_argss_kwargss _closeableslocalsthread(sselfsmaxusages setsessionsargsskwargs((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentPg.pys__init__ks    cCs#t|i|i|i|iŽSdS(s1Get a steady, non-persistent PyGreSQL connection.N(sSteadyPgConnectionsselfs _maxusages _setsessions_argss_kwargs(sself((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentPg.pyssteady_connectionscCsRy|ii}Wn7tj o+|iƒ}|i|_||i_nX|SdS(s-Get a steady, persistent PyGreSQL connection.N(sselfsthreads connectionsconsAttributeErrorssteady_connections _closeable(sselfscon((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentPg.pys connection†s  (s__name__s __module__s__doc__sNones__init__ssteady_connections connection(((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentPg.pys PersistentPgcs  (slocal(s currentThreads enumeratesRLocks _localbasecBs tZdddfZd„ZRS(Ns _local__keys _local__argss _local__lockcOsÈti|ƒ}ddtt|ƒƒf}ti|d|ƒti|d||fƒti|dt ƒƒ|p|o|i ti jot dƒ‚nti |dƒ}|tƒi|<|SdS(Ns _local__keys thread.local.s _local__argss _local__locks*Initialization arguments are not supporteds__dict__(sobjects__new__sclssselfsstrsidskeys __setattr__sargsskwargssRLocks__init__s TypeErrors__getattribute__sds currentThreads__dict__(sclssargsskwargssselfsdskey((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentPg.pys__new__—s!(s__name__s __module__s __slots__s__new__(((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentPg.pys _localbase•scCsÆti|dƒ}tƒii|ƒ}|tjo{h}|tƒi|x;|io,|iidƒi iƒ|id8_qTWn|ii ƒWd|ii ƒXdS(s"Close all connections in the pool.iiN( sselfs _conditionsacquires _idle_cachespopscloses _connectionss _maxshareds _shared_cachescons notifyAllsrelease(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysclose7s    cCs"t|dƒo|iƒndS(sDelete the pool.s _connectionsN(shasattrsselfsclose(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys__del__Fs( s__name__s __module__s__doc__sNones__init__ssteady_connections connectionsunsharescachescloses__del__(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysPooledDB‹s J  0   sPooledDedicatedDBConnectioncBs2tZdZd„Zd„Zd„Zd„ZRS(s7Auxiliary proxy class for pooled dedicated connections.cCs4|iƒ otdƒ‚n||_||_dS(s€Create a pooled dedicated connection. pool: the corresponding PooledDB instance con: the underlying SteadyDB connection s#Database module is not thread-safe.N(scons threadsafetysNotSupportedErrorspoolsselfs_pools_con(sselfspoolscon((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys__init__Qs  cCs.|io |ii|iƒt|_ndS(s&Close the pooled dedicated connection.N(sselfs_cons_poolscachesNone(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysclose]s cCs(|iot|i|ƒSnt‚dS(sProxy all members of the class.N(sselfs_consgetattrsnamesInvalidConnection(sselfsname((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys __getattr__es cCs|iƒdS(sDelete the pooled connection.N(sselfsclose(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys__del__ls(s__name__s __module__s__doc__s__init__scloses __getattr__s__del__(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysPooledDedicatedDBConnectionNs   sSharedDBConnectioncBs2tZdZd„Zd„Zd„Zd„ZRS(s'Auxiliary class for shared connections.cCs||_d|_dS(sJCreate a shared connection. con: the underlying SteadyDB connection iN(sconsselfsshared(sselfscon((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys__init__ts cCs|i|iSdS(s-Compare how often the connections are shared.N(sselfssharedsother(sselfsother((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys__cmp__}scCs|id7_dS(s&Increase the share of this connection.iN(sselfsshared(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pyssharescCs|id8_dS(s&Decrease the share of this connection.iN(sselfsshared(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysunshare…s(s__name__s __module__s__doc__s__init__s__cmp__ssharesunshare(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysSharedDBConnectionqs   sPooledSharedDBConnectioncBs2tZdZd„Zd„Zd„Zd„ZRS(s4Auxiliary proxy class for pooled shared connections.cCsL|i}|iƒdj otdƒ‚n||_||_||_dS(s|Create a pooled shared connection. pool: the corresponding PooledDB instance con: the underlying SharedDBConnection is'Database connection is not thread-safe.N( s shared_conscons threadsafetysNotSupportedErrorspoolsselfs_pools _shared_cons_con(sselfspools shared_conscon((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys__init__s   cCs5|io'|ii|iƒt|_|_ndS(s#Close the pooled shared connection.N(sselfs_cons_poolsunshares _shared_consNone(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysclose›s cCs(|iot|i|ƒSnt‚dS(sProxy all members of the class.N(sselfs_consgetattrsnamesInvalidConnection(sselfsname((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys __getattr__£s cCs|iƒdS(sDelete the pooled connection.N(sselfsclose(sself((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys__del__ªs(s__name__s __module__s__doc__s__init__scloses __getattr__s__del__(((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pysPooledSharedDBConnectionŠs    N(s__doc__s __version__s __revision__s__date__s threadings ConditionsDBUtils.SteadyDBsconnects Exceptions PooledDBErrorsInvalidConnectionsNotSupportedErrorsTooManyConnectionssPooledDBsPooledDedicatedDBConnectionsSharedDBConnectionsPooledSharedDBConnection( s PooledDBErrors __revision__sNotSupportedErrorsPooledDBs__date__sTooManyConnectionssSharedDBConnectionsconnectsInvalidConnections __version__sPooledSharedDBConnections ConditionsPooledDedicatedDBConnection((s4build/bdist.darwin-8.0.1-x86/egg/DBUtils/PooledDB.pys?ss  Ã#PKCM58Çòó$º/º/DBUtils/PersistentDB.pyo;ò õÇFc@sÝdZdZdZdZdklZdefd„ƒYZdefd„ƒYZd fd „ƒYZ yd k l Z Wnae j oUd k l Z lZlZd efd„ƒYZd„Zdefd„ƒYZ nXdS(sPersistentDB - persistent DB-API 2 connections. Implements steady, thread-affine persistent connections to a database based on an arbitrary DB-API 2 compliant database interface module. This should result in a speedup for persistent applications such as the application server of "Webware for Python," without loss of robustness. Robustness is provided by using "hardened" SteadyDB connections. Even if the underlying database is restarted and all connections are lost, they will be automatically and transparently reopened. Measures are taken to make the database connections thread-affine. This means the same thread always uses the same cached connection, and no other thread will use it. So even if the underlying DB-API module is not thread-safe at the connection level this will be no problem here. For best performance, the application server should keep threads persistent. For this, you have to set MinServerThreads = MaxServerThreads in Webware. For the Python DB-API 2 specification, see: http://www.python.org/peps/pep-0249.html For information on Webware for Python, see: http://www.webwareforpython.org Usage: First you need to set up a generator for your kind of database connections by creating an instance of PersistentDB, passing the following parameters: creator: either an arbitrary function returning new DB-API 2 connection objects or a DB-API 2 compliant database module maxusage: the maximum number of reuses of a single connection (the default of 0 or False means unlimited reuse) Whenever the limit is reached, the connection will be reset. setsession: an optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to german", ...]. The creator function or the connect function of the DB-API 2 compliant database module specified as the creator will receive any additional parameters such as the host, database, user, password etc. You may choose some or all of these parameters in your own creator function, allowing for sophisticated failover and load-balancing mechanisms. For instance, if you are using pgdb as your DB-API 2 database module and want every connection to your local database 'mydb' to be reused 1000 times: import pgdb # import used DB-API 2 module from DBUtils.PersistentDB import PersistentDB persist = PersistentDB(pgdb, 1000, database='mydb') Once you have set up the generator with these parameters, you can request database connections of that kind: db = persist.connection() You can use these connections just as if they were ordinary DB-API 2 connections. Actually what you get is the hardened SteadyDB version of the underlying DB-API 2 connection. Closing a persistent connection with db.close() will be silently ignored since it would be reopened at the next usage anyway and contrary to the intent of having persistent connections. Instead, the connection will be automatically closed when the thread dies. You can change this behavior be setting persist._closeable to True. Requirements: Minimum requirement: Python 2.2. Recommended: Python 2.4.3. Ideas for improvement: * Add thread for monitoring and restarting bad or expired connections (similar to DBConnectionPool/ResourcePool by Warren Smith). * Optionally log usage, bad connections and exceeding of limits. Copyright, credits and license: * Contributed as supplement for Webware for Python and PyGreSQL by Christoph Zwerschke in September 2005 * Based on an idea presented on the Webware developer mailing list by Geoffrey Talvola in July 2005 Licensed under the Open Software License version 2.1. s0.9.4s $Rev: 6696 $s5$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $(sconnectsPersistentDBErrorcBstZdZRS(sGeneral PersistentDB error.(s__name__s __module__s__doc__(((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentDB.pysPersistentDBErrorcs sNotSupportedErrorcBstZdZRS(s,DB-API module not supported by PersistentDB.(s__name__s __module__s__doc__(((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentDB.pysNotSupportedErrorfs s PersistentDBcBs2tZdZded„Zd„Zdd„ZRS(s¬Generator for persistent DB-API 2 connections. After you have created the connection pool, you can use connection() to get thread-affine, steady DB-API 2 connections. icOsÄy |i}WnPtj oDy!t|iƒodpd}Wq`tj o d}q`XnX| otdƒ‚n||_||_ ||_ ||f\|_|_d|_tƒ|_dS(söSet up the persistent DB-API 2 connection generator. creator: either an arbitrary function returning new DB-API 2 connection objects or a DB-API 2 compliant database module maxusage: maximum number of reuses of a single connection (number of database operations, 0 or False means unlimited) Whenever the limit is reached, the connection will be reset. setsession: optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to ...", "set time zone ..."] args, kwargs: the parameters that shall be passed to the creator function or the connection constructor of the DB-API 2 module Set the _closeable attribute to True or 1 to allow closing connections. By default, this will be silently ignored. iis#Database module is not thread-safe.N(screators threadsafetysAttributeErrorscallablesconnectsNotSupportedErrorsselfs_creatorsmaxusages _maxusages setsessions _setsessionsargsskwargss_argss_kwargss _closeableslocalsthread(sselfscreatorsmaxusages setsessionsargsskwargss threadsafety((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentDB.pys__init__rs  !    cCs)t|i|i|i|i|iŽSdS(s1Get a steady, non-persistent DB-API 2 connection.N(sconnectsselfs_creators _maxusages _setsessions_argss_kwargs(sself((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentDB.pyssteady_connection”s cCspy|ii}WnUtj oI|iƒ}|iƒ otdƒ‚n|i|_||i_nX|SdS(såGet a steady, persistent DB-API 2 connection. The shareable parameter exists only for compatibility with the PooledDB connection method. In reality, persistent connections are of course never shared with other threads. s#Database module is not thread-safe.N( sselfsthreads connectionsconsAttributeErrorssteady_connections threadsafetysNotSupportedErrors _closeable(sselfs shareablescon((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentDB.pys connection™s  (s__name__s __module__s__doc__sNones__init__ssteady_connections connection(((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentDB.pys PersistentDBjs " (slocal(s currentThreads enumeratesRLocks _localbasecBs tZdddfZd„ZRS(Ns _local__keys _local__argss _local__lockcOsÈti|ƒ}ddtt|ƒƒf}ti|d|ƒti|d||fƒti|dt ƒƒ|p|o|i ti jot dƒ‚nti |dƒ}|tƒi|<|SdS(Ns _local__keys thread.local.s _local__argss _local__locks*Initialization arguments are not supporteds__dict__(sobjects__new__sclssselfsstrsidskeys __setattr__sargsskwargssRLocks__init__s TypeErrors__getattribute__sds currentThreads__dict__(sclssargsskwargssselfsdskey((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentDB.pys__new__²s!(s__name__s __module__s __slots__s__new__(((s8build/bdist.darwin-8.0.1-x86/egg/DBUtils/PersistentDB.pys _localbase°scCsÆti|dƒ}tƒii|ƒ}|tjo{h}|tƒi|DBUtils example

You can set the DBUtils parameters in the following file

  • Configs/Database.config

With the default settings,

  • you must have the PostgreSQL database
  • and the PyGreSQL adapter installed, and
  • you must have created a database with the name "demo" and
  • a database user with the name "demo" and password "demo".

Start the demo!

(sselfswriteln(sself((s9build/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/Main.pys writeContents(s__name__s __module__s writeContent(((s9build/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/Main.pysMainsN(sWebKit.Examples.ExamplePages ExamplePagesMain(sMains ExamplePage((s9build/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/Main.pys?s PK¼hç6–EDBUtils/Examples/__init__.py# DBUtils Examples PK¼hç6@õþ3Ž2Ž2"DBUtils/Examples/DBUtilsExample.pyfrom WebKit.Examples.ExamplePage import ExamplePage from MiscUtils.Configurable import Configurable class DBConfig(Configurable): """Database configuration.""" def defaultConfig(self): return { 'dbapi': 'pg', 'database': 'demo', 'user': 'demo', 'password': 'demo', 'mincached': 5, 'maxcached': 25 } def configFilename(self): return 'Configs/Database.config' # the database tables used in this example: tables = ('''seminars ( id varchar(4) primary key, title varchar(64) unique not null, cost money, places_left smallint)''', '''attendees ( name varchar(64) not null, seminar varchar(4), paid boolean, primary key(name, seminar), foreign key (seminar) references seminars(id) on delete cascade)''') class DBUtilsExample(ExamplePage): """Example page for the DBUtils package.""" # Initialize the database class once when this class is loaded: config = DBConfig().config() if config.get('maxcached', None) is None: dbmod_name = 'Persistent' else: dbmod_name = 'Pooled' dbapi_name = config.get('dbapi', 'pg') if dbapi_name == 'pg': # use the PyGreSQL classic DB API dbmod_name += 'Pg' if config.has_key('database'): config['dbname'] = config['database'] del config['database'] if config.has_key('password'): config['passwd'] = config['password'] del config['password'] else: # use a DB-API 2 compliant module dbmod_name += 'DB' dbapi = dbmod = dbclass = dbstatus = None try: dbapi = __import__(dbapi_name) try: dbmod = getattr(__import__('DBUtils.' + dbmod_name), dbmod_name) try: if dbapi_name == 'pg': del config['dbapi'] else: config['dbapi'] = dbapi dbclass = getattr(dbmod, dbmod_name)(**config) except dbapi.Error, error: dbstatus = str(error) except Exception: dbstatus = 'Could not connect to the database.' except Exception: dbstatus = 'Could not import DBUtils.%s.' % dbmod_name except Exception: dbstatus = 'Could not import %s.' % dbapi_name # Initialize the buttons _actions = [] _buttons = [] for action in ('create tables', 'list seminars', 'list attendees', 'new seminar', 'new attendee'): value = action.capitalize() action = action.split() action[1] = action[1].capitalize() action = ''.join(action) _actions.append(action) _buttons.append('' % (action, value)) _buttons = tuple(_buttons) def title(self): return "DBUtils Example" def actions(self): return ExamplePage.actions(self) + self._actions def awake(self, transaction): ExamplePage.awake(self, transaction) self._output = [] def postAction(self, actionName): self.writeBody() del self._output ExamplePage.postAction(self, actionName) def output(self, s): self._output.append(s) def outputMsg(self, msg, error=0): self._output.append('

%s

' % (error and 'red' or 'green', msg)) def connection(self, shareable=1): if self.dbstatus: error = self.dbstatus else: try: if self.dbmod_name == 'PooledDB': return self.dbclass.connection(shareable) else: return self.dbclass.connection() except self.dbapi.Error, error: error = str(error) except Exception: error = 'Cannot connect to the database.' self.outputMsg(error, 1) def sqlEncode(self, s): if s is None: return 'null' s = s.replace('\\', '\\\\').replace('\'', '\\\'') return "'%s'" % s def createTables(self): db = self.connection(0) if not db: return for table in tables: self._output.append('

Creating the following table:

' '
%s
' % table) ddl = 'create table ' + table try: if self.dbapi_name == 'pg': db.query(ddl) else: db.cursor().execute(ddl) db.commit() except self.dbapi.Error, error: if self.dbapi_name != 'pg': db.rollback() self.outputMsg(error, 1) else: self.outputMsg('The table was successfully created.') db.close() def listSeminars(self): id = self.request().field('id', None) if id: if type(id) != type([]): id = [id] cmd = ','.join(map(self.sqlEncode, id)) cmd = 'delete from seminars where id in (%s)' % cmd db = self.connection(0) if not db: return try: if self.dbapi_name == 'pg': db.query('begin') db.query(cmd) db.query('end') else: db.cursor().execute(cmd) db.commit() except self.dbapi.Error, error: try: if self.dbapi_name == 'pg': db.query('end') else: db.rollback() except Exception: pass self.outputMsg(error, 1) return else: self.outputMsg('Entries deleted: %d' % len(id)) db = self.connection() if not db: return query = ('select id, title, cost, places_left from seminars ' 'order by title') try: if self.dbapi_name == 'pg': result = db.query(query).getresult() else: cursor = db.cursor() cursor.execute(query) result = cursor.fetchall() cursor.close() except self.dbapi.Error, error: self.outputMsg(error, 1) return if not result: self.outputMsg('There are no seminars in the database.', 1) return wr = self.output button = self._buttons[1].replace('List seminars', 'Delete') wr('

List of seminars in the database:

') wr('
' '' '' % button) for id, title, cost, places in result: if places is None: places = 'unlimited' if not cost: cost = 'free' wr('' % (id, title, cost, places, id)) wr('
IDSeminar titleCostPlaces left%s
%s%s%s%s' '' '
') def listAttendees(self): id = self.request().field('id', None) if id: if type(id) != type([]): id = [id] cmds = ['delete from attendees ' 'where rpad(seminar,4)||name in (%s)' % ','.join(map(self.sqlEncode, id))] places = {} for i in id: i = i[:4].rstrip() if places.has_key(i): places[i] += 1 else: places[i] = 1 for i, n in places.items(): cmds.append("update seminars set places_left=places_left+%d " "where id=%s" % (n, self.sqlEncode(i))) db = self.connection(0) if not db: return try: if self.dbapi_name == 'pg': db.query('begin') for cmd in cmds: db.query(cmd) db.query('end') else: for cmd in cmds: db.cursor().execute(cmd) db.commit() except self.dbapi.Error, error: if self.dbapi_name == 'pg': db.query('end') else: db.rollback() self.outputMsg(error, 1) return else: self.outputMsg('Entries deleted: %d' % len(id)) db = self.connection() if not db: return query = ('select a.name, s.id, s.title, a.paid ' ' from attendees a,seminars s' ' where s.id=a.seminar' ' order by a.name, s.title') try: if self.dbapi_name == 'pg': result = db.query(query).getresult() else: cursor = db.cursor() cursor.execute(query) result = cursor.fetchall() cursor.close() except self.dbapi.Error, error: self.outputMsg(error, 1) return if not result: self.outputMsg('There are no attendees in the database.', 1) return wr = self.output button = self._buttons[2].replace('List attendees', 'Delete') wr('

List of attendees in the database:

') wr('
' '' '' % button) for name, id, title, paid in result: paid = paid and 'Yes' or 'No' id = id.ljust(4) + name wr('' '' '' % (name, title, paid, id)) wr('
NameSeminarPaid%s
%s%s%s
') def newSeminar(self): wr = self.output wr('

Create a new seminar entry in the database:

') wr('
' '' '' '' '' '' '
ID
Title
Cost
Places
%s
' % self._buttons[3]) request = self.request() if not request.hasField('id'): return values = [] for name in ('id', 'title', 'cost', 'places'): values.append(request.field(name, '').strip()) if not values[0] or not values[1]: self.outputMsg('You must enter a seminar ID and a title!') return if not values[2]: values[2] = None if not values[3]: values[3] = None db = self.connection(0) if not db: return cmd = ('insert into seminars values (%s,%s,%s,%s)' % tuple(map(self.sqlEncode, values))) try: if self.dbapi_name == 'pg': db.query('begin') db.query(cmd) db.query('end') else: db.cursor().execute(cmd) db.commit() except self.dbapi.Error, error: if self.dbapi_name == 'pg': db.query('end') else: db.rollback() self.outputMsg(error, 1) else: self.outputMsg('"%s" added to seminars.' % values[1]) db.close() def newAttendee(self): db = self.connection() if not db: return query = ('select id, title from seminars ' 'where places_left is null or places_left>0 order by title') try: if self.dbapi_name == 'pg': result = db.query(query).getresult() else: cursor = db.cursor() cursor.execute(query) result = cursor.fetchall() cursor.close() except self.dbapi.Error, error: self.outputMsg(error, 1) return if not result: self.outputMsg('You have to define seminars first.') return sem = ['') sem = ''.join(sem) wr = self.output wr('

Create a new attendee entry in the database:

') wr('
' '' '' '' '
Name
Seminar%s
Paid' 'Yes ' 'No' '
%s
' % (sem, self._buttons[4])) request = self.request() if not request.hasField('name'): return values = [] for name in ('name', 'seminar', 'paid'): values.append(request.field(name, '').strip()) if not values[0] or not values[1]: self.outputMsg('You must enter a name and a seminar!') return db = self.connection(0) if not db: return try: if self.dbapi_name == 'pg': db.query('begin') cmd = ("update seminars set places_left=places_left-1 " "where id=%s" % self.sqlEncode(values[1])) db.query(cmd) cmd = ("select places_left from seminars " "where id=%s" % self.sqlEncode(values[1])) if (db.query(cmd).getresult()[0][0] or 0) < 0: raise self.dbapi.Error("No more places left.") cmd = ("insert into attendees values (%s,%s,%s)" % tuple(map(self.sqlEncode, values))) db.query(cmd) db.query('end') else: cursor = db.cursor() cmd = ("update seminars set places_left=places_left-1 " "where id=%s" % self.sqlEncode(values[1])) cursor.execute(cmd) cmd = ("select places_left from seminars " "where id=%s" % self.sqlEncode(values[1])) cursor.execute(cmd) if (cursor.fetchone()[0] or 0) < 0: raise self.dbapi.Error("No more places left.") cmd = ("insert into attendees values (%s,%s,%s)" % tuple(map(self.sqlEncode, values))) db.cursor().execute(cmd) cursor.close() db.commit() except self.dbapi.Error, error: if self.dbapi_name == 'pg': db.query('end') else: db.rollback() self.outputMsg(error, 1) else: self.outputMsg('%s added to attendees.' % values[0]) db.close() def writeContent(self): wr = self.writeln if self._output: wr('\n'.join(self._output)) wr('

Back

') else: wr('

Welcome to the %s!

' % self.title()) wr('

We are using DBUtils.%s and the %s database module.

' % (self.dbmod_name, self.dbapi_name)) wr('

Configuration: %r

' % DBConfig().config()) wr('

This example uses a small demo database ' 'designed to track the attendees for a series of seminars ' '(see "The ' 'Python DB-API" by Andrew Kuchling).

') wr('
' '

%s (create the needed database tables first)

' '

%s %s (list all database entries)

' '

%s %s (create new entries)

' '
' % self._buttons) PKAM58dƒ DBUtils/Examples/__init__.pyo;ò õÇFc@sdS(N((((s=build/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/__init__.pys?sPKAM582¼)üqqDBUtils/Examples/Main.pyo;ò õÇFc@s'dklZdefd„ƒYZdS((s ExamplePagesMaincBstZd„ZRS(NcCs|idƒdS(NsÕ

DBUtils example

You can set the DBUtils parameters in the following file

  • Configs/Database.config

With the default settings,

  • you must have the PostgreSQL database
  • and the PyGreSQL adapter installed, and
  • you must have created a database with the name "demo" and
  • a database user with the name "demo" and password "demo".

Start the demo!

(sselfswriteln(sself((s9build/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/Main.pys writeContents(s__name__s __module__s writeContent(((s9build/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/Main.pysMainsN(sWebKit.Examples.ExamplePages ExamplePagesMain(sMains ExamplePage((s9build/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/Main.pys?s PK¼hç6íˆ UUDBUtils/Examples/Main.pyfrom WebKit.Examples.ExamplePage import ExamplePage class Main(ExamplePage): def writeContent(self): self.writeln('''

DBUtils example

You can set the DBUtils parameters in the following file

  • Configs/Database.config

With the default settings,

  • you must have the PostgreSQL database
  • and the PyGreSQL adapter installed, and
  • you must have created a database with the name "demo" and
  • a database user with the name "demo" and password "demo".

Start the demo!

''') PKAM58ø'¶ƒ"B"B#DBUtils/Examples/DBUtilsExample.pyo;ò õÇFc@sVdklZdklZdefd„ƒYZddfZdefd„ƒYZdS( (s ExamplePage(s ConfigurablesDBConfigcBs tZdZd„Zd„ZRS(sDatabase configuration.cCs>hdd<dd<dd<dd<dd<d d cCsdSdS(NsDBUtils Example((sself((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pystitleZscCsti|ƒ|iSdS(N(s ExamplePagesactionssselfs_actions(sself((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pysactions]scCsti||ƒg|_dS(N(s ExamplePagesawakesselfs transactions_output(sselfs transaction((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pysawake`scCs$|iƒ|`ti||ƒdS(N(sselfs writeBodys_outputs ExamplePages postActions actionName(sselfs actionName((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys postActionds cCs|ii|ƒdS(N(sselfs_outputsappendss(sselfss((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pysoutputisicCs,|iid|odpd|fƒdS(Ns

%s

sredsgreen(sselfs_outputsappendserrorsmsg(sselfsmsgserror((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys outputMsglscCs¢|io |i}nxy5|idjo|ii|ƒSn|iiƒSWn?|iij o}t |ƒ}nt j o d}nX|i |dƒdS(NsPooledDBsCannot connect to the database.i( sselfsdbstatusserrors dbmod_namesdbclasss connections shareablesdbapisErrorsstrs Exceptions outputMsg(sselfs shareableserror((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys connectionps   cCs?|tjodSn|iddƒiddƒ}d|SdS(Nsnulls\s\\s's\'s'%s'(sssNonesreplace(sselfss((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys sqlEncodes cCs÷|idƒ}| odSnxÇtD]¿}|iid|ƒd|}yB|idjo|i |ƒn|i ƒi |ƒ|i ƒWnI|i ij o7}|idjo|iƒn|i|dƒq&X|idƒq&W|iƒdS(Nis1

Creating the following table:

%s
s create table spgis#The table was successfully created.(sselfs connectionsdbstablesstables_outputsappendsddls dbapi_namesqueryscursorsexecutescommitsdbapisErrorserrorsrollbacks outputMsgsclose(sselfserrorsdbsddlstable((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys createTables…s$ c Csò|iƒidtƒ} | oXt| ƒtgƒjo | g} ndit|i| ƒƒ}d|}|i dƒ}| odSny\|i djo+|i dƒ|i |ƒ|i dƒn|iƒi|ƒ|iƒWnt|iij ob}y/|i djo|i dƒn |iƒWntj onX|i|dƒdSqwX|id t| ƒƒn|i ƒ}| odSnd } y\|i djo|i | ƒiƒ}n0|iƒ}|i| ƒ|iƒ}|iƒWn/|iij o}|i|dƒdSnX| o|id dƒdSn|i} |idid d ƒ} | dƒ| d| ƒx`|D]X\} }}}|tjo d}n| o d}n| d| |||| fƒqˆW| dƒdS(Nsids,s%delete from seminars where id in (%s)ispgsbeginsendisEntries deleted: %ds@select id, title, cost, places_left from seminars order by titles&There are no seminars in the database.s List seminarssDeletes*

List of seminars in the database:

s unlimitedsfreesjs
IDSeminar titleCostPlaces left%s
%s%s%s%s
($sselfsrequestsfieldsNonesidstypesjoinsmaps sqlEncodescmds connectionsdbs dbapi_namesqueryscursorsexecutescommitsdbapisErrorserrorsrollbacks Exceptions outputMsgslens getresultsresultsfetchallsclosesoutputswrs_buttonssreplacesbuttonstitlescostsplaces( sselfsplacesstitlescmdsdbscursorscostsresultserrorsbuttonsquerysidswr((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys listSeminars›sn               !cCs„|iƒidtƒ}|oït|ƒtgƒjo |g}nddit|i|ƒƒg}h}xL|D]D}|d i ƒ}|i |ƒo||cd7List of attendees in the database:sv
sYessNos_s
NameSeminarPaid%s
%s%s%s
(,sselfsrequestsfieldsNonesidstypesjoinsmaps sqlEncodescmdssplacessisrstripshas_keysitemssnsappends connectionsdbs dbapi_namesqueryscmdscursorsexecutescommitsdbapisErrorserrorsrollbacks outputMsgslens getresultsresultsfetchallsclosesoutputswrs_buttonssreplacesbuttonsnamestitlespaidsljust(sselfspaidsnamesplacesstitlesiscmdsdbscmdsscursorsresultserrorsbuttonsquerysnsidswr((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys listAttendeesÜs~ " $          cCs|i}|dƒ|d|idƒ|iƒ}|idƒ odSng}x9ddddfD]%}|i|i |dƒi ƒƒqfW|d  p |d  o|i d ƒdSn|d  ot |d Create a new seminar entry in the database:s
ID
Title
Cost
Places
%s
isidstitlescostsplacessiis(You must enter a seminar ID and a title!is)insert into seminars values (%s,%s,%s,%s)spgsbeginsends"%s" added to seminars.(sselfsoutputswrs_buttonssrequestshasFieldsvaluessnamesappendsfieldsstrips outputMsgsNones connectionsdbstuplesmaps sqlEncodescmds dbapi_namesqueryscursorsexecutescommitsdbapisErrorserrorsrollbacksclose(sselfsnamesdbscmdsrequestsvaluesswrserror((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys newSeminar'sF   #      cCs|iƒ}| odSnd} y\|idjo|i| ƒiƒ}n0|iƒ}|i| ƒ|i ƒ}|i ƒWn/|i i j o} |i| dƒdSnX| o|idƒdSndg} x+|D]#\} }| id| |fƒqÝW| idƒdi| ƒ} |i} | d ƒ| d | |id fƒ|iƒ}|id ƒ odSng}x6d d dfD]%}|i|i|dƒiƒƒq‰W|d p |d o|idƒdSn|idƒ}| odSny¢|idjoÃ|idƒd|i|dƒ}|i|ƒd|i|dƒ}|i|ƒiƒddpddjo|i i dƒ‚ndtt |i|ƒƒ}|i|ƒ|idƒnÌ|iƒ}d|i|dƒ}|i|ƒd|i|dƒ}|i|ƒ|i!ƒdpddjo|i i dƒ‚ndtt |i|ƒƒ}|iƒi|ƒ|i ƒ|i"ƒWnV|i i j oD} |idjo|idƒn |i#ƒ|i| dƒnX|id|dƒ|i ƒdS(NsXselect id, title from seminars where places_left is null or places_left>0 order by titlespgis"You have to define seminars first.sss5

Create a new attendee entry in the database:

sA
Name
Seminar%s
PaidYes No
%s
isnamesseminarspaidis$You must enter a name and a seminar!sbegins9update seminars set places_left=places_left-1 where id=%ss,select places_left from seminars where id=%ssNo more places left.s'insert into attendees values (%s,%s,%s)sends%s added to attendees.($sselfs connectionsdbsquerys dbapi_names getresultsresultscursorsexecutesfetchallsclosesdbapisErrorserrors outputMsgssemsidstitlesappendsjoinsoutputswrs_buttonssrequestshasFieldsvaluessnamesfieldsstrips sqlEncodescmdstuplesmapsfetchonescommitsrollback(sselfsnamestitlesrequestscmdsdbscursorsvaluessresultserrorsqueryssemsidswr((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys newAttendeeYsˆ            #   +      cCs›|i}|io$|di|iƒƒ|dƒna|d|iƒƒ|d|i|ifƒ|dtƒi ƒƒ|dƒ|d|i ƒdS(Ns s(

Back

s

Welcome to the %s!

s<

We are using DBUtils.%s and the %s database module.

s

Configuration: %r

This example uses a small demo database designed to track the attendees for a series of seminars (see "The Python DB-API" by Andrew Kuchling).

s‰

%s (create the needed database tables first)

%s %s (list all database entries)

%s %s (create new entries)

( sselfswritelnswrs_outputsjoinstitles dbmod_names dbapi_namesDBConfigsconfigs_buttons(sselfswr((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys writeContent°s   (+s__name__s __module__s__doc__sDBConfigsconfigsgetsNones dbmod_names dbapi_nameshas_keysdbapisdbmodsdbclasssdbstatuss __import__sgetattrsErrorserrorsstrs Exceptions_actionss_buttonssactions capitalizesvaluessplitsjoinsappendstuplestitlesactionssawakes postActionsoutputs outputMsgs connections sqlEncodes createTabless listSeminarss listAttendeess newSeminars newAttendees writeContent(((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pysDBUtilsExample#st                        A K 2 WN(sWebKit.Examples.ExamplePages ExamplePagesMiscUtils.Configurables ConfigurablesDBConfigstablessDBUtilsExample(sDBConfigsDBUtilsExamples ExamplePagestabless Configurable((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys?s   PK6M58dƒ DBUtils/Examples/__init__.pyc;ò õÇFc@sdS(N((((s=build/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/__init__.pys?sPK6M58ø'¶ƒ"B"B#DBUtils/Examples/DBUtilsExample.pyc;ò õÇFc@sVdklZdklZdefd„ƒYZddfZdefd„ƒYZdS( (s ExamplePage(s ConfigurablesDBConfigcBs tZdZd„Zd„ZRS(sDatabase configuration.cCs>hdd<dd<dd<dd<dd<d d cCsdSdS(NsDBUtils Example((sself((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pystitleZscCsti|ƒ|iSdS(N(s ExamplePagesactionssselfs_actions(sself((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pysactions]scCsti||ƒg|_dS(N(s ExamplePagesawakesselfs transactions_output(sselfs transaction((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pysawake`scCs$|iƒ|`ti||ƒdS(N(sselfs writeBodys_outputs ExamplePages postActions actionName(sselfs actionName((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys postActionds cCs|ii|ƒdS(N(sselfs_outputsappendss(sselfss((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pysoutputisicCs,|iid|odpd|fƒdS(Ns

%s

sredsgreen(sselfs_outputsappendserrorsmsg(sselfsmsgserror((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys outputMsglscCs¢|io |i}nxy5|idjo|ii|ƒSn|iiƒSWn?|iij o}t |ƒ}nt j o d}nX|i |dƒdS(NsPooledDBsCannot connect to the database.i( sselfsdbstatusserrors dbmod_namesdbclasss connections shareablesdbapisErrorsstrs Exceptions outputMsg(sselfs shareableserror((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys connectionps   cCs?|tjodSn|iddƒiddƒ}d|SdS(Nsnulls\s\\s's\'s'%s'(sssNonesreplace(sselfss((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys sqlEncodes cCs÷|idƒ}| odSnxÇtD]¿}|iid|ƒd|}yB|idjo|i |ƒn|i ƒi |ƒ|i ƒWnI|i ij o7}|idjo|iƒn|i|dƒq&X|idƒq&W|iƒdS(Nis1

Creating the following table:

%s
s create table spgis#The table was successfully created.(sselfs connectionsdbstablesstables_outputsappendsddls dbapi_namesqueryscursorsexecutescommitsdbapisErrorserrorsrollbacks outputMsgsclose(sselfserrorsdbsddlstable((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys createTables…s$ c Csò|iƒidtƒ} | oXt| ƒtgƒjo | g} ndit|i| ƒƒ}d|}|i dƒ}| odSny\|i djo+|i dƒ|i |ƒ|i dƒn|iƒi|ƒ|iƒWnt|iij ob}y/|i djo|i dƒn |iƒWntj onX|i|dƒdSqwX|id t| ƒƒn|i ƒ}| odSnd } y\|i djo|i | ƒiƒ}n0|iƒ}|i| ƒ|iƒ}|iƒWn/|iij o}|i|dƒdSnX| o|id dƒdSn|i} |idid d ƒ} | dƒ| d| ƒx`|D]X\} }}}|tjo d}n| o d}n| d| |||| fƒqˆW| dƒdS(Nsids,s%delete from seminars where id in (%s)ispgsbeginsendisEntries deleted: %ds@select id, title, cost, places_left from seminars order by titles&There are no seminars in the database.s List seminarssDeletes*

List of seminars in the database:

s unlimitedsfreesjs
IDSeminar titleCostPlaces left%s
%s%s%s%s
($sselfsrequestsfieldsNonesidstypesjoinsmaps sqlEncodescmds connectionsdbs dbapi_namesqueryscursorsexecutescommitsdbapisErrorserrorsrollbacks Exceptions outputMsgslens getresultsresultsfetchallsclosesoutputswrs_buttonssreplacesbuttonstitlescostsplaces( sselfsplacesstitlescmdsdbscursorscostsresultserrorsbuttonsquerysidswr((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys listSeminars›sn               !cCs„|iƒidtƒ}|oït|ƒtgƒjo |g}nddit|i|ƒƒg}h}xL|D]D}|d i ƒ}|i |ƒo||cd7List of attendees in the database:sv
sYessNos_s
NameSeminarPaid%s
%s%s%s
(,sselfsrequestsfieldsNonesidstypesjoinsmaps sqlEncodescmdssplacessisrstripshas_keysitemssnsappends connectionsdbs dbapi_namesqueryscmdscursorsexecutescommitsdbapisErrorserrorsrollbacks outputMsgslens getresultsresultsfetchallsclosesoutputswrs_buttonssreplacesbuttonsnamestitlespaidsljust(sselfspaidsnamesplacesstitlesiscmdsdbscmdsscursorsresultserrorsbuttonsquerysnsidswr((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys listAttendeesÜs~ " $          cCs|i}|dƒ|d|idƒ|iƒ}|idƒ odSng}x9ddddfD]%}|i|i |dƒi ƒƒqfW|d  p |d  o|i d ƒdSn|d  ot |d Create a new seminar entry in the database:s
ID
Title
Cost
Places
%s
isidstitlescostsplacessiis(You must enter a seminar ID and a title!is)insert into seminars values (%s,%s,%s,%s)spgsbeginsends"%s" added to seminars.(sselfsoutputswrs_buttonssrequestshasFieldsvaluessnamesappendsfieldsstrips outputMsgsNones connectionsdbstuplesmaps sqlEncodescmds dbapi_namesqueryscursorsexecutescommitsdbapisErrorserrorsrollbacksclose(sselfsnamesdbscmdsrequestsvaluesswrserror((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys newSeminar'sF   #      cCs|iƒ}| odSnd} y\|idjo|i| ƒiƒ}n0|iƒ}|i| ƒ|i ƒ}|i ƒWn/|i i j o} |i| dƒdSnX| o|idƒdSndg} x+|D]#\} }| id| |fƒqÝW| idƒdi| ƒ} |i} | d ƒ| d | |id fƒ|iƒ}|id ƒ odSng}x6d d dfD]%}|i|i|dƒiƒƒq‰W|d p |d o|idƒdSn|idƒ}| odSny¢|idjoÃ|idƒd|i|dƒ}|i|ƒd|i|dƒ}|i|ƒiƒddpddjo|i i dƒ‚ndtt |i|ƒƒ}|i|ƒ|idƒnÌ|iƒ}d|i|dƒ}|i|ƒd|i|dƒ}|i|ƒ|i!ƒdpddjo|i i dƒ‚ndtt |i|ƒƒ}|iƒi|ƒ|i ƒ|i"ƒWnV|i i j oD} |idjo|idƒn |i#ƒ|i| dƒnX|id|dƒ|i ƒdS(NsXselect id, title from seminars where places_left is null or places_left>0 order by titlespgis"You have to define seminars first.sss5

Create a new attendee entry in the database:

sA
Name
Seminar%s
PaidYes No
%s
isnamesseminarspaidis$You must enter a name and a seminar!sbegins9update seminars set places_left=places_left-1 where id=%ss,select places_left from seminars where id=%ssNo more places left.s'insert into attendees values (%s,%s,%s)sends%s added to attendees.($sselfs connectionsdbsquerys dbapi_names getresultsresultscursorsexecutesfetchallsclosesdbapisErrorserrors outputMsgssemsidstitlesappendsjoinsoutputswrs_buttonssrequestshasFieldsvaluessnamesfieldsstrips sqlEncodescmdstuplesmapsfetchonescommitsrollback(sselfsnamestitlesrequestscmdsdbscursorsvaluessresultserrorsqueryssemsidswr((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys newAttendeeYsˆ            #   +      cCs›|i}|io$|di|iƒƒ|dƒna|d|iƒƒ|d|i|ifƒ|dtƒi ƒƒ|dƒ|d|i ƒdS(Ns s(

Back

s

Welcome to the %s!

s<

We are using DBUtils.%s and the %s database module.

s

Configuration: %r

This example uses a small demo database designed to track the attendees for a series of seminars (see "The Python DB-API" by Andrew Kuchling).

s‰

%s (create the needed database tables first)

%s %s (list all database entries)

%s %s (create new entries)

( sselfswritelnswrs_outputsjoinstitles dbmod_names dbapi_namesDBConfigsconfigs_buttons(sselfswr((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys writeContent°s   (+s__name__s __module__s__doc__sDBConfigsconfigsgetsNones dbmod_names dbapi_nameshas_keysdbapisdbmodsdbclasssdbstatuss __import__sgetattrsErrorserrorsstrs Exceptions_actionss_buttonssactions capitalizesvaluessplitsjoinsappendstuplestitlesactionssawakes postActionsoutputs outputMsgs connections sqlEncodes createTabless listSeminarss listAttendeess newSeminars newAttendees writeContent(((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pysDBUtilsExample#st                        A K 2 WN(sWebKit.Examples.ExamplePages ExamplePagesMiscUtils.Configurables ConfigurablesDBConfigstablessDBUtilsExample(sDBConfigsDBUtilsExamples ExamplePagestabless Configurable((sCbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Examples/DBUtilsExample.pys?s   PK¼hç6nô‚Ñ\f\fDBUtils/Docs/UsersGuide.zh.html DBUtils 用户指å—

DBUtils 用户指å—

版本: 0.9.4
å‘行版:07/07/07
翻译:English German Chinese

摘è¦

DBUtils 是一套å…许线程化 Python 程åºå¯ä»¥å®‰å…¨å’Œæœ‰æ•ˆçš„访问数æ®åº“的模å—。DBUtilså·²ç»ä½œä¸º Webware for Python 一部分用æ¥ç»“åˆ PyGreSQL 访问 PostgreSQL æ•°æ®åº“,当然他也å¯ä»¥ç”¨åœ¨å…¶ä»–Python应用程åºä¸­æ¥è®¿é—® DB-API 2 兼容的数æ®åº“接å£ã€‚

模å—

DBUtils实际上是一个包å«ä¸¤ä¸ªå­æ¨¡å—çš„Python包,一个用于连接DB-API 2模å—,å¦ä¸€ä¸ªç”¨äºŽè¿žæŽ¥å…¸åž‹çš„PyGreSQL模å—。

全局的DB-API 2å˜é‡
SteadyDB.py 用于稳定数æ®åº“连接
PooledDB.py 连接池
PersistentDB.py ç»´æŒæŒç»­çš„æ•°æ®åº“连接
SimplePooledDB.py 简å•连接池
典型的 PyGreSQL å˜é‡
SteadyPg.py 稳定PyGreSQL连接
PooledPg.py PyGreSQL连接池
PersistentPg.py ç»´æŒæŒç»­çš„PyGreSQL连接
SimplePooledPg.py 简å•çš„PyGreSQL连接池

对标准DB-API 2模å—çš„ä¾èµ–如下图所示:

dbdep.gif

对典型的PyGreSQL模å—ä¾èµ–如下图所示:

pgdep.gif

下载

ä½ å¯ä»¥ä»Ž Webware 的网站下载最新版本:

http://www.webwareforpython.org/downloads/DBUtils/

也å¯ä»¥ä»ŽPython Package Indexæ¥ä¸‹è½½ï¼š

http://www.python.org/pypi/DBUtils/

安装

安装为顶层模å—

如果你打算在除了Webware之外的程åºä¸­ä½¿ç”¨ï¼ŒæŽ¨è安装为顶层模å—:

python setup.py install

安装为Webwareçš„å­æ¨¡å—(æ’ä»¶)

å¦‚æžœä½ åªæ˜¯æ‰“算在Webware中使用,则å¯ä»¥æŒ‰ç…§å¦‚下安装:

python setup.py install --install-lib=/path/to/Webware

æ›¿æ¢ /path/to/Webware 为Webware安装的根路径。你还需è¦è¿è¡ŒWebwareçš„å®‰è£…ç¨‹åºæ¥åŒæ—¶åŒ…å«DBUtils的文档:

cd path/to/Webware
python install.py

è¦æ±‚

DBUtils需è¦Python2.2或更高的版本。而典型的PyGreSQL则需è¦PyGreSQL3.4版本或更高。而DB-API ç›¸å…³çš„åˆ™éœ€è¦ DB-API 2 版本或更高的数æ®åº“æŽ¥å£æ¨¡å—。

功能

这一节的主è¦ä¾‹å­é¢å‘DB-API 2,但是也适用于典型的PyGreSQL模å—。

SimplePooledDB

DBUtils.SimplePooledDB 是一个éžå¸¸ç®€å•的数æ®åº“连接池实现。他比完善的 PooledDB 模å—缺少很多功能。 DBUtils.SimplePooledDB 本质上类似于 MiscUtils.DBPool 这个Webware的组æˆéƒ¨åˆ†ã€‚ä½ å¯ä»¥æŠŠå®ƒçœ‹ä½œä¸€ç§æ¼”示程åºã€‚

SteadyDB

DBUtils.SteadyDB 是一个模å—实现了"强硬"的数æ®åº“连接,基于DB-API 2建立的原始连接。一个"强硬"的连接æ„味ç€åœ¨è¿žæŽ¥å…³é—­ä¹‹åŽï¼Œæˆ–者使用次数æ“作é™åˆ¶æ—¶ä¼šé‡æ–°è¿žæŽ¥ã€‚

ä¸€ä¸ªå…¸åž‹çš„ä¾‹å­æ˜¯æ•°æ®åº“é‡å¯æ—¶ï¼Œè€Œä½ çš„程åºä»ç„¶åœ¨è¿è¡Œå¹¶éœ€è¦è®¿é—®æ•°æ®åº“,或者当你的程åºè¿žæŽ¥äº†ä¸€ä¸ªé˜²ç«å¢™åŽé¢çš„远程数æ®åº“,而防ç«å¢™é‡å¯æ—¶ä¸¢å¤±äº†çŠ¶æ€æ—¶ã€‚

一般æ¥è¯´ä½ ä¸éœ€è¦ç›´æŽ¥ä½¿ç”¨ SteadyDB å®ƒåªæ˜¯ç»™æŽ¥ä¸‹æ¥çš„ä¸¤ä¸ªæ¨¡å—æä¾›åŸºæœ¬æœåŠ¡ï¼Œ PersistentDB å’Œ PooledDB 。

PersistentDB

DBUtils.PersistentDB 实现了强硬的ã€çº¿ç¨‹å®‰å…¨çš„ã€é¡½å›ºçš„æ•°æ®åº“连接,使用DB-API 2模å—。如下图展示了使用 PersistentDB 时的连接层步骤:

persist.gif

当一个线程首次打开一个数æ®åº“连接时,一个连接会打开并仅供这个线程使用。当线程关闭连接时,连接ä»ç„¶æŒç»­æ‰“å¼€ä¾›è¿™ä¸ªçº¿ç¨‹ä¸‹æ¬¡è¯·æ±‚æ—¶ä½¿ç”¨è¿™ä¸ªå·²ç»æ‰“开的连接。连接在线程死亡时自动关闭。

简å•çš„æ¥è¯´ PersistentDB å°è¯•é‡ç”¨æ•°æ®åº“è¿žæŽ¥æ¥æé«˜çº¿ç¨‹åŒ–ç¨‹åºçš„æ•°æ®åº“访问性能,并且他确ä¿è¿žæŽ¥ä¸ä¼šè¢«çº¿ç¨‹ä¹‹é—´å…±äº«ã€‚

因此, PersistentDB å¯ä»¥åœ¨åº•层DB-API模å—å¹¶éžçº¿ç¨‹å®‰å…¨çš„æ—¶å€™åŒæ ·å·¥ä½œçš„å¾ˆå¥½ï¼Œå¹¶ä¸”ä»–ä¼šåœ¨å…¶ä»–çº¿ç¨‹æ”¹å˜æ•°æ®åº“ä¼šè¯æˆ–者使用多语å¥äº‹åŠ¡æ—¶åŒæ ·é¿å…问题的å‘生。

PooledDB

DBUtils.PooledDB 实现了一个强硬的ã€çº¿ç¨‹å®‰å…¨çš„ã€æœ‰ç¼“存的ã€å¯å¤ç”¨çš„æ•°æ®åº“连接,使用任何DB-API 2模å—。如下图展示了使用 PooledDB 时的工作æµç¨‹ï¼š

pool.gif

如图所示 PooledDB å¯ä»¥åœ¨ä¸åŒçº¿ç¨‹ä¹‹é—´å…±äº«æ‰“开的数æ®åº“连接。这在你连接并指定 maxshared 傿•°ï¼Œå¹¶ä¸”底层的DB-API 2æŽ¥å£æ˜¯çº¿ç¨‹å®‰å…¨æ‰å¯ä»¥ï¼Œä½†æ˜¯ä½ ä»ç„¶å¯ä»¥ä½¿ç”¨ä¸“用数æ®åº“连接而ä¸åœ¨çº¿ç¨‹ä¹‹é—´å…±äº«è¿žæŽ¥ã€‚除了共享连接以外,还å¯ä»¥è®¾ç«‹ä¸€ä¸ªè‡³å°‘ mincached 的连接池,并且最多å…许使用 maxcached 个连接,这å¯ä»¥åŒæ—¶ç”¨äºŽä¸“用和共享连接池。当一个线程关闭了一个éžå…±äº«è¿žæŽ¥ï¼Œåˆ™ä¼šè¿”还到空闲连接池中等待下次使用。

如果底层DB-APIæ¨¡å—æ˜¯éžçº¿ç¨‹å®‰å…¨çš„,线程é”会确ä¿ä½¿ç”¨ PooledDB 是线程安全的。所以你并ä¸éœ€è¦ä¸ºæ­¤æ‹…å¿ƒï¼Œä½†æ˜¯ä½ åœ¨ä½¿ç”¨ä¸“ç”¨è¿žæŽ¥æ¥æ”¹å˜æ•°æ®åº“ä¼šè¯æˆ–执行多命令事务时必须å°å¿ƒã€‚

该选择哪一个?

PersistentDB å’Œ PooledDB 都是为了é‡ç”¨æ•°æ®åº“è¿žæŽ¥æ¥æé«˜æ€§èƒ½ï¼Œå¹¶ä¿æŒæ•°æ®åº“的稳定性。

æ‰€ä»¥é€‰æ‹©ä½•ç§æ¨¡å—,å¯ä»¥å‚考上é¢çš„解释。 PersistentDB å°†ä¼šä¿æŒä¸€å®šæ•°é‡çš„连接供频ç¹ä½¿ç”¨ã€‚åœ¨è¿™ç§æƒ…å†µä¸‹ä½ æ€»æ˜¯ä¿æŒå›ºå®šæ•°é‡çš„连接。如果你的程åºé¢‘ç¹çš„å¯åŠ¨å’Œå…³é—­çº¿ç¨‹ï¼Œæœ€å¥½ä½¿ç”¨ PooledDB 。åŽé¢å°†ä¼šæåˆ°æ›´å¥½çš„调整,尤其在使用线程安全的DB-API 2æ¨¡å—æ—¶ã€‚

当然,这两个模å—çš„æŽ¥å£æ˜¯å¾ˆç›¸ä¼¼çš„,你å¯ä»¥æ–¹ä¾¿çš„在他们之间转æ¢ï¼Œå¹¶æŸ¥çœ‹å“ªä¸ªæ›´å¥½ä¸€äº›ã€‚

使用方法

所有模å—的使用方法都很相似,但是在åˆå§‹åŒ– "Pooled" å’Œ "Persistent" 时还有有些ä¸åŒï¼Œå°¤å…¶æ˜¯DB-APIå’ŒPyGreSQL之间。

这里åªè®²è§£ PersistentDB å’Œæ›´å¤æ‚çš„ PooledDB 模å—。其他模å—的细节请å‚与其文档。使用Python解释器控制å°ï¼Œä½ å¯ä»¥æ˜¾ç¤º PooledDB 的文档,如下:

help(PooledDB)

PersistentDB

为了使用 PersistentDB 你首先需è¦é€šè¿‡åˆ›å»º PersistentDB 的实例æ¥è®¾ç½®ä¸€ä¸ªç‰¹å®šæ•°æ®åº“连接的生æˆå™¨ï¼ŒåºŠåº•如䏋傿•°ï¼š

  • creator: å¯ä»¥ä½¿ç”¨ä»»æ„返回 DB-API 2 连接对象的函数活 DB-API 2 兼容的数æ®åº“模å—。
  • maxusage: 一个连接最大å…许å¤ç”¨æ¬¡æ•°(缺çœä¸º 0 或 False æ„å‘³ç€æ— é™åˆ¶çš„é‡ç”¨),当达到é™åˆ¶æ—¶ï¼Œå°†ä¼šé‡æ–°è¿žæŽ¥æ•°æ®åº“
  • setsession: 一个å¯é€‰çš„SQL命令列表å¯ä»¥ç”¨äºŽå‡†å¤‡ä¼šè¯ï¼Œå¦‚ ["set datestyle to german", ...]
  • creator å‡½æ•°æˆ–ç”Ÿæˆ DB-API 2 连接的函数,å¯ä»¥æŽ¥å—è¿™é‡Œçš„é™„åŠ å‚æ•°ï¼Œæ¯”如主机åã€æ•°æ®åº“ã€ç”¨æˆ·åã€å¯†ç ç­‰ç­‰ã€‚你也å¯ä»¥é€‰æ‹©ä¼ é€’ç»™ creator çš„å…¶ä»–å‚æ•°ï¼Œå¹¶å…许æä¾›å¤±è´¥é‡è¿žå’Œè´Ÿè½½å‡è¡¡ã€‚

举个例å­ï¼Œå¦‚果你正在使用 pgdb 作为数æ®åº“模å—并想è¦è¿žæŽ¥æœ¬æœºæ•°æ®åº“ mydb ,å…许é‡ç”¨1000次:

import pgdb # import used DB-API 2 module
from DBUtils.PersistentDB import PersistentDB
persist = PersistentDB(pgdb, 1000, database='mydb')

按照如上设置完æˆäº†è¿žæŽ¥ç”Ÿæˆå™¨ä¹‹åŽï¼Œä½ å¯ä»¥æŒ‰ç…§å¦‚下æ¥è¯·æ±‚一个连接:

db = persist.connection()

ä½ å¯ä»¥ä½¿ç”¨è¿™äº›è¿žæŽ¥å°±åƒä½¿ç”¨åŽŸå§‹çš„DB-API 2连接一样。实际上你得到的是一个通过``SteadyDB``得到的强硬的连接,基于DB-API 2。

关闭一个强硬的连接使用 db.close() ,这在内部实际上被忽略掉了,并且供下次使用。在线程关闭时,也会自动关闭数æ®åº“连接。你å¯ä»¥æ”¹å˜è¿™ä¸ªè¡Œä¸ºé€šè¿‡ persist._closeable 为 True 。

PooledDB

为了使用 PooledDB 模å—,你首先需è¦é€šè¿‡åˆ›å»º PooledDB æ¥è®¾ç½®æ•°æ®åº“è¿žæŽ¥æ± ï¼Œä¼ é€’å¦‚ä¸‹å‚æ•°ï¼š

  • creator: å¯ä»¥ç”Ÿæˆ DB-API 2 连接的任何函数或 DB-API 2 兼容的数æ®åº“连接模å—。
  • mincached : å¯åŠ¨æ—¶å¼€å¯çš„空连接数é‡(缺çœå€¼ 0 æ„味ç€å¼€å§‹æ—¶ä¸åˆ›å»ºè¿žæŽ¥)
  • maxcached: 连接池使用的最多连接数é‡(缺çœå€¼ 0 代表ä¸é™åˆ¶è¿žæŽ¥æ± å¤§å°)
  • maxshared: 最大å…许的共享连接数é‡(缺çœå€¼ 0 代表所有连接都是专用的)如果达到了最大数é‡ï¼Œè¢«è¯·æ±‚为共享的连接将会被共享使用。
  • maxconnections: 最大å…许连接数é‡(缺çœå€¼ 0 代表ä¸é™åˆ¶)
  • blocking: è®¾ç½®åœ¨è¾¾åˆ°æœ€å¤§æ•°é‡æ—¶çš„行为(缺çœå€¼ 0 或 False 代表返回一个错误;其他代表阻塞直到连接数å‡å°‘)
  • maxusage: å•个连接的最大å…许å¤ç”¨æ¬¡æ•°(缺çœå€¼ 0 或 False 代表ä¸é™åˆ¶çš„å¤ç”¨)ã€‚å½“è¾¾åˆ°æœ€å¤§æ•°å€¼æ—¶ï¼Œè¿žæŽ¥ä¼šè‡ªåŠ¨é‡æ–°è¿žæŽ¥(å…³é—­å’Œé‡æ–°æ‰“å¼€)
  • setsession: 一个å¯é€‰çš„SQL命令列表用于准备æ¯ä¸ªä¼šè¯ï¼Œå¦‚ ["set datestyle to german", ...]
  • creator 函数或å¯ä»¥ç”Ÿæˆè¿žæŽ¥çš„函数å¯ä»¥æŽ¥å—è¿™é‡Œä¼ å…¥çš„å…¶ä»–å‚æ•°ï¼Œä¾‹å¦‚主机åã€æ•°æ®åº“ã€ç”¨æˆ·åã€å¯†ç ç­‰ã€‚你还å¯ä»¥é€‰æ‹©ä¼ å…¥creatorå‡½æ•°çš„å…¶ä»–å‚æ•°ï¼Œå…许失败é‡è¿žå’Œè´Ÿè½½å‡è¡¡ã€‚

举个例å­ï¼Œå¦‚果你正在使用 pgdb 作为DB-API模å—,并希望连接池中至少有5个连接到数æ®åº“ mydb

import pgdb # import used DB-API 2 module
from DBUtils.PooledDB import PooledDB
pool = PooledDB(pgdb, 5, database='mydb')

一旦设置好了连接池,你就å¯ä»¥æŒ‰ç…§å¦‚下请求一个连接:

db = pool.connection()

ä½ å¯ä»¥ä½¿ç”¨è¿™äº›è¿žæŽ¥æœ‰å¦‚原始的DB-API 2一样。而实际使用的是``SteadyDB``版本的强硬连接。

请注æ„连接å¯ä»¥ä¸Žå…¶ä»–线程共享,åªè¦ä½ è®¾ç½® maxshared 傿•°ä¸ºéžé›¶ï¼Œå¹¶ä¸”DB-API 2模å—也å…许。如果你想è¦ä½¿ç”¨ä¸“用连接则使用:

db = pool.connection(0)

如果你ä¸å†éœ€è¦è¿™ä¸ªè¿žæŽ¥äº†ï¼Œåˆ™å¯ä»¥è¿”回给连接池使用 db.close() 。你也å¯ä»¥ä½¿ç”¨ç›¸åŒçš„æ–¹æ³•获å–å¦ä¸€ä¸ªè¿žæŽ¥ã€‚

警告: 在一个多线程环境,ä¸è¦ä½¿ç”¨ä¸‹é¢çš„æ–¹æ³•:

pool.connection().cursor().execute(...)

这将会导致过早的释放连接以供å¤ç”¨ï¼Œè€Œä¸”如果是éžçº¿ç¨‹å®‰å…¨è¿˜ä¼šå‡ºé”™ã€‚ç¡®ä¿è¿žæŽ¥å¯¹è±¡åœ¨ä½ çš„使用过程中是一直存在的,例如:

db = pool.connection()
cur = db.cursor()
cur.execute(...)
res = cur.fetchone()
cur.close() # or del cur
db.close() # or del db

在Webware中使用

如果你正在 Webware for Python çš„ servlets 中使用DBUtilsæ¥å­˜å–æ•°æ®åº“,你è¦ç¡®ä¿æ•°æ®åº“连接生æˆå™¨åªè¢«åº”用å¯åŠ¨ä¸€æ¬¡ï¼Œè€Œä¸æ˜¯æ¯ä¸ªservletå¯åŠ¨æ—¶éƒ½åˆ›å»ºä¸€ä¸ªã€‚ä¸ºäº†è¾¾åˆ°è¿™ä¸ªç›®çš„ï¼Œä½ å¯ä»¥åœ¨æ¨¡å—或类的åˆå§‹åŒ–代ç ä¸­æ·»åŠ è¿™äº›ä»£ç ï¼Œæˆ–者使用 __init__.py 中的 contextInitialize() 函数。

目录 Examples 是DBUtilså‘行包的一部分,包å«äº†ä¸€ä¸ªä½¿ç”¨ç¤ºä¾‹æ•°æ®åº“çš„Webware的例å­ï¼Œç”¨æ¥è·Ÿè¸ªæ¼”讲会的出席者(这个例å­çš„ä¸»æ„æ¥è‡ªAndrew Kuchlingçš„ "The Python DB-API")。

例å­çš„æ­£æ–‡å¯ä»¥é€šè¿‡åˆ›å»ºé…置文件 Configs/Database.config æ¥é…置,改å˜ä¾‹å­ Examples/DBUtilsExample.py 的缺çœå‚æ•°ã€‚è¿™ç§æ–¹å¼å¯ä»¥è®¾ç½®ä¸€ä¸ªä¸“用数æ®åº“的用户å和密ç ï¼Œä½ ä¹Ÿå¯ä»¥é€‰æ‹©åº•层的数æ®åº“模å—。如果设置了 maxcached ,则例å­ä¼šä½¿ç”¨ "Pooled" 模å—,å¦åˆ™ä¼šä½¿ç”¨ "Persistent" 模å—。

注æ„

如果你正在使用一个æµè¡Œçš„ORM SQLObject 或 SQLAlchemy ,你并ä¸éœ€è¦ä½¿ç”¨DBUtiils,因为他已ç»å†…å«è¿žæŽ¥æ± äº†ã€‚ SQLObject 2 (SQL-API) 事实上还从DBUtils这里借用了连接池分层的代ç ã€‚

未æ¥åŠŸèƒ½

一些未æ¥ä¼šä½¿ç”¨çš„æ–¹æ³•:

  • 一个连接最大被使用的次数,或一个连接最大活动时间。
  • åˆ›å»ºæ¨¡å— MonitorDB å’Œ MonitorPg è¿è¡Œåœ¨å•独的线程中,监控连接池中å„个共享连接的状æ€ã€‚如果检测到一个æŸå的连接,则会自动æ¢å¤è¿™ä¸ªè¿žæŽ¥ã€‚这在很多网站中是很实用的,因为晚上往往è¦é‡å¯æ•°æ®åº“æœåŠ¡å™¨ã€‚å¦‚æžœä¸ä½¿ç”¨ç›‘控线程,则用户è¦ç­‰åˆ°ç¬¬äºŒå¤©æ—©ä¸Šæ‰å¯ä»¥ä½¿ç”¨ã€‚正是因为如此,检测æŸå的连接并自动æ¢å¤æ˜¯å¾ˆæœ‰ç”¨çš„。使用了监控线程之åŽï¼Œé—´æ–­æ—¶é—´åœ¨æ™šä¸Šï¼Œè€Œä¸”å¾ˆçŸ­ã€‚ç›‘æŽ§çº¿ç¨‹åŒæ ·å¯ä»¥é…置连接生æˆå™¨çš„线程池,并且确ä¿ç”¨æˆ·åˆ°è¾¾ä¹‹å‰å®Œæˆã€‚
  • å¯é€‰çš„æ—¥å¿—,记录æŸå的连接和最大é™åˆ¶ã€‚

错误报告与回馈

请将错误报告ã€è¡¥ä¸ã€å›žé¦ˆç›´æŽ¥å‘é€ç»™ä½œè€…(使用下é¢ç»™å‡ºçš„邮件地å€)。

如果有Webware相关的问题,å¯ä»¥åˆ°é‚®ä»¶åˆ—表讨论 Webware for Python mailing list 。

链接

一些相关软件的链接:

作者列表

作者:Christoph Zwerschke <cito@online.de>
贡献:DBUtils收到了如下朋å‹çš„帮助和建议 Ian Bicking, Chuck Esterbrook (Webware for Python), Dan Green (DBTools), Jay Love, Michael Palmer, Tom Schwaller, Geoffrey Talvola, Warren Smith (DbConnectionPool) and Ezio Vernacotola.
翻译:gashero <harry.python@gmail.com>

版æƒä¸Žè®¸å¯

Copyright @ 2005-2007 by Christoph Zwerschke. All Rights Reserved.

DBUtils是一个自由开æºè½¯ä»¶ï¼Œä½¿ç”¨ Open Software License version 2.1 许å¯ã€‚

PK¼hç6Kˆ&ÒÒDBUtils/Docs/persist.gifGIF89aÛƒ$$$:::JJJQQQggg{{{‰‰‰‘‘‘§§§¼¼¼ÈÈÈÙÙÙèèèþþþ!ù,Û@ÿðÉI«½8ëÍ»ÿ`(Ždižhª®+À¾p,Ïtmßxêf{: 0$ƒAðI£@H‹ˆ rðŒ>¦U-\mÅ#m4»Íé+öAx2´Nè–­¨¼pzcE €j_‹yQkqŒjG ‹dVIK‡NmMJL@† VlPC“¢’}†>!=¹·¼5§Bb½ ¥ ‹ÂÊ «* GË»ÒÕÖ×ÔØÛÜÝÞßàE.Táçèéêë1æìïðÚñôõö÷6ó,úøâüý4¤00 ®kü ú+ñk‹cf¢Ù‚Hç’ Q”ªÐ°DA…ÿ:yÈdH­(}¹8 ãF ÈL€yAä’O~Ù¨²«–4Ö ˆM uñq)®G—F•1õ©ˆ$ƒº4üókA¯f¶:èh*ØM¯&“ÃrÂ;¬¾öÁ(†k0 h=8Ëê¬À´•ðV X°tÝŽ½k¦(_«Õ’¢¨Ú/­S3/ûµ&Y³çÏ Ù´)F)kߢrÐlKØÐ°cË&(p¶íÛ¸‘ʦ›·mß¹E—“0.¸…q;Š—7œðåáÜA×¥|:êÖ'<Ïν;¼Î©ˆO¾¼ùóïΫ_Ï~;¯öðã»_6?ß ²äÒÇM;½úQTÿ~ø€Ç™C¯©tZO%á ~Ö°ÃH VƒoœrÚAñô@á‚•4€a†APq•Õ¶M„*®Ã"ÿÝò¢3zgãçHÖQLt Ô`%R4ø†1 MÔ`ýBÖ[ P¡× ¶„!H¹”>Öb¡ƒZ^I¥—ZP„ã˜-´Hæ™hж™5Ôfš3$ç_vr¢è]u™žt݉Ç&Ÿ}ê)è +šI衈æðæ 3’µh™ûqÑÆœÆ Ø!jö(rY‘"^"äee£ŸkoD*˜¨nhjŒ­Jiá§IriâZvÂ*7›fªN¯½î#£=Á&j챘QPG¨ ¥ÿE‹¹D*“wQ;Þ“Ÿþ2åUšÑmWv™Xª¢zËj¸È¦»Ð®¾ ð’ºðÚ›h/fãÝ™¯¾~ÞË«½é`§ï™ûk0nJ¬šÃVJãÁ-‚‘ŰpÁRJiÀYM Ǥ±œA"ýùÊðXˆÁŸ'f`\¹Þ“0} ÿúž®8,,Œ÷ìóÏ@ÿ¬c0˜ Še©eÁe~ ¼®¤¢¤i¶Bí0[YšÑY}ïÌ^‡-6ιéüÙcË´&th§m_s¶ý¶ÛÆ¡÷+ ™Gw=òõ»wd} lð.~ÿvá&×møâÓÐÉøãN'÷=½¡Ôz¹ÿÔjŽéV«;¹ÂåA>6y¦§®úê¬ËÛúëNmM±¢ÆP=òøKÑè~×åÑJ €¯a‰P|Ô[kÜï0%ãêo¥Æ@&Éã®ZP ,¢@kʇzí'á‡ßÄØU»ÖSO0<8²Ã.ÿwóÓ\ÿý±ï‹ÿþ2óïÿÿ6ŠßfBÐ$-†ç;d åj…1&0Ÿ¤JÖ—d]ERTø s)µ¡ã9¼¡´vŠ(€%GÊÒ ¸@ž‘@„ËÓILˆÂ ¼kzà_Ä%‚‹†‹Iá»nåÁÈÌMgY–Ó8@*i|l ’X„%n ‰·‹Ã‰Ð¢ÃÿPVÔ³RŠ-VЈ.,b %ÖB‹*ö&q§u„Fù ØøÆ.´Ñ ÙÐ'UÇ ° ÑÀ#£¸Æþ,«(Ëb@ 娅Hæ%­„"Ïî“  ¥|þ!ÊRšò”P9¥*W9Ê5‡ ,õ˜FR t$„j$fDÎò—·7„y6`JGÄä•1™ƒ8Éé/€Ï\f̧dºRšØTV3›=ÌaÚ Íè&t“ ‘ LßâÚ4?ˆ ³VédÔ¬yÌ%JÑ—Ä„ѳ‹¯Â9oðÏ㨓*ºRàÎú—Æl:TäO¯ÈB†`ÿdÐ2úÐñL¶èQûFx˰à.¤˜sÍi:¥ÞYMUÛR©§À®(Ý¡y1%éA;Ú„P#pÇé[P[‰'¡fèAªv”J¦:§•I…êR¥ÚT©–é@=*UŸ„Ñ+M=êúMîŒõ¡‚£SXI7¦µòôq„h79öMpæì3ÄìTÄ%+t¢KnÍÕîJÏmÅSž´Ih˜O ÑÊJü$ ¦kІ"d®ì¬+ý4»Yv½õ³G<œaÑ\4Ô¨28 ZØtæk‰É‚<®цîë×ZjH¨áó±$ .MQZ‰›¾sT1dmkéêÙ©vU«Ïÿjt“ƒÕên5«Ò…ÏP£ë\íB×»ÙmOܬËݪ–—«àW¦(«›õº.Om¦uä;_¼¹n¹øåÔ6óËßææ³0sïêÚBíEzÈ»–FzÐÀöÀwWÃZù<Õ4ÿº±CÂûfª,@°×‰½,gÿ+à̆nýM1B5®‘–VxYRš•à£~”Å\D6 Š…?uР(Z6²½øRÅ|Û/’Süa5Jî«K®l0Íå¤Õ£e«2A‹*ú¾Z¦—WÔdØ7¾e ³kÓ¬¸ž–ro¦Tæ|Õ|£23J]3FÉhéàGMyR~f…/‡,:ÇÑùNB eÿ˜AyèF«×Ñø+¤±)iaˆPÊeqi XÑlò0S@œ‘—â ¤¯téPvÚ>Ó²Ø ‰Pb½Õ´&ÃnaÀ­9º9áwÆ»%ô.Ò¶(•Ûô¶·—Uàp 1¾„÷°lIjOAa@(±šÓT[ÂþÜE7¢šq­´¤"E¶Þ÷j_ÖF[#ty‰”•e¼´€hgA-6TÂß:ýX4ö­ÕˆVò£ps}ïI½ …ð»ÇP”) v‚Dþ±%VÂ9zOrHc™3`qÂÒS!3ª{ªäIÇ·å.§´ËíóxѼæÈ:+Î—Ëæ¿õÌ‹ö9O+ÿ-tÿµ‰•HOºÞÄ¡ô¦+=•Nº*Eìîþ†–Yfä”MìdNKÓwAƒÇº¹~=dùvµîõ£½Ó+·ºœ­AXœ ptã­ðiVëw]fGZ ñ Iéaï}ß‹jå^õÀ{w㹸¯¸ÿèl,ãU¶ožêeÏap8¿u¬wóqÚ£cuR‡2*©9 Ÿ F œPiH¼ç¥ÜH¡´öœ€½bæH{e;ƒº7ý1{ÏRÍÿõ±'þ—Øä€¤ö1Õrþ% íð~W—ëeü«6$¶4Ïû&ü¶·ö׫w~ƒ‚¹üõ~ÿñË?äôgRöw|”ì7LJ1EëçfÄx…D ˜ ¨ËçEˆx€Fw£§|W·{ÆM°VtÀDt$ˆ?£ÁCD ¤àc^hùfd w‚ð'Ãö¹ƒ`·Ã}417÷ƒ‚„BHe!HM`õYD¸bõ¢„PF0C×s£'…lC…ÿc…3fÎt¿Ä…Ëá…õµ„wV„%sdX?&x†¬“†GDP§rboH`‡Sbí&‡qè†b!bÇ” j·NÞD¨„l(!F3<0c;„ñ—¶1tÕˆ5ÕÆ`  ZM¦W¾–ˆßÆ`Gˆzh”i“q*¢ÈUÿŠ¢ÇP™w3#Fbpx2v˜d#¨ R·t.R‹:×e¸†jØ‹¾HgC³+€ŠœX+Âhiö‹0Œ@xÿ÷1;F1³yâÁˆ%•gy¦jO“kí3RΘˆí3‰(')¨ŒØ~æ8?…˜Žì興–„?÷„òørmUMU:f•‹ùˆ…üÿ¡…UÈ‹WxeY/ù…ä•^æ¥è%^ßåáÅÛÅØÕ]i‘ù‘ë1‘¹Ù‰‘ùfØŽ³Ž(™6*Ù^¯ÈuxhW1)“6“5Ù†°h“B#{xŽ0©Xf5²rvÖ’©×p_+â¨Nއ ”c`ÿ=œX‰“%‹Òø=’(•&Cžˆ xM±ø“†H68™“> –:éŠaya­È–«Ø »èá—tY—¶’z¹—ÈÔ"¨flmgj1*Ø ¨È—í°_q Î(P@yͶÑØaÙˆaÛ¸ˆÝh+‘w`à–`˜9ŽE†˜‹ô–o'šƒb”¦ „kÓ—PZb¸ŒM…ù—›7´ù\u™…É›·9¯Ù¿É›r] ’ ’#©œ%É‘êá‘Ë)’ÍI’Ï©‘ÓÉœÕéœv£¶HÛéÝ ’'™š§3žä9‡³—wé`ëy‰ë™7æ™–.y“eIŸó4Ôp˜@ÿNã`éW=áOd©Ÿ=øWDˆš;³kžr½Öˆ]9w a <;ÒŸ°¡Ê<çÖŒ/q ñ971(o)ç<|‹!Šq"Ç% °™îˆ1(p)j4lð.šž¬ø’y‰£öy”(FškyŸjù£b ¤dbçy¤Hz‡¯ÂR´P¡Ô3j\#[Œ >(ɘ¤LÈ!K²z%¡‰P@eÄBV9n$µ5ß6lSCBúlX ‚R@ýQ@¾…)S@}w±¢Õ˜E86É•p“£¢%C6R‡DAoZg™¨èy„sÖš*œ£‰„j&©pšu5g©>*N?¨©-úy¿(©žj£jxÿsÈÑ›o8ªòsU쉪·8œéžð«$—¢I«Lמº¸úsúȨI(® ¬TÑ«±ƒ祌[åH¬ehΊ–m­¨÷…x  E =£ª—ª'[ÚmÔkÜÖa:(¡Ì–sÐz,rêô6oG@pý¦pò ‡ £5¸®ÔJ‹z’ûjE·«ËÿZ°{°û»° Û°û°—š°§9±Û¯{±ð¸©xQKLt¥©¦ŸÜ*™Ïà S ª ˜6°¢P´B²±m9ŠŽ±fw`çx"«³jå˜àŠdy%û;ëv4Õ™$ƒHª«ÅÿC8‘?DXÐr*4µ¯qµÏÂqö´›Ð1Ä[T¶åb.bâ{YR±x¾f²‡aÎB!ј ´ò‘¶ Z.&qvRê‡ )Á·Ü‚.éÚ´Ë€vç› é xô ³ëkøknˆŽy@ŒYkŸ c…¹4‹ HAK θ´@ ð§»¹Ôxd¨²”ø2Và#Õ¹Ü8SÇrN‹ŒJË<%T ¶eW‹R·¥µµõ_ëµaA¶aD‹YIeˉÍÇ•§A•Ð=z± °ºž³OÊfIù-Å+Èûu9uv0< nÍB¸Fs¸ø•‡BEËÿ(FG ùK¦/[­‹J(øÛ¿5°¿í[EÓ¥A:Àk,ÁïÈL{ÁœÁ¼Á ;sܨ¼“!Ü­¹â­#,#¿zÂ9g«* V»ÙÂÂ:¬0l&<Ã(â³BžÃÍÄV¥x|£à Æpƒ 7pïúÈœŒ´†lÍ\ƒÍÒÏü ¨,ZÏÉ\»øŒ¯ó¶ÏòÌ3ÊÊöcÏjüßüÅé Ñ"ÈÐË,Ñí&Ÿ mƒ 5œÇ ¬ÑÆÒ ›ß×%œÈÔ|À]Ñb” 6¦¹á̾¶½?kžU1À)}φ± ,ýÆê<ÆžæPSj–³q€§€ÿÔï[É®ÆÌ.Š[ú†$`KýÔN-É2Õ˜±Um5N­Õ‘ÀÕXíÕ{Ö!MlÛ%l»Î£(L¤A£À¥Ñ$x]»A}’SQ×Ó›AJƒKÝw-{¨ð$MÅ:ƒ- …½‡Í׊^ÐØ )›80´ŽÔºÑØhФAPj€évl ÆUÚGƒÚˆmH=æ°M¢ˆºÚ-ÝП½µ:Û¤=ÛM=ÚD³!…ÛB]¿ÕÌÕ Ùo™Ó†Å£Ð¼`ðKÏÇ®ƒÃ³íÖ<¬`¡à”íjо{Íbgkíõ )èž=ÜîÓ¶î»ñ>€4ÖVt‰ÚÌ=é~4œÈ•îþÞíø:¢Šènð"j1Ís z*» ïŠ q…Ja ¬ÛŸXï ó¿èý¬^=†§à“\¤ºîê˜>â¨ëæß¿Ý/þåæáærþퟫ4…ï_åóÿ/õôzäDÎû-ßü?éð䔀^œõæÝ0G²4O4UW¶­ vgº¶o<×w>•³_O8$G¤1xY&+hT:¥V­Tçèºåv›ÙW<þ‚=åú¨¦±Í•¡ûM‘·ês|è¾Ú;û¾ ü.Œ7O`B‚pÿÈIÔp®Fu óý³÷^AHOiô'¡á€’D)Jd¸…(MLùï94ÛP°6ëX²e :ÊÜx3$ÏbØ®á*Óž‚)³ÊM$–í§¶ ôìñb9•ª¹<:õ°+髲Dr†})홉^y¼E öUÛ£uÏö Ë×®ðéʼn—ì߸‰/fÜØñcÈ‘%O¦\ÙòeÌ™5o+˜ógС V€`ÂÓC¨®IÀ×ÕHX‹¦y­ÔЂ2ýÅt'(P–‡ÀãIž¿óeÃÆÍ™®çÍ×)e@`·ÓmM£÷¬ÝÝ%bxR£$y@ê¿¿í™æÑüÃTûú¥<ÿÙT—ýòœHjEÉ ýy¼Ð-»â£à=òæÓfx`ú¨€°f¢°¢k»NìCü*¦é4ñÛ$€ Š~@æ*ܼa¯àˆ¢Ñ'e’:†E `ämÄ©[î*« ¹;qI3RÌ!=&£”R'§´òÊÁ*ÂrK.»¼!0ÆÀlLL/s 3±3K³Ì‹¦\3®7Ùt!Îì¤SNB,€ŠùÜóNCø,GP<ÁÂÄC¢ÐUTŠ%e4PHOt4Ò(&mÐF2•ÒSMÕRB™5Ô@8ÍËM;QuõÕÀƒuVZ)Z¤V\i­2W^'ݵW`Ùÿü5Xb·V ÃDUk¯¹0Su”d]¶0‚óY-¦5(Z\—˜mÕ°µG¢L€±%cRƬХvÕ¢NˆE8h³ñ„üŒ²·&âqw[ÏüXðT‰Æžhâ3Åù•«Ó|@)ؤd(…/¾ÀÁ xb‹ÕIãŽÈ”\:þ.à$`€R9N¨E#9ŒWeÀŠ› fó R¥”õM÷å Ti>Ÿm¾À_[Ñ” Láäƒõ™¿{…–V›© N”«D¨^€¥&˜ ªÛf˜O\>ž^ƒ[¶èV¶Z§Y†ÚîœùNÕoxÉÎâÚ•ñÞ—Ê1åFÖð»ÿñ0/‚ Ê·p©rÌ%½ÚË}€éˆ•žÉ£|À=÷Yw÷=Ö{q`‹Þwž<¬Úb…KÖ8cým¸ê¡¸Z“éiù+•_zB›N›Â8ê+öjz¦YlØ-Fæ¡ k¥|}­rÅC¢Q!™‡¥‰ŸG”ðýN?$ ‘͘vÁd0 §þä7À( „#LœÞHxÂň…+|L©ž@†QP.†0ôJåf8†Š!‡^ØazÈ…ZŽ 2"1aÄ#ÒH|!A·&ÿ…bËX5E3u§Š(¢_D³ÅÁuQ[œãÞĨ„2â “;£Àlã5²0Žv¨Í±hÇÑ<±“ Û´ÇÇ¥ð3~$Î:µ§4’…dÖÃY©ÈJ‘ŒÔR"7wª1ù‰’™Ä$¥\ÈIÍmÒ-VÆ'SJQâäR†2%š ™Êvò.±œ$,9wKR’—»”%#}KQQWU¦‰ù©Z“RúS2•Ù2I23Wx¦³¨YI-š sÕ<Ã6Õ(ÍHòRœã$g9Q)H8rSSÎ܉:ÅÎÀÓaLç<ñ$O:ÚSNød?³ÀºóˆàxŸó§ šÞ•"~#ÝA©)÷p"aŸ`ˆ~(:ÓtÏ¢J…øPÑ•B9ô"5Âqš…‹)¥¸yMŽd—#è9ëç¤ 8A]ô£9Hù ¤n,è‚%zgMõé%’– ©GÍb=™Ú¥¥ö³—O­Ì+]%LªúAˆ¢4§1ÕÕ_fU¬c%k°";PK¼hç6ËðV=z z DBUtils/Docs/pgdep.gifGIF89a^–ƒ$$$555HHHQQQeee{{{‰‰‰“““¤¤¤½½½ÈÈÈÙÙÙæææþþþ!ù,^–@ÿðÉI«½8ëÍ»ÿ`(ŽdižhªbÀꢭ¿t8×Ïï<§k¿ @Ç!Q•̇y<ESmÃâséEú:·0ñˆÕJ¹ƒdˆRªt»¤ÛÞ‚åRcQjFH]fA&Š DQU‡€UIdˆU Y~`E…‡S¡_•}o£H„_¨Œ®=8°­³±.D±µ¶»)¸¼%Ÿº¿;ŸÃÆ5ÁÂÇ˶E9Ì·9ÉÊÐÕ-ÅÖÚÛ,ÜÔÞËàáäáã²åäçéìþí ïð½óõíÊŽu–L¦ VˆXAÕe’U†.M9cMÇ×™ƒøŠ¢Å‹¿¦a„±±£ÇŒÎÿ$Îù±¤ÉhOª\‰Œå ’.cN´FPák0eê·“FΞ@›UpH‰3¤˜)pAÉž ÁR(  ¨œ6…:Aë¦ ˜‘ ¶ë¯¸¡ð3¨[¡o¿Å8­®Ý»xóâE¦·¯ß¿v«L¸°á»‹8X‡6”á #žTbˆò„"+®T‹jE…6ÂBBØ[n,Ø"N¨W•Uý— Ü4DMpG6çaG:3R>Så•îT(S”Xvùà \ò¦—d¾Ϙe¦É–šè±é&CÕ@!MÞh šoºxZF­—AŸzhÆ|WÁÀS õ¢V=—ç£kR À¡ŒdÁ ˆNw¨'?j ôùÈk @¥žšÏ«fÅÕ7)¤´Öjë­¸æ §G"á铆l‚ãë. ›KKµÖR‹dtlªÝÿú 7*€8É,‡Öi`E»^›í¨P~ôÇŸ¹õM;IDhÑ›Þ褕f JhrÁ@”Æ÷£jÓ~÷@³æþölÓÙ1Dµ¦…­¼vÒÛJãÕÅB¥(ùÔÅ SÀÊ®ßW)¬Â`/‰ˆ$ø}|š0GrÉjðqL…›¬%²Ç6¹ªs¹$W‡IÅA‡ r;·0à‡6|Ô´ &xˆES;jˆ"r-ƒ×#-‹ØR6Ù[« Ùº² aŽÁ¨YWÛBx‘–WæE÷Tª}K6enˆöÞQß=k—~ãšø“iN8±êÈýø™‚5>ù…Ž«“¹ÿJ‹?Þ9J[^Î.âò&€'÷ÙØÂÈ5ðÙ^E°'H2¡è)‚Ð,Ë>þ$+ 0/ÒC³øÑç¸k}L銑òt›P&¿ÑaÔS_òÒkζ…ØgÏÛ@uï½=zë9~®}›¾ôâã¸þúíCý>ÝÛOXÿüeKŽ¿ýÚä»z€ÛºÓþæâ7‹•Añ ²ât :9ïB |K#Á ü`R– S0H”&lªQD|4H…±t°R˃%ô5?©G…žˆ·*>…+X@Ö‚Á¯¸*S)Ó¥rœ‡CA¢SЯ$M ŒR‹ühÈ HqO3IGEûÿUï‹`rŽ´*–b>‘E Ìæ‘!d—¦4„”à)p¤Ò@Ǥӡl䔟6s/Útç(~œdâÅÉÔÆa ¥ÖHé‚«uf¨4^½F(d’•Ȥ¤:6°‡áF–‚²Í?Ny´÷üŽ ªáeé’¹H.®R˜¢‚þѬÙѧš¾„eAH‘3—áÌ„Þ,1@ƒÁ>Ü´DÇ*aXÄ Ä$&ŒªNÌ€³>›Å²b67쮟-ì2âS àž%-&2Uµ€Qͳ@ ¨ e6ËêVSaÌŘ??%+ÊÎZ®É¨U«è  .ô¸Ëf6Ôv%YH‚äJŒÐÈ4¿„U:ÅSFBd°GÑyúúÄnët&ß®,ýÁ1Œ˜-ßH3ËÙ¹A£³  -Þê1GEvt§¥Ki×¶Z/¶6XÉØIÜ`;Ûìy–sµ%ÓhÙg·éÅÖKš=_n£wÛÆ W¸¾Hí5ú¸À¡çµºÿz‡r¡–Æ*iº}tæCÀd¹)žñ´ØàÑpÇðfd¼2 œeÑ;ÙÜ9—½Ýzáßʽ—¾#e†y…_`ˆ6´hìo{y—ýêV}:10p=€©ü•T pvœ^Åбx0dWÑÀšˆÂ$ÐE9ÍRÕ‚ˆŸ 1¿¹V¤þÄ!n zIHñp¢t1ƒIŠ4Jvm0&¾ÚVªºl_¥Ã=c†…ýŒ7qÅ«á‚Lj8"•Ébx|+莀*X&g„Ý=*-µÕ‘™ËŒ%.Ã8Í\³iáÜ7Ë|”sLvë;ë™-½}ñŸÜÜ>ZŽ1°³ÿ—Ý5:ÑÒÁ–!-%4SºÍÛ½ô‚G¢éÿ÷Ó`ì´Eü\_Q³ƒÔã4µ|ƒ¥jo úW­F`ÿŽúÖpò(Ööe`þéãÏâ:×ÐPPÕiWÈýZ¿³®e]e}léÚ«cv³Ïû¦WÑÚ°ž¶;,pÄ 4àiPˆÏ˜´©¢þiâ+‘ˆ‚+zWÛÆÖ ¿}-4À eI¢³ì-§9‘„(ÌÄ¡¾í”²8E+çJÂ~…ކÛTÔ½3¨U×ùp…0e ¨(± p‹™ÒSXØ'©‚<-ã–¼ãM >Ñ,fÞÅA&^ÝùQ÷Re (rŠWn'èžk¥‡Ž^ye÷ð¼$ÈH&î¾«Ò©é© fÑPºշÎõ® ;PK¼hç623g{_Z_ZDBUtils/Docs/UsersGuide.de.txtBenutzeranleitung für DBUtils +++++++++++++++++++++++++++++ :Version: 0.9.4 :Released: 07/07/07 :Translations: English_ German Chinese_ .. _English: UsersGuide.html .. _Chinese: UsersGuide.zh.html .. contents:: Inhalt Zusammenfassung =============== DBUtils_ ist eine Sammlung von Python-Modulen, mit deren Hilfe man in Python_ geschriebene Multithread-Anwendungen auf sichere und effiziente Weise an Datenbanken anbinden kann. DBUtils wurde mit Blick auf `Webware for Python`_ als Anwendung und PyGreSQL_ als PostgreSQL_-Datenbankadapter entwickelt, kann aber für beliebige Python-Anwendungen und beliebige auf `DB-API 2`_ beruhende Python-Datenbankadapter verwendet werden. Module ====== DBUtils ist als Python-Package realisiert worden, das aus zwei verschiedenen Gruppen von Modulen besteht: Einer Gruppe zur Verwendung mit beliebigen DB-API-2-Datenbankadaptern, und einer Gruppe zur Verwendung mit dem klassischen PyGreSQL-Datenbankadapter-Modul. +-------------------+----------------------------------------------+ | Allgemeine Variante für beliebige DB-API-2-Adapter | +===================+==============================================+ | SteadyDB.py | Gehärtete DB-API-2-Datenbankverbindungen | +-------------------+----------------------------------------------+ | PooledDB.py | Pooling für DB-API-2-Datenbankverbindungen | +-------------------+----------------------------------------------+ | PersistentDB.py | Persistente DB-API-2-Datenbankverbindungen | +-------------------+----------------------------------------------+ | SimplePooledDB.py | Einfaches Pooling für DB-API 2 | +-------------------+----------------------------------------------+ +-------------------+----------------------------------------------+ | Variante speziell für den klassischen PyGreSQL-Adapter | +===================+==============================================+ | SteadyPg.py | Gehärtete klassische PyGreSQL-Verbindungen | +-------------------+----------------------------------------------+ | PooledPg.py | Pooling für klassische PyGreSQL-Verbindungen | +-------------------+----------------------------------------------+ | PersistentPg.py | Persistente klassische PyGreSQL-Verbindungen | +-------------------+----------------------------------------------+ | SimplePooledPg.py | Einfaches Pooling für klassisches PyGreSQL | +-------------------+----------------------------------------------+ Die Abhängigkeiten der Module in der Variante für beliebige DB-API-2-Adapter sind im folgenden Diagramm dargestellt: .. image:: dbdep.gif Die Abhängigkeiten der Module in der Variante für den klassischen PyGreSQL-Adapter sehen ähnlich aus: .. image:: pgdep.gif Download ======== Die aktuelle Version von DBUtils kann von der Homepage von Webware for Python heruntergeladen werden: http://www.webwareforpython.org/downloads/DBUtils/ Außerdem befindet sie sich im Python Package Index (auch bekannt als der "Cheese Shop") und kann von dort heruntergeladen werden: http://www.python.org/pypi/DBUtils/ Installation ============ Installation als eigenständiges Paket ------------------------------------- Wenn Sie DBUtils für andere Anwendungen als Webware for Python verwenden möchten, empfiehlt es sich, das Paket auf die übliche Weise zu installieren:: python setup.py install Installation als Unterpaket (Plug-In) von Webware for Python ------------------------------------------------------------ Wenn Sie DBUtils nur als Ergänzung für das Web-Framework Webware for Python verwenden wollen, sollten Sie DBUtils als Webware-Plug-In installieren:: python setup.py install --install-lib=/pfad/zu/Webware Ersetzen Sie ``/pfad/zu/Webware`` hierbei durch den Pfad zum Wurzelverzeichnis der Installation von Webware for Python. Sie müssen auch das Installationsskript von Webware for Python laufen lassen, wenn dies noch nicht geschehen ist, oder wenn Sie DBUtils in die Webware-Dokumentation integrieren wollen:: cd /pfad/zu/Webware python install.py Anforderungen ============= DBUtils benötigt Python_ Version 2.2 oder höher. Die Module in der Variante für klassisches PyGreSQL benötigen PyGreSQL_ Version 3.4 oder höher, während die Module in der allgemeinen Variante für DB-API 2 mit jedem beliebigen Python-Datenbankadapter-Modul zusammenarbeiten, das auf `DB-API 2`_ basiert. Funktionalität ============== Dieser Abschnitt verwendet nur die Bezeichnungen der DB-API-2-Variante, aber Entsprechendes gilt auch für die PyGreSQL-Variante. SimplePooledDB -------------- ``DBUtils.SimplePooledDB`` ist eine sehr elementare Referenz-Implementierung eines Pools von Datenbankverbindungen. Hiermit ist ein Vorratsspeicher an Datenbankverbindungen gemeint, aus dem sich die Python-Anwendung bedienen kann. Diese Implementierung ist weit weniger ausgefeilt als das eigentliche ``PooledDB``-Modul und stellt insbesondere keine Ausfallsicherung zur Verfügung. ``DBUtils.SimplePooledDB`` ist im Wesentlichen identisch mit dem zu Webware for Python gehörenden Modul ``MiscUtils.DBPool``. Es ist eher zur Verdeutlichung des Konzepts gedacht, als zum Einsatz im produktiven Betrieb. SteadyDB -------- ``DBUtils.SteadyDB`` ist ein Modul, das "gehärtete" Datenbankverbindungen bereitstellt, denen gewöhnlichen Verbindungen eines DB-API-2-Datenbankadapters zugrunde liegen. Eine "gehärtete" Verbindung wird bei Zugriff automatisch, ohne dass die Anwendung dies bemerkt, wieder geöffnet, wenn sie geschlossen wurde, die Datenbankverbindung unterbrochen wurde, oder wenn sie öfter als ein optionales Limit genutzt wurde. Ein typisches Beispiel wo dies benötig wird, ist, wenn die Datenbank neu gestartet wurde, während Ihre Anwendung immer noch läuft und Verbindungen zur Datenbank offen hat, oder wenn Ihre Anwendung auf eine entfernte Datenbank über ein Netzwerk zugreift, das durch eine Firewall geschützt ist, und die Firewall neu gestartet wurde und dabei ihren Verbindungsstatus verloren hat. Normalerweise benutzen Sie das ``SteadyDB``-Modul nicht direkt; es wird aber von den beiden nächsten Modulen benötigt, ``PersistentDB`` und ``PooledDB``. PersistentDB ------------ ``DBUtils.PersistentDB`` stellt gehärtete, thread-affine, persistente Datenbankverbindungen zur Verfügung, unter Benutzung eines beliebigen DB-API-2-Datenbankadapters. Mit "thread-affin" und "persistent" ist hierbei gemeint, dass die einzelnen Datenbankverbindungen den jeweiligen Threads fest zugeordnet bleiben und während der Laufzeit des Threads nicht geschlossen werden. Das folgende Diagramm zeigt die beteiligten Verbindungsschichten, wenn Sie ``PersistentDB``-Datenbankverbindungen einsetzen: .. image:: persist.gif Immer wenn ein Thread eine Datenbankverbindung zum ersten Mal öffnet, wird eine neue Datenbankverbindung geöffnet, die von da an immer wieder für genau diesen Thread verwendet wird. Wenn der Thread die Datenbankverbindung schließt, wird sie trotzdem weiter offen gehalten, damit beim nächsten Mal, wenn der gleiche Thread wieder eine Datenbankverbindung anfordert, diese gleiche bereits geöffnete Datenbankverbindung wieder verwendet werden kann. Die Verbindung wird automatisch geschlossen, wenn der Thread beendet wird. Kurz gesagt versucht ``PersistentDB`` Datenbankverbindungen wiederzuverwerten, um die Gesamteffizienz der Datenbankzugriffe Ihrer Multithread-Anwendungen zu steigern, aber es wird dabei sichergestellt, dass verschiedene Threads niemals die gleiche Verbindung benutzen. Daher arbeitet ``PersistentDB`` sogar dann problemlos, wenn der zugrunde liegende DB-API-2-Datenbankadapter nicht thread-sicher auf der Verbindungsebene ist, oder wenn parallele Threads Parameter der Datenbank-Sitzung verändern oder Transaktionen mit mehreren SQL-Befehlen durchführen. PooledDB -------- ``DBUtils.PooledDB`` stellt, unter Benutzung eines beliebigen DB-API-2-Datenbankadapters, einen Pool von gehärteten, thread-sicheren Datenbankverbindungen zur Verfügung, die automatisch, ohne dass die Anwendung dies bemerkt, wiederverwendet werden. Das folgende Diagramm zeigt die beteiligten Verbindungsschichten, wenn Sie ``PooledDB``-Datenbankverbindungen einsetzen: .. image:: pool.gif Wie im Diagramm angedeutet, kann ``PooledDB`` geöffnete Datenbankverbindungen den verschiedenen Threads beliebig zuteilen. Dies geschieht standardmäßig, wenn Sie den Verbindungspool mit einem positiven Wert für ``maxshared`` einrichten und der zugrunde liegende DB-API-2-Datenbankadapter auf der Verbindungsebene thread-sicher ist, aber sie können auch dedizierte Datenbankverbindungen anfordern, die nicht von anderen Threads verwendet werden sollen. Neben dem Pool gemeinsam genutzter Datenbankverbindungen ("shared pool") können Sie auch einen Pool von mindestens ``mincached`` und höchstens ``maxcached`` inaktiven Verbindungen auf Vorrat einrichten ("idle pool"), aus dem immer dann geschöpft wird, wenn ein Thread eine dedizierte Datenbankverbindung anfordert, oder wenn der Pool gemeinsam genutzter Datenbankverbindungen noch nicht voll ist. Wenn ein Thread eine Datenbankverbindung schließt, die auch von keinem anderen Thread mehr benutzt wird, wird sie an den Vorratsspeicher inaktiver Datenbankverbindungen zurückgegeben, damit sie wiederverwertet werden kann. Wenn der zugrunde liegende DB-API-Datenbankadapter nicht thread-sicher ist, werden Thread-Locks verwendet, um sicherzustellen, dass die ``PooledDB``-Verbindungen dennoch thread-sicher sind. Sie brauchen sich also hierum keine Sorgen zu machen, aber Sie sollten darauf achten, dedizierte Datenbankverbindungen zu verwenden, sobald Sie Parameter der Datenbanksitzung verändern oder Transaktionen mit mehreren SQL-Befehlen ausführen. Die Qual der Wahl ----------------- Sowohl ``PersistentDB`` als auch ``PooledDB`` dienen dem gleichen Zweck, nämlich die Effizienz des Datenbankzugriffs durch Wiederverwendung von Datenbankverbindungen zu steigern, und dabei gleichzeitig die Stabilität zu gewährleisten, selbst wenn die Datenbankverbindung unterbrochen wird. Welches der beiden Module sollte also verwendet werden? Nach den obigen Erklärungen ist es klar, dass ``PersistentDB`` dann sinnvoller ist, wenn Ihre Anwendung eine gleich bleibende Anzahl Threads verwendet, die häufig auf die Datenbank zugreifen. In diesem Fall werden Sie ungefähr die gleiche Anzahl geöffneter Datenbankverbindungen erhalten. Wenn jedoch Ihre Anwendung häufig Threads beendet und neu startet, dann ist ``PooledDB`` die bessere Lösung, die auch mehr Möglichkeiten zur Feineinstellung zur Verbesserung der Effizienz erlaubt, insbesondere bei Verwendung eines thread-sicheren DB-API-2-Datenbankadapters. Da die Schnittstellen beider Module sehr ähnlich sind, können Sie recht einfach von einem Modul zum anderen wechseln und austesten, welches geeigneter ist. Benutzung ========= Die Benutzung aller Module ist zwar recht ähnlich, aber es gibt vor allem bei der Initialisierung auch einige Unterschiede, sowohl zwischen den "Pooled"- und den "Persistent"-Varianten, als auch zwischen den DB-API-2- und den PyGreSQL-Varianten. Wir werden hier nur auf das ``PersistentDB``-Modul und das etwas kompliziertere ``PooledDB``-Modul eingehen. Einzelheiten zu den anderen Modulen finden Sie in deren Docstrings. Unter Verwendung der Python-Interpreter-Konsole können Sie sich die Dokumentation des ``PooledDB``-Moduls wie folgt anzeigen lassen (dies funktioniert entsprechend auch mit den anderen Modulen):: help(PooledDB) PersistentDB ------------ Wenn Sie das ``PersistentDB``-Modul einsetzen möchten, müssen Sie zuerst einen Generator für die von Ihnen gewünschte Art von Datenbankverbindungen einrichten, indem Sie eine Instanz der Klasse ``PersistentDB`` erzeugen, wobei Sie folgende Parameter angeben müssen: * ``creator``: entweder eine Funktion, die neue DB-API-2-Verbindungen erzeugt, oder ein DB-API-2-Datenbankadapter-Modul * ``maxusage``: Obergrenze dafür, wie oft eine einzelne Verbindung wiederverwendet werden darf (der Standardwert ``0`` oder ``False`` bedeutet unbegrenzte Wiederverwendung) Sobald diese Obergrenze erreicht wird, wird die Verbindung zurückgesetzt. * ``setsession``: eine optionale Liste von SQL-Befehlen zur Initialisierung der Datenbanksitzung, z.B. ``["set datestyle to german", ...]`` * Die als ``creator`` angegebene Funktion oder die Funktion ``connect`` des DB-API-2-Datenbankadapter-Moduls erhalten alle weiteren Parameter, wie ``host``, ``database``, ``user``, ``password`` usw. Sie können einige oder alle dieser Parameter in Ihrer eigenen ``creator``-Funktion setzen, was ausgefeilte Mechanismen zur Ausfallsicherung und Lastverteilung ermöglicht. Wenn Sie beispielsweise ``pgdb`` als DB-API-2-Datenbankadapter verwenden, und möchten, dass jede Verbindung Ihrer lokalen Datenbank ``meinedb`` 1000 mal wiederverwendet werden soll, sieht die Initialisierung so aus:: import pgdb # importiere das verwendete DB-API-2-Modul from DBUtils.PersistentDB import PersistentDB persist = PersistentDB(pgdb, 1000, database='meinedb') Nachdem Sie den Generator mit diesen Parametern eingerichtet haben, können Sie derartige Datenbankverbindungen von da an wie folgt anfordern:: db = persist.connection() Sie können diese Verbindungen verwenden, als wären sie gewöhnliche DB-API-2-Datenbankverbindungen. Genauer genommen erhalten Sie die "gehärtete" ``SteadyDB``-Version der zugrunde liegenden DB-API-2-Verbindung. Wenn Sie eine solche persistente Verbindung mit ``db.close()`` schließen, wird dies stillschweigend ignoriert, denn sie würde beim nächsten Zugriff sowieso wieder geöffnet, und das wäre nicht im Sinne persistenter Verbindungen. Stattdessen wird die Verbindung automatisch dann geschlossen, wenn der Thread endet. Sie können dieses Verhalten ändern, indem Sie ``persist._closeable`` auf ``True`` setzen. PooledDB -------- Wenn Sie das ``PooledDB``-Modul einsetzen möchten, müssen Sie zuerst einen Pool für die von Ihnen gewünschte Art von Datenbankverbindungen einrichten, indem Sie eine Instanz der Klasse ``PooledDB`` erzeugen, wobei Sie folgende Parameter angeben müssen: * ``creator``: entweder eine Funktion, die neue DB-API-2-Verbindungen erzeugt, oder ein DB-API-2-Datenbankadapter-Modul * ``mincached`` : die anfängliche Anzahl inaktiver Verbindungen, die auf Vorrat gehalten werden sollen (der Standardwert ``0`` bedeutet, dass beim Start keine Verbindungen geöffnet werden) * ``maxcached``: Obergrenze für die Anzahl inaktiver Verbindungen, die auf Vorrat gehalten werden sollen (der Standardwert ``0`` bedeutet unbegrenzte Größe des Vorratsspeichers) * ``maxshared``: Obergrenze für die Anzahl gemeinsam genutzer Verbindungen (der Standardwert ``0`` bedeutet, dass alle Verbindungen dediziert sind) Wenn diese Obergrenze erreicht wird, werden Verbindungen wiederverwendet, wenn diese als wiederverwendbar angefordert werden. * ``maxconnections``: Obergrenze für die Anzahl an Datenbankverbindungen, die insgesamt überhaupt erlaubt werden sollen (der Standardwert ``0`` bedeutet unbegrenzte Anzahl von Datenbankverbindungen) * ``blocking``: bestimmt das Verhalten, wenn diese Obergrenze überschritten wird (der Standardwert ``0`` oder ``False`` bedeutet, dass eine Fehlermeldung ausgegeben wird, andernfalls wird blockiert und gewartet, bis die Anzahl an Datenbankverbindungen wieder abnimmt) * ``maxusage``: Obergrenze dafür, wie oft eine einzelne Verbindung wiederverwendet werden darf (der Standardwert ``0`` oder ``False`` bedeutet unbegrenzte Wiederverwendung) Sobald diese Obergrenze erreicht wird, wird die Verbindung automatisch zurückgesetzt (geschlossen und wieder neu geöffnet). * ``setsession``: eine optionale Liste von SQL-Befehlen zur Initialisierung der Datenbanksitzung, z.B. ``["set datestyle to german", ...]`` * Die als ``creator`` angegebene Funktion oder die Funktion ``connect`` des DB-API-2-Datenbankadapter-Moduls erhalten alle weiteren Parameter, wie ``host``, ``database``, ``user``, ``password`` usw. Sie können einige oder alle dieser Parameter in Ihrer eigenen ``creator``-Funktion setzen, was ausgefeilte Mechanismen zur Ausfallsicherung und Lastverteilung ermöglicht. Wenn Sie beispielsweise ``pgdb`` als DB-API-2-Datenbankadapter benutzen, und einen Pool von mindestens fünf Datenbankverbindungen zu Ihrer Datenbank ``meinedb`` verwenden möchten, dann sieht die Initialisierung so aus:: import pgdb # importiere das verwendete DB-API-2-Modul from DBUtils.PooledDB import PooledDB pool = PooledDB(pgdb, 5, database='meinedb') Nachdem Sie den Pool für Datenbankverbindungen so eingerichtet haben, können Sie Verbindungen daraus wie folgt anfordern:: db = pool.connection() Sie können diese Verbindungen verwenden, als wären sie gewöhnliche DB-API-2-Datenbankverbindungen. Genauer genommen erhalten Sie die "gehärtete" ``SteadyDB``-Version der zugrunde liegenden DB-API-2-Verbindung. Bitte beachten Sie, dass die Verbindung von anderen Threads mitgenutzt werden kann, wenn Sie den Parameter ``maxshared`` auf einen Wert größer als Null gesetzt haben, und der zugrunde liegende DB-API-2-Datenbankadapter dies erlaubt. Eine dedizierte Datenbankverbindung, die garantiert nicht von anderen Threads mitgenutzt wird, fordern Sie wie folgt an:: db = pool.connection(0) Wenn Sie die Datenbankverbindung nicht mehr benötigen, sollten Sie diese sofort wieder mit ``db.close()`` an den Pool zurückgeben. Sie können auf die gleiche Weise eine neue Verbindung erhalten. *Warnung:* In einer Multithread-Umgebung benutzen Sie niemals:: pool.connection().cursor().execute(...) Dies würde die Datenbankverbindung zu früh zur Wiederverwendung zurückgeben, was fatale Folgen haben könnte, wenn die Verbindungen nicht thread-sicher sind. Stellen Sie sicher, dass die Verbindungsobjekte so lange vorhanden sind, wie sie gebraucht werden, etwa so:: db = pool.connection() cur = db.cursor() cur.execute(...) res = cur.fetchone() cur.close() # oder del cur db.close() # oder del db Benutzung in Webware for Python ------------------------------- Wenn Sie DBUtils verwenden, um von Servlets des Web-Framworks `Webware for Python`_ auf eine Datenbank zuzugreifen, dann müssen Sie sicherstellen, dass die Generatoren zur Erzeugung von Datenbankverbindungen nur einmal eingerichtet werden, wenn die Anwendung startet, und nicht jedes Mal, wenn eine Servlet-Instanz erzeugt wird. Den hierfür nötigen Code können Sie bei der Basis-Servlet-Klasse einfügen, dort wo das Modul oder die Klasse initialisiert wird, oder Sie können die Funktion ``contextInitialize()`` im ``__init__.py``-Skript Ihres Anwendungskontextes verwenden. Das zusammen mit DButils ausgelieferte Verzeichnis ``Examples`` enthält einen Beispielkontext für Webware for Python, der eine kleine Demo-Datenbank verwendet, um Teilnehmer an einer Seminarreihe zu verwalten (die Idee für dieses Beispiel wurde dem Artikel "`The Python DB-API`_" von Andrew Kuchling entnommen). Der Beispielkontext kann konfiguriert werden, indem entweder eine Konfig-Datei ``Configs/Database.config`` angelegt wird, oder indem die Standard-Parameter direkt im Beispielservlet ``Examples/DBUtilsExample.py`` geändert werden. Auf diese Weise können Sie einen passenden Datenbanknutzer und sein Passwort festlegen, sowie den zugrunde liegenden Datenbankadapter auswählen (das klassische PyGreSQL-Modul oder irgendein DB-API-2-Modul). Wenn der Parameter ``maxcached`` vorhanden ist, verwendet das Beispielservlet die ``Pooled``-Variante, andernfalls die ``Persistent``-Variante. Anmerkungen =========== Wenn Sie einen der bekannten "Object-Relational Mapper" SQLObject_ oder SQLAlchemy_ verwenden, dann benötigen Sie DBUtils nicht, denn diese haben ihre eigenen Mechanismen zum Pooling von Datenbankverbindungen eingebaut. Tatsächlich hat `SQLObject 2`_ (SQL-API_) das Pooling in eine separate Schicht ausgelagert, in der Code von DBUtils verwendet wird. Zukunft ======= Einige Ideen für zukünftige Verbesserungen: * Alternativ zur Obergrenze in der Anzahl der Nutzung einer Datenbankverbindung könnte eine maximale Lebensdauer für die Verbindung implementiert werden. * Es könnten Module ``MonitorDB`` und ``MonitorPg`` hinzugefügt werden, die in einem separaten Thread ständig den "idle pool" und eventuell auch den "shared pool" bzw. die persistenten Verbindungen überwachen. Wenn eine unterbrochene Datenbankverbindung entdeckt wird, wird diese automatisch durch den Monitor-Thread wiederhergestellt. Dies ist in einem Szenario sinnvoll, bei dem die Datenbank einer Website jede Nacht neu gestartet wird. Ohne den Monitor-Thread würden die Benutzer morgens eine kleine Verzögerung bemerken, weil erst dann die unterbrochenen Datenbankverbindungen entdeckt würden und sich der Pool langsam wieder neu aufbaut. Mit dem Monitor-Thread würde dies schon während der Nacht passieren, kurz nach der Unterbrechung. Der Monitor-Thread könnte auch so konfiguriert werden, dass er überhaupt täglich den Verbindungspool erneuert, kurz bevor die Benutzer erscheinen. * Optional sollten Benutzung, schlechte Verbindungen und Überschreitung von Obergrenzen in Logs gespeichert werden können. Fehlermeldungen und Feedback ============================ Bitte Senden Sie Fehlermeldungen, Patches und Feedback direkt an den Autor (unter Verwendung der unten angegebenen E-Mail-Adresse). Probleme, die Webware betreffen, können auch in der `Webware for Python mailing list`_ diskutiert werden. Links ===== Einige Links zu verwandter und alternativer Software: * DBUtils_ * Python_ * `Webware for Python`_ framework * Python `DB-API 2`_ * PostgreSQL_ database * PyGreSQL_ adapter * SQLObject_ object-relational mapper * SQLAlchemy_ object-relational mapper .. _DBUtils: http://www.webwareforpython.org/DBUtils .. _Python: http://www.python.org .. _Webware for Python: http://www.webwareforpython.org .. _Webware for Python mailing list: https://lists.sourceforge.net/lists/listinfo/webware-discuss .. _DB-API 2: http://www.python.org/dev/peps/pep-0249/ .. _The Python DB-API: http://www.linuxjournal.com/article/2605 .. _PostgresQL: http://www.postgresql.org .. _PyGreSQL: http://www.pygresql.org .. _SQLObject: http://www.sqlobject.org .. _SQLObject 2: http://www.sqlobject.org/2/ .. _SQL-API: http://www.sqlobject.org/sqlapi/ .. _SQLAlchemy: http://www.sqlalchemy.org Autoren ======= :Autor: Christoph Zwerschke :Beiträge: DBUtils benutzt Code, Anmerkungen und Vorschläge von Ian Bicking, Chuck Esterbrook (Webware for Python), Dan Green (DBTools), Jay Love, Michael Palmer, Tom Schwaller, Geoffrey Talvola, Warren Smith (DbConnectionPool) and Ezio Vernacotola. Copyright und Lizenz ==================== Copyright © 2005-2007 Christoph Zwerschke. Alle Rechte vorbehalten. DBUtils ist freie und quelloffene Software, lizenziert unter der `Open Software License version 2.1`__. __ http://www.opensource.org/licenses/osl-2.1.php PK¼hç6þV;«K«KDBUtils/Docs/UsersGuide.txtDBUtils User's Guide ++++++++++++++++++++ :Version: 0.9.4 :Released: 07/07/07 :Translations: English German_ Chinese_ .. _German: UsersGuide.de.html .. _Chinese: UsersGuide.zh.html .. contents:: Contents Synopsis ======== DBUtils_ is a suite of Python modules allowing to connect in a safe and efficient way between a threaded Python_ application and a database. DBUtils has been written in view of `Webware for Python`_ as the application and PyGreSQL_ as the adapter to a PostgreSQL_ database, but it can be used for any other Python application and `DB-API 2`_ conformant database adapter. Modules ======= The DBUtils suite is realized as a Python package containing two subsets of modules, one for use with arbitrary DB-API 2 modules, the other one for use with the classic PyGreSQL module. +-------------------+------------------------------------------+ | Universal DB-API 2 variant | +===================+==========================================+ | SteadyDB.py | Hardened DB-API 2 connections | +-------------------+------------------------------------------+ | PooledDB.py | Pooling for DB-API 2 connections | +-------------------+------------------------------------------+ | PersistentDB.py | Persistent DB-API 2 connections | +-------------------+------------------------------------------+ | SimplePooledDB.py | Simple pooling for DB-API 2 | +-------------------+------------------------------------------+ +-------------------+------------------------------------------+ | Classic PyGreSQL variant | +===================+==========================================+ | SteadyPg.py | Hardened classic PyGreSQL connections | +-------------------+------------------------------------------+ | PooledPg.py | Pooling for classic PyGreSQL connections | +-------------------+------------------------------------------+ | PersistentPg.py | Persistent classic PyGreSQL connections | +-------------------+------------------------------------------+ | SimplePooledPg.py | Simple pooling for classic PyGreSQL | +-------------------+------------------------------------------+ The dependencies of the modules in the universal DB-API 2 variant are as indicated in the following diagram: .. image:: dbdep.gif The dependencies of the modules in the classic PyGreSQL variant are similar: .. image:: pgdep.gif Download ======== You can download the actual version of DBUtils from the Webware for Python homepage at: http://www.webwareforpython.org/downloads/DBUtils/ You can also download it from the Python Package Index (also known as the "Cheese Shop") at: http://www.python.org/pypi/DBUtils/ Installation ============ Installation as a standalone (top-level) package ------------------------------------------------ If you intend to use DBUtils from other applications than Webware for Python, it is recommended to install the package in the usual way:: python setup.py install Installation as a Webware for Python subpackage (plug-in) --------------------------------------------------------- If you want to use DBUtils as a supplement for the Webware for Python framework only, you should install it as a Webware plug-in:: python setup.py install --install-lib=/path/to/Webware Replace ``/path/to/Webware`` with the path to the root directory of your Webware for Python installation. You will also need to run the Webware installer if this has not been done already or if you want to integrate the DBUtils documentation into the Webware documentation:: cd path/to/Webware python install.py Requirements ============ DBUtils runs with Python_ version 2.2 and above. The modules in the classic PyGreSQL variant need PyGreSQL_ version 3.4 or above, while the modules in the universal DB-API 2 variant run with any Python `DB-API 2`_ compliant database interface module. Functionality ============= This section will refer to the names in the DB-API 2 variant only, but the same applies to the classic PyGreSQL variant. SimplePooledDB -------------- ``DBUtils.SimplePooledDB`` is a very basic reference implementation of a pooled database connection. It is much less sophisticated than the regular ``PooledDB`` module and is particularly lacking the failover functionality. ``DBUtils.SimplePooledDB`` is essentially the same as the ``MiscUtils.DBPool`` module that is part of Webware for Python. You should consider it a demonstration of concept rather than something that should go into production. SteadyDB -------- ``DBUtils.SteadyDB`` is a module implementing "hardened" connections to a database, based on ordinary connections made by any DB-API 2 database module. A "hardened" connection will transparently reopen upon access when it has been closed or the database connection has been lost or when it is used more often than an optional usage limit. A typical example where this is needed is when the database has been restarted while your application is still running and has open connections to the database, or when your application accesses a remote database in a network that is separated by a firewall and the firewall has been restarted and lost its state. Usually, you will not use the ``SteadyDB`` module directly; it merely serves as a basis for the next two modules, ``PersistentDB`` and ``PooledDB``. PersistentDB ------------ ``DBUtils.PersistentDB`` implements steady, thread-affine, persistent connections to a database, using any DB-API 2 database module. The following diagram shows the connection layers involved when you are using ``PersistentDB`` connections: .. image:: persist.gif Whenever a thread opens a database connection for the first time, a new connection to the database will be opened that will be used from now on for this specific thread. When the thread closes the database connection, it will still be kept open so that the next time when a connection is requested by the same thread, this already opened connection can be used. The connecton will be closed automatically when the thread dies. In short: ``PersistentDB`` tries to recycle database connections to increase the overall database access performance of your threaded application, but it makes sure that connections are never shared between threads. Therefore, ``PersistentDB`` will work perfectly even if the underlying DB-API module is not thread-safe at the connection level, and it will avoid problems when other threads change the database session or perform transactions spreading over more than one SQL command. PooledDB -------- ``DBUtils.PooledDB`` implements a pool of steady, thread-safe cached connections to a database which are transparently reused, using any DB-API 2 database module. The following diagram shows the connection layers involved when you are using ``PooledDB`` connections: .. image:: pool.gif As the diagram indicates, ``PooledDB`` can share opened database connections between different threads. This will happen by default if you set up the connection pool with a positive value of ``maxshared`` and the underlying DB-API 2 is thread-safe at the connection level, but you can also request dedicated database connections that will not be shared between threads. Besides the pool of shared connections, you can also set up a pool of at least ``mincached`` and at the most ``maxcached`` idle connections that will be used whenever a thread is requesting a dedicated database connection or the pool of shared connections is not yet full. When a thread closes a connection that is not shared any more, it is returned back to the pool of idle connections so that it can be recycled again. If the underlying DB-API module is not thread-safe, thread locks will be used to ensure that the ``PooledDB`` connections are thread-safe. So you don't need to worry about that, but you should be careful to use dedicated connections whenever you change the database session or perform transactions spreading over more than one SQL command. Which one to use? ----------------- Both ``PersistentDB`` and ``PooledDB`` serve the same purpose to improve the database access performance by recycling database connections, while preserving stability even if database connection will be disrupted. So which of these two modules should you use? From the above explanations it is clear that ``PersistentDB`` will make more sense if your application keeps a constant number of threads which frequently use the database. In this case, you will always have the same amount of open database connections. However, if your application frequently starts and ends threads, then it will be better to use ``PooledDB``. The latter will also allow more fine-tuning, particularly if you are using a thread-safe DB-API 2 module. Since the interface of both modules is similar, you can easily switch from one to the other and check which one will suit better. Usage ===== The usage of all the modules is similar, but there are also some differences in the initialization between the "Pooled" and "Persistent" variants and also between the universal DB-API 2 and the classic PyGreSQL variants. We will cover here only the ``PersistentDB`` module and the more complex ``PooledDB`` module. For the details of the other modules, have a look at their module docstrings. Using the Python interpreter console, you can display the documentation of the ``PooledDB`` module as follows (this works analogously for the other modules):: help(PooledDB) PersistentDB ------------ In order to make use of the ``PersistentDB`` module, you first need to set up a generator for your kind of database connections by creating an instance of ``PersistentDB``, passing the following parameters: * ``creator``: either an arbitrary function returning new DB-API 2 connection objects or a DB-API 2 compliant database module * ``maxusage``: the maximum number of reuses of a single connection (the default of ``0`` or ``False`` means unlimited reuse) Whenever the limit is reached, the connection will be reset. * ``setsession``: an optional list of SQL commands that may serve to prepare the session, e.g. ``["set datestyle to german", ...]`` * The creator function or the connect function of the DB-API 2 compliant database module specified as the creator will receive any additional parameters such as the host, database, user, password etc. You may choose some or all of these parameters in your own creator function, allowing for sophisticated failover and load-balancing mechanisms. For instance, if you are using ``pgdb`` as your DB-API 2 database module and want every connection to your local database ``mydb`` to be reused 1000 times:: import pgdb # import used DB-API 2 module from DBUtils.PersistentDB import PersistentDB persist = PersistentDB(pgdb, 1000, database='mydb') Once you have set up the generator with these parameters, you can request database connections of that kind:: db = persist.connection() You can use these connections just as if they were ordinary DB-API 2 connections. Actually what you get is the hardened ``SteadyDB`` version of the underlying DB-API 2 connection. Closing a persistent connection with ``db.close()`` will be silently ignored since it would be reopened at the next usage anyway and contrary to the intent of having persistent connections. Instead, the connection will be automatically closed when the thread dies. You can change this behavior be setting ``persist._closeable`` to ``True``. PooledDB -------- In order to make use of the ``PooledDB`` module, you first need to set up the database connection pool by creating an instance of ``PooledDB``, passing the following parameters: * ``creator``: either an arbitrary function returning new DB-API 2 connection objects or a DB-API 2 compliant database module * ``mincached`` : the initial number of idle connections in the pool (the default of ``0`` means no connections are made at startup) * ``maxcached``: the maximum number of idle connections in the pool (the default value of ``0`` means unlimited pool size) * ``maxshared``: maximum number of shared connections allowed (the default value of ``0`` means all connections are dedicated) When this maximum number is reached, connections are shared if they have been requested as shareable. * ``maxconnections``: maximum number of connections generally allowed (the default value of ``0`` means any number of connections) * ``blocking``: determines behavior when exceeding the maximum (the default of ``0`` or ``False`` means report an error; otherwise block and wait until the number of connections decreases) * ``maxusage``: maximum number of reuses of a single connection (the default of ``0`` or ``False`` means unlimited reuse) When this maximum usage number of the connection is reached, the connection is automatically reset (closed and reopened). * ``setsession``: an optional list of SQL commands that may serve to prepare the session, e.g. ``["set datestyle to german", ...]`` * The creator function or the connect function of the DB-API 2 compliant database module specified as the creator will receive any additional parameters such as the host, database, user, password etc. You may choose some or all of these parameters in your own creator function, allowing for sophisticated failover and load-balancing mechanisms. For instance, if you are using ``pgdb`` as your DB-API 2 database module and want a pool of at least five connections to your local database ``mydb``:: import pgdb # import used DB-API 2 module from DBUtils.PooledDB import PooledDB pool = PooledDB(pgdb, 5, database='mydb') Once you have set up the connection pool you can request database connections from that pool:: db = pool.connection() You can use these connections just as if they were ordinary DB-API 2 connections. Actually what you get is the hardened ``SteadyDB`` version of the underlying DB-API 2 connection. Please note that the connection may be shared with other threads by default if you set a non-zero ``maxshared`` parameter and the DB-API 2 module allows this. If you want to have a dedicated connection, use:: db = pool.connection(0) If you don't need it any more, you should immediately return it to the pool with ``db.close()``. You can get another connection in the same way. *Warning:* In a threaded environment, never do the following:: pool.connection().cursor().execute(...) This would release the connection too early for reuse which may be fatal if the connections are not thread-safe. Make sure that the connection object stays alive as long as you are using it, like that:: db = pool.connection() cur = db.cursor() cur.execute(...) res = cur.fetchone() cur.close() # or del cur db.close() # or del db Usage in Webware for Python --------------------------- If you are using DBUtils in order to access a database from `Webware for Python`_ servlets, you need to make sure that you set up your database connection generators only once when the application starts, and not every time a servlet instance is created. For this purpose, you can add the necessary code to the module or class initialization code of your base servlet class, or you can use the ``contextInitialize()`` function in the ``__init__.py`` script of your application context. The directory ``Examples`` that is part of the DButils distribution contains an example context for Webware for Python that uses a small demo database designed to track the attendees for a series of seminars (the idea for this example has been taken from the article "`The Python DB-API`_" by Andrew Kuchling). The example context can be configured by either creating a config file ``Configs/Database.config`` or by directly changing the default parameters in the example servlet ``Examples/DBUtilsExample.py``. This way you can set an appropriate database user and password, and you can choose the underlying database module (PyGreSQL classic or any DB-API 2 module). If the setting ``maxcached`` is present, then the example servlet will use the "Pooled" variant, otherwise it will use the "Persistent" variant. Notes ===== If you are using one of the popular object-relational mappers SQLObject_ or SQLAlchemy_, you won't need DBUtils, since they come with their own connection pools. `SQLObject 2`_ (SQL-API_) is actually borrowing some code from DBUtils to split the pooling out into a separate layer. Future ====== Some ideas for future improvements: * Alternatively to the maximum number of uses of a connection, implement a maximum time to live for connections. * Create modules ``MonitorDB`` and ``MonitorPg`` that will run in a separate thread, monitoring the pool of the idle connections and maybe also the shared connections respectively the thread-affine connections. If a disrupted connection is detected, then it will be reestablished automatically by the monitoring thread. This will be useful in a scenario where a database powering a website is restarted during the night. Without the monitoring thread, the users would experience a slight delay in the next morning, because only then, the disrupted database connections will be detected and the pool will be rebuilt. With the monitoring thread, this will already happen during the night, shortly after the disruption. The monitoring thread could also be configured to generally recreate the connection pool every day shortly before the users arrive. * Optionally log usage, bad connections and exceeding of limits. Bug reports and feedback ======================== Please send bug reports, patches and feedback directly to the author (using the email address given below). If there are Webware related problems, these can also be discussed in the `Webware for Python mailing list`_. Links ===== Some links to related and alternative software: * DBUtils_ * Python_ * `Webware for Python`_ framework * Python `DB-API 2`_ * PostgreSQL_ database * PyGreSQL_ adapter * SQLObject_ object-relational mapper * SQLAlchemy_ object-relational mapper .. _DBUtils: http://www.webwareforpython.org/DBUtils .. _Python: http://www.python.org .. _Webware for Python: http://www.webwareforpython.org .. _Webware for Python mailing list: https://lists.sourceforge.net/lists/listinfo/webware-discuss .. _DB-API 2: http://www.python.org/dev/peps/pep-0249/ .. _The Python DB-API: http://www.linuxjournal.com/article/2605 .. _PostgresQL: http://www.postgresql.org .. _PyGreSQL: http://www.pygresql.org .. _SQLObject: http://www.sqlobject.org .. _SQLObject 2: http://www.sqlobject.org/2/ .. _SQL-API: http://www.sqlobject.org/sqlapi/ .. _SQLAlchemy: http://www.sqlalchemy.org Credits ======= :Author: Christoph Zwerschke :Contributions: DBUtils uses code, input and suggestions made by Ian Bicking, Chuck Esterbrook (Webware for Python), Dan Green (DBTools), Jay Love, Michael Palmer, Tom Schwaller, Geoffrey Talvola, Warren Smith (DbConnectionPool) and Ezio Vernacotola. Copyright and License ===================== Copyright © 2005-2007 by Christoph Zwerschke. All Rights Reserved. DBUtils is free and open source software, licensed under the `Open Software License version 2.1`__. __ http://www.opensource.org/licenses/osl-2.1.php PK¼hç6ÎÅj  DBUtils/Docs/Doc.css/* Webware for Python (http://www.webwareforpython.org) Common style sheet for Webware's documentation pages */ /* First import default style for pages created with Docutils: */ @import url(DocUtils.css); /* Customization for Webware goes here: */ body { background-color: #FFFFFF; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10pt; padding: 12pt; } table { empty-cells: show; } td, th { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10pt; } p { margin-top: 6pt; margin-bottom: 6pt; text-align: justify; } li { margin-bottom: 6pt; } h1, h2 { font-family: Verdana, Arial, Helvetica, sans-serif; color: #002352; } h3, h4 { font-family: Verdana, Arial, Helvetica, sans-serif; color: #002352; } h1 { font-size: 18pt; } h2 { font-size: 16pt; } h3 { font-size: 14pt; } h4 { font-size: 12pt; } h5 { font-size: 11pt; } h6 { font-size: 10pt; } h1.titlebar { padding: 4pt; margin-bottom: 12pt; text-align: center; color: white; background-color: #025; } h1.header { padding: 4pt; margin-bottom: 12pt; text-align: center; border-bottom: 1pt solid #025; padding-bottom: 8pt; } div.footer { font-family: Tahoma, Arial, Helvetica, sans-serif; font-size: 9pt; text-align: center; padding: 4pt; margin-top: 16pt; border-top: 1pt solid #025; } .left { text-align: left; } .right { text-align: right; } .center { text-align: center; } .contents { font-family: Tahoma, Arial, Helvetica, sans-serif; } .contents ul { list-style: none; margin-bottom: 24pt; padding-left: 0em; margin-left: 2em; } .contents ul li { font-size: 11pt; margin-bottom: 3pt; } .contents ul ul { list-style-type: none; margin-top: 2pt; margin-bottom: 2pt; padding-left: 0em; margin-left: 1.5em; } .contents ul ul li { font-size: 10pt; margin-bottom: 1pt; } .contents .topic-title { font-size: 16pt; } span.name { font-weight: bold; } span.filename { font-family: Tahoma, Arial, Helvetica, sans-serif; font-size: 9pt; } code, .literal, .literal-block, .pre, .py { font-family: "Andale Mono", "Lucida Console", Monaco, "Courier New", Courier, monospace; font-size: 10pt; color: #052; } tt.literal, span.pre { background-color: #FFFFFF; } pre.py, pre.literal-block { margin: 0; padding: 2pt 1pt 1pt 2pt; background-color: #F0F0F8; } .typed { font-weight: bold; } .error { color: red; } .warning { color: brown; } /* Configuration documentation: */ dl.config { } dt.config { } dd.config { } span.setting { font-family: Tahoma, Arial, Helvetica, sans-serif; font-size: 9pt; font-weight: bold; } PK¼hç6»«§ÕŽ4Ž4DBUtils/Docs/pool.gifGIF89aÚƒ$$$:::JJJQQQfff{{{‰‰‰“““§§§¼¼¼ÈÈÈÙÙÙèèèþþþ!ù,Ú@ÿðÉI«½8ëÍ»ÿ`(Ždižhª®lë¾p,Ïtýv®ï|ïÿÀ pH,8KòÈl:)Žt€x4(CBpX±Üm#àˆzàî7;8ƒ)19Z5³ëí(;ÌvÄ­sR{Wl kSj†Sgd ˆ ““U„^†tk U •„r^Z\™oz¢‰¥Š ª z›«šˆ¸´O¿ÀCKÃÁÆÇÈ6²ËA” ¨É+QÔ(ÕÜÝ+ÅÞáâãäàåèéêëìíîïßÒòçðõö÷øùúû2òüÿ H° Áƒ}œ£—¡=‡ÄB¬0ñ]Å„3Ž[â"†evÿTÙù4ÁR ²ÐLÄEd…4r›“‹¼¤Ta¶Ž `²\ÙgOÍ’[N>ØÙR.B5Jú0àK‰A­RÝÊ•Ǭ"H-3@^ TÛec–QWK¸Öf-e¥Í’–T›¼öV WÂ3—`Cˆ½;À­Ùµ|gùò¸©)Ã…vÝÌÙÉ×QÓÑå34:ÓS«^ͺµë×°ƒ|æ9ÈÖÊól¡å¥TJË»¸ñãÈ…ÌNμ¹óçÐ5 ®á/Þ±a¹Mνû:iæÅ¨~c;Tñ9Š™gxïðãë#OL<ýòè•ÜŸ¿^î÷²(ßÿ€"Và&¨àr 6èàƒÈ1ÈÁz–¡fføM QQ8 …š“XˆÒ5(”„ê€ÝzÅbD*Ô¢ˆÌ8¡:6n°bŒ aãˆ:23ÀÒ$Å›‘eA‘ÈÕmáý¸d‘ÂéÆ$l0IÜ*äèˆ7fIe•»%é—–Àòc”bZIæ•gGZoyyÃm&Å–•”)9¤œ7y¡ŒSºy¤p~¢i›§ É$’Tö)h¡™©¹f…êy¨¤mæËbŒò°^‡  IÃŽPâ ˜A¦ª*›‹²‡ «%ºú%¡oÁ`ç­­Ú*k*Q÷ÉìJâ±È&Û±ƒú¨,ÿ°¥>Û¬´ÔË¡VØ%‰]Á-¦†6Nýî"z#Mmü¡‡ ˆ«Ò¹|˜.c9…¦¿ÅÑ€»û’ \¶Hâ­´ô[Á\Nf·ùÖ² ÂùÀÛÇ_Á6£.ŦE”,jtYÄf\,»—,#2Hè6ñ öÞ»¦KÿÅÜ_—2׬_Í1ߌsvíüŸÎ> HsÐûUkôÑ%0KQ°¯ØÅA¬L›ŒÈ2>5ÒXg]ŽÄ¿ZÆ)œµå•n €î<Êãô›`à ²ØBRy€nçö¶aò”«õÞȾ½”4Ðò©MØMÈ4QcÌñ˜…Crª¼ÑÞ2Dƒ“ùÿ~› yæ@ºÏ£ï\:ΧÛÜóæ©ËÜzΫƒ;ѯÿ<»è·“ž»é»£Þ»êõ±þ»ëÃüìÇÓ^¼íÉãÞ¼îÏó½ïÇ?a,Ý]omö²u¦ýö2¿,ÏЉ?ƒùÇ¡*ù ³ßûñ=Fó¿ü\ýàw…?´íÏ÷ÿ¬–öð‡*ø¯ ´ßùdÔ¹ïsŒ`9"HAU°‚.š– 0%ˆF\Ìb˜Ü.Á´K1̓e!+Fø”¥¬í€LX‚*® ÂÈ…ð$Œ–øÇ¨  †‚(äXJ´†DÈo^¨ÀÌ­IK#‡È&Ì,ÁK_ãáuòw-ÿyÌ‹ÀÍØÜ$Æ ¾H‹§â@­@F7yC†)û`.†¬F€Ë„‰¢„x·H‚„_ÜHââ5€ð±³Ð[ áÈ´‹ò†\;À$¨D¨ð’Ú9c hF/sÉßË–\UiL¼Ñ Ë‚p5Lºò•Œâ,ì¢&;tŒ`P@ ¶€†€)À&&+,å/[Br^»¥ .æ¿ðA›,§IÍîa µƒ6—§ÍÎesft^¼ÉMpnszÀ§ðØtNu"ÏÊC'ñäùÀ¡½Óžñ„§8ñ¹ÏpBOŸÿäg@ý)=€T %(õ ºP„6ôrò[$®X>h]ÿ¢MŸDuµQÎ$£¼b§ƒÀiÀ¢5‡¤ã1éIUÊ–n¥-õÜ?@YÍšÚÔ8(º©NwJ¢œZŒ ,HP7), 5£•¢&?Ù¨_YJ âI¸–ª=U Q]™ÄªÆE­¸ð„NÓª4Ã2«³ƒa]ÉT¥Y8´¡qK ›ÙâÆ'3uª$«äa\¥1×=A*QrZMQ°×²ÍPv¥Ô0ׯ¨aÈõ° °&þ§¡ª&e´Ù£Î´³›ÅÀGëÆa-UTjlã¹@ òôµ°MÉJ5w¦ ´d0ð‡) 2±‚¢bÁF¦ÆA†SÃeRicËÜæÒH–Îÿ®t£3ØxÈô|.]ͫێùq×z×ÅÏtÏ“]†÷³¨Õ('óQÞ¤µw¼á€©{Ï»Åô"U#]o5Þ þÂ÷~þ-V€O¿÷Ñ7#Þ`‚±;ªÿ7¶éÌ'CzÓ &ô¡Îpñ©av°ï»þˆC F›Øe'foŠW\+×,C,vÀ„m–9™›Ô¢ —’¢›³Øhóü±8Ô'ä"ùȱ°’—Ìä&;ùÉP޲”§Lå*[ùÊXβ–·Ìå.ù­EN¥*[ù«‘¹¶Á™Ó´¥(à7¸)Ì›cbÊDƒ±óOà$É×ì* QÍza"º$ ÿ/Ó@ãRô’Hô&f‚‡µØ0K¹ „3çˆÈ*ÓKÙ¡~Y˜$ 0ÊŒ/Àð‰I€Ñ~2tÇyÃTYf[ïâ#ÉÚ#cÐÀö|,lôûØÈöŒ|“ àuNøË M§C¥mh·sÚÖ&'=Ñwíj×ÓÛÜÖö³¿Ýír‹Ûä>7¸»élt‡»Ýë6§ºÍ ozß3Þœ“)±™ÍoÿºjÞXI`ì9Z(îóJÖŒæ·BÔÎêÕm Ÿ‚ÀýÞ›Ò&.ðA²í‰ ø_ëÌp×6Ä2‘fÊÇr“<–•Ë[Ò°ЧùãÃqùÈ{"ƒ#<ã²t‹ûÿL¸¤ÓMi nŠØfŒ†è|øjÍM©Û¢[Ï…:—ŽÞp:»b'WÇ:ÐõoËnàŽ@{Ä=q<ï@í?O8ÒÝ®¸Ç}ìÔÚ7Þ÷>ÞÙP\%ç»à™[öÁþð±ìÆÍAS-øUˆüÌ‘°x˜!pÙfG ä7?Ì;ÄÁ QOŽyз€ôœ×©½%Œï%3ßõž·ìcïl –ó>|½çVßOÞÔ÷žý½ÿPâSÛøÙ¦ýð+Ÿúæ3»ð`zMi•wmøîÏ¢¾´ôîüa?³Ôä>U´ßýî }è/*Qӌу¶Ä—¥ùù“ºþÖf2ýì¯?LKXÿ±·8Ƴ6bUBP‚*¨ ²2}ÄUçò×,XYžv\¦4k; ¨Vȹ¡'â§W~Ä i•Teh¡ÂA‚€ôb n³8q_û¥c#ƒ€%x\óGÐ¥‚5(Rµ?}ùçtô}ã‘y!%D¨Yðg=Ø€ö'ƒ§‡#ï—³2ld6E~Êò÷0*bW9d°/Ñ€%•ódH•ó•£×Úð(•S&EòG`7f¿U$Úð8ˆ …ƒj@+m(k0ÃU—@EIq†7Q‡|s‰øR$`0…ˆ/#‰÷‡H7m`zèFÆåW¡¨ÿ'’³e3köÀ‰º1‡¤h‡ùÒ‡RŠdqŠ«XVk~Óä…øõ„å§„&7ŒÆˆl4"d‚UvA L1V6öb¨U͈c3¶‹18®ps2†RcÇhŒ~CÁñ7Sóçøï‚L0èÝØë¸VïŠ 8ŽøhdÄV]ÀH…öE]Ö´Û• í9 áÙlQÂ|&P¦×>Éæ‘ý(*yQY‘&‘ºÂ‘¯ñ0£‘Šç‘ &’ãóI$ùù¸’?6@[¶mOf\“NÆ’Ò… G„„7&B8/@6W@-°“FU…ú5d§Zñ5…}äH‡DÿUFùEÉT&´BÑ”W?©by$G»6/vÄDüs.zÄiR™+&Y„'ôC"c–DÄ`9›ÄH_DÏ4D«–-‚“38(ÔQù–H1-tù—!sLyYÀX9@H©~œÅ„Vx”’™”¢¥ZN±\˲”Mx0˜ÉF½v„Åh“¤ibÃÐV¿9÷LšæGt4oA b6YÅDˆ¹ª–¸T›U‰›oéC¥œMÙ× œÆÙ…÷Çñá?i9œ–©]Y Df` ©?¨W’Õi˜G`׉`ÝI^Ù‰SH”’¬Ažç!æÍ) ß“žMuœðIx ™žåU“yŸáƒÿ…Øòr¤Ø6Áå$Uõ#þY‹È Ð[øÉ•ldXtE‡€E›MƒG ÚW¤x h‚Wu™÷)…¿"HžôõÅ—?Õ¡õi¤µZd¢L‰¢Ÿ¹Fodgå7ÈŽ®b0rU>øƒ/8˜[y:jÌXB:(KK¤x…–c Cú¹Ÿ•9Ÿ1¢-º*üù¤X@_ñbÛPu£ð8i²gBê‚îXGŒ•Kj£*ƒcYú¦F°žp:§©!§óåžN‡§@¹™ÉÑžž¡§§Åö!‰̉SÏ)E‚êNtÊ"Ṏ:4%E¨29 ‰ü§z ©Jž·äÁ©7c‘ujÿ,€jO 9! j§ú¢ §”ÚªËYzT!¤y²z!¬ŠŒ¹ª«°á¥TTƬ*±— JJ³‡×»Ú«ïé¬Â­|ƒAÎe{Òz­ØÚ§Ùº­}Üú­Îá­&öw)`fo¨pèzvÇqP0Zé+,Àp^ªG£¼:šGfsáØAX%d°ÿBEE"°ëHW‚‘[+! iÆu¼±Έ'([Zk̰ ëè®çX±7Vˆ@   °›æ±Š°ÂÔ‚=QÏps3ôŒËElâú¦-q¯.°®q®›è³ŠAwúx¥àZ´'%`^–´J»´LÛ´Nûÿ´PµR;µT[µF«’W›µèiQZÛµÜa©^¶=vªb[¶ ±¨f›¶j{“kÛ¶®á­Í­Mj~FXnk·$J´t+w_(·î·w[ŒpSÀ¨8Cd8ÄZ¡¹ò$:;·Ó‘r†k(ˆK\‹Ë¸  þ‡~é ¦‘R¹_s¹þ™&B›uË KHp×GÖHc:êu9iº[Ž­{¯û >W·úÚussµ{h·› ñª»§ ¢!hløg¨~»·Åëa×W© ½ÄkO@;d½,ƒ½Í›…<Ù½°ŽÀX’0¥ |¡ ãû ^³°¡™¼z[à»6éÛ¥!‘¡óëÿ+£í{rÓ{ñ[ù[¾¤@¿³@‚¶"°ü[¢Ûëy»»0¨H0éÈDRÁ<1=0ýë¿|˼#[Á²pÁÁ2¾ÞÈŠ´À›ëÁ!Â\0Âó “…¿$L32̽ ü¬?ê½Î+»Êû¿ÌÛÃÔ»¼AüÁþÄXkÄ>ìÄPlŸC‘‚Q®@ÅXœŸ¡‚2ž0D¬›£`½œY\Æô·&üJÊi»äšfÆpü¼sÇtüF»'|¬‡|é¦|yŒÇ½çÇ¿ÈÁÇÇLÈlȃ¼|ˆ\|‚ÌÈ‹|| Éœ|÷v…³‚§h«–yúª¢YÇ®ô]§šÉ_‚ÿ" ¸žÌ¡ùURÉžœìÂØX§¬q±ª#¦ê’d{©4£©­Ë"_¸'ʤL•¶íGm)ʼü!¢gÌØÙmFµË-•Ì)ÍÔÕ|ÍɉÍÚŒ«¼ÍÞ¼ü¾ÝÊÄã,Í`Ø‹l«ÄÈÂ…é,kG*GÃÎëLÎa;¸“§…DÜËßì¾Ô‰e4ÙdILËZöÏLö·›œeíz#¨=nPfÉÝ|ÏIy¢Nš„ôY¥J%Äà<Çš¼¢ÑC(Äð¬Ñ*`p;Ç‹íç·J„cOA”-ðh?, Zœ£WvF¿«´«ÆòÒ@ À€ZÓèìÊÿç¦,kµi˜ÿ‚48‚jŠƒà8L””Íê -X£K*>ÕHÀ_ºÕ²pÑ$EY­Ôd±i1v°øÕeúÎg€°Óf…Õ‡6_ŠÓ"øGz-Öj5I?ý¡Ñ;Ó3 GÆj ÀE€Í`€Á•6:)ós>)~òìÕÆz¡mÁ=wÒyò ÚÔ}×üŒÖ‘-ÚZBLRÕš½‡ˆe7‘䓽ÒÅ Û“íq‡Ú™¢Ú½r¢CöÌÀ§ý*í™* šQxյ݈-Ç.šÜ0ºÜ}ÑÑ9)š™;œ¨=ÔÕ}Ù­ÜRÒCxÜÎYÜIhÞJyÖÆ ÒÃÆÜ†­Þq*ÎYcʰaÿß|7Ü#-@ôL“Ø f>‰‡QæŠé „0†ŸMÃM‚æ”`ÎçN2èQ6J.Uvç9N‹cEç(ˆÃÛj8‚#va\’nÿ‹É䓈±\Þ\øM?X“êðp³ûüêýܰ>ë)Ru_³Ú–»sPB¯à.Œ-Û:\Yt$ÆU7*ÊEà´N ®È°x(²h‹¹È§¨ ¸8퇆„8‘ƒ8ÔN%L²C[JuJj¦;úº\ºë,×¼³X•¦7èíþâ¸ì’ämI2P¯dy¦}M–ü.²Àêö^¶_ðõì„Iô!|úµ©?=b} ¿µ"z?Ï)ñ4Mñî­^Ê ñ  ÄÜϯ³ žÈ,T'©Ð<+ß/?¶·¬ž3_5´)_©9ÏÐÚ¹óÕC>¯ª%/?A¯N_[ô£ª9ÿôFðN¿¹LÿôÒêêRÿôŽ¥äXOÝUÿÊ}êÇëÝмÖÝ¡d_ÞoÕùÇT=öê èº*[Ø-¬Ó*ð hÉ¡}ݦmlŸÑÞÇ®i2ÛiSÙCyQøØ}ø\³ËõÜKø\§².~÷h¼ø•/³”³²tïÀ,àà~ݦ.ö^ÿ:RóªŸôÞNÙÜaè}oö¤á[M²ù+LêÔtõåkcù`yø²ÎÍ„/uøjcˆ$°?2 Çt¯ۘߗ_Øhï÷¨[öÜý×oûŠÇ™Þo¥ë3Г*OþîfþR¬ýãxêø/ùÛ;“å_ÿ“ŠŠþ]öÄ]¿ÿ‰1k)æÃoB<\Š9„ð嬮 ¹r$kÁ ç[`‰A#q43Dñ¼ôj$ðxï7ò´{î¾+Ḇºñz4/9¸ð „c¡.9,-ŒÕq$<8¢ ÃÇàb×1ð™Ø ƒM1Üf±; M”ŠÉ[€0¥{ÑÁ ûˆ3ŒL306(±eÓUw]´˜%ÔÏjˆ²¼3èü¯åÑÍFᤱ[ìbÜW`gçxãÁ½˜3OvvøazV…xbŠ+¶øžSJRÌ¢‡%fuâÛ<^…¡…H¾8 ŽÇIùUE~'ävM¾Gæ“!ÓXeš¿jÙáÚ\Nh±›kÆ«‡|Fdgua.gåOrúb¢™a:ã€Òí™6§£™úi®›Îú… 7)B¶ƒÂÎËš±í²Ò“­]h»k¸áQËly¢ÞA$Ríže¾–ëí¸w†î¿oyˆðpŒpÿ_Ö¥Ãý|ò³5Ö›ï$׺%Î;÷üsÐgÊ<®ŒþâˆrÔ…F óÔcæ¼uØ+Öyæ[i¾æåŸ—ž emýãÞŠU~zî§Kv²p;.„1î _Œ#»w_d£ïþýL—ý>“ ·OêW \ VVÿp-¬_~R–ûàw@~ g d ˆJ×À¥±‚¤ BwA fЀä`=øA†P„#$a Mxª¡P…+„›»XøBÖnL1¤a “åBæP‡ÈÓÈcPÍ@{×"MM`D©u€x¥‡ëÿ c`$˜˜™s!1 `ŸÛÒC/ºˆ 8‘ HU(AÔ…ÆÆAa€ Uè¼0''ŒQj”v° Í)Šj`R¥*’/f8”ã¨;6ˆèŒâÐÇ ˜þZN åMJQ €ð P’€$úÂø;0¾r@ôaI\j`€.Ià£qá> PÀŠô…æ‹9æ:ƒenÉ>,1)[UࢸªùLó±Á \L€³ºX>çlãµ°WÅF&ü4 s0å1±ÌfÖ#—ß´f-À'ÌÈ,r•ÿ¡veÓù¬Tü@0`¬Ò{Ñ ó‡=B;ÀÐr‚¢Ÿ`NFËÙÑ&gy&½J»†Åó´Ÿ×%ôbÌÃ9ïwM4¤fµ‘kýjXÂÕ8öG«Ék D5ØÒ6®‹Á^d—` ÙAg VÓ7ZÓl•Á²ýh//:¨™Ì4­[`íSbÛÙAœLx,mo{VÙmï ªi+&òÜ}Z_pèäyã+¿£Ùó´µëîŸò9ß™¤·’éÇ&‹û=Ðk¿WÍë¼›;c8( NÈ.a{àX´B·Õ-¼dÇÇÙ<:0Hy‚eo¦k˜ïh¬gûº—äkæÓÁS.ÿÌáŒæäF<Àõ^nkjË\Žð58Ê¿„óšÃuQý9Ð?+v‡œ=…O‡vÊq^Ú¨f«à™n©g†ê &@u΀‡æëÀébÓÁÞî‘[§êe_»D/mvèÕíozÞÂ.èõÚÂî2p@n¡™<8Ü[ øp ñ\µhÆótF2|HŒ‡ø¿]y<_;à—ÆÎäåš9E•óï»ßsì] ì3ì_ û@Ð>Áþfî¡ûÝ·>×¼/ß—æôˆ ÿÔ¥nH0dÝ ä¿LùÃ/\u­ï¹ê__ûF©Ëö½Ïýé»>üãGàóÉþ¡¡_ýÓá=qâõÿÇÿRâc1V4ófQ”ÿËÒþ,«%‹'dÒ%ˆò?ô‘s?˜ª¨x›‚´Ã"LK@ ìµ1aÀ­Û¶‚±ŸÎh-H³ A„ˆ:,Áð2A„ž\Á2? ŠœDpŒÒbô!$-T‹ÐJŠ£©Aäb›D Í2œÖ2„ôAÄ‘Èx¾4,$ì¬I¨­µ°,¢ Â|Bj+T.,¿«,lÁ±!­’™™ôB*SBVÙÂ0„ŸÔŠ564‘Âé‹.DÃ6„ 7lœ8¬2Ä™>”›@ÌCö›Ž¡C.4‰cÀCZiÂ’)DC;tŠ¢« E¬ÃV옎ÙÃ[|5ÜE_<¾_ ÆùFbüµb<Æä{=d\FOQFf|F@qÆé?¤FÑ™ Œà‰l¬ŠmÄÆê¾ÝyEk| nüFqôs„Åt” ?|.+QˆGxœÇw¬Ç‘°ÇW¼G}ÌG~Ä~”G|ôGÈ}HzÇp¬FtTHudHv\ÇYŠTµÁ KÝËY ^0´ìÊâ½Ã`KÀK c¤Ë¹Äip>¯Ü°Œ¹ ‹Ë½ô-±I˯¼I””¨lK±¼ËôbÛ#Ì¿4“ÈtÌŸ¬H˜ NÙ/ª:Z1L(¹ïøÍ ¬Å´L,[ÙÌЮ,LÖãj¸Ö|?NbL²¬½ÓDÍjk#‘ó DLçÙMÇH¤ÚÄ4ØYcÊ×¼§Í 1Ï •!ÉLDáÍÇÔM³ü  #ç–.éŒMR×(M ùN‚Ïáˆ1ÿóô§Õ„LâD2}ú)|#Ï.ˆOà@°ÄPÏû,'÷ÜÏ$ÂbRNÓ4ËZðŒ7üP àO0€7ºÎ.hP=…Ï$C8Å‘ „ÒwÒ‚%¥Ò³â³'E)ÈQlâà΀½$µ+qм²Ð$åÒ)ÝQ-sR4åËÀôÈúZÑ ]OýRô”>eÏÐ3;@íÃú¼P‚êS (Ô?ÅŽQSQmTBÝÐf ÔÿNð‹ÅPGHM2>˜T8­ÔÒ`OÀÔç(½Sª±Oí‚Pe±³Â¥0eÔ}TUå“/q-IW½Ìƒ¿à³QKQL%"·| b-Vdm¼ÇhV*ÓR»ÜT5µ1œiÕÓøVnVlÕMGØV—+sÅËd­‘ܤVu¥«’Â߃:ä [¯³ºè¦ Û5Ñ4Á3Pg™ÀÉ¡ÚWµZ¤¾Î|X>cJ¼%¸E[¾%‹#tûžp¥—Žø3ΦõHåÈ€¡ƒ/á àÉí4è9Í͎ý„U%1pr€0]I5€ÐMƒÒÅ*g]^Ò‚ÏÉúðÜÎ}ÝÛ%3H¹÷œËÏÛåÜÜýÜate«Ý -[ä^uÝ$ñ#àPå )Ò=ê]]5€Ý‚3pp^اÍCÝØMN¹^ée$ØM§7“&£5Ùÿ׳ øZ’Ê? ;C€ëxÎNx/È—M’&‰ÿ=šÈÈüU€ûMà·Õ úÍbº_Õß³ÈÈFbàà£5zþ^r™—>(©–ü2`ÜDþm"tº»ík±Û7 a$0áÅ Öÿê1x"nSE[8‚’1ç8´¿Í„¾´{Û]òà’zýÊÞçàÜ%±áø˜1Ds¤*îCÛÓn²#‰b*bZ„%è¦0^8[â^g(b>˜¤7h7^(Îå(Ž*¹}´rºFât‚_Ò‹ãê˜c/¨c1NÙÚ«ÅÚDöŪô ;®`îyduèÅ’äÿ‹dÿ¦Z$GM­k¬Ù…üdˆìFPnHœM€˜‰T~‰UމV®‰W¾‰XΉY~ÈŸ%åQ6Ç[ÖeQÞeRÌe]t¼Zb>¶–-fd¦ÏxQ¼zÂ0¶#9PãBÐÛd®²|Ü®kf ñŽÉÀæ  æjž,pn/+b]UÕ-&(EŸšMñÑÐ?ÏÐõbEÕ…ÚPyÞ2fçãñ^qß8Ý ¡Þ`—ÕÅ^ÜÍó­VÕºÑÝ?X]ƒ2Õà9h³0•Ó9}Jͳ«;¨èCñ~æžval›.:=á+á—R;Œƒir—ö0Tt~À[ç‰=,ˆÿTíSn†éÒ{Àìø©T¢‘]ݺq>i®)âK£=’š¤‚΃–cœëc𿀆>”#&K†êPk²6D³>ë6¤dµnë“uÂ(ì‰Ikê¹BLÊYºþL¼¶2»v¤Ékc~š¹N ì·ŒÛÁV#4ìÄÆÊÇn¬ÅvìÔźkŒMµiìÙkÎ^ÃIÙì†Ùl!í³‘œÏ~DUlÄÖ^·`ŽEN$ÜØ¾›Úv ×æÃÜNšÝ†CG„íß~œàΛÞîZìµâ†ˆä¾¡á~†æÆÈçžÆÕ¾†ã6îév›è–n—…îžFÙùn°ï—!ïSÎëÙïë>šÿôvG¨ioœløÂõ6¬á™ï žëú®›3„ºUÁoµääR¶å^.pfç2ð„Tp„lpt|rüe_NðŸpO®pe ßðçpoÈ q×p¶vk/Ùc>qר£]qWX)~q×ä¯qÓWz]Y­ ÙʶñgÅñjÕñæLzõñ'ØÏì[£X‘…ZÇSUËÿþØÆ„ò?K´r!/¾'O̹…ò)7JçÊ/¿p2sÚïaN[ª“+‡K;amøË-çYß óf¬CþÛ£Oâ©?hvå”='˜>o¥wvßdÄ´)V2i ÈÑÍä?Fç¤:z^ÿBú¦s%WËOÙôK(ñƒ¨ñ 'wº–ÿ´(|¥ÒÅ•!Ss•¦Šj'o107WTõr§ 6޵ ͪƒN¨]ˆZÉÃhUÑÖ`ÉDçëçÖ#uDáQ^¯”goiµâeOñD_Ž=)v%±ãì-Y&=7”ó¼|ôEïLü«ô?øZ3W÷.ƒæ@2éb!ö̃æ;wôy9öAïÌF·ôt*uØ øyçw@ÅtÐPø}«Þx`uuHtv‡$옓VO Œ§÷´2õ^G\/f’ß4<õY;.ƒçbtNQ·vz)õ*IOT×Q)™u1èÕfÿtÿ›4ä*¯s©:W£Ïs-ßt~=XWw–?8`Ió?zU—ú Ä%|—@hw%þºc7¼®Ïõ:U«˜WÔŸ_d#z.gòwrEŸ÷žz#lo6 û;›û£Ê)„ÝúÔw5cxHƒ[€?wB§ô³2¤7Ÿì5_Ø$oòw{+ü¤‡|9bú£ÿk0ïë‚Åü¢·|,¯ü·§|†ým/ýÑUá|¢5òŒýÉÿò;g}”uý×GýØÆ¯Äó(·}ßwÖß~¡~w¡ËÕàÝ´l¾+ÚçßK\âG-9€_÷#D«P>Ò¿69þÝèæƒ{~ùª.h¥~Ç¿ :%Dÿÿòßóèg¬â:%à=Óò%«fgI@Ñ’oy‚ê§ñµv˜Òpýj/Îzóî?Š#Yš'šª+Ûº/Ë3Úý4v0’ΑPÇBøV …Yi¥•£…Š‘™@ï ˜ÑZÀËðÕa¾kî7<.ŸÓëö;>¯?å0ý‡€ ÒÀÏ€ ƒÅ ‚Ž ¤â™`b…Ä%a¢a&b@ÚWé)f(&ã¡êèYhÅÂeåží-n®î.o¯ï¯Å_pÜð1r²ò2s³ósž0ô4uµõ5v¶¶³ô¶÷7x¸ø89u÷î¹\z9Þ:;;üË|<ß\½½mþ ¿~¿ÿÿÙÀGÆ@ ªÓ³!‹‡ !Þ‘HÂ"ÅEl̈СÇ:GŒ ù¡¤”ÿTr`iò☂ðÅÔ8ó¥™2ß\Òh§ 6] í ´CÑ›9k*=Js“ÈM._Jz¡ªÕUÝluŠT*@°^å‰}jtlIJ\Õ¢UÑõÛ¶Þ+·Ô¨gï¦ÈÇ/_…€ñî laáÀ„Û5U̧1OÈŽIJ®›U\âÅ“á^ÞysˆÏœA›¸38Óô*“^Úsë{"c—xý:µÁŒ·ióîíû÷±n»/nü8@È—3oî—ðçÒ§S¯.P¹õìÚ·s¿Œõ;øðொ/ÿož.ÃóêÏ“_ïþ;÷ø±½Ë»Z_÷ý¹ùåóWL?·~BtÛø‚j%¸ kË0¸`0&ØLtôìg ~bxІ> ͆» ÔG[L’‚ªè‰ š€b_†lœxB‚¼2 Ž2¶âˆÐ]¸ˆù‰xMIÒ¤XÂ,’dPà3’@ƵxH‘‘N¦€ÅŠU²@ÅŒ=ÞÒa‡A8¤5E†B<¡(²Ã è f,~ÀØFšW°‰†›sÆéçIØ™!žtöIDŸpJ 'œžÜ˜å™€º§‰ò°( , 6¹‚‹0iâ Œ 'Œæ|ŠB› ªb7G’ Éÿ£+&S¡ 9c‚^¥kÔ™ª‡»6¡i'bTì),P«­ÊḇÈþJ³Ã^€å”ÅRû€Öfm+°²ç Ò’ª‚¯«å•E,Yæª+ô™j¬VŠÀ…¼ÝÞŠ]®¡(’çšgP`©¹V9ª«yè+Úl{z†Ã@ÜÂk4ꀨw±žgpüæ¥ÍêHìJ‘\0¢(ÿÙ¨P+à qÉ3ʳ¼˜ã49Zr›2cJs”óªx4Ì|*=ÀÏ‹pâ´ƒGôã‡ê6D4^î3-¯²tl¹²r;ª±àŠ;î"i‡6ËÏèúm¯É¢-lÛø:‹÷ÿÛSk¿u§µk\ÝA•4>ÅÐE+þ×S¹” ,©Æ{žì§Çj‚üîæ;S*qÊu¶›i´Ü”þðé«Ü4Ö}4ÌyÔO]çr.@gëÀàz†@zM9Ø<]¼¸¿ÊWâlÌüÇ|˜Ç‡mxréM~½–{yEBFÏø‹ßgîüZº×žúêyÔþúÂÏžöÅwíú˜ã+#výÿk?óÄ´82e kþ;`zæG¿¹(Б Ù¨_¿º  :'¹è|xÕc(CÐTÈ ÷”êï~4$é9Z“¦T­§LÿÂÞô359åMkÊ ~å§žt©c0ú@£ž„©B )Q=ãTtX´5=U§J¢úÔj•}vÛéO <â5ï]•àV—ƒÏÒL•+ÃhkhÊiÀ51k]ÑšÖø¬õ¤©”kdú ô8”®ÍëPö*CÁ‚à¬0¹©eK²-¬bCÉØ¢~T²E,;,PÏ/ª¢Íì@ƒJЩžö4þ­]³ªzº’´¨%ÿdE3ΓFåµéó(G÷ÒÚÛ—³È¬L8›úY!.¡êKr…YÜéF¶œ ¢newkËnb·»…Šv½ë‹ðŠ·¼e©yñ’ÞõÎ˶ì†PÞûÞÚ~S¾!ïXíK]«L¢ý}‡~׋ÞN°À>ðf¥àôxÁnqpy aÙL»®ðE0la WÃŽ°‡Obâ‚ø)taž8X:,þ… ·. ¨ØÅ-Fí‹}‘¢GHl—lÀ+$`ŒF%ÊÇh 2õyãÌæ¸)Â’‹Œ¬Š›‘brŠ2)‰M Ø?KVl“yHÇ©IFv@£ÌLŠª¥YÊæ’ä';æ/gÎ7¶3/šç£î¹£xñŸûÌO÷ š™…v0w¿œèC3z¦®/U ØFSºÒ–¾4¦3;PK¼hç6i˽>MM DBUtils/Docs/RelNotes-0.9.3.html DBUtils 0.9.3 Release Notes

DBUtils 0.9.3 Release Notes

DBUtils 0.9.3 was released on May 21, 2007.

This is the fourth public release of DBUtils.

Changes:

  • Support custom creator functions for database connections. These can now be used as the first parameter instead of an DB-API module (suggested by Ezio Vernacotola).
  • Added destructor for steady connections.
  • Use setuptools if available.
  • Some code cleanup.
  • Some fixes in the documentation. Added Chinese translation of the User's Guide, kindly contributed by gashero.
PK¼hç6/ó'] ] DBUtils/Docs/dbdep.gifGIF89a^–ƒ$$$888HHHQQQeee{{{‰‰‰”””¤¤¤½½½ÈÈÈÙÙÙçççþþþ!ù,^–@ÿðÉI«½8ëÍ»ÿ`(ŽdižhªbÀꢭ¿t8×Ïï<§k? @Ç!Q•̇y<ESm„è5  _g6,±Z)w`,âIõžO.Çq VuROepazh9/A DQU]`…U~QSU dr`EFH˜S¨_›‹rªH‹±Ÿ, ’=<¹Dº¿¾=¼ÀÅ*ÂÆ2¥ÉÌ¥ÄÍÑÏÐÒÖ»ÏË×)ÙÜßÓ9ÈàäßÕåçåàéêíäìÃîòÁóõêðöù8øûþü (áÁÔJ#s:bBˆ‘˜V´Î¤éõOFÅ‹òúÕÓ˜£ÇÃÿ¼\Áq¤É“¸ŠhC „¥Ë—æ.–„I³f…™6oæÜÉò‡’ ,SÀÁÐ $ü”p ΕBŸÒ,­ „È!¥ì0Yàô©KÃfÅR lÖ[<ÓbÄ©VgÛ·ù‚Lej–B+@%`¶Þ¹ॠäÔÃ~òS,VPL´À®å_•if¾ÌŒšçÏ C‹M­éÓ¨S‡¾¦ºµë×°W— ÖÑ›8xŠ…‰ÁÒŨ 消Ü$¡Ü!V1¾­l¦‡!wmäÇS NÀ¸ìv3F=¸ÚP+œ~}äÁmö"Lð¥M¥ ö‰L6žQzüDÔIÿ-ìQ°‰{PR_€þy„‚ ä—G~L·wX…Ä' 5È!'g fƒ™TG"S'"€ÐK)Ð=³Ÿ[íX’páÈž½ÚŽÓ´ðæÜ c1Fé#Dþ£ä OÖe“ÜLI•aiR5Ö ¸ ž\À"‰0¢ÝV²¦¥MÕdhŠo’R œ-°`‹·Q┄Ûɨƒk‰ üj¨.£µ•桌¢åÌ¢;@Úè¤hÆf饘ªDé¦ÇœàX;Ÿ’ )§;ùtVr§rf¤¶J‘s Å\‚U—Àx ˜*#i4à «N¬£®Ë$Ve![Ä•ÿB¨Nâ§°g}ZÕmd!pV† $•XU¶\iì¸ä–kî¹èÂàÒL£Ò`e»ke™“p¥šfn5ÐwÇDô€xh€‹eŽ‘†oÌ¢¹~Pí+'PüF`{VôK ^mDAHDh±Þ Ù‚ð…$i ±z ­Ç@R-qÆm#\¢¶X<±ðÝÇ{Ó‚ÅÁÐ%L]KG­B¼òa+Ï9X°xŠˆBô«3GÝÕ€²ÈüaÖã1Á´‡©'F˜>“1Ý9_Bž&V( ŠÔ†HØH/ ·Ò´@uWǪ™ lFJÖ ©G‡›xE‹#:Ž gôxŽ“sºMºÁ‰$eÿi›þˆù²}$©=~nƒJðº«MåŒÆ¹éýõíOê7Ân í ‹ûç»Ë>iï¶;£¦«ÀŸûú>Ç[Vü½ó*üðœŒ"´;Ë îmC @¹ý\°÷í·”Ï¯# ò5ø„(í+ÁOc2ß Ã´|ù$G#ý ëâï$ëÈ âüw¨ËAŽ€¤gî‡ÀÙiŽ' l èŒD> Z0‚¹³ }w ƒ֡“1“PÉcX±áŽL±ÃÆI;Ì(8qíð¥†B¯¡…»$†.ÛéUÛªõ6 >TÂŒ†¦BçQå…y¡b˜ƒø¡‡6"V,`İÿm± `Ö “(ÃO9ëˆ(aíõD äLÑPµÆË¨±ƒuÌQ´(PZõA+R˜Õ®ú¸« ÜZb@"‘…­JdÅZ@œê—Ç·˜Ê.ºªÀ¿ø˜Bþ00s„ä'‹²€B4†ˆšð*iGJÝ‘•ŽË”,g‰XÚò–¸Ìeëhäé•7᥻„ $_R­'¢¦ž¤Ì*Á£™áÀEáØ¨»hf ?¿êx0°LCÊ674‚mª€Oß|“xÑÍQ›sgv:ÐÍ"ÄÈ ä×11 ¯p}ç ªÏØ ”lêsjý\" ·Þ tCyûÂÙLöǘ³ÿjà @ ‹‡Æ/Ÿd"?÷‚—ݤLÁ˜®˜`‚îMNà 'BIZ"(È‘fŠ ×ÐÑÞ¬´8T¢ÆæW½˜N4d¡ØM•°Š!Ö‡m5ýwJúT§]G¥4liG­ÓIRr|bb–â°¯±âôCn² @V—ì{p#V¡Ä—V#¬Õ E˜ÌòÚ´ºn¯6tsNÖ&R6-•hªOSJäM~XÙŠS³:ö›ðëZÛºÕÁ•~"•«†RάK Òj™ÊÑ}M|3kßÜÐ`YqÌ,{ÒX!X—Ž :]'°` ¼¨M·Œe*, ZÞ’¶ª¦ÿ½ª‡¢Úß Ö´_Ú4eú7Õ ŽLõ²& g¿x¸€¡å5\ÿ‡L`@3•¡¥|Cç‚ùÚ÷¹¯~÷KÌwôw^ï]G€øßuÓPøµçJ•à].Ø ´ßƒw)Ž—Ïs'ÁpG·A¯…¾–3 —1`…8PB*ðóQâ¡©˜H,nñzC˸¢X—`˸d\L'íÇâíH±x¼¦IG> :† äNU‰ÉM.™4’̪(ŸŽ¿ó%•©Dä-§ÄÊAn¯ÁœÁ¢a£“¼™NƒÚx¼d.ó5ó€Þ4»9¢õ¨v›ç0—DjHbA]ŒÁazDÿQ½šã÷9…Hì]iVŠ¿’á7–"‡,[6ÂÕµ(yñ£õ¡â2vd™0õ*fhˆÎiµdÂ3¨·4êÙpƒ íœk-ªh%×PÚ5¯Ù+æP›Xβ¼ÜdQëñØ[1—¡Ý“Òõ˜ÚËŽ°¢°½9k†ÙÜ®°ÔîpƒÅ|67¹uär«ÛÏ2y·’eâny÷zvöve/ómIg»ÞVø½ù=›à5ò*Aµð#<&O\ä²à¬lQâÔŠ“ ²L Ü’‚Ž’ñ"¶¸Ö)8GƒçÑT É 3s"nH2ÔRŒ@ªÉ"&*Ÿe ±ÿ‚½|å…Ù}ø”a%Ã@–’èOÿ!ÒqÎIg­ 鄬ú'ò9•¬K},ÿI£Ò!.7‰“¥[Ht$Vîð+•sÒ@“L¨À'·8I’ú ú›ÇNÇ6Ú/QÿÉoÇwè‘®ð!„2â›!IòÕ•æ¹,n®3¿]YÀ QxÐÅžé×û&©eB4îÊè@LÁæ=)ZÏWÙïGw|@[ñLNàé( :贡献: DBUtils收到了如下朋å‹çš„帮助和建议 Ian Bicking, Chuck Esterbrook (Webware for Python), Dan Green (DBTools), Jay Love, Michael Palmer, Tom Schwaller, Geoffrey Talvola, Warren Smith (DbConnectionPool) and Ezio Vernacotola. :翻译: gashero 版æƒä¸Žè®¸å¯ ------------ Copyright @ 2005-2007 by Christoph Zwerschke. All Rights Reserved. DBUtils是一个自由开æºè½¯ä»¶ï¼Œä½¿ç”¨ `Open Software License version 2.1`__ 许å¯ã€‚ __ http://www.opensource.org/licenses/osl-2.1.php PK¼hç6`]@6„„DBUtils/Docs/DocUtils.css/* Default cascading style sheet for the HTML output of Docutils. Written by David Goodger. Version as of Docutils 0.3.9. This stylesheet has been placed in the public domain. */ .first { margin-top: 0 ! important } .last, .with-subtitle { margin-bottom: 0 ! important } .hidden { display: none } a.toc-backref { text-decoration: none; color: black } blockquote.epigraph { margin: 2em 5em } dl.docutils dd { margin-bottom: 0.5em } dl.docutils dt { font-weight: bold } div.abstract { margin: 2em 5em } div.abstract p.topic-title { font-weight: bold; text-align: center } div.admonition, div.attention, div.caution, div.danger, div.error, div.hint, div.important, div.note, div.tip, div.warning { margin: 2em; border: medium outset; padding: 1em } div.admonition p.admonition-title, div.hint p.admonition-title, div.important p.admonition-title, div.note p.admonition-title, div.tip p.admonition-title { font-weight: bold; font-family: sans-serif } div.attention p.admonition-title, div.caution p.admonition-title, div.danger p.admonition-title, div.error p.admonition-title, div.warning p.admonition-title { color: red; font-weight: bold; font-family: sans-serif } div.compound .compound-first, div.compound .compound-middle { margin-bottom: 0.5em } div.compound .compound-last, div.compound .compound-middle { margin-top: 0.5em } div.dedication { margin: 2em 5em; text-align: center; font-style: italic } div.dedication p.topic-title { font-weight: bold; font-style: normal } div.figure { margin-left: 2em } div.footer, div.header { font-size: smaller } div.line-block { display: block; margin-top: 1em; margin-bottom: 1em } div.line-block div.line-block { margin-top: 0; margin-bottom: 0; margin-left: 1.5em } div.sidebar { margin-left: 1em; border: medium outset; padding: 1em; background-color: #ffffee; width: 40%; float: right; clear: right } div.sidebar p.rubric { font-family: sans-serif; font-size: medium } div.system-messages { margin: 5em } div.system-messages h1 { color: red } div.system-message { border: medium outset; padding: 1em } div.system-message p.system-message-title { color: red; font-weight: bold } div.topic { margin: 2em } h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { margin-top: 0.4em } h1.title { text-align: center } h2.subtitle { text-align: center } hr.docutils { width: 75% } ol.simple, ul.simple { margin-bottom: 1em } ol.arabic { list-style: decimal } ol.loweralpha { list-style: lower-alpha } ol.upperalpha { list-style: upper-alpha } ol.lowerroman { list-style: lower-roman } ol.upperroman { list-style: upper-roman } p.attribution { text-align: right; margin-left: 50% } p.caption { font-style: italic } p.credits { font-style: italic; font-size: smaller } p.label { white-space: nowrap } p.rubric { font-weight: bold; font-size: larger; color: maroon; text-align: center } p.sidebar-title { font-family: sans-serif; font-weight: bold; font-size: larger } p.sidebar-subtitle { font-family: sans-serif; font-weight: bold } p.topic-title { font-weight: bold } pre.address { margin-bottom: 0; margin-top: 0; font-family: serif; font-size: 100% } pre.line-block { font-family: serif; font-size: 100% } pre.literal-block, pre.doctest-block { margin-left: 2em; margin-right: 2em; background-color: #eeeeee } span.classifier { font-family: sans-serif; font-style: oblique } span.classifier-delimiter { font-family: sans-serif; font-weight: bold } span.interpreted { font-family: sans-serif } span.option { white-space: nowrap } span.pre { white-space: pre } span.problematic { color: red } span.section-subtitle { font-size: 80% } table.citation { border-left: solid thin gray } table.docinfo { margin: 2em 4em } table.docutils { margin-top: 0.5em; margin-bottom: 0.5em } table.footnote { border-left: solid thin black } table.docutils td, table.docutils th, table.docinfo td, table.docinfo th { padding-left: 0.5em; padding-right: 0.5em; vertical-align: top } table.docutils th.field-name, table.docinfo th.docinfo-name { font-weight: bold; text-align: left; white-space: nowrap; padding-left: 0 } h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { font-size: 100% } tt.docutils { background-color: #eeeeee } ul.auto-toc { list-style-type: none } PK(tç6}Gì88 DBUtils/Docs/RelNotes-0.9.4.html DBUtils 0.9.4 Release Notes

DBUtils 0.9.4 Release Notes

DBUtils 0.9.4 was released on July 7, 2007.

This is the fifth public release of DBUtils.

This release fixes a problem in the destructor code and has been supplemented with a German User's Guide.

Please note that the dbapi parameter has been renamed to creator in the last release since you can now pass custom creator functions for database connections instead of DB-API 2 modules.

PK¼hç6¬©»Ëïï DBUtils/Docs/RelNotes-0.8.1.html DBUtils 0.8.1 Release Notes

DBUtils 0.8.1 Release Notes

DBUtils 0.8.1 was released on September 13, 2005.

This is the first public release of DBUtils.

PK¼hç6xÔô/¡¡ DBUtils/Docs/RelNotes-0.9.1.html DBUtils 0.9.1 Release Notes

DBUtils 0.9.1 Release Notes

DBUtils 0.9.1 was released on May 8, 2006.

This is the second public release of DBUtils.

Changes:

  • Added _closeable attribute and made persistent connections not closeable by default. This allows PersistentDB to be used in the same way as you would use PooledDB.
  • Allowed arguments in the DB-API 2 cursor() method. MySQLdb is using this to specify cursor classes. [Suggested by Michael Palmer]
  • Improved the documentation and added a User's Guide.
PK¼hç6Ñ,¢î¦x¦xDBUtils/Docs/UsersGuide.html DBUtils User's Guide

DBUtils User's Guide

Version: 0.9.4
Released:07/07/07
Translations:English German Chinese

Synopsis

DBUtils is a suite of Python modules allowing to connect in a safe and efficient way between a threaded Python application and a database. DBUtils has been written in view of Webware for Python as the application and PyGreSQL as the adapter to a PostgreSQL database, but it can be used for any other Python application and DB-API 2 conformant database adapter.

Modules

The DBUtils suite is realized as a Python package containing two subsets of modules, one for use with arbitrary DB-API 2 modules, the other one for use with the classic PyGreSQL module.

Universal DB-API 2 variant
SteadyDB.py Hardened DB-API 2 connections
PooledDB.py Pooling for DB-API 2 connections
PersistentDB.py Persistent DB-API 2 connections
SimplePooledDB.py Simple pooling for DB-API 2
Classic PyGreSQL variant
SteadyPg.py Hardened classic PyGreSQL connections
PooledPg.py Pooling for classic PyGreSQL connections
PersistentPg.py Persistent classic PyGreSQL connections
SimplePooledPg.py Simple pooling for classic PyGreSQL

The dependencies of the modules in the universal DB-API 2 variant are as indicated in the following diagram:

dbdep.gif

The dependencies of the modules in the classic PyGreSQL variant are similar:

pgdep.gif

Download

You can download the actual version of DBUtils from the Webware for Python homepage at:

http://www.webwareforpython.org/downloads/DBUtils/

You can also download it from the Python Package Index (also known as the "Cheese Shop") at:

http://www.python.org/pypi/DBUtils/

Installation

Installation as a standalone (top-level) package

If you intend to use DBUtils from other applications than Webware for Python, it is recommended to install the package in the usual way:

python setup.py install

Installation as a Webware for Python subpackage (plug-in)

If you want to use DBUtils as a supplement for the Webware for Python framework only, you should install it as a Webware plug-in:

python setup.py install --install-lib=/path/to/Webware

Replace /path/to/Webware with the path to the root directory of your Webware for Python installation. You will also need to run the Webware installer if this has not been done already or if you want to integrate the DBUtils documentation into the Webware documentation:

cd path/to/Webware
python install.py

Requirements

DBUtils runs with Python version 2.2 and above. The modules in the classic PyGreSQL variant need PyGreSQL version 3.4 or above, while the modules in the universal DB-API 2 variant run with any Python DB-API 2 compliant database interface module.

Functionality

This section will refer to the names in the DB-API 2 variant only, but the same applies to the classic PyGreSQL variant.

SimplePooledDB

DBUtils.SimplePooledDB is a very basic reference implementation of a pooled database connection. It is much less sophisticated than the regular PooledDB module and is particularly lacking the failover functionality. DBUtils.SimplePooledDB is essentially the same as the MiscUtils.DBPool module that is part of Webware for Python. You should consider it a demonstration of concept rather than something that should go into production.

SteadyDB

DBUtils.SteadyDB is a module implementing "hardened" connections to a database, based on ordinary connections made by any DB-API 2 database module. A "hardened" connection will transparently reopen upon access when it has been closed or the database connection has been lost or when it is used more often than an optional usage limit.

A typical example where this is needed is when the database has been restarted while your application is still running and has open connections to the database, or when your application accesses a remote database in a network that is separated by a firewall and the firewall has been restarted and lost its state.

Usually, you will not use the SteadyDB module directly; it merely serves as a basis for the next two modules, PersistentDB and PooledDB.

PersistentDB

DBUtils.PersistentDB implements steady, thread-affine, persistent connections to a database, using any DB-API 2 database module.

The following diagram shows the connection layers involved when you are using PersistentDB connections:

persist.gif

Whenever a thread opens a database connection for the first time, a new connection to the database will be opened that will be used from now on for this specific thread. When the thread closes the database connection, it will still be kept open so that the next time when a connection is requested by the same thread, this already opened connection can be used. The connecton will be closed automatically when the thread dies.

In short: PersistentDB tries to recycle database connections to increase the overall database access performance of your threaded application, but it makes sure that connections are never shared between threads.

Therefore, PersistentDB will work perfectly even if the underlying DB-API module is not thread-safe at the connection level, and it will avoid problems when other threads change the database session or perform transactions spreading over more than one SQL command.

PooledDB

DBUtils.PooledDB implements a pool of steady, thread-safe cached connections to a database which are transparently reused, using any DB-API 2 database module.

The following diagram shows the connection layers involved when you are using PooledDB connections:

pool.gif

As the diagram indicates, PooledDB can share opened database connections between different threads. This will happen by default if you set up the connection pool with a positive value of maxshared and the underlying DB-API 2 is thread-safe at the connection level, but you can also request dedicated database connections that will not be shared between threads. Besides the pool of shared connections, you can also set up a pool of at least mincached and at the most maxcached idle connections that will be used whenever a thread is requesting a dedicated database connection or the pool of shared connections is not yet full. When a thread closes a connection that is not shared any more, it is returned back to the pool of idle connections so that it can be recycled again.

If the underlying DB-API module is not thread-safe, thread locks will be used to ensure that the PooledDB connections are thread-safe. So you don't need to worry about that, but you should be careful to use dedicated connections whenever you change the database session or perform transactions spreading over more than one SQL command.

Which one to use?

Both PersistentDB and PooledDB serve the same purpose to improve the database access performance by recycling database connections, while preserving stability even if database connection will be disrupted.

So which of these two modules should you use? From the above explanations it is clear that PersistentDB will make more sense if your application keeps a constant number of threads which frequently use the database. In this case, you will always have the same amount of open database connections. However, if your application frequently starts and ends threads, then it will be better to use PooledDB. The latter will also allow more fine-tuning, particularly if you are using a thread-safe DB-API 2 module.

Since the interface of both modules is similar, you can easily switch from one to the other and check which one will suit better.

Usage

The usage of all the modules is similar, but there are also some differences in the initialization between the "Pooled" and "Persistent" variants and also between the universal DB-API 2 and the classic PyGreSQL variants.

We will cover here only the PersistentDB module and the more complex PooledDB module. For the details of the other modules, have a look at their module docstrings. Using the Python interpreter console, you can display the documentation of the PooledDB module as follows (this works analogously for the other modules):

help(PooledDB)

PersistentDB

In order to make use of the PersistentDB module, you first need to set up a generator for your kind of database connections by creating an instance of PersistentDB, passing the following parameters:

  • creator: either an arbitrary function returning new DB-API 2 connection objects or a DB-API 2 compliant database module

  • maxusage: the maximum number of reuses of a single connection (the default of 0 or False means unlimited reuse)

    Whenever the limit is reached, the connection will be reset.

  • setsession: an optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to german", ...]

  • The creator function or the connect function of the DB-API 2 compliant database module specified as the creator will receive any additional parameters such as the host, database, user, password etc. You may choose some or all of these parameters in your own creator function, allowing for sophisticated failover and load-balancing mechanisms.

For instance, if you are using pgdb as your DB-API 2 database module and want every connection to your local database mydb to be reused 1000 times:

import pgdb # import used DB-API 2 module
from DBUtils.PersistentDB import PersistentDB
persist = PersistentDB(pgdb, 1000, database='mydb')

Once you have set up the generator with these parameters, you can request database connections of that kind:

db = persist.connection()

You can use these connections just as if they were ordinary DB-API 2 connections. Actually what you get is the hardened SteadyDB version of the underlying DB-API 2 connection.

Closing a persistent connection with db.close() will be silently ignored since it would be reopened at the next usage anyway and contrary to the intent of having persistent connections. Instead, the connection will be automatically closed when the thread dies. You can change this behavior be setting persist._closeable to True.

PooledDB

In order to make use of the PooledDB module, you first need to set up the database connection pool by creating an instance of PooledDB, passing the following parameters:

  • creator: either an arbitrary function returning new DB-API 2 connection objects or a DB-API 2 compliant database module

  • mincached : the initial number of idle connections in the pool (the default of 0 means no connections are made at startup)

  • maxcached: the maximum number of idle connections in the pool (the default value of 0 means unlimited pool size)

  • maxshared: maximum number of shared connections allowed (the default value of 0 means all connections are dedicated)

    When this maximum number is reached, connections are shared if they have been requested as shareable.

  • maxconnections: maximum number of connections generally allowed (the default value of 0 means any number of connections)

  • blocking: determines behavior when exceeding the maximum (the default of 0 or False means report an error; otherwise block and wait until the number of connections decreases)

  • maxusage: maximum number of reuses of a single connection (the default of 0 or False means unlimited reuse)

    When this maximum usage number of the connection is reached, the connection is automatically reset (closed and reopened).

  • setsession: an optional list of SQL commands that may serve to prepare the session, e.g. ["set datestyle to german", ...]

  • The creator function or the connect function of the DB-API 2 compliant database module specified as the creator will receive any additional parameters such as the host, database, user, password etc. You may choose some or all of these parameters in your own creator function, allowing for sophisticated failover and load-balancing mechanisms.

For instance, if you are using pgdb as your DB-API 2 database module and want a pool of at least five connections to your local database mydb:

import pgdb # import used DB-API 2 module
from DBUtils.PooledDB import PooledDB
pool = PooledDB(pgdb, 5, database='mydb')

Once you have set up the connection pool you can request database connections from that pool:

db = pool.connection()

You can use these connections just as if they were ordinary DB-API 2 connections. Actually what you get is the hardened SteadyDB version of the underlying DB-API 2 connection.

Please note that the connection may be shared with other threads by default if you set a non-zero maxshared parameter and the DB-API 2 module allows this. If you want to have a dedicated connection, use:

db = pool.connection(0)

If you don't need it any more, you should immediately return it to the pool with db.close(). You can get another connection in the same way.

Warning: In a threaded environment, never do the following:

pool.connection().cursor().execute(...)

This would release the connection too early for reuse which may be fatal if the connections are not thread-safe. Make sure that the connection object stays alive as long as you are using it, like that:

db = pool.connection()
cur = db.cursor()
cur.execute(...)
res = cur.fetchone()
cur.close() # or del cur
db.close() # or del db

Usage in Webware for Python

If you are using DBUtils in order to access a database from Webware for Python servlets, you need to make sure that you set up your database connection generators only once when the application starts, and not every time a servlet instance is created. For this purpose, you can add the necessary code to the module or class initialization code of your base servlet class, or you can use the contextInitialize() function in the __init__.py script of your application context.

The directory Examples that is part of the DButils distribution contains an example context for Webware for Python that uses a small demo database designed to track the attendees for a series of seminars (the idea for this example has been taken from the article "The Python DB-API" by Andrew Kuchling).

The example context can be configured by either creating a config file Configs/Database.config or by directly changing the default parameters in the example servlet Examples/DBUtilsExample.py. This way you can set an appropriate database user and password, and you can choose the underlying database module (PyGreSQL classic or any DB-API 2 module). If the setting maxcached is present, then the example servlet will use the "Pooled" variant, otherwise it will use the "Persistent" variant.

Notes

If you are using one of the popular object-relational mappers SQLObject or SQLAlchemy, you won't need DBUtils, since they come with their own connection pools. SQLObject 2 (SQL-API) is actually borrowing some code from DBUtils to split the pooling out into a separate layer.

Future

Some ideas for future improvements:

  • Alternatively to the maximum number of uses of a connection, implement a maximum time to live for connections.
  • Create modules MonitorDB and MonitorPg that will run in a separate thread, monitoring the pool of the idle connections and maybe also the shared connections respectively the thread-affine connections. If a disrupted connection is detected, then it will be reestablished automatically by the monitoring thread. This will be useful in a scenario where a database powering a website is restarted during the night. Without the monitoring thread, the users would experience a slight delay in the next morning, because only then, the disrupted database connections will be detected and the pool will be rebuilt. With the monitoring thread, this will already happen during the night, shortly after the disruption. The monitoring thread could also be configured to generally recreate the connection pool every day shortly before the users arrive.
  • Optionally log usage, bad connections and exceeding of limits.

Bug reports and feedback

Please send bug reports, patches and feedback directly to the author (using the email address given below).

If there are Webware related problems, these can also be discussed in the Webware for Python mailing list.

Links

Some links to related and alternative software:

Credits

Author:Christoph Zwerschke <cito@online.de>
Contributions:DBUtils uses code, input and suggestions made by Ian Bicking, Chuck Esterbrook (Webware for Python), Dan Green (DBTools), Jay Love, Michael Palmer, Tom Schwaller, Geoffrey Talvola, Warren Smith (DbConnectionPool) and Ezio Vernacotola.

Copyright and License

Copyright © 2005-2007 by Christoph Zwerschke. All Rights Reserved.

DBUtils is free and open source software, licensed under the Open Software License version 2.1.

PK¼hç6E.™]‹]‹DBUtils/Docs/UsersGuide.de.html Benutzeranleitung für DBUtils

Benutzeranleitung für DBUtils

Version: 0.9.4
Released:07/07/07
Translations:English German Chinese

Zusammenfassung

DBUtils ist eine Sammlung von Python-Modulen, mit deren Hilfe man in Python geschriebene Multithread-Anwendungen auf sichere und effiziente Weise an Datenbanken anbinden kann. DBUtils wurde mit Blick auf Webware for Python als Anwendung und PyGreSQL als PostgreSQL-Datenbankadapter entwickelt, kann aber für beliebige Python-Anwendungen und beliebige auf DB-API 2 beruhende Python-Datenbankadapter verwendet werden.

Module

DBUtils ist als Python-Package realisiert worden, das aus zwei verschiedenen Gruppen von Modulen besteht: Einer Gruppe zur Verwendung mit beliebigen DB-API-2-Datenbankadaptern, und einer Gruppe zur Verwendung mit dem klassischen PyGreSQL-Datenbankadapter-Modul.

Allgemeine Variante für beliebige DB-API-2-Adapter
SteadyDB.py Gehärtete DB-API-2-Datenbankverbindungen
PooledDB.py Pooling für DB-API-2-Datenbankverbindungen
PersistentDB.py Persistente DB-API-2-Datenbankverbindungen
SimplePooledDB.py Einfaches Pooling für DB-API 2
Variante speziell für den klassischen PyGreSQL-Adapter
SteadyPg.py Gehärtete klassische PyGreSQL-Verbindungen
PooledPg.py Pooling für klassische PyGreSQL-Verbindungen
PersistentPg.py Persistente klassische PyGreSQL-Verbindungen
SimplePooledPg.py Einfaches Pooling für klassisches PyGreSQL

Die Abhängigkeiten der Module in der Variante für beliebige DB-API-2-Adapter sind im folgenden Diagramm dargestellt:

dbdep.gif

Die Abhängigkeiten der Module in der Variante für den klassischen PyGreSQL-Adapter sehen ähnlich aus:

pgdep.gif

Download

Die aktuelle Version von DBUtils kann von der Homepage von Webware for Python heruntergeladen werden:

http://www.webwareforpython.org/downloads/DBUtils/

Außerdem befindet sie sich im Python Package Index (auch bekannt als der "Cheese Shop") und kann von dort heruntergeladen werden:

http://www.python.org/pypi/DBUtils/

Installation

Installation als eigenständiges Paket

Wenn Sie DBUtils für andere Anwendungen als Webware for Python verwenden möchten, empfiehlt es sich, das Paket auf die übliche Weise zu installieren:

python setup.py install

Installation als Unterpaket (Plug-In) von Webware for Python

Wenn Sie DBUtils nur als Ergänzung für das Web-Framework Webware for Python verwenden wollen, sollten Sie DBUtils als Webware-Plug-In installieren:

python setup.py install --install-lib=/pfad/zu/Webware

Ersetzen Sie /pfad/zu/Webware hierbei durch den Pfad zum Wurzelverzeichnis der Installation von Webware for Python. Sie müssen auch das Installationsskript von Webware for Python laufen lassen, wenn dies noch nicht geschehen ist, oder wenn Sie DBUtils in die Webware-Dokumentation integrieren wollen:

cd /pfad/zu/Webware
python install.py

Anforderungen

DBUtils benötigt Python Version 2.2 oder höher. Die Module in der Variante für klassisches PyGreSQL benötigen PyGreSQL Version 3.4 oder höher, während die Module in der allgemeinen Variante für DB-API 2 mit jedem beliebigen Python-Datenbankadapter-Modul zusammenarbeiten, das auf DB-API 2 basiert.

Funktionalität

Dieser Abschnitt verwendet nur die Bezeichnungen der DB-API-2-Variante, aber Entsprechendes gilt auch für die PyGreSQL-Variante.

SimplePooledDB

DBUtils.SimplePooledDB ist eine sehr elementare Referenz-Implementierung eines Pools von Datenbankverbindungen. Hiermit ist ein Vorratsspeicher an Datenbankverbindungen gemeint, aus dem sich die Python-Anwendung bedienen kann. Diese Implementierung ist weit weniger ausgefeilt als das eigentliche PooledDB-Modul und stellt insbesondere keine Ausfallsicherung zur Verfügung. DBUtils.SimplePooledDB ist im Wesentlichen identisch mit dem zu Webware for Python gehörenden Modul MiscUtils.DBPool. Es ist eher zur Verdeutlichung des Konzepts gedacht, als zum Einsatz im produktiven Betrieb.

SteadyDB

DBUtils.SteadyDB ist ein Modul, das "gehärtete" Datenbankverbindungen bereitstellt, denen gewöhnlichen Verbindungen eines DB-API-2-Datenbankadapters zugrunde liegen. Eine "gehärtete" Verbindung wird bei Zugriff automatisch, ohne dass die Anwendung dies bemerkt, wieder geöffnet, wenn sie geschlossen wurde, die Datenbankverbindung unterbrochen wurde, oder wenn sie öfter als ein optionales Limit genutzt wurde.

Ein typisches Beispiel wo dies benötig wird, ist, wenn die Datenbank neu gestartet wurde, während Ihre Anwendung immer noch läuft und Verbindungen zur Datenbank offen hat, oder wenn Ihre Anwendung auf eine entfernte Datenbank über ein Netzwerk zugreift, das durch eine Firewall geschützt ist, und die Firewall neu gestartet wurde und dabei ihren Verbindungsstatus verloren hat.

Normalerweise benutzen Sie das SteadyDB-Modul nicht direkt; es wird aber von den beiden nächsten Modulen benötigt, PersistentDB und PooledDB.

PersistentDB

DBUtils.PersistentDB stellt gehärtete, thread-affine, persistente Datenbankverbindungen zur Verfügung, unter Benutzung eines beliebigen DB-API-2-Datenbankadapters. Mit "thread-affin" und "persistent" ist hierbei gemeint, dass die einzelnen Datenbankverbindungen den jeweiligen Threads fest zugeordnet bleiben und während der Laufzeit des Threads nicht geschlossen werden.

Das folgende Diagramm zeigt die beteiligten Verbindungsschichten, wenn Sie PersistentDB-Datenbankverbindungen einsetzen:

persist.gif

Immer wenn ein Thread eine Datenbankverbindung zum ersten Mal öffnet, wird eine neue Datenbankverbindung geöffnet, die von da an immer wieder für genau diesen Thread verwendet wird. Wenn der Thread die Datenbankverbindung schließt, wird sie trotzdem weiter offen gehalten, damit beim nächsten Mal, wenn der gleiche Thread wieder eine Datenbankverbindung anfordert, diese gleiche bereits geöffnete Datenbankverbindung wieder verwendet werden kann. Die Verbindung wird automatisch geschlossen, wenn der Thread beendet wird.

Kurz gesagt versucht PersistentDB Datenbankverbindungen wiederzuverwerten, um die Gesamteffizienz der Datenbankzugriffe Ihrer Multithread-Anwendungen zu steigern, aber es wird dabei sichergestellt, dass verschiedene Threads niemals die gleiche Verbindung benutzen.

Daher arbeitet PersistentDB sogar dann problemlos, wenn der zugrunde liegende DB-API-2-Datenbankadapter nicht thread-sicher auf der Verbindungsebene ist, oder wenn parallele Threads Parameter der Datenbank-Sitzung verändern oder Transaktionen mit mehreren SQL-Befehlen durchführen.

PooledDB

DBUtils.PooledDB stellt, unter Benutzung eines beliebigen DB-API-2-Datenbankadapters, einen Pool von gehärteten, thread-sicheren Datenbankverbindungen zur Verfügung, die automatisch, ohne dass die Anwendung dies bemerkt, wiederverwendet werden.

Das folgende Diagramm zeigt die beteiligten Verbindungsschichten, wenn Sie PooledDB-Datenbankverbindungen einsetzen:

pool.gif

Wie im Diagramm angedeutet, kann PooledDB geöffnete Datenbankverbindungen den verschiedenen Threads beliebig zuteilen. Dies geschieht standardmäßig, wenn Sie den Verbindungspool mit einem positiven Wert für maxshared einrichten und der zugrunde liegende DB-API-2-Datenbankadapter auf der Verbindungsebene thread-sicher ist, aber sie können auch dedizierte Datenbankverbindungen anfordern, die nicht von anderen Threads verwendet werden sollen. Neben dem Pool gemeinsam genutzter Datenbankverbindungen ("shared pool") können Sie auch einen Pool von mindestens mincached und höchstens maxcached inaktiven Verbindungen auf Vorrat einrichten ("idle pool"), aus dem immer dann geschöpft wird, wenn ein Thread eine dedizierte Datenbankverbindung anfordert, oder wenn der Pool gemeinsam genutzter Datenbankverbindungen noch nicht voll ist. Wenn ein Thread eine Datenbankverbindung schließt, die auch von keinem anderen Thread mehr benutzt wird, wird sie an den Vorratsspeicher inaktiver Datenbankverbindungen zurückgegeben, damit sie wiederverwertet werden kann.

Wenn der zugrunde liegende DB-API-Datenbankadapter nicht thread-sicher ist, werden Thread-Locks verwendet, um sicherzustellen, dass die PooledDB-Verbindungen dennoch thread-sicher sind. Sie brauchen sich also hierum keine Sorgen zu machen, aber Sie sollten darauf achten, dedizierte Datenbankverbindungen zu verwenden, sobald Sie Parameter der Datenbanksitzung verändern oder Transaktionen mit mehreren SQL-Befehlen ausführen.

Die Qual der Wahl

Sowohl PersistentDB als auch PooledDB dienen dem gleichen Zweck, nämlich die Effizienz des Datenbankzugriffs durch Wiederverwendung von Datenbankverbindungen zu steigern, und dabei gleichzeitig die Stabilität zu gewährleisten, selbst wenn die Datenbankverbindung unterbrochen wird.

Welches der beiden Module sollte also verwendet werden? Nach den obigen Erklärungen ist es klar, dass PersistentDB dann sinnvoller ist, wenn Ihre Anwendung eine gleich bleibende Anzahl Threads verwendet, die häufig auf die Datenbank zugreifen. In diesem Fall werden Sie ungefähr die gleiche Anzahl geöffneter Datenbankverbindungen erhalten. Wenn jedoch Ihre Anwendung häufig Threads beendet und neu startet, dann ist PooledDB die bessere Lösung, die auch mehr Möglichkeiten zur Feineinstellung zur Verbesserung der Effizienz erlaubt, insbesondere bei Verwendung eines thread-sicheren DB-API-2-Datenbankadapters.

Da die Schnittstellen beider Module sehr ähnlich sind, können Sie recht einfach von einem Modul zum anderen wechseln und austesten, welches geeigneter ist.

Benutzung

Die Benutzung aller Module ist zwar recht ähnlich, aber es gibt vor allem bei der Initialisierung auch einige Unterschiede, sowohl zwischen den "Pooled"- und den "Persistent"-Varianten, als auch zwischen den DB-API-2- und den PyGreSQL-Varianten.

Wir werden hier nur auf das PersistentDB-Modul und das etwas kompliziertere PooledDB-Modul eingehen. Einzelheiten zu den anderen Modulen finden Sie in deren Docstrings. Unter Verwendung der Python-Interpreter-Konsole können Sie sich die Dokumentation des PooledDB-Moduls wie folgt anzeigen lassen (dies funktioniert entsprechend auch mit den anderen Modulen):

help(PooledDB)

PersistentDB

Wenn Sie das PersistentDB-Modul einsetzen möchten, müssen Sie zuerst einen Generator für die von Ihnen gewünschte Art von Datenbankverbindungen einrichten, indem Sie eine Instanz der Klasse PersistentDB erzeugen, wobei Sie folgende Parameter angeben müssen:

  • creator: entweder eine Funktion, die neue DB-API-2-Verbindungen erzeugt, oder ein DB-API-2-Datenbankadapter-Modul

  • maxusage: Obergrenze dafür, wie oft eine einzelne Verbindung wiederverwendet werden darf (der Standardwert 0 oder False bedeutet unbegrenzte Wiederverwendung)

    Sobald diese Obergrenze erreicht wird, wird die Verbindung zurückgesetzt.

  • setsession: eine optionale Liste von SQL-Befehlen zur Initialisierung der Datenbanksitzung, z.B. ["set datestyle to german", ...]

  • Die als creator angegebene Funktion oder die Funktion connect des DB-API-2-Datenbankadapter-Moduls erhalten alle weiteren Parameter, wie host, database, user, password usw. Sie können einige oder alle dieser Parameter in Ihrer eigenen creator-Funktion setzen, was ausgefeilte Mechanismen zur Ausfallsicherung und Lastverteilung ermöglicht.

Wenn Sie beispielsweise pgdb als DB-API-2-Datenbankadapter verwenden, und möchten, dass jede Verbindung Ihrer lokalen Datenbank meinedb 1000 mal wiederverwendet werden soll, sieht die Initialisierung so aus:

import pgdb # importiere das verwendete DB-API-2-Modul
from DBUtils.PersistentDB import PersistentDB
persist = PersistentDB(pgdb, 1000, database='meinedb')

Nachdem Sie den Generator mit diesen Parametern eingerichtet haben, können Sie derartige Datenbankverbindungen von da an wie folgt anfordern:

db = persist.connection()

Sie können diese Verbindungen verwenden, als wären sie gewöhnliche DB-API-2-Datenbankverbindungen. Genauer genommen erhalten Sie die "gehärtete" SteadyDB-Version der zugrunde liegenden DB-API-2-Verbindung.

Wenn Sie eine solche persistente Verbindung mit db.close() schließen, wird dies stillschweigend ignoriert, denn sie würde beim nächsten Zugriff sowieso wieder geöffnet, und das wäre nicht im Sinne persistenter Verbindungen. Stattdessen wird die Verbindung automatisch dann geschlossen, wenn der Thread endet. Sie können dieses Verhalten ändern, indem Sie persist._closeable auf True setzen.

PooledDB

Wenn Sie das PooledDB-Modul einsetzen möchten, müssen Sie zuerst einen Pool für die von Ihnen gewünschte Art von Datenbankverbindungen einrichten, indem Sie eine Instanz der Klasse PooledDB erzeugen, wobei Sie folgende Parameter angeben müssen:

  • creator: entweder eine Funktion, die neue DB-API-2-Verbindungen erzeugt, oder ein DB-API-2-Datenbankadapter-Modul

  • mincached : die anfängliche Anzahl inaktiver Verbindungen, die auf Vorrat gehalten werden sollen (der Standardwert 0 bedeutet, dass beim Start keine Verbindungen geöffnet werden)

  • maxcached: Obergrenze für die Anzahl inaktiver Verbindungen, die auf Vorrat gehalten werden sollen (der Standardwert 0 bedeutet unbegrenzte Größe des Vorratsspeichers)

  • maxshared: Obergrenze für die Anzahl gemeinsam genutzer Verbindungen (der Standardwert 0 bedeutet, dass alle Verbindungen dediziert sind)

    Wenn diese Obergrenze erreicht wird, werden Verbindungen wiederverwendet, wenn diese als wiederverwendbar angefordert werden.

  • maxconnections: Obergrenze für die Anzahl an Datenbankverbindungen, die insgesamt überhaupt erlaubt werden sollen (der Standardwert 0 bedeutet unbegrenzte Anzahl von Datenbankverbindungen)

  • blocking: bestimmt das Verhalten, wenn diese Obergrenze überschritten wird (der Standardwert 0 oder False bedeutet, dass eine Fehlermeldung ausgegeben wird, andernfalls wird blockiert und gewartet, bis die Anzahl an Datenbankverbindungen wieder abnimmt)

  • maxusage: Obergrenze dafür, wie oft eine einzelne Verbindung wiederverwendet werden darf (der Standardwert 0 oder False bedeutet unbegrenzte Wiederverwendung)

    Sobald diese Obergrenze erreicht wird, wird die Verbindung automatisch zurückgesetzt (geschlossen und wieder neu geöffnet).

  • setsession: eine optionale Liste von SQL-Befehlen zur Initialisierung der Datenbanksitzung, z.B. ["set datestyle to german", ...]

  • Die als creator angegebene Funktion oder die Funktion connect des DB-API-2-Datenbankadapter-Moduls erhalten alle weiteren Parameter, wie host, database, user, password usw. Sie können einige oder alle dieser Parameter in Ihrer eigenen creator-Funktion setzen, was ausgefeilte Mechanismen zur Ausfallsicherung und Lastverteilung ermöglicht.

Wenn Sie beispielsweise pgdb als DB-API-2-Datenbankadapter benutzen, und einen Pool von mindestens fünf Datenbankverbindungen zu Ihrer Datenbank meinedb verwenden möchten, dann sieht die Initialisierung so aus:

import pgdb # importiere das verwendete DB-API-2-Modul
from DBUtils.PooledDB import PooledDB
pool = PooledDB(pgdb, 5, database='meinedb')

Nachdem Sie den Pool für Datenbankverbindungen so eingerichtet haben, können Sie Verbindungen daraus wie folgt anfordern:

db = pool.connection()

Sie können diese Verbindungen verwenden, als wären sie gewöhnliche DB-API-2-Datenbankverbindungen. Genauer genommen erhalten Sie die "gehärtete" SteadyDB-Version der zugrunde liegenden DB-API-2-Verbindung.

Bitte beachten Sie, dass die Verbindung von anderen Threads mitgenutzt werden kann, wenn Sie den Parameter maxshared auf einen Wert größer als Null gesetzt haben, und der zugrunde liegende DB-API-2-Datenbankadapter dies erlaubt. Eine dedizierte Datenbankverbindung, die garantiert nicht von anderen Threads mitgenutzt wird, fordern Sie wie folgt an:

db = pool.connection(0)

Wenn Sie die Datenbankverbindung nicht mehr benötigen, sollten Sie diese sofort wieder mit db.close() an den Pool zurückgeben. Sie können auf die gleiche Weise eine neue Verbindung erhalten.

Warnung: In einer Multithread-Umgebung benutzen Sie niemals:

pool.connection().cursor().execute(...)

Dies würde die Datenbankverbindung zu früh zur Wiederverwendung zurückgeben, was fatale Folgen haben könnte, wenn die Verbindungen nicht thread-sicher sind. Stellen Sie sicher, dass die Verbindungsobjekte so lange vorhanden sind, wie sie gebraucht werden, etwa so:

db = pool.connection()
cur = db.cursor()
cur.execute(...)
res = cur.fetchone()
cur.close() # oder del cur
db.close() # oder del db

Benutzung in Webware for Python

Wenn Sie DBUtils verwenden, um von Servlets des Web-Framworks Webware for Python auf eine Datenbank zuzugreifen, dann müssen Sie sicherstellen, dass die Generatoren zur Erzeugung von Datenbankverbindungen nur einmal eingerichtet werden, wenn die Anwendung startet, und nicht jedes Mal, wenn eine Servlet-Instanz erzeugt wird. Den hierfür nötigen Code können Sie bei der Basis-Servlet-Klasse einfügen, dort wo das Modul oder die Klasse initialisiert wird, oder Sie können die Funktion contextInitialize() im __init__.py-Skript Ihres Anwendungskontextes verwenden.

Das zusammen mit DButils ausgelieferte Verzeichnis Examples enthält einen Beispielkontext für Webware for Python, der eine kleine Demo-Datenbank verwendet, um Teilnehmer an einer Seminarreihe zu verwalten (die Idee für dieses Beispiel wurde dem Artikel "The Python DB-API" von Andrew Kuchling entnommen).

Der Beispielkontext kann konfiguriert werden, indem entweder eine Konfig-Datei Configs/Database.config angelegt wird, oder indem die Standard-Parameter direkt im Beispielservlet Examples/DBUtilsExample.py geändert werden. Auf diese Weise können Sie einen passenden Datenbanknutzer und sein Passwort festlegen, sowie den zugrunde liegenden Datenbankadapter auswählen (das klassische PyGreSQL-Modul oder irgendein DB-API-2-Modul). Wenn der Parameter maxcached vorhanden ist, verwendet das Beispielservlet die Pooled-Variante, andernfalls die Persistent-Variante.

Anmerkungen

Wenn Sie einen der bekannten "Object-Relational Mapper" SQLObject oder SQLAlchemy verwenden, dann benötigen Sie DBUtils nicht, denn diese haben ihre eigenen Mechanismen zum Pooling von Datenbankverbindungen eingebaut. Tatsächlich hat SQLObject 2 (SQL-API) das Pooling in eine separate Schicht ausgelagert, in der Code von DBUtils verwendet wird.

Zukunft

Einige Ideen für zukünftige Verbesserungen:

  • Alternativ zur Obergrenze in der Anzahl der Nutzung einer Datenbankverbindung könnte eine maximale Lebensdauer für die Verbindung implementiert werden.
  • Es könnten Module MonitorDB und MonitorPg hinzugefügt werden, die in einem separaten Thread ständig den "idle pool" und eventuell auch den "shared pool" bzw. die persistenten Verbindungen überwachen. Wenn eine unterbrochene Datenbankverbindung entdeckt wird, wird diese automatisch durch den Monitor-Thread wiederhergestellt. Dies ist in einem Szenario sinnvoll, bei dem die Datenbank einer Website jede Nacht neu gestartet wird. Ohne den Monitor-Thread würden die Benutzer morgens eine kleine Verzögerung bemerken, weil erst dann die unterbrochenen Datenbankverbindungen entdeckt würden und sich der Pool langsam wieder neu aufbaut. Mit dem Monitor-Thread würde dies schon während der Nacht passieren, kurz nach der Unterbrechung. Der Monitor-Thread könnte auch so konfiguriert werden, dass er überhaupt täglich den Verbindungspool erneuert, kurz bevor die Benutzer erscheinen.
  • Optional sollten Benutzung, schlechte Verbindungen und Überschreitung von Obergrenzen in Logs gespeichert werden können.

Fehlermeldungen und Feedback

Bitte Senden Sie Fehlermeldungen, Patches und Feedback direkt an den Autor (unter Verwendung der unten angegebenen E-Mail-Adresse).

Probleme, die Webware betreffen, können auch in der Webware for Python mailing list diskutiert werden.

Links

Einige Links zu verwandter und alternativer Software:

Autoren

Autor:Christoph Zwerschke <cito@online.de>
Beiträge:DBUtils benutzt Code, Anmerkungen und Vorschläge von Ian Bicking, Chuck Esterbrook (Webware for Python), Dan Green (DBTools), Jay Love, Michael Palmer, Tom Schwaller, Geoffrey Talvola, Warren Smith (DbConnectionPool) and Ezio Vernacotola.

Copyright und Lizenz

Copyright © 2005-2007 Christoph Zwerschke. Alle Rechte vorbehalten.

DBUtils ist freie und quelloffene Software, lizenziert unter der Open Software License version 2.1.

PK¼hç6Vú•›ÄÄ DBUtils/Docs/RelNotes-0.9.2.html DBUtils 0.9.2 Release Notes

DBUtils 0.9.2 Release Notes

DBUtils 0.9.2 was released on September 22, 2006.

This is the third public release of DBUtils.

Changes:

  • Renamed SolidDB to SteadyDB to avoid confusion with the solidDB storage engine.
  • Accordingly, renamed SolidPg to SteadyPg.
PK7M58”ªî¼’’&DBUtils/Testing/TestSimplePooledPg.pyc;ò õÇFc@s©dZdZdZdZdkZeieeidtZd„Zd„Zd„Zd„Zd„Zd„ZRS(NcCsti|ddƒSdS(NsSimplePooledPgTestDBsSimplePooledPgTestUser(sSimplePooledPgsPooledPgsmaxConnections(sselfsmaxConnections((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledPg.pys my_dbpool.s cCs|ititƒdS(N(sselfs assertEqualsSimplePooledPgs __version__(sself((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledPg.pystest0_check_version2scCsÍ|idƒ}|iƒ}|it|dƒƒ|it|dƒƒ|i|idƒ|it|dƒƒ|i|i dƒ|it|dƒƒ|i|i dƒ|i ƒ|i|idƒdS( Nisquerys num_queriesisdbnamesSimplePooledPgTestDBsusersSimplePooledPgTestUser( sselfs my_dbpoolsdbpools connectionsdbsassert_shasattrs assertEquals num_queriessdbnamesusersquery(sselfsdbsdbpool((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledPg.pystest1_create_connection5s  cCsþ|idƒ}|iƒ}|i|idƒ|iƒ|i|idƒ|iƒ|i t |dƒ ƒ|iƒ}|i t |dƒƒ|i|i dƒ|i t |dƒƒ|i|i dƒ|i|idƒ|iƒ|i|idƒdS( Niis num_queriessdbnamesSimplePooledPgTestDBsusersSimplePooledPgTestUseri( sselfs my_dbpoolsdbpools connectionsdbs assertEquals num_queriessquerysclosesassert_shasattrsdbnamesuser(sselfsdbsdbpool((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledPg.pystest2_close_connectionBs     cCs\|idƒ}|iƒ}xtdƒD]}|iƒq(W|iƒ}|i ||ƒ|i |i |i ƒxtdƒD]}|iƒq{W|i |i dƒ|i |i dƒ|i ƒ|iƒ}|i ||ƒ|i |i |i ƒ|it|dƒƒxtdƒD]}|iƒqW|i |i dƒ|iƒ|i |i dƒdS(Niiisqueryii(sselfs my_dbpoolsdbpools connectionsdb1srangesisquerysdb2sassertNotEquals_cons assertEquals num_queriessclosesassert_shasattr(sselfsisdbpoolsdb1sdb2((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledPg.pystest3_two_connectionsSs0        c sÃ|idƒ‰dkl}l} |dƒ‰‡‡d†}dkl}|d|ƒi ƒ}|d|ƒi ƒ}|d|ƒi ƒ}y(ˆi ddƒ} ˆi ddƒ} Wn1tj o%ˆi dƒ} ˆi dƒ} nX|i| | ƒ|i| i| iƒy|i| ˆi ddƒWn)tj o|i| ˆi d ƒnX| iƒyˆi ddƒ} Wn"tj oˆi dƒ} nX|i| | ƒ|i| i| iƒdS( Ni(sQueuesEmptyicsˆiˆiƒƒdS(N(squeuesputsdbpools connection((squeuesdbpool(sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledPg.pys connectionns(sThreadstargetif0.10000000000000001i(sselfs my_dbpoolsdbpoolsQueuesEmptysqueues connections threadingsThreadsstartsthread1sthread2sthread3sgetsdb1sdb2s TypeErrorsassertNotEquals_cons assertRaisessclosesdb3( sselfsqueuesThreadsdbpoolsQueues connectionsthread3sthread2sthread1sdb1sdb3sdb2sEmpty((squeuesdbpoolsFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledPg.pys test4_threadsjs6   (s__name__s __module__s my_dbpoolstest0_check_versionstest1_create_connectionstest2_close_connectionstest3_two_connectionss test4_threads(((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledPg.pysTestSimplePooledPg,s     s__main__(s__doc__s __version__s __revision__s__date__ssyssmoduless__name__sDBsunittestspathsinsertsDBUtilssSimplePooledPgsTestCasesTestSimplePooledPgsmain(ssyss __revision__sunittestsDBsTestSimplePooledPgs__date__sSimplePooledPgs __version__((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledPg.pys? s   ] PK9M58íJÂ;K)K) DBUtils/Testing/TestPooledPg.pyc;ò õÇFc@sdZdZdZdZdkZdkZeiiddƒdkl Z dk l Z d ei fd „ƒYZ ed joeiƒndS( s:Test the PooledPg module. Note: We don't test performance here, so the test does not predicate whether PooledPg actually will help in improving performance or not. We also assume that the underlying SteadyPg connections are tested. Copyright and credit info: * This test was contributed by Christoph Zwerschke s0.9.4s $Rev: 6696 $s5$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $Nis../..(s TestSteadyPg(sPooledPgs TestPooledPgcBsGtZd„Zd„Zd„Zd„Zd„Zd„Zd„ZRS(NcCs't}dkl}|i||ƒdS(N(s __version__(s __version__sTestPooledPgVersionsDBUtils.PooledPgsPooledPgVersionsselfs assertEqual(sselfsTestPooledPgVersionsPooledPgVersion((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pystest0_CheckVersions c Cs]tdddddtdddƒ}|it|dƒƒ|i|iiƒdƒ|it|dƒƒ|i|i dƒ|it|dƒƒ|i|i tjƒ|ii dƒ}|ii |dƒd kl}|it||ƒƒ|iƒ}|i|iiƒdƒ|it|d ƒƒ|i|i|ƒ|it|d ƒƒ|it|d ƒƒ|i|idƒ|it|dƒƒ|i|i dƒ|it|d ƒƒ|i|itjƒ|it|dƒƒ|i|idƒ|it|dƒƒ|i|idƒ|idƒ|i|idƒtdƒ}|iƒ}|it|dƒƒ|i|itjƒ|it|dƒƒ|i|itjƒ|it|d ƒƒ|i|idƒtddddddfƒ}|i|i dƒ|i|i dfƒ|iƒ}|i|i dƒ|i|idfƒdS(NiisPooledPgTestDBsusersPooledPgTestUsers_caches _maxusages _setsession(sSteadyPgConnections_consquerys num_queriess_setsession_sqlsdbnames select testis set datestyle(sPooledPgsNonespoolsselfsassert_shasattrs assertEquals_cachesqsizes _maxusages _setsessionsgetsdb_consputsDBUtils.SteadyPgsSteadyPgConnections isinstances connectionsdbs_cons num_queriess_setsession_sqlsdbnamesusersquery(sselfsdbspoolsSteadyPgConnectionsdb_con((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pystest1_CreateConnection#sV      c CsËtdddddtdddƒ}|iƒ}|it|dƒƒ|i}dk l }|it ||ƒƒ|it|dƒƒ|i |iiƒdƒ|i |idƒ|id ƒ|i |idƒ|iƒ|it|d ƒ ƒ|iƒ}|it|d ƒƒ|i |idƒ|it|dƒƒ|i |idƒ|i |idƒ|id ƒ|i |id ƒ|iƒ}|i |iiƒdƒ|i |iidƒ|ƒdS( NiisPooledPgTestDBsusersPooledPgTestUsers_con(sSteadyPgConnections_caches select tests num_queriessdbnamei(sPooledPgsNonespools connectionsdbsselfsassert_shasattrs_consdb_consDBUtils.SteadyPgsSteadyPgConnections isinstances assertEquals_cachesqsizes num_queriessquerysclosesdbnamesusersget(sselfsdbspoolsSteadyPgConnectionsdb_con((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pystest2_CloseConnectionPs2        cCs#tdƒ}|it|dƒƒ|i|iiƒdƒg}x't dƒD]}|i |i ƒƒqNW|i|iiƒdƒx$t dƒD]}|i ƒiƒq‘W|i|iiƒdƒx't dƒD]}|i |i ƒƒqÑW|i|iiƒdƒx$t dƒD]}|i ƒiƒqW|i|iiƒdƒtddƒ}|it|dƒƒ|i|iiƒdƒg}x't dƒD]}|i |i ƒƒq˜W|i|iiƒdƒx$t dƒD]}|i ƒiƒqÛW|i|iiƒdƒx't dƒD]}|i |i ƒƒqW|i|iiƒdƒx$t dƒD]}|i ƒiƒq^W|i|iiƒdƒtddƒ}|it|dƒƒ|i|iiƒdƒg}x't dƒD]}|i |i ƒƒqâW|i|iiƒdƒx$t dƒD]}|i ƒiƒq%W|i|iiƒdƒtddƒ}|it|dƒƒ|i|iiƒdƒg}x't dƒD]}|i |i ƒƒq©W|i|iiƒdƒx$t dƒD]}|i ƒiƒqìW|i|iiƒdƒdS( Nis_cacheiiiiii (sPooledPgspoolsselfsassert_shasattrs assertEquals_cachesqsizescachesrangesisappends connectionspopsclose(sselfsiscachespool((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pystest3_MinMaxCachedks€             c ssdkl}tdddƒ‰|iˆiiƒdƒg}x't dƒD]}|i ˆi ƒƒqKW|iˆiiƒdƒ|i |ˆi ƒtddddƒ‰|iˆidƒ|iˆiiƒdƒˆi ƒ}|iˆiiƒdƒ|i |ˆi ƒtdddƒ‰|iˆiiƒdƒg}|i ˆi ƒƒ|iˆiiƒdƒ|i ˆi ƒƒ|iˆiiƒdƒ|i |ˆi ƒtddddƒ‰|iˆiiƒdƒg}x't dƒD]}|i ˆi ƒƒqêW|iˆiiƒdƒ|i |ˆi ƒtddddƒ‰|iˆidƒ|iˆiiƒdƒˆi ƒ}|iˆiiƒdƒ‡d†}dkl}|d|ƒiƒd kl}|d ƒ|iˆiiƒdƒ|ii}|i|gƒ~|d ƒ|iˆiiƒdƒˆi ƒ}|iˆiiƒdƒ|i|d gƒdS( N(sTooManyConnectionsiiiicsˆiƒidƒdS(Ns set thread(spools connectionsquery((spool(s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pys connectionÄs(sThreadstarget(ssleepf0.10000000000000001sthread(sDBUtils.PooledPgsTooManyConnectionssPooledPgspoolsselfs assertEquals_cachesqsizescachesrangesisappends connections assertRaisess _blockingsdbs threadingsThreadsstartstimessleeps_conssession( sselfsThreadsis connectionscachesdbssessionssleepsTooManyConnectionsspool((spools@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pystest4_MaxConnections¡sd            cCs^tdƒ}|iƒ}x!tdƒD]}|idƒq%W|iƒ}|i ||ƒ|i |i |i ƒx!tdƒD]}|idƒq{W|i |i dƒ|i |i dƒ~|iƒ}|i ||ƒ|i |i |i ƒ|i t|dƒƒx!tdƒD]}|idƒqW|i |i dƒ|idƒ|i |i dƒdS(Niis select testisqueryii(sPooledPgspools connectionsdb1srangesisquerysdb2sselfsassertNotEquals_cons assertEquals num_queriessassert_shasattr(sselfsisdb1sdb2spool((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pystest5_OneThreadTwoConnectionsÔs0        c sÌtddddƒ‰dkl}l} |dƒ‰‡‡d†}dkl}x'tdƒD]}|d|ƒi ƒq]Wy(ˆi ddƒ}ˆi ddƒ} Wn1tj o%ˆi dƒ}ˆi dƒ} nX|i} | i}|i|| ƒ|i| |ƒy|i| ˆi ddƒWn)tj o|i| ˆi d ƒnX~yˆi ddƒ}Wn"tj oˆi dƒ}nX|i|| ƒ|i|i| iƒ|i|i| ƒdS( Nii(sQueuesEmptyicsMyˆiˆiƒddƒWn)tj oˆiˆiƒdƒnXdS(Nif0.10000000000000001(squeuesputspools connections TypeError((squeuespool(s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pys connectionïs(sThreadstargetf0.10000000000000001i(sPooledPgspoolsQueuesEmptysqueues connections threadingsThreadsrangesisstartsgetsdb1sdb2s TypeErrors_consdb1_consdb2_consselfsassertNotEquals assertRaisess assertEqual( sselfsqueuesThreadsisdb2_cons connectionsQueuespoolsdb1sdb2sEmptysdb1_con((squeuespools@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pys test6_ThreeThreadsTwoConnectionsës<     ( s__name__s __module__stest0_CheckVersionstest1_CreateConnectionstest2_CloseConnectionstest3_MinMaxCachedstest4_MaxConnectionsstest5_OneThreadTwoConnectionss test6_ThreeThreadsTwoConnections(((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pys TestPooledPgs  -  6 3 s__main__(s__doc__s __version__s __revision__s__date__ssyssunittestspathsinsertsDBUtils.Testings TestSteadyPgsDBUtils.PooledPgsPooledPgsTestCases TestPooledPgs__name__smain(ssyss __revision__s TestSteadyPgsunittests__date__sPooledPgs TestPooledPgs __version__((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pys? s    ó PK¼hç6 XˆDBUtils/Testing/__init__.py# DBUtils Testing PK8M58Ï /Z Z &DBUtils/Testing/TestSimplePooledDB.pyc;ò õÇFc@s±dZdZdZdZdkZeieZdad„Z dfd„ƒYZ dk Z ei i dd ƒd klZd e ifd „ƒYZed joe iƒndS(s~Test the SimplePooledDB module. Note: We don't test performance here, so the test does not predicate whether SimplePooledDB actually will help in improving performance or not. We also do not test any real world DB-API 2 module, we just mock the basic connection functionality of an arbitrary module. Copyright and credit info: * This test was contributed by Christoph Zwerschke s0.9.4s $Rev: 6696 $s5$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $NicCst||ƒSdS(N(s Connectionsdatabasesuser(sdatabasesuser((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledDB.pysconnectss ConnectioncBs#tZd„Zd„Zd„ZRS(NcCs||_||_d|_dS(Ni(sdatabasesselfsusers open_cursors(sselfsdatabasesuser((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledDB.pys__init__!s  cCs d|_dS(Ni(sselfs open_cursors(sself((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledDB.pysclose&scCs|id7_dS(Ni(sselfs open_cursors(sself((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledDB.pyscursor)s(s__name__s __module__s__init__sclosescursor(((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledDB.pys Connections  s../..(sSimplePooledDBsTestSimplePooledDBcBsPtZd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„Z RS( NcCs |atit|ddƒSdS(NsSimplePooledDBTestDBsSimplePooledDBTestUser(smythreadsafetys threadsafetysSimplePooledDBsPooledDBsdbModulesmaxConnections(sselfsmythreadsafetysmaxConnections((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledDB.pys my_dbpool4s cCs|ititƒdS(N(sselfs assertEqualsSimplePooledDBs __version__(sself((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledDB.pystest0_check_version:scCs=x6tdddfD]"}|iti|i|dƒqWdS(Niÿÿÿÿiii(sNones threadsafetysselfs assertRaisessSimplePooledDBsNotSupportedErrors my_dbpool(sselfs threadsafety((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledDB.pystest1_no_threadsafety=s cCsêxãdddfD]Ò}|i|dƒ}|iƒ}|it|dƒƒ|it|dƒƒ|i|i dƒ|it|dƒƒ|i|i dƒ|it|d ƒƒ|i|i d ƒ|i ƒ|i|i dƒqWdS( Niiiscursors open_cursorsisdatabasesSimplePooledDBTestDBsusersSimplePooledDBTestUser( s threadsafetysselfs my_dbpoolsdbpools connectionsdbsassert_shasattrs assertEquals open_cursorssdatabasesuserscursor(sselfsdbsdbpools threadsafety((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledDB.pystest2_create_connectionBs  cCsxdddfD]}|i|dƒ}|iƒ}|i|idƒ|iƒ|i|idƒ|i ƒ|i t |dƒ ƒ|iƒ}|i t |dƒƒ|i|i dƒ|i t |dƒƒ|i|i d ƒ|i|idƒ|iƒ|i|idƒqWdS( Niiiis open_cursorssdatabasesSimplePooledDBTestDBsusersSimplePooledDBTestUser(s threadsafetysselfs my_dbpoolsdbpools connectionsdbs assertEquals open_cursorsscursorsclosesassert_shasattrsdatabasesuser(sselfsdbsdbpools threadsafety((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledDB.pystest3_close_connectionPs"     cCsMxFdddfD]5}|i|dƒ}|iƒ}xtdƒD]}|iƒqAW|iƒ}|i ||ƒxtdƒD]}|iƒq~W|i |i dƒ|i |i dƒ|i ƒ|iƒ}|i ||ƒ|it|dƒƒxtdƒD]}|iƒqW|i |i dƒ|iƒ|i |i dƒqWdS(Niiiiiscursori(s threadsafetysselfs my_dbpoolsdbpools connectionsdb1srangesiscursorsdb2sassertNotEquals assertEquals open_cursorssclosesassert_shasattr(sselfsisdbpoolsdb1sdb2s threadsafety((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledDB.pystest4_two_connectionsbs0        c sÆ|iddƒ‰dkl}l} |dƒ‰‡‡d†}dkl}|d|ƒi ƒ}|d|ƒi ƒ}|d|ƒi ƒ}y(ˆi ddƒ} ˆi ddƒ} Wn1tj o%ˆi dƒ} ˆi dƒ} nX|i| | ƒ|i| i| iƒy|i| ˆi ddƒWn)tj o|i| ˆi d ƒnX| iƒyˆi ddƒ} Wn"tj oˆi dƒ} nX|i| | ƒ|i| i| iƒdS( Nii(sQueuesEmptyicsˆiˆiƒƒdS(N(squeuesputsdbpools connection((squeuesdbpool(sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledDB.pys connection|s(sThreadstargetf0.10000000000000001i(sselfs my_dbpoolsdbpoolsQueuesEmptysqueues connections threadingsThreadsstartsthread1sthread2sthread3sgetsdb1sdb2s TypeErrorsassertNotEquals_cons assertRaisessclosesdb3( sselfsqueuesThreadsdbpoolsQueues connectionsthread3sthread2sthread1sdb1sdb3sdb2sEmpty((squeuesdbpoolsFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledDB.pystest5_threadsafety_1xs6   cCs’x‹ddfD]}}|i|dƒ}|iƒ}|iƒ}x$tdƒD]}|iƒi ƒqJW|i |i dƒ|i |i dƒq WdS(Niiidi2( s threadsafetysselfs my_dbpoolsdbpools connectionsdb1sdb2sxrangesiscursors assertEquals open_cursors(sselfsisdbpoolsdb1sdb2s threadsafety((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledDB.pystest6_threadsafety_2–s    ( s__name__s __module__s my_dbpoolstest0_check_versionstest1_no_threadsafetystest2_create_connectionstest3_close_connectionstest4_two_connectionsstest5_threadsafety_1stest6_threadsafety_2(((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledDB.pysTestSimplePooledDB2s       s__main__(s__doc__s __version__s __revision__s__date__ssyssmoduless__name__sdbModules threadsafetysconnects ConnectionsunittestspathsinsertsDBUtilssSimplePooledDBsTestCasesTestSimplePooledDBsmain( ssyss __revision__sSimplePooledDBsdbModules__date__s Connectionsconnects __version__sunittestsTestSimplePooledDB((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledDB.pys? s     o PK¼hç6ÍùªÇ Ç %DBUtils/Testing/TestSimplePooledPg.py"""Test the SimplePooledPg module. Note: We don't test performance here, so the test does not predicate whether SimplePooledPg actually will help in improving performance or not. Copyright and credit info: * This test was contributed by Christoph Zwerschke """ __version__ = '0.9.4' __revision__ = "$Rev: 6696 $" __date__ = "$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $" import sys # This module also serves as a mock object for the pg API module: sys.modules['pg'] = sys.modules[__name__] class DB: def __init__(self, dbname, user): self.dbname = dbname self.user = user self.num_queries = 0 def close(self): self.num_queries = 0 def query(self): self.num_queries += 1 import unittest sys.path.insert(1, '../..') from DBUtils import SimplePooledPg class TestSimplePooledPg(unittest.TestCase): def my_dbpool(self, maxConnections): return SimplePooledPg.PooledPg(maxConnections, 'SimplePooledPgTestDB', 'SimplePooledPgTestUser') def test0_check_version(self): self.assertEqual(SimplePooledPg.__version__, __version__) def test1_create_connection(self): dbpool = self.my_dbpool(1) db = dbpool.connection() self.assert_(hasattr(db, 'query')) self.assert_(hasattr(db, 'num_queries')) self.assertEqual(db.num_queries, 0) self.assert_(hasattr(db, 'dbname')) self.assertEqual(db.dbname, 'SimplePooledPgTestDB') self.assert_(hasattr(db, 'user')) self.assertEqual(db.user, 'SimplePooledPgTestUser') db.query() self.assertEqual(db.num_queries, 1) def test2_close_connection(self): dbpool = self.my_dbpool(1) db = dbpool.connection() self.assertEqual(db.num_queries, 0) db.query() self.assertEqual(db.num_queries, 1) db.close() self.assert_(not hasattr(db, 'num_queries')) db = dbpool.connection() self.assert_(hasattr(db, 'dbname')) self.assertEqual(db.dbname, 'SimplePooledPgTestDB') self.assert_(hasattr(db, 'user')) self.assertEqual(db.user, 'SimplePooledPgTestUser') self.assertEqual(db.num_queries, 1) db.query() self.assertEqual(db.num_queries, 2) def test3_two_connections(self): dbpool = self.my_dbpool(2) db1 = dbpool.connection() for i in range(5): db1.query() db2 = dbpool.connection() self.assertNotEqual(db1, db2) self.assertNotEqual(db1._con, db2._con) for i in range(7): db2.query() self.assertEqual(db1.num_queries, 5) self.assertEqual(db2.num_queries, 7) db1.close() db1 = dbpool.connection() self.assertNotEqual(db1, db2) self.assertNotEqual(db1._con, db2._con) self.assert_(hasattr(db1, 'query')) for i in range(3): db1.query() self.assertEqual(db1.num_queries, 8) db2.query() self.assertEqual(db2.num_queries, 8) def test4_threads(self): dbpool = self.my_dbpool(2) from Queue import Queue, Empty queue = Queue(3) def connection(): queue.put(dbpool.connection()) from threading import Thread thread1 = Thread(target=connection).start() thread2 = Thread(target=connection).start() thread3 = Thread(target=connection).start() try: db1 = queue.get(1, 1) db2 = queue.get(1, 1) except TypeError: db1 = queue.get(1) db2 = queue.get(1) self.assertNotEqual(db1, db2) self.assertNotEqual(db1._con, db2._con) try: self.assertRaises(Empty, queue.get, 1, 0.1) except TypeError: self.assertRaises(Empty, queue.get, 0) db2.close() try: db3 = queue.get(1, 1) except TypeError: db3 = queue.get(1) self.assertNotEqual(db1, db3) self.assertNotEqual(db1._con, db3._con) if __name__ == '__main__': unittest.main() PK¼hç6^ž¤À ( (DBUtils/Testing/TestSteadyPg.py"""Test the SteadyPg module. Note: We do not test the real PyGreSQL module, but we just mock the basic connection functionality of that module. We assume that the PyGreSQL module will detect lost connections correctly and set the status flag accordingly. Copyright and credit info: * This test was contributed by Christoph Zwerschke """ __version__ = '0.9.4' __revision__ = "$Rev: 6696 $" __date__ = "$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $" import sys # This module also serves as a mock object for the pg API module: sys.modules['pg'] = sys.modules[__name__] class Error(StandardError): pass class DatabaseError(Error): pass class InternalError(DatabaseError): pass class ProgrammingError(DatabaseError): pass def connect(*args, **kwargs): return pgConnection(*args, **kwargs) class pgConnection: """The underlying pg API connection class.""" def __init__(self, dbname=None, user=None): self.db = dbname self.user = user self.num_queries = 0 self.session = [] if dbname == 'error': self.status = 0 self.valid = 0 raise InternalError self.status = 1 self.valid = 1 def close(self): if not self.valid: raise InternalError self.num_queries = 0 self.session = [] self.status = 0 self.valid = 0 def reset(self): self.num_queries = 0 self.session = [] self.status = 1 self.valid = 1 def query(self, qstr): if not self.valid: raise InternalError if qstr.startswith('select '): self.num_queries += 1 return qstr[7:] elif qstr.startswith('set '): self.session.append(qstr[4:]) return None else: raise ProgrammingError class DB: """Wrapper class for the pg API connection class.""" def __init__(self, *args, **kw): self.db = connect(*args, **kw) self.dbname = self.db.db self.__args = args, kw def __getattr__(self, name): if self.db: return getattr(self.db, name) else: raise InternalError def close(self): if self.db: self.db.close() self.db = None else: raise InternalError def reopen(self): if self.db: self.close() try: self.db = connect(*self.__args[0], **self.__args[1]) except Exception: self.db = None raise def query(self, qstr): if not self.db: raise InternalError return self.db.query(qstr) def get_tables(self): if not self.db: raise InternalError return 'test' import unittest sys.path.insert(1, '../..') from DBUtils.SteadyPg import SteadyPgConnection class TestSteadyPg(unittest.TestCase): def test0_CheckVersion(self): TestSteadyPgVersion = __version__ from DBUtils.SteadyPg import __version__ as SteadyPgVersion self.assertEqual(SteadyPgVersion, TestSteadyPgVersion) def test1_MockedPgConnection(self): PgConnection = DB db = PgConnection('SteadyPgTestDB', user='SteadyPgTestUser') self.assert_(hasattr(db, 'db')) self.assert_(hasattr(db.db, 'status')) self.assert_(db.db.status) self.assert_(hasattr(db.db, 'query')) self.assert_(hasattr(db.db, 'close')) self.assert_(not hasattr(db.db, 'reopen')) self.assert_(hasattr(db, 'reset')) self.assert_(hasattr(db.db, 'num_queries')) self.assert_(hasattr(db.db, 'session')) self.assert_(not hasattr(db.db, 'get_tables')) self.assert_(hasattr(db.db, 'db')) self.assertEqual(db.db.db, 'SteadyPgTestDB') self.assert_(hasattr(db.db, 'user')) self.assertEqual(db.db.user, 'SteadyPgTestUser') self.assert_(hasattr(db, 'query')) self.assert_(hasattr(db, 'close')) self.assert_(hasattr(db, 'reopen')) self.assert_(hasattr(db, 'reset')) self.assert_(hasattr(db, 'num_queries')) self.assert_(hasattr(db, 'session')) self.assert_(hasattr(db, 'get_tables')) self.assert_(hasattr(db, 'dbname')) self.assertEqual(db.dbname, 'SteadyPgTestDB') self.assert_(hasattr(db, 'user')) self.assertEqual(db.user, 'SteadyPgTestUser') for i in range(3): self.assertEqual(db.num_queries, i) self.assertEqual(db.query('select test%d' % i), 'test%d' % i) self.assert_(db.db.status) db.reopen() self.assert_(db.db.status) self.assertEqual(db.num_queries, 0) self.assertEqual(db.query('select test4'), 'test4') self.assertEqual(db.get_tables(), 'test') db.close() try: status = db.db.status except AttributeError: status = 0 self.assert_(not status) self.assertRaises(InternalError, db.close) self.assertRaises(InternalError, db.query, 'select test') self.assertRaises(InternalError, db.get_tables) def test2_BrokenPgConnection(self): db = SteadyPgConnection(dbname='ok') InternalError = sys.modules[db._con.__module__].InternalError for i in range(3): db.close() del db self.assertRaises(InternalError, SteadyPgConnection, dbname='error') def test3_SteadyPgClose(self): for closeable in (0, 1): db = SteadyPgConnection() db._closeable = closeable self.assert_(db._con.db and db._con.valid) db.close() self.assert_(closeable ^ (db._con.db is not None and db._con.valid)) db.close() self.assert_(closeable ^ (db._con.db is not None and db._con.valid)) db._close() self.assert_(not db._con.db or not db._con.valid) db._close() self.assert_(not db._con.db or not db._con.valid) def test4_SteadyPgConnection(self): db = SteadyPgConnection(0, None, 'SteadyPgTestDB', user='SteadyPgTestUser') self.assert_(hasattr(db, 'db')) self.assert_(hasattr(db, '_con')) self.assertEqual(db.db, db._con.db) self.assert_(hasattr(db, '_usage')) self.assertEqual(db._usage, 0) self.assert_(hasattr(db.db, 'status')) self.assert_(db.db.status) self.assert_(hasattr(db.db, 'query')) self.assert_(hasattr(db.db, 'close')) self.assert_(not hasattr(db.db, 'reopen')) self.assert_(hasattr(db.db, 'reset')) self.assert_(hasattr(db.db, 'num_queries')) self.assert_(hasattr(db.db, 'session')) self.assert_(hasattr(db.db, 'db')) self.assertEqual(db.db.db, 'SteadyPgTestDB') self.assert_(hasattr(db.db, 'user')) self.assertEqual(db.db.user, 'SteadyPgTestUser') self.assert_(not hasattr(db.db, 'get_tables')) self.assert_(hasattr(db, 'query')) self.assert_(hasattr(db, 'close')) self.assert_(hasattr(db, 'reopen')) self.assert_(hasattr(db, 'reset')) self.assert_(hasattr(db, 'num_queries')) self.assert_(hasattr(db, 'session')) self.assert_(hasattr(db, 'dbname')) self.assertEqual(db.dbname, 'SteadyPgTestDB') self.assert_(hasattr(db, 'user')) self.assertEqual(db.user, 'SteadyPgTestUser') self.assert_(hasattr(db, 'get_tables')) for i in range(3): self.assertEqual(db._usage, i) self.assertEqual(db.num_queries, i) self.assertEqual(db.query('select test%d' % i), 'test%d' % i) self.assert_(db.db.status) self.assertEqual(db.get_tables(), 'test') self.assert_(db.db.status) self.assertEqual(db._usage, 4) self.assertEqual(db.num_queries, 3) db.reopen() self.assert_(db.db.status) self.assertEqual(db._usage, 0) self.assertEqual(db.num_queries, 0) self.assertEqual(db.query('select test'), 'test') self.assert_(db.db.status) self.assert_(hasattr(db._con, 'status')) self.assert_(db._con.status) self.assert_(hasattr(db._con, 'close')) self.assert_(hasattr(db._con, 'query')) db.close() try: status = db.db.status except AttributeError: status = 0 self.assert_(not status) self.assert_(hasattr(db._con, 'close')) self.assert_(hasattr(db._con, 'query')) InternalError = sys.modules[db._con.__module__].InternalError self.assertRaises(InternalError, db._con.close) self.assertRaises(InternalError, db._con.query, 'select test') self.assertEqual(db.query('select test'), 'test') self.assert_(db.db.status) self.assertEqual(db._usage, 1) self.assertEqual(db.num_queries, 1) db.db.status = 0 self.assert_(not db.db.status) self.assertEqual(db.query('select test'), 'test') self.assert_(db.db.status) self.assertEqual(db._usage, 1) self.assertEqual(db.num_queries, 1) db.db.status = 0 self.assert_(not db.db.status) self.assertEqual(db.get_tables(), 'test') self.assert_(db.db.status) self.assertEqual(db._usage, 1) self.assertEqual(db.num_queries, 0) def test5_SteadyPgConnectionMaxUsage(self): db = SteadyPgConnection(10) for i in range(100): r = db.query('select test%d' % i) self.assertEqual(r, 'test%d' % i) self.assert_(db.db.status) j = i % 10 + 1 self.assertEqual(db._usage, j) self.assertEqual(db.num_queries, j) for i in range(100): r = db.get_tables() self.assertEqual(r, 'test') self.assert_(db.db.status) j = i % 10 + 1 self.assertEqual(db._usage, j) self.assertEqual(db.num_queries, 0) for i in range(10): if i == 7: db.db.status = 0 r = db.query('select test%d' % i) self.assertEqual(r, 'test%d' % i) j = i % 7 + 1 self.assertEqual(db._usage, j) self.assertEqual(db.num_queries, j) for i in range(10): if i == 5: db.db.status = 0 r = db.get_tables() self.assertEqual(r, 'test') j = (i + (i < 5 and 3 or -5)) % 10 + 1 self.assertEqual(db._usage, j) j = i < 5 and 3 or 0 self.assertEqual(db.num_queries, j) db.close() self.assertEqual(db.query('select test1'), 'test1') self.assertEqual(db._usage, 1) self.assertEqual(db.num_queries, 1) db.reopen() self.assertEqual(db._usage, 0) self.assertEqual(db.num_queries, 0) self.assertEqual(db.query('select test2'), 'test2') self.assertEqual(db._usage, 1) self.assertEqual(db.num_queries, 1) def test6_SteadyPgConnectionSetSession(self): db = SteadyPgConnection(3, ('set time zone', 'set datestyle')) self.assert_(hasattr(db, 'num_queries')) self.assertEqual(db.num_queries, 0) self.assert_(hasattr(db, 'session')) self.assertEqual(tuple(db.session), ('time zone', 'datestyle')) for i in range(11): db.query('select test') self.assertEqual(db.num_queries, 2) self.assertEqual(db.session, ['time zone', 'datestyle']) db.query('set test') self.assertEqual(db.num_queries, 2) self.assertEqual(db.session, ['time zone', 'datestyle', 'test']) db.query('select test') self.assertEqual(db.num_queries, 1) self.assertEqual(db.session, ['time zone', 'datestyle']) db.close() db.query('set test') self.assertEqual(db.num_queries, 0) self.assertEqual(db.session, ['time zone', 'datestyle', 'test']) if __name__ == '__main__': unittest.main() PK8M58JÈ…âGG DBUtils/Testing/TestSteadyDB.pyc;ò õÇFc@s8dZdZdZdZdkZeieZdZde fd„ƒYZ de fd „ƒYZ d e fd „ƒYZ d e fd „ƒYZ de fd„ƒYZeed„Zdfd„ƒYZdfd„ƒYZdkZeiiddƒdklZdeifd„ƒYZedjoeiƒndS(sÙTest the SteadyDB module. Note: We do not test any real DB-API 2 module, but we just mock the basic DB-API 2 connection functionality. Copyright and credit info: * This test was contributed by Christoph Zwerschke s0.9.4s $Rev: 6696 $s5$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $NisErrorcBstZRS(N(s__name__s __module__(((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysErrorss DatabaseErrorcBstZRS(N(s__name__s __module__(((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys DatabaseErrorssOperationalErrorcBstZRS(N(s__name__s __module__(((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysOperationalErrorss InternalErrorcBstZRS(N(s__name__s __module__(((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys InternalErrorssProgrammingErrorcBstZRS(N(s__name__s __module__(((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysProgrammingErrorscCst||ƒSdS(N(s Connectionsdatabasesuser(sdatabasesuser((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysconnect ss ConnectioncBs>tZeed„Zd„Zd„Zd„Zed„ZRS(NcCsc||_||_d|_d|_d|_g|_|djod|_t‚nd|_dS(Niserrori( sdatabasesselfsusers open_cursorssnum_usess num_queriesssessionsvalidsOperationalError(sselfsdatabasesuser((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys__init__%s         cCsF|i o t‚nd|_d|_d|_g|_d|_dS(Ni(sselfsvalids InternalErrors open_cursorssnum_usess num_queriesssession(sself((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysclose1s      cCs|iidƒdS(Nscommit(sselfssessionsappend(sself((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pyscommit:scCs|iidƒdS(Nsrollback(sselfssessionsappend(sself((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysrollback=scCs&|i o t‚nt||ƒSdS(N(sselfsvalids InternalErrorsCursorsname(sselfsname((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pyscursor@s  (s__name__s __module__sNones__init__sclosescommitsrollbackscursor(((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys Connection#s   sCursorcBsAtZed„Zd„Zd„Zd„Zd„Zd„ZRS(NcCsN||_t|_|djod|_t‚n|id7_d|_dS(Nserrorii(sconsselfsNonesresultsnamesvalidsOperationalErrors open_cursors(sselfsconsname((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys__init__Gs     cCs4|i o t‚n|iid8_d|_dS(Nii(sselfsvalids InternalErrorscons open_cursors(sself((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysclosePs  cCs¦|i p |ii o t‚n|iid7_|idƒo#|iid7_|d|_n;|idƒo$|ii i |dƒt |_nt ‚dS(Nisselect isset i( sselfsvalidscons InternalErrorsnum_usess operations startswiths num_queriessresultssessionsappendsNonesProgrammingError(sselfs operation((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysexecuteVs  cCs/|i o t‚n|i}t|_|SdS(N(sselfsvalids InternalErrorsresultsNone(sselfsresult((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysfetchonecs     cCs9|i p |ii o t‚n|iid7_dS(Ni(sselfsvalidscons InternalErrorsnum_uses(sselfsprocname((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pyscallprocjs cCs|io|iƒndS(N(sselfsvalidsclose(sself((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys__del__os ( s__name__s __module__sNones__init__sclosesexecutesfetchonescallprocs__del__(((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysCursorEs    is../..(sconnects TestSteadyDBcBsPtZd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„Z RS( NcCs't}dkl}|i||ƒdS(N(s __version__(s __version__sTestSteadyDBVersionsDBUtils.SteadyDBsSteadyDBVersionsselfs assertEqual(sselfsSteadyDBVersionsTestSteadyDBVersion((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pystest0_CheckVersion{s cCstdddƒ}|it|dƒƒ|i|idƒ|it|dƒƒ|i|idƒ|it|dƒƒ|it|dƒƒ|it|dƒƒ|it|dƒƒ|it|d ƒƒ|it|d ƒƒ|it|d ƒƒ|i|iƒ|i|i d ƒxPt d ƒD]B}|i ƒ}|i|i dƒ|i ƒ|i|i d ƒq.Wg}x>t d ƒD]0}|i|i ƒƒ|i|i |dƒq‡W~|i|i d ƒ|i ƒ}|it|dƒƒ|it|dƒƒ|it|dƒƒ|it|dƒƒ|it|d ƒƒ|i|iƒ|i|i dƒxet d ƒD]W}|i|i|ƒ|i|i|ƒ|id|ƒ|i|iƒd|ƒq{W|i|iƒ|i|i dƒx!t dƒD]}|idƒqW|i ƒ|i|i ƒ|i|i d ƒ|i|idƒ|i|id ƒ|it|i ƒ|it|idƒ|i|iƒ|i ƒ|i|i ƒ|i|id ƒ|i|id ƒ|it|i ƒ|it|i ƒdS(NsSteadyDBTestDBsusersSteadyDBTestUsersdatabasescursorscloses open_cursorssnum_usess num_queriesssessionsvalidiiisexecutesfetchonescallprocs select test%dstest%distestis select test(sconnectsdbsselfsassert_shasattrs assertEqualsdatabasesusersvalids open_cursorssrangesiscursorsclosesappendsnum_usess num_queriessexecutesfetchonescallprocs assertRaisess InternalError(sselfsisdbscursor((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pystest1_MockedDBConnection€sz          cCsØttddƒ}xtdƒD]}|iƒqW~|itttddƒttddƒ}|i ƒ}xtdƒD]}|iƒqzW|i dƒ}xtdƒD]}|iƒqªW|it|i dƒdS(Nsdatabasesokiserror( sSteadyDBconnectsdbapisdbsrangesisclosesselfs assertRaisessOperationalErrorscursor(sselfsisdbscursor((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pystest2_BrokenDBConnection»s"      cCsÁxºddfD]¬}ttƒ}||_|i|iiƒ|i ƒ|i||iiAƒ|i ƒ|i||iiAƒ|i ƒ|i|ii ƒ|i ƒ|i|ii ƒq WdS(Nii( s closeablesSteadyDBconnectsdbapisdbs _closeablesselfsassert_s_consvalidscloses_close(sselfsdbs closeable((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pystest3_SteadyDBCloseËs       cCsHttdtdddƒ}|it|dƒƒ|it|dƒƒ|i|idƒ|it|i dƒƒ|i|i i ƒ|it|i dƒƒ|it|i d ƒƒ|it|i d ƒƒ|it|i d ƒƒ|it|i d ƒƒ|it|i d ƒƒ|it|i dƒƒ|i|i i dƒ|it|i dƒƒ|i|i i dƒ|it|dƒƒ|it|d ƒƒ|i|i i dƒxVtdƒD]H}|iƒ}|i|i i dƒ|iƒ|i|i i dƒqÉWg}xAtdƒD]3}|i|iƒƒ|i|i i |dƒq(W~|i|i i dƒ|iƒ}|it|dƒƒ|it|dƒƒ|it|dƒƒ|it|d ƒƒ|it|dƒƒ|i|i ƒ|i|i i dƒx~tdƒD]p}|i|i|ƒ|i|i i|ƒ|i|i i|ƒ|id|ƒ|i|iƒd|ƒq%W|i|i ƒ|i|i i dƒx!tdƒD]}|idƒqÌW|iƒ|i|i ƒ|i|i i dƒ|i|idƒ|i|i idƒ|i|i idƒ|iƒ|idƒ|i|i ƒ|i|i i dƒ|i|iƒdƒ|i|idƒ|i|i idƒ|i|i idƒ|i|i i ƒ|iƒ|i|i i ƒ|i|i i dƒ|i|idƒ|i|i idƒ|i|i idƒ|it|i iƒ|iƒ|it|i iƒ|iƒ}|i|i i ƒ|idƒ|i|iƒdƒ|idƒ|i|iƒdƒ|idƒ|i|idƒ|i|i idƒ|i|i id ƒ|iƒ}|i|i i d ƒ|id!ƒ|i|iƒd"ƒ|i|i idƒ|iƒ|i|i i dƒ|i|i idƒ|iƒ}|i|i ƒ|idƒd|i_ |i|i ƒ|it|iidƒ|idƒ|i|i ƒ|iidƒ|i|id ƒ|i|i idƒd|i _ |i_ |idƒ|i|i ƒ|i|idƒ|i|i idƒ|id#ƒ|iƒ|id$ƒ|iƒ|i|i id%d&d'd(gƒdS()NisSteadyDBTestDBsusersSteadyDBTestUsers_cons_usagesvalidscursorscloses open_cursorssnum_usess num_queriesssessionsdatabaseiisexecutesfetchonescallprocs select test%dstest%distestis select test8stest8is select test11stest11s select test12stest12is select test13stest13sset doitsset dontsdoitscommitsdontsrollback(sSteadyDBconnectsdbapisNonesdbsselfsassert_shasattrs assertEquals_usages_consvalidsdatabasesusers open_cursorssrangesiscursorsclosesappendsnum_usess num_queriessexecutesfetchonescallprocs assertRaisess InternalErrorscursor2s_cursorscommitsrollbackssession(sselfsisdbscursorscursor2((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pystest4_SteadyDBConnectionÙsê                             cCsÈttdtdddƒ}ttdtdddƒ}|i|iƒ|iƒƒ|i|iƒ|iƒƒ|i|i |i ƒ|i|i |i ƒ|i|i |i ƒ|i ƒ|i ƒdS(NisSteadyDBTestDBsusersSteadyDBTestUser( sSteadyDBconnectsdbapisNonesdb1sconnectsdb2sselfs assertEquals threadsafetys_creators_argss_kwargssclose(sselfsdb1sdb2((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys'test5_SteadyDBConnectionCreatorFunctionLs   cCsSttdƒ}|iƒ}x¥tdƒD]—}|id|ƒ|iƒ}|i |d|ƒ|i |i i ƒ|dd}|i |i|ƒ|i |i i|ƒ|i |i i|ƒq(W|i |i idƒxtdƒD]s}|idƒ|i |i i ƒ|dd}|i |i|ƒ|i |i i|ƒ|i |i idƒqæWx¹tdƒD]«}|djod|i _ |i_ n|id|ƒ|iƒ}|i |d|ƒ|dd}|i |i|ƒ|i |i i|ƒ|i |i i|ƒqjWxÇtdƒD]¹}|d jod|i _ |i_ n|idƒ||d jod pd dd}|i |i|ƒ|i |i i|ƒ|d jod pd}|i |i i|ƒq&W|iƒ|id ƒ|i |iƒd ƒ|i |idƒ|i |i idƒ|i |i idƒdS(Ni ids select test%dstest%distestiiiiiûÿÿÿs select test1stest1(sSteadyDBconnectsdbapisdbscursorsrangesisexecutesfetchonesrsselfs assertEqualsassert_s_consvalidsjs_usagesnum_usess num_queriess open_cursorsscallprocs_cursorsclose(sselfsisjsdbscursorsr((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys test6_SteadyDBConnectionMaxUsageYs`           &  cCsàttdddfƒ}|it|dƒƒ|i|idƒ|it|idƒƒ|i|ii dƒ|it|idƒƒ|i|ii dƒ|it|id ƒƒ|i|ii dƒ|it|id ƒƒ|it |ii ƒd d fƒx'td ƒD]}|iƒidƒqW|i|ii dƒ|i|idƒ|i|ii dƒ|i|ii dƒ|i|ii d d gƒ|iƒidƒ|i|ii dƒ|i|idƒ|i|ii dƒ|i|ii dƒ|i|ii d d dgƒ|iƒidƒ|i|ii dƒ|i|idƒ|i|ii dƒ|i|ii dƒ|i|ii d d gƒ|iƒidƒ|i|ii dƒ|i|idƒ|i|ii dƒ|i|ii dƒ|i|ii d d dgƒ|iƒidƒ|i|ii dƒ|i|idƒ|i|ii dƒ|i|ii dƒ|i|ii d d dgƒ|iƒ|iƒidƒ|i|ii dƒ|i|idƒ|i|ii dƒ|i|ii dƒ|i|ii d d dgƒ|iƒ|iƒidƒ|i|ii dƒ|i|idƒ|i|ii dƒ|i|ii dƒ|i|ii d d gƒdS(Nis set time zones set datestyles_usageis open_cursorssnum_usesis num_queriesssessions time zones datestylei s select testisset testistesti(sSteadyDBconnectsdbapisdbsselfsassert_shasattrs assertEquals_usages_cons open_cursorssnum_usess num_queriesstuplessessionsrangesiscursorsexecutesclose(sselfsisdb((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys"test7_SteadyDBConnectionSetSession‡sr"   ( s__name__s __module__stest0_CheckVersionstest1_MockedDBConnectionstest2_BrokenDBConnectionstest3_SteadyDBClosestest4_SteadyDBConnections'test5_SteadyDBConnectionCreatorFunctions test6_SteadyDBConnectionMaxUsages"test7_SteadyDBConnectionSetSession(((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys TestSteadyDBys  ;   s .s__main__(s__doc__s __version__s __revision__s__date__ssyssmoduless__name__sdbapis threadsafetys StandardErrorsErrors DatabaseErrorsOperationalErrors InternalErrorsProgrammingErrorsNonesconnects ConnectionsCursorsunittestspathsinsertsDBUtils.SteadyDBsSteadyDBconnectsTestCases TestSteadyDBsmain(sProgrammingErrorssyss __revision__s TestSteadyDBsconnects InternalErrors__date__sSteadyDBconnects Connections DatabaseErrorsOperationalErrorsErrors __version__sCursorsunittests threadsafetysdbapi((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys? s*  "/  ÿJ PKBM58¬ BÓôô$DBUtils/Testing/TestPersistentPg.pyo;ò õÇFc@sdZdZdZdZdkZdkZeiiddƒdkl Z dk l Z d ei fd „ƒYZ ed joeiƒndS( sBTest the PersistentPg module. Note: We don't test performance here, so the test does not predicate whether PersistentPg actually will help in improving performance or not. We also assume that the underlying SteadyPg connections are tested. Copyright and credit info: * This test was contributed by Christoph Zwerschke s0.9.4s $Rev: 6696 $s5$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $Nis../..(s TestSteadyPg(s PersistentPgsTestPersistentPgcBs5tZd„Zd„Zd„Zd„Zd„ZRS(NcCs't}dkl}|i||ƒdS(N(s __version__(s __version__sTestPersistentPgVersionsDBUtils.PersistentPgsPersistentPgVersionsselfs assertEqual(sselfsPersistentPgVersionsTestPersistentPgVersion((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentPg.pystest0_CheckVersions cCsxddfD]}tƒ}||_|iƒ}|i|iio |ii ƒ|i ƒ|i||iit j o |ii Aƒ|i ƒ|i||iit j o |ii Aƒ|i ƒ|i|ii p |ii ƒ|i ƒ|i|ii p |ii ƒq WdS(Nii( s closeables PersistentPgspersists _closeables connectionsdbsselfsassert_s_consvalidsclosesNones_close(sselfsdbspersists closeable((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentPg.pystest1_PersistentPgClose#s      * * " c s’d}tƒ‰dkl}l‰ggf\‰‰x:t|ƒD],}ˆi |dƒƒˆi |dƒƒqAW‡‡‡‡d†}dk l }g} xCt|ƒD]5}|d|d|fƒ}| i |ƒ|iƒq¦WxYt|ƒD]K}yˆ|iddd ƒWqìtj oˆ|iddƒqìXqìWx‚t|ƒD]t}yˆ|idd ƒ} Wn&tj oˆ|idƒ} nX|i| d |ƒ|i| |iƒƒqHWxÆt|ƒD]¸}x¯t|dƒD]}y5ˆ|id |dd ƒˆ|idd ƒ} Wn>tj o2ˆ|id |dƒˆ|idƒ} nX|i| d ||d|fƒqäWqÍWy1ˆdid dd ƒˆdidd ƒ} Wn:tj o.ˆdid dƒˆdidƒ} nX|i| dƒy1ˆdiddd ƒˆdidd ƒ} Wn:tj o.ˆdiddƒˆdidƒ} nX|i| dƒx¨tdƒD]š}y5ˆdid |dd ƒˆdidd ƒ} Wn>tj o2ˆdid |dƒˆdidƒ} nX|i| d|d|fƒq’Wxpt|ƒD]b}|i| |iƒƒyˆ|iddd ƒWq=tj oˆ|iddƒq=Xq=WxŒt|ƒD]~}yˆ|idd ƒ} Wn&tj oˆ|idƒ} nX|i| d||dfƒ|i| |iƒƒq°WxYt|ƒD]K}yˆ|itddƒWq?tj oˆ|itdƒq?Xq?WdS(Ni(sQueuesEmptyicsgˆiƒi}xGno?yGyˆ|iddƒ}Wn&tj oˆ|idƒ}nXWnˆj o t }nX| oPnˆiƒ}|i|jo d}nK|djo d}n4|djo|ii ƒd}n|i |ƒ}d||i|f}yˆ|i|ddƒWqtj oˆ|i|dƒqXqW|i ƒdS( Niserror - not persistentspingsok - thread alivesclosesok - connection closeds %d(%d): %sf0.10000000000000001(spersists connectionsdbsthis_dbs queryQueuesisgetsqs TypeErrorsEmptysNonesrsclosesquerys_usages resultQueuesput(sisdbsqsthis_dbsr(s resultQueues queryQueuespersistsEmpty(sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentPg.pys runQueries<s6        (sThreadstargetsargsspingf0.10000000000000001s%d(0): ok - thread alives select test%ds%d(%d): test%ds select test4s 1(3): test4scloses1(3): ok - connection closedis 1(%d): test%ds%d(%d): ok - thread alive(s numThreadss PersistentPgspersistsQueuesEmptys queryQueues resultQueuesrangesisappends runQueriess threadingsThreadsthreadssthreadsstartsputs TypeErrorsgetsrsselfs assertEqualsassert_sisAlivesjsNone(sselfs runQueriessthreadsThreadsis numThreadss resultQueuesjsQueues queryQueuesthreadsspersistsrsEmpty((s resultQueues queryQueuespersistsEmptysDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentPg.pystest2_PersistentPgThreads4sª        ) "   cCs´tdƒ}|iƒ}|i|idƒx‚tdƒD]t}|i d|ƒ}|i|d|ƒ|i |ii ƒ|dd}|i|i|ƒ|i|i|ƒq8WdS(Niids select test%dstest%di(s PersistentPgspersists connectionsdbsselfs assertEquals _maxusagesrangesisquerysrsassert_sstatussjs_usages num_queries(sselfsisjsdbsrspersist((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentPg.pystest3_PersistentPgMaxUsages   cCsÊtddfƒ}|iƒ}|i|idƒ|i|idfƒ|i|iidgƒ|i dƒx=t dƒD]/}|i|iiddgƒ|i dƒqzW|i|iidgƒdS(Nis set datestyles datestylesset teststests select test( s PersistentPgspersists connectionsdbsselfs assertEquals _maxusages_setsession_sqlssessionsquerysrangesi(sselfsisdbspersist((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentPg.pystest4_PersistentPgSetSession©s   (s__name__s __module__stest0_CheckVersionstest1_PersistentPgClosestest2_PersistentPgThreadsstest3_PersistentPgMaxUsagestest4_PersistentPgSetSession(((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentPg.pysTestPersistentPgs    i s__main__(s__doc__s __version__s __revision__s__date__ssyssunittestspathsinsertsDBUtils.Testings TestSteadyPgsDBUtils.PersistentPgs PersistentPgsTestCasesTestPersistentPgs__name__smain(ssyss __revision__s PersistentPgs TestSteadyPgsunittests__date__sTestPersistentPgs __version__((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentPg.pys? s    š PK¼hç6=&ƒýSS#DBUtils/Testing/TestPersistentPg.py"""Test the PersistentPg module. Note: We don't test performance here, so the test does not predicate whether PersistentPg actually will help in improving performance or not. We also assume that the underlying SteadyPg connections are tested. Copyright and credit info: * This test was contributed by Christoph Zwerschke """ __version__ = '0.9.4' __revision__ = "$Rev: 6696 $" __date__ = "$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $" import sys import unittest sys.path.insert(1, '../..') # The TestSteadyPg module serves as a mock object for the pg API module: from DBUtils.Testing import TestSteadyPg from DBUtils.PersistentPg import PersistentPg class TestPersistentPg(unittest.TestCase): def test0_CheckVersion(self): TestPersistentPgVersion = __version__ from DBUtils.PersistentPg import __version__ as PersistentPgVersion self.assertEqual(PersistentPgVersion, TestPersistentPgVersion) def test1_PersistentPgClose(self): for closeable in (0, 1): persist = PersistentPg() persist._closeable = closeable db = persist.connection() self.assert_(db._con.db and db._con.valid) db.close() self.assert_(closeable ^ (db._con.db is not None and db._con.valid)) db.close() self.assert_(closeable ^ (db._con.db is not None and db._con.valid)) db._close() self.assert_(not db._con.db or not db._con.valid) db._close() self.assert_(not db._con.db or not db._con.valid) def test2_PersistentPgThreads(self): numThreads = 3 persist = PersistentPg() from Queue import Queue, Empty queryQueue, resultQueue = [], [] for i in range(numThreads): queryQueue.append(Queue(1)) resultQueue.append(Queue(1)) def runQueries(i): this_db = persist.connection().db while 1: try: try: q = queryQueue[i].get(1, 1) except TypeError: q = queryQueue[i].get(1) except Empty: q = None if not q: break db = persist.connection() if db.db != this_db: r = 'error - not persistent' else: if q == 'ping': r = 'ok - thread alive' elif q == 'close': db.db.close() r = 'ok - connection closed' else: r = db.query(q) r = '%d(%d): %s' % (i, db._usage, r) try: resultQueue[i].put(r, 1, 0.1) except TypeError: resultQueue[i].put(r, 1) db.close() from threading import Thread threads = [] for i in range(numThreads): thread = Thread(target=runQueries, args=(i,)) threads.append(thread) thread.start() for i in range(numThreads): try: queryQueue[i].put('ping', 1, 0.1) except TypeError: queryQueue[i].put('ping', 1) for i in range(numThreads): try: r = resultQueue[i].get(1, 0.1) except TypeError: r = resultQueue[i].get(1) self.assertEqual(r, '%d(0): ok - thread alive' % i) self.assert_(threads[i].isAlive()) for i in range(numThreads): for j in range(i + 1): try: queryQueue[i].put('select test%d' % j, 1, 0.1) r = resultQueue[i].get(1, 0.1) except TypeError: queryQueue[i].put('select test%d' % j, 1) r = resultQueue[i].get(1) self.assertEqual(r, '%d(%d): test%d' % (i, j + 1, j)) try: queryQueue[1].put('select test4', 1, 0.1) r = resultQueue[1].get(1, 0.1) except TypeError: queryQueue[1].put('select test4', 1) r = resultQueue[1].get(1) self.assertEqual(r, '1(3): test4') try: queryQueue[1].put('close', 1, 0.1) r = resultQueue[1].get(1, 0.1) except TypeError: queryQueue[1].put('close', 1) r = resultQueue[1].get(1) self.assertEqual(r, '1(3): ok - connection closed') for j in range(2): try: queryQueue[1].put('select test%d' % j, 1, 0.1) r = resultQueue[1].get(1, 0.1) except TypeError: queryQueue[1].put('select test%d' % j, 1) r = resultQueue[1].get(1) self.assertEqual(r, '1(%d): test%d' % (j + 1, j)) for i in range(numThreads): self.assert_(threads[i].isAlive()) try: queryQueue[i].put('ping', 1, 0.1) except TypeError: queryQueue[i].put('ping', 1) for i in range(numThreads): try: r = resultQueue[i].get(1, 0.1) except TypeError: r = resultQueue[i].get(1) self.assertEqual(r, '%d(%d): ok - thread alive' % (i, i + 1)) self.assert_(threads[i].isAlive()) for i in range(numThreads): try: queryQueue[i].put(None, 1, 1) except TypeError: queryQueue[i].put(None, 1) def test3_PersistentPgMaxUsage(self): persist = PersistentPg(20) db = persist.connection() self.assertEqual(db._maxusage, 20) for i in range(100): r = db.query('select test%d' % i) self.assertEqual(r, 'test%d' % i) self.assert_(db.db.status) j = i % 20 + 1 self.assertEqual(db._usage, j) self.assertEqual(db.num_queries, j) def test4_PersistentPgSetSession(self): persist = PersistentPg(3, ('set datestyle',)) db = persist.connection() self.assertEqual(db._maxusage, 3) self.assertEqual(db._setsession_sql, ('set datestyle',)) self.assertEqual(db.db.session, ['datestyle']) db.query('set test') for i in range(3): self.assertEqual(db.db.session, ['datestyle', 'test']) db.query('select test') self.assertEqual(db.db.session, ['datestyle']) if __name__ == '__main__': unittest.main() PKAM58h&IŒŒDBUtils/Testing/__init__.pyo;ò õÇFc@sdS(N((((s<build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/__init__.pys?sPK¼hç6ãe¹bb#DBUtils/Testing/TestPersistentDB.py"""Test the PersistentDB module. Note: We don't test performance here, so the test does not predicate whether PersistentDB actually will help in improving performance or not. We also assume that the underlying SteadyDB connections are tested. Copyright and credit info: * This test was contributed by Christoph Zwerschke """ __version__ = '0.9.4' __revision__ = "$Rev: 6696 $" __date__ = "$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $" import sys import unittest sys.path.insert(1, '../..') # The TestSteadyDB module serves as a mock object for the DB-API 2 module: from DBUtils.Testing import TestSteadyDB as dbapi from DBUtils.PersistentDB import PersistentDB class TestPersistentDB(unittest.TestCase): def setUp(self): dbapi.threadsafety = 1 def test0_CheckVersion(self): TestPersistentDBVersion = __version__ from DBUtils.PersistentDB import __version__ as PersistentDBVersion self.assertEqual(PersistentDBVersion, TestPersistentDBVersion) def test1_NoThreadsafety(self): from DBUtils.PersistentDB import NotSupportedError for dbapi.threadsafety in (None, 0): self.assertRaises(NotSupportedError, PersistentDB, dbapi) def test2_PersistentDBClose(self): for closeable in (0, 1): persist = PersistentDB(dbapi) persist._closeable = closeable db = persist.connection() self.assert_(db._con.valid) db.close() self.assert_(closeable ^ db._con.valid) db.close() self.assert_(closeable ^ db._con.valid) db._close() self.assert_(not db._con.valid) db._close() self.assert_(not db._con.valid) def test3_PersistentDBThreads(self): numThreads = 3 persist = PersistentDB(dbapi) persist._closeable = 1 from Queue import Queue, Empty queryQueue, resultQueue = [], [] for i in range(numThreads): queryQueue.append(Queue(1)) resultQueue.append(Queue(1)) def runQueries(i): this_db = persist.connection() while 1: try: try: q = queryQueue[i].get(1, 1) except TypeError: q = queryQueue[i].get(1) except Empty: q = None if not q: break db = persist.connection() if db != this_db: r = 'error - not persistent' else: if q == 'ping': r = 'ok - thread alive' elif q == 'close': db.close() r = 'ok - connection closed' else: cursor = db.cursor() cursor.execute(q) r = cursor.fetchone() cursor.close() r = '%d(%d): %s' % (i, db._usage, r) try: resultQueue[i].put(r, 1, 0.1) except TypeError: resultQueue[i].put(r, 1) db.close() from threading import Thread threads = [] for i in range(numThreads): thread = Thread(target=runQueries, args=(i,)) threads.append(thread) thread.start() for i in range(numThreads): try: queryQueue[i].put('ping', 1, 0.1) except TypeError: queryQueue[i].put('ping', 1) for i in range(numThreads): try: r = resultQueue[i].get(1, 0.1) except TypeError: r = resultQueue[i].get(1) self.assertEqual(r, '%d(0): ok - thread alive' % i) self.assert_(threads[i].isAlive()) for i in range(numThreads): for j in range(i + 1): try: queryQueue[i].put('select test%d' % j, 1, 0.1) r = resultQueue[i].get(1, 0.1) except TypeError: queryQueue[i].put('select test%d' % j, 1) r = resultQueue[i].get(1) self.assertEqual(r, '%d(%d): test%d' % (i, j + 1, j)) try: queryQueue[1].put('select test4', 1, 0.1) except TypeError: queryQueue[1].put('select test4', 1) try: r = resultQueue[1].get(1, 0.1) except TypeError: r = resultQueue[1].get(1) self.assertEqual(r, '1(3): test4') try: queryQueue[1].put('close', 1, 0.1) r = resultQueue[1].get(1, 0.1) except TypeError: queryQueue[1].put('close', 1) r = resultQueue[1].get(1) self.assertEqual(r, '1(3): ok - connection closed') for j in range(2): try: queryQueue[1].put('select test%d' % j, 1, 0.1) r = resultQueue[1].get(1, 0.1) except TypeError: queryQueue[1].put('select test%d' % j, 1) r = resultQueue[1].get(1) self.assertEqual(r, '1(%d): test%d' % (j + 1, j)) for i in range(numThreads): self.assert_(threads[i].isAlive()) try: queryQueue[i].put('ping', 1, 0.1) except TypeError: queryQueue[i].put('ping', 1) for i in range(numThreads): try: r = resultQueue[i].get(1, 0.1) except TypeError: r = resultQueue[i].get(1) self.assertEqual(r, '%d(%d): ok - thread alive' % (i, i + 1)) self.assert_(threads[i].isAlive()) for i in range(numThreads): try: queryQueue[i].put(None, 1, 1) except TypeError: queryQueue[i].put(None, 1) def test4_PersistentDBMaxUsage(self): persist = PersistentDB(dbapi, 20) db = persist.connection() self.assertEqual(db._maxusage, 20) for i in range(100): cursor = db.cursor() cursor.execute('select test%d' % i) r = cursor.fetchone() cursor.close() self.assertEqual(r, 'test%d' % i) self.assert_(db._con.valid) j = i % 20 + 1 self.assertEqual(db._usage, j) self.assertEqual(db._con.num_uses, j) self.assertEqual(db._con.num_queries, j) def test5_PersistentDBSetSession(self): persist = PersistentDB(dbapi, 3, ('set datestyle',)) db = persist.connection() self.assertEqual(db._maxusage, 3) self.assertEqual(db._setsession_sql, ('set datestyle',)) self.assertEqual(db._con.session, ['datestyle']) cursor = db.cursor() cursor.execute('set test') cursor.fetchone() cursor.close() for i in range(3): self.assertEqual(db._con.session, ['datestyle', 'test']) cursor = db.cursor() cursor.execute('select test') cursor.fetchone() cursor.close() self.assertEqual(db._con.session, ['datestyle']) if __name__ == '__main__': unittest.main() PK¼hç6¼˜J!7!7DBUtils/Testing/TestSteadyDB.py"""Test the SteadyDB module. Note: We do not test any real DB-API 2 module, but we just mock the basic DB-API 2 connection functionality. Copyright and credit info: * This test was contributed by Christoph Zwerschke """ __version__ = '0.9.4' __revision__ = "$Rev: 6696 $" __date__ = "$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $" import sys # This module also serves as a mock object for the DB-API 2 module: dbapi = sys.modules[__name__] threadsafety = 2 class Error(StandardError): pass class DatabaseError(Error): pass class OperationalError(DatabaseError): pass class InternalError(DatabaseError): pass class ProgrammingError(DatabaseError): pass def connect(database=None, user=None): return Connection(database, user) class Connection: def __init__(self, database=None, user=None): self.database = database self.user = user self.open_cursors = 0 self.num_uses = 0 self.num_queries = 0 self.session = [] if database == 'error': self.valid = 0 raise OperationalError self.valid = 1 def close(self): if not self.valid: raise InternalError self.open_cursors = 0 self.num_uses = 0 self.num_queries = 0 self.session = [] self.valid = 0 def commit(self): self.session.append('commit') def rollback(self): self.session.append('rollback') def cursor(self, name=None): if not self.valid: raise InternalError return Cursor(self, name) class Cursor: def __init__(self, con, name=None): self.con = con self.result = None if name == 'error': self.valid = 0 raise OperationalError con.open_cursors += 1 self.valid = 1 def close(self): if not self.valid: raise InternalError self.con.open_cursors -= 1 self.valid = 0 def execute(self, operation): if not self.valid or not self.con.valid: raise InternalError self.con.num_uses += 1 if operation.startswith('select '): self.con.num_queries += 1 self.result = operation[7:] elif operation.startswith('set '): self.con.session.append(operation[4:]) self.result = None else: raise ProgrammingError def fetchone(self): if not self.valid: raise InternalError result = self.result self.result = None return result def callproc(self, procname): if not self.valid or not self.con.valid: raise InternalError self.con.num_uses += 1 def __del__(self): if self.valid: self.close() import unittest sys.path.insert(1, '../..') from DBUtils.SteadyDB import connect as SteadyDBconnect class TestSteadyDB(unittest.TestCase): def test0_CheckVersion(self): TestSteadyDBVersion = __version__ from DBUtils.SteadyDB import __version__ as SteadyDBVersion self.assertEqual(SteadyDBVersion, TestSteadyDBVersion) def test1_MockedDBConnection(self): db = connect('SteadyDBTestDB', user='SteadyDBTestUser') self.assert_(hasattr(db, 'database')) self.assertEqual(db.database, 'SteadyDBTestDB') self.assert_(hasattr(db, 'user')) self.assertEqual(db.user, 'SteadyDBTestUser') self.assert_(hasattr(db, 'cursor')) self.assert_(hasattr(db, 'close')) self.assert_(hasattr(db, 'open_cursors')) self.assert_(hasattr(db, 'num_uses')) self.assert_(hasattr(db, 'num_queries')) self.assert_(hasattr(db, 'session')) self.assert_(hasattr(db, 'valid')) self.assert_(db.valid) self.assertEqual(db.open_cursors, 0) for i in range(3): cursor = db.cursor() self.assertEqual(db.open_cursors, 1) cursor.close() self.assertEqual(db.open_cursors, 0) cursor = [] for i in range(3): cursor.append(db.cursor()) self.assertEqual(db.open_cursors, i + 1) del cursor self.assertEqual(db.open_cursors, 0) cursor = db.cursor() self.assert_(hasattr(cursor, 'execute')) self.assert_(hasattr(cursor, 'fetchone')) self.assert_(hasattr(cursor, 'callproc')) self.assert_(hasattr(cursor, 'close')) self.assert_(hasattr(cursor, 'valid')) self.assert_(cursor.valid) self.assertEqual(db.open_cursors, 1) for i in range(3): self.assertEqual(db.num_uses, i) self.assertEqual(db.num_queries, i) cursor.execute('select test%d' % i) self.assertEqual(cursor.fetchone(), 'test%d' % i) self.assert_(cursor.valid) self.assertEqual(db.open_cursors, 1) for i in range(4): cursor.callproc('test') cursor.close() self.assert_(not cursor.valid) self.assertEqual(db.open_cursors, 0) self.assertEqual(db.num_uses, 7) self.assertEqual(db.num_queries, 3) self.assertRaises(InternalError, cursor.close) self.assertRaises(InternalError, cursor.execute, 'select test') self.assert_(db.valid) db.close() self.assert_(not db.valid) self.assertEqual(db.num_uses, 0) self.assertEqual(db.num_queries, 0) self.assertRaises(InternalError, db.close) self.assertRaises(InternalError, db.cursor) def test2_BrokenDBConnection(self): db = SteadyDBconnect(dbapi, database='ok') for i in range(3): db.close() del db self.assertRaises(OperationalError, SteadyDBconnect, dbapi, database='error') db = SteadyDBconnect(dbapi, database='ok') cursor = db.cursor() for i in range(3): cursor.close() cursor = db.cursor('ok') for i in range(3): cursor.close() self.assertRaises(OperationalError, db.cursor, 'error') def test3_SteadyDBClose(self): for closeable in (0, 1): db = SteadyDBconnect(dbapi) db._closeable = closeable self.assert_(db._con.valid) db.close() self.assert_(closeable ^ db._con.valid) db.close() self.assert_(closeable ^ db._con.valid) db._close() self.assert_(not db._con.valid) db._close() self.assert_(not db._con.valid) def test4_SteadyDBConnection(self): db = SteadyDBconnect(dbapi, 0, None, 'SteadyDBTestDB', user='SteadyDBTestUser') self.assert_(hasattr(db, '_con')) self.assert_(hasattr(db, '_usage')) self.assertEqual(db._usage, 0) self.assert_(hasattr(db._con, 'valid')) self.assert_(db._con.valid) self.assert_(hasattr(db._con, 'cursor')) self.assert_(hasattr(db._con, 'close')) self.assert_(hasattr(db._con, 'open_cursors')) self.assert_(hasattr(db._con, 'num_uses')) self.assert_(hasattr(db._con, 'num_queries')) self.assert_(hasattr(db._con, 'session')) self.assert_(hasattr(db._con, 'database')) self.assertEqual(db._con.database, 'SteadyDBTestDB') self.assert_(hasattr(db._con, 'user')) self.assertEqual(db._con.user, 'SteadyDBTestUser') self.assert_(hasattr(db, 'cursor')) self.assert_(hasattr(db, 'close')) self.assertEqual(db._con.open_cursors, 0) for i in range(3): cursor = db.cursor() self.assertEqual(db._con.open_cursors, 1) cursor.close() self.assertEqual(db._con.open_cursors, 0) cursor = [] for i in range(3): cursor.append(db.cursor()) self.assertEqual(db._con.open_cursors, i + 1) del cursor self.assertEqual(db._con.open_cursors, 0) cursor = db.cursor() self.assert_(hasattr(cursor, 'execute')) self.assert_(hasattr(cursor, 'fetchone')) self.assert_(hasattr(cursor, 'callproc')) self.assert_(hasattr(cursor, 'close')) self.assert_(hasattr(cursor, 'valid')) self.assert_(cursor.valid) self.assertEqual(db._con.open_cursors, 1) for i in range(3): self.assertEqual(db._usage, i) self.assertEqual(db._con.num_uses, i) self.assertEqual(db._con.num_queries, i) cursor.execute('select test%d' % i) self.assertEqual(cursor.fetchone(), 'test%d' % i) self.assert_(cursor.valid) self.assertEqual(db._con.open_cursors, 1) for i in range(4): cursor.callproc('test') cursor.close() self.assert_(not cursor.valid) self.assertEqual(db._con.open_cursors, 0) self.assertEqual(db._usage, 7) self.assertEqual(db._con.num_uses, 7) self.assertEqual(db._con.num_queries, 3) cursor.close() cursor.execute('select test8') self.assert_(cursor.valid) self.assertEqual(db._con.open_cursors, 1) self.assertEqual(cursor.fetchone(), 'test8') self.assertEqual(db._usage, 8) self.assertEqual(db._con.num_uses, 8) self.assertEqual(db._con.num_queries, 4) self.assert_(db._con.valid) db.close() self.assert_(not db._con.valid) self.assertEqual(db._con.open_cursors, 0) self.assertEqual(db._usage, 8) self.assertEqual(db._con.num_uses, 0) self.assertEqual(db._con.num_queries, 0) self.assertRaises(InternalError, db._con.close) db.close() self.assertRaises(InternalError, db._con.cursor) cursor = db.cursor() self.assert_(db._con.valid) cursor.execute('select test11') self.assertEqual(cursor.fetchone(), 'test11') cursor.execute('select test12') self.assertEqual(cursor.fetchone(), 'test12') cursor.callproc('test') self.assertEqual(db._usage, 3) self.assertEqual(db._con.num_uses, 3) self.assertEqual(db._con.num_queries, 2) cursor2 = db.cursor() self.assertEqual(db._con.open_cursors, 2) cursor2.execute('select test13') self.assertEqual(cursor2.fetchone(), 'test13') self.assertEqual(db._con.num_queries, 3) db.close() self.assertEqual(db._con.open_cursors, 0) self.assertEqual(db._con.num_queries, 0) cursor = db.cursor() self.assert_(cursor.valid) cursor.callproc('test') cursor._cursor.valid = 0 self.assert_(not cursor.valid) self.assertRaises(InternalError, cursor._cursor.callproc, 'test') cursor.callproc('test') self.assert_(cursor.valid) cursor._cursor.callproc('test') self.assertEqual(db._usage, 2) self.assertEqual(db._con.num_uses, 3) db._con.valid = cursor._cursor.valid = 0 cursor.callproc('test') self.assert_(cursor.valid) self.assertEqual(db._usage, 1) self.assertEqual(db._con.num_uses, 1) cursor.execute('set doit') db.commit() cursor.execute('set dont') db.rollback() self.assertEqual(db._con.session, ['doit', 'commit', 'dont', 'rollback']) def test5_SteadyDBConnectionCreatorFunction(self): db1 = SteadyDBconnect(dbapi, 0, None, 'SteadyDBTestDB', user='SteadyDBTestUser') db2 = SteadyDBconnect(connect, 0, None, 'SteadyDBTestDB', user='SteadyDBTestUser') self.assertEqual(db1.dbapi(), db2.dbapi()) self.assertEqual(db1.threadsafety(), db2.threadsafety()) self.assertEqual(db1._creator, db2._creator) self.assertEqual(db1._args, db2._args) self.assertEqual(db1._kwargs, db2._kwargs) db2.close() db1.close() def test6_SteadyDBConnectionMaxUsage(self): db = SteadyDBconnect(dbapi, 10) cursor = db.cursor() for i in range(100): cursor.execute('select test%d' % i) r = cursor.fetchone() self.assertEqual(r, 'test%d' % i) self.assert_(db._con.valid) j = i % 10 + 1 self.assertEqual(db._usage, j) self.assertEqual(db._con.num_uses, j) self.assertEqual(db._con.num_queries, j) self.assertEqual(db._con.open_cursors, 1) for i in range(100): cursor.callproc('test') self.assert_(db._con.valid) j = i % 10 + 1 self.assertEqual(db._usage, j) self.assertEqual(db._con.num_uses, j) self.assertEqual(db._con.num_queries, 0) for i in range(10): if i == 7: db._con.valid = cursor._cursor.valid = 0 cursor.execute('select test%d' % i) r = cursor.fetchone() self.assertEqual(r, 'test%d' % i) j = i % 7 + 1 self.assertEqual(db._usage, j) self.assertEqual(db._con.num_uses, j) self.assertEqual(db._con.num_queries, j) for i in range(10): if i == 5: db._con.valid = cursor._cursor.valid = 0 cursor.callproc('test') j = (i + (i < 5 and 3 or -5)) % 10 + 1 self.assertEqual(db._usage, j) self.assertEqual(db._con.num_uses, j) j = i < 5 and 3 or 0 self.assertEqual(db._con.num_queries, j) db.close() cursor.execute('select test1') self.assertEqual(cursor.fetchone(), 'test1') self.assertEqual(db._usage, 1) self.assertEqual(db._con.num_uses, 1) self.assertEqual(db._con.num_queries, 1) def test7_SteadyDBConnectionSetSession(self): db = SteadyDBconnect(dbapi, 3, ('set time zone', 'set datestyle')) self.assert_(hasattr(db, '_usage')) self.assertEqual(db._usage, 0) self.assert_(hasattr(db._con, 'open_cursors')) self.assertEqual(db._con.open_cursors, 0) self.assert_(hasattr(db._con, 'num_uses')) self.assertEqual(db._con.num_uses, 2) self.assert_(hasattr(db._con, 'num_queries')) self.assertEqual(db._con.num_queries, 0) self.assert_(hasattr(db._con, 'session')) self.assertEqual(tuple(db._con.session), ('time zone', 'datestyle')) for i in range(11): db.cursor().execute('select test') self.assertEqual(db._con.open_cursors, 0) self.assertEqual(db._usage, 2) self.assertEqual(db._con.num_uses, 4) self.assertEqual(db._con.num_queries, 2) self.assertEqual(db._con.session, ['time zone', 'datestyle']) db.cursor().execute('set test') self.assertEqual(db._con.open_cursors, 0) self.assertEqual(db._usage, 3) self.assertEqual(db._con.num_uses, 5) self.assertEqual(db._con.num_queries, 2) self.assertEqual(db._con.session, ['time zone', 'datestyle', 'test']) db.cursor().execute('select test') self.assertEqual(db._con.open_cursors, 0) self.assertEqual(db._usage, 1) self.assertEqual(db._con.num_uses, 3) self.assertEqual(db._con.num_queries, 1) self.assertEqual(db._con.session, ['time zone', 'datestyle']) db.cursor().execute('set test') self.assertEqual(db._con.open_cursors, 0) self.assertEqual(db._usage, 2) self.assertEqual(db._con.num_uses, 4) self.assertEqual(db._con.num_queries, 1) self.assertEqual(db._con.session, ['time zone', 'datestyle', 'test']) db.cursor().execute('select test') self.assertEqual(db._con.open_cursors, 0) self.assertEqual(db._usage, 3) self.assertEqual(db._con.num_uses, 5) self.assertEqual(db._con.num_queries, 2) self.assertEqual(db._con.session, ['time zone', 'datestyle', 'test']) db.close() db.cursor().execute('set test') self.assertEqual(db._con.open_cursors, 0) self.assertEqual(db._usage, 1) self.assertEqual(db._con.num_uses, 3) self.assertEqual(db._con.num_queries, 0) self.assertEqual(db._con.session, ['time zone', 'datestyle', 'test']) db.close() db.cursor().execute('select test') self.assertEqual(db._con.open_cursors, 0) self.assertEqual(db._usage, 1) self.assertEqual(db._con.num_uses, 3) self.assertEqual(db._con.num_queries, 1) self.assertEqual(db._con.session, ['time zone', 'datestyle']) if __name__ == '__main__': unittest.main() PK7M58ñ4ñ ñ $DBUtils/Testing/TestPersistentDB.pyc;ò õÇFc@sdZdZdZdZdkZdkZeiiddƒdkl Z dk l Z d ei fd „ƒYZed joeiƒndS( sBTest the PersistentDB module. Note: We don't test performance here, so the test does not predicate whether PersistentDB actually will help in improving performance or not. We also assume that the underlying SteadyDB connections are tested. Copyright and credit info: * This test was contributed by Christoph Zwerschke s0.9.4s $Rev: 6696 $s5$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $Nis../..(s TestSteadyDB(s PersistentDBsTestPersistentDBcBsGtZd„Zd„Zd„Zd„Zd„Zd„Zd„ZRS(NcCs dt_dS(Ni(sdbapis threadsafety(sself((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pyssetUpscCs't}dkl}|i||ƒdS(N(s __version__(s __version__sTestPersistentDBVersionsDBUtils.PersistentDBsPersistentDBVersionsselfs assertEqual(sselfsPersistentDBVersionsTestPersistentDBVersion((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pystest0_CheckVersion!s cCs>dkl}x*tdfD]t_|i|ttƒqWdS(N(sNotSupportedErrori(sDBUtils.PersistentDBsNotSupportedErrorsNonesdbapis threadsafetysselfs assertRaisess PersistentDB(sselfsNotSupportedError((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pystest1_NoThreadsafety&s  cCsÍxÆddfD]¸}ttƒ}||_|iƒ}|i|i i ƒ|i ƒ|i||i i Aƒ|i ƒ|i||i i Aƒ|i ƒ|i|i i ƒ|i ƒ|i|i i ƒq WdS(Nii( s closeables PersistentDBsdbapispersists _closeables connectionsdbsselfsassert_s_consvalidscloses_close(sselfsdbs closeablespersist((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pystest2_PersistentDBClose+s        c s¸d}ttƒ‰dˆ_dkl}l‰ggf\‰‰x:t |ƒD],}ˆi |dƒƒˆi |dƒƒqMW‡‡‡‡d†}dk l}g} xCt |ƒD]5}|d|d|fƒ}| i |ƒ|iƒq²WxYt |ƒD]K}yˆ|iddd ƒWqøtj oˆ|iddƒqøXqøWx‚t |ƒD]t}yˆ|idd ƒ} Wn&tj oˆ|idƒ} nX|i| d |ƒ|i| |iƒƒqTWxÆt |ƒD]¸}x¯t |dƒD]}y5ˆ|id |dd ƒˆ|idd ƒ} Wn>tj o2ˆ|id |dƒˆ|idƒ} nX|i| d ||d|fƒqðWqÙWyˆdid dd ƒWn'tj oˆdid dƒnXyˆdidd ƒ} Wn&tj oˆdidƒ} nX|i| dƒy1ˆdiddd ƒˆdidd ƒ} Wn:tj o.ˆdiddƒˆdidƒ} nX|i| dƒx¨t dƒD]š}y5ˆdid |dd ƒˆdidd ƒ} Wn>tj o2ˆdid |dƒˆdidƒ} nX|i| d|d|fƒq¸Wxpt |ƒD]b}|i| |iƒƒyˆ|iddd ƒWqctj oˆ|iddƒqcXqcWxŒt |ƒD]~}yˆ|idd ƒ} Wn&tj oˆ|idƒ} nX|i| d||dfƒ|i| |iƒƒqÖWxYt |ƒD]K}yˆ|itddƒWqetj oˆ|itdƒqeXqeWdS(Nii(sQueuesEmptycs~ˆiƒ}xanoYyGyˆ|iddƒ}Wn&tj oˆ|idƒ}nXWnˆj o t }nX| oPnˆiƒ}||jo d}nh|djo d}nQ|djo|i ƒd}n0|i ƒ}|i|ƒ|iƒ}|i ƒd||i|f}yˆ|i|ddƒWqtj oˆ|i|dƒqXqW|i ƒdS( Niserror - not persistentspingsok - thread alivesclosesok - connection closeds %d(%d): %sf0.10000000000000001(spersists connectionsthis_dbs queryQueuesisgetsqs TypeErrorsEmptysNonesdbsrsclosescursorsexecutesfetchones_usages resultQueuesput(siscursorsdbsqsthis_dbsr(s resultQueues queryQueuespersistsEmpty(sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pys runQueriesCs<              (sThreadstargetsargsspingf0.10000000000000001s%d(0): ok - thread alives select test%ds%d(%d): test%ds select test4s 1(3): test4scloses1(3): ok - connection closedis 1(%d): test%ds%d(%d): ok - thread alive(s numThreadss PersistentDBsdbapispersists _closeablesQueuesEmptys queryQueues resultQueuesrangesisappends runQueriess threadingsThreadsthreadssthreadsstartsputs TypeErrorsgetsrsselfs assertEqualsassert_sisAlivesjsNone(sselfs runQueriessthreadsThreadsis numThreadss resultQueuesjsQueues queryQueuesthreadsspersistsrsEmpty((s resultQueues queryQueuespersistsEmptysDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pystest3_PersistentDBThreads:s°         ) "   cCsðttdƒ}|iƒ}|i|idƒx»tdƒD]­}|i ƒ}|i d|ƒ|i ƒ}|iƒ|i|d|ƒ|i|iiƒ|dd}|i|i|ƒ|i|ii|ƒ|i|ii|ƒq;WdS(Niids select test%dstest%di(s PersistentDBsdbapispersists connectionsdbsselfs assertEquals _maxusagesrangesiscursorsexecutesfetchonesrsclosesassert_s_consvalidsjs_usagesnum_usess num_queries(sselfsisjsdbscursorsrspersist((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pystest4_PersistentDBMaxUsage©s     cCs ttddfƒ}|iƒ}|i|idƒ|i|idfƒ|i|i i dgƒ|i ƒ}|i dƒ|i ƒ|iƒx]tdƒD]O}|i|i i ddgƒ|i ƒ}|i dƒ|i ƒ|iƒqW|i|i i dgƒdS(Nis set datestyles datestylesset teststests select test(s PersistentDBsdbapispersists connectionsdbsselfs assertEquals _maxusages_setsession_sqls_conssessionscursorsexecutesfetchonesclosesrangesi(sselfsisdbscursorspersist((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pystest5_PersistentDBSetSession¹s"         ( s__name__s __module__ssetUpstest0_CheckVersionstest1_NoThreadsafetystest2_PersistentDBClosestest3_PersistentDBThreadsstest4_PersistentDBMaxUsagestest5_PersistentDBSetSession(((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pysTestPersistentDBs     o s__main__(s__doc__s __version__s __revision__s__date__ssyssunittestspathsinsertsDBUtils.Testings TestSteadyDBsdbapisDBUtils.PersistentDBs PersistentDBsTestCasesTestPersistentDBs__name__smain(ssyss __revision__sunittestsTestPersistentDBs__date__s __version__s PersistentDBsdbapi((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pys? s    ° PK7M58 æ²9²9 DBUtils/Testing/TestSteadyPg.pyc;ò õÇFc@sdZdZdZdZdkZeieeidtZd„Zd„Zd„Zd„Zd„Zd„ZRS(NcCsti|ddƒSdS(NsSimplePooledPgTestDBsSimplePooledPgTestUser(sSimplePooledPgsPooledPgsmaxConnections(sselfsmaxConnections((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledPg.pys my_dbpool.s cCs|ititƒdS(N(sselfs assertEqualsSimplePooledPgs __version__(sself((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledPg.pystest0_check_version2scCsÍ|idƒ}|iƒ}|it|dƒƒ|it|dƒƒ|i|idƒ|it|dƒƒ|i|i dƒ|it|dƒƒ|i|i dƒ|i ƒ|i|idƒdS( Nisquerys num_queriesisdbnamesSimplePooledPgTestDBsusersSimplePooledPgTestUser( sselfs my_dbpoolsdbpools connectionsdbsassert_shasattrs assertEquals num_queriessdbnamesusersquery(sselfsdbsdbpool((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledPg.pystest1_create_connection5s  cCsþ|idƒ}|iƒ}|i|idƒ|iƒ|i|idƒ|iƒ|i t |dƒ ƒ|iƒ}|i t |dƒƒ|i|i dƒ|i t |dƒƒ|i|i dƒ|i|idƒ|iƒ|i|idƒdS( Niis num_queriessdbnamesSimplePooledPgTestDBsusersSimplePooledPgTestUseri( sselfs my_dbpoolsdbpools connectionsdbs assertEquals num_queriessquerysclosesassert_shasattrsdbnamesuser(sselfsdbsdbpool((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledPg.pystest2_close_connectionBs     cCs\|idƒ}|iƒ}xtdƒD]}|iƒq(W|iƒ}|i ||ƒ|i |i |i ƒxtdƒD]}|iƒq{W|i |i dƒ|i |i dƒ|i ƒ|iƒ}|i ||ƒ|i |i |i ƒ|it|dƒƒxtdƒD]}|iƒqW|i |i dƒ|iƒ|i |i dƒdS(Niiisqueryii(sselfs my_dbpoolsdbpools connectionsdb1srangesisquerysdb2sassertNotEquals_cons assertEquals num_queriessclosesassert_shasattr(sselfsisdbpoolsdb1sdb2((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledPg.pystest3_two_connectionsSs0        c sÃ|idƒ‰dkl}l} |dƒ‰‡‡d†}dkl}|d|ƒi ƒ}|d|ƒi ƒ}|d|ƒi ƒ}y(ˆi ddƒ} ˆi ddƒ} Wn1tj o%ˆi dƒ} ˆi dƒ} nX|i| | ƒ|i| i| iƒy|i| ˆi ddƒWn)tj o|i| ˆi d ƒnX| iƒyˆi ddƒ} Wn"tj oˆi dƒ} nX|i| | ƒ|i| i| iƒdS( Ni(sQueuesEmptyicsˆiˆiƒƒdS(N(squeuesputsdbpools connection((squeuesdbpool(sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledPg.pys connectionns(sThreadstargetif0.10000000000000001i(sselfs my_dbpoolsdbpoolsQueuesEmptysqueues connections threadingsThreadsstartsthread1sthread2sthread3sgetsdb1sdb2s TypeErrorsassertNotEquals_cons assertRaisessclosesdb3( sselfsqueuesThreadsdbpoolsQueues connectionsthread3sthread2sthread1sdb1sdb3sdb2sEmpty((squeuesdbpoolsFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledPg.pys test4_threadsjs6   (s__name__s __module__s my_dbpoolstest0_check_versionstest1_create_connectionstest2_close_connectionstest3_two_connectionss test4_threads(((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledPg.pysTestSimplePooledPg,s     s__main__(s__doc__s __version__s __revision__s__date__ssyssmoduless__name__sDBsunittestspathsinsertsDBUtilssSimplePooledPgsTestCasesTestSimplePooledPgsmain(ssyss __revision__sunittestsDBsTestSimplePooledPgs__date__sSimplePooledPgs __version__((sFbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSimplePooledPg.pys? s   ] PK7M58¬ BÓôô$DBUtils/Testing/TestPersistentPg.pyc;ò õÇFc@sdZdZdZdZdkZdkZeiiddƒdkl Z dk l Z d ei fd „ƒYZ ed joeiƒndS( sBTest the PersistentPg module. Note: We don't test performance here, so the test does not predicate whether PersistentPg actually will help in improving performance or not. We also assume that the underlying SteadyPg connections are tested. Copyright and credit info: * This test was contributed by Christoph Zwerschke s0.9.4s $Rev: 6696 $s5$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $Nis../..(s TestSteadyPg(s PersistentPgsTestPersistentPgcBs5tZd„Zd„Zd„Zd„Zd„ZRS(NcCs't}dkl}|i||ƒdS(N(s __version__(s __version__sTestPersistentPgVersionsDBUtils.PersistentPgsPersistentPgVersionsselfs assertEqual(sselfsPersistentPgVersionsTestPersistentPgVersion((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentPg.pystest0_CheckVersions cCsxddfD]}tƒ}||_|iƒ}|i|iio |ii ƒ|i ƒ|i||iit j o |ii Aƒ|i ƒ|i||iit j o |ii Aƒ|i ƒ|i|ii p |ii ƒ|i ƒ|i|ii p |ii ƒq WdS(Nii( s closeables PersistentPgspersists _closeables connectionsdbsselfsassert_s_consvalidsclosesNones_close(sselfsdbspersists closeable((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentPg.pystest1_PersistentPgClose#s      * * " c s’d}tƒ‰dkl}l‰ggf\‰‰x:t|ƒD],}ˆi |dƒƒˆi |dƒƒqAW‡‡‡‡d†}dk l }g} xCt|ƒD]5}|d|d|fƒ}| i |ƒ|iƒq¦WxYt|ƒD]K}yˆ|iddd ƒWqìtj oˆ|iddƒqìXqìWx‚t|ƒD]t}yˆ|idd ƒ} Wn&tj oˆ|idƒ} nX|i| d |ƒ|i| |iƒƒqHWxÆt|ƒD]¸}x¯t|dƒD]}y5ˆ|id |dd ƒˆ|idd ƒ} Wn>tj o2ˆ|id |dƒˆ|idƒ} nX|i| d ||d|fƒqäWqÍWy1ˆdid dd ƒˆdidd ƒ} Wn:tj o.ˆdid dƒˆdidƒ} nX|i| dƒy1ˆdiddd ƒˆdidd ƒ} Wn:tj o.ˆdiddƒˆdidƒ} nX|i| dƒx¨tdƒD]š}y5ˆdid |dd ƒˆdidd ƒ} Wn>tj o2ˆdid |dƒˆdidƒ} nX|i| d|d|fƒq’Wxpt|ƒD]b}|i| |iƒƒyˆ|iddd ƒWq=tj oˆ|iddƒq=Xq=WxŒt|ƒD]~}yˆ|idd ƒ} Wn&tj oˆ|idƒ} nX|i| d||dfƒ|i| |iƒƒq°WxYt|ƒD]K}yˆ|itddƒWq?tj oˆ|itdƒq?Xq?WdS(Ni(sQueuesEmptyicsgˆiƒi}xGno?yGyˆ|iddƒ}Wn&tj oˆ|idƒ}nXWnˆj o t }nX| oPnˆiƒ}|i|jo d}nK|djo d}n4|djo|ii ƒd}n|i |ƒ}d||i|f}yˆ|i|ddƒWqtj oˆ|i|dƒqXqW|i ƒdS( Niserror - not persistentspingsok - thread alivesclosesok - connection closeds %d(%d): %sf0.10000000000000001(spersists connectionsdbsthis_dbs queryQueuesisgetsqs TypeErrorsEmptysNonesrsclosesquerys_usages resultQueuesput(sisdbsqsthis_dbsr(s resultQueues queryQueuespersistsEmpty(sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentPg.pys runQueries<s6        (sThreadstargetsargsspingf0.10000000000000001s%d(0): ok - thread alives select test%ds%d(%d): test%ds select test4s 1(3): test4scloses1(3): ok - connection closedis 1(%d): test%ds%d(%d): ok - thread alive(s numThreadss PersistentPgspersistsQueuesEmptys queryQueues resultQueuesrangesisappends runQueriess threadingsThreadsthreadssthreadsstartsputs TypeErrorsgetsrsselfs assertEqualsassert_sisAlivesjsNone(sselfs runQueriessthreadsThreadsis numThreadss resultQueuesjsQueues queryQueuesthreadsspersistsrsEmpty((s resultQueues queryQueuespersistsEmptysDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentPg.pystest2_PersistentPgThreads4sª        ) "   cCs´tdƒ}|iƒ}|i|idƒx‚tdƒD]t}|i d|ƒ}|i|d|ƒ|i |ii ƒ|dd}|i|i|ƒ|i|i|ƒq8WdS(Niids select test%dstest%di(s PersistentPgspersists connectionsdbsselfs assertEquals _maxusagesrangesisquerysrsassert_sstatussjs_usages num_queries(sselfsisjsdbsrspersist((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentPg.pystest3_PersistentPgMaxUsages   cCsÊtddfƒ}|iƒ}|i|idƒ|i|idfƒ|i|iidgƒ|i dƒx=t dƒD]/}|i|iiddgƒ|i dƒqzW|i|iidgƒdS(Nis set datestyles datestylesset teststests select test( s PersistentPgspersists connectionsdbsselfs assertEquals _maxusages_setsession_sqlssessionsquerysrangesi(sselfsisdbspersist((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentPg.pystest4_PersistentPgSetSession©s   (s__name__s __module__stest0_CheckVersionstest1_PersistentPgClosestest2_PersistentPgThreadsstest3_PersistentPgMaxUsagestest4_PersistentPgSetSession(((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentPg.pysTestPersistentPgs    i s__main__(s__doc__s __version__s __revision__s__date__ssyssunittestspathsinsertsDBUtils.Testings TestSteadyPgsDBUtils.PersistentPgs PersistentPgsTestCasesTestPersistentPgs__name__smain(ssyss __revision__s PersistentPgs TestSteadyPgsunittests__date__sTestPersistentPgs __version__((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentPg.pys? s    š PKBM58íJÂ;K)K) DBUtils/Testing/TestPooledPg.pyo;ò õÇFc@sdZdZdZdZdkZdkZeiiddƒdkl Z dk l Z d ei fd „ƒYZ ed joeiƒndS( s:Test the PooledPg module. Note: We don't test performance here, so the test does not predicate whether PooledPg actually will help in improving performance or not. We also assume that the underlying SteadyPg connections are tested. Copyright and credit info: * This test was contributed by Christoph Zwerschke s0.9.4s $Rev: 6696 $s5$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $Nis../..(s TestSteadyPg(sPooledPgs TestPooledPgcBsGtZd„Zd„Zd„Zd„Zd„Zd„Zd„ZRS(NcCs't}dkl}|i||ƒdS(N(s __version__(s __version__sTestPooledPgVersionsDBUtils.PooledPgsPooledPgVersionsselfs assertEqual(sselfsTestPooledPgVersionsPooledPgVersion((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pystest0_CheckVersions c Cs]tdddddtdddƒ}|it|dƒƒ|i|iiƒdƒ|it|dƒƒ|i|i dƒ|it|dƒƒ|i|i tjƒ|ii dƒ}|ii |dƒd kl}|it||ƒƒ|iƒ}|i|iiƒdƒ|it|d ƒƒ|i|i|ƒ|it|d ƒƒ|it|d ƒƒ|i|idƒ|it|dƒƒ|i|i dƒ|it|d ƒƒ|i|itjƒ|it|dƒƒ|i|idƒ|it|dƒƒ|i|idƒ|idƒ|i|idƒtdƒ}|iƒ}|it|dƒƒ|i|itjƒ|it|dƒƒ|i|itjƒ|it|d ƒƒ|i|idƒtddddddfƒ}|i|i dƒ|i|i dfƒ|iƒ}|i|i dƒ|i|idfƒdS(NiisPooledPgTestDBsusersPooledPgTestUsers_caches _maxusages _setsession(sSteadyPgConnections_consquerys num_queriess_setsession_sqlsdbnames select testis set datestyle(sPooledPgsNonespoolsselfsassert_shasattrs assertEquals_cachesqsizes _maxusages _setsessionsgetsdb_consputsDBUtils.SteadyPgsSteadyPgConnections isinstances connectionsdbs_cons num_queriess_setsession_sqlsdbnamesusersquery(sselfsdbspoolsSteadyPgConnectionsdb_con((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pystest1_CreateConnection#sV      c CsËtdddddtdddƒ}|iƒ}|it|dƒƒ|i}dk l }|it ||ƒƒ|it|dƒƒ|i |iiƒdƒ|i |idƒ|id ƒ|i |idƒ|iƒ|it|d ƒ ƒ|iƒ}|it|d ƒƒ|i |idƒ|it|dƒƒ|i |idƒ|i |idƒ|id ƒ|i |id ƒ|iƒ}|i |iiƒdƒ|i |iidƒ|ƒdS( NiisPooledPgTestDBsusersPooledPgTestUsers_con(sSteadyPgConnections_caches select tests num_queriessdbnamei(sPooledPgsNonespools connectionsdbsselfsassert_shasattrs_consdb_consDBUtils.SteadyPgsSteadyPgConnections isinstances assertEquals_cachesqsizes num_queriessquerysclosesdbnamesusersget(sselfsdbspoolsSteadyPgConnectionsdb_con((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pystest2_CloseConnectionPs2        cCs#tdƒ}|it|dƒƒ|i|iiƒdƒg}x't dƒD]}|i |i ƒƒqNW|i|iiƒdƒx$t dƒD]}|i ƒiƒq‘W|i|iiƒdƒx't dƒD]}|i |i ƒƒqÑW|i|iiƒdƒx$t dƒD]}|i ƒiƒqW|i|iiƒdƒtddƒ}|it|dƒƒ|i|iiƒdƒg}x't dƒD]}|i |i ƒƒq˜W|i|iiƒdƒx$t dƒD]}|i ƒiƒqÛW|i|iiƒdƒx't dƒD]}|i |i ƒƒqW|i|iiƒdƒx$t dƒD]}|i ƒiƒq^W|i|iiƒdƒtddƒ}|it|dƒƒ|i|iiƒdƒg}x't dƒD]}|i |i ƒƒqâW|i|iiƒdƒx$t dƒD]}|i ƒiƒq%W|i|iiƒdƒtddƒ}|it|dƒƒ|i|iiƒdƒg}x't dƒD]}|i |i ƒƒq©W|i|iiƒdƒx$t dƒD]}|i ƒiƒqìW|i|iiƒdƒdS( Nis_cacheiiiiii (sPooledPgspoolsselfsassert_shasattrs assertEquals_cachesqsizescachesrangesisappends connectionspopsclose(sselfsiscachespool((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pystest3_MinMaxCachedks€             c ssdkl}tdddƒ‰|iˆiiƒdƒg}x't dƒD]}|i ˆi ƒƒqKW|iˆiiƒdƒ|i |ˆi ƒtddddƒ‰|iˆidƒ|iˆiiƒdƒˆi ƒ}|iˆiiƒdƒ|i |ˆi ƒtdddƒ‰|iˆiiƒdƒg}|i ˆi ƒƒ|iˆiiƒdƒ|i ˆi ƒƒ|iˆiiƒdƒ|i |ˆi ƒtddddƒ‰|iˆiiƒdƒg}x't dƒD]}|i ˆi ƒƒqêW|iˆiiƒdƒ|i |ˆi ƒtddddƒ‰|iˆidƒ|iˆiiƒdƒˆi ƒ}|iˆiiƒdƒ‡d†}dkl}|d|ƒiƒd kl}|d ƒ|iˆiiƒdƒ|ii}|i|gƒ~|d ƒ|iˆiiƒdƒˆi ƒ}|iˆiiƒdƒ|i|d gƒdS( N(sTooManyConnectionsiiiicsˆiƒidƒdS(Ns set thread(spools connectionsquery((spool(s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pys connectionÄs(sThreadstarget(ssleepf0.10000000000000001sthread(sDBUtils.PooledPgsTooManyConnectionssPooledPgspoolsselfs assertEquals_cachesqsizescachesrangesisappends connections assertRaisess _blockingsdbs threadingsThreadsstartstimessleeps_conssession( sselfsThreadsis connectionscachesdbssessionssleepsTooManyConnectionsspool((spools@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pystest4_MaxConnections¡sd            cCs^tdƒ}|iƒ}x!tdƒD]}|idƒq%W|iƒ}|i ||ƒ|i |i |i ƒx!tdƒD]}|idƒq{W|i |i dƒ|i |i dƒ~|iƒ}|i ||ƒ|i |i |i ƒ|i t|dƒƒx!tdƒD]}|idƒqW|i |i dƒ|idƒ|i |i dƒdS(Niis select testisqueryii(sPooledPgspools connectionsdb1srangesisquerysdb2sselfsassertNotEquals_cons assertEquals num_queriessassert_shasattr(sselfsisdb1sdb2spool((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pystest5_OneThreadTwoConnectionsÔs0        c sÌtddddƒ‰dkl}l} |dƒ‰‡‡d†}dkl}x'tdƒD]}|d|ƒi ƒq]Wy(ˆi ddƒ}ˆi ddƒ} Wn1tj o%ˆi dƒ}ˆi dƒ} nX|i} | i}|i|| ƒ|i| |ƒy|i| ˆi ddƒWn)tj o|i| ˆi d ƒnX~yˆi ddƒ}Wn"tj oˆi dƒ}nX|i|| ƒ|i|i| iƒ|i|i| ƒdS( Nii(sQueuesEmptyicsMyˆiˆiƒddƒWn)tj oˆiˆiƒdƒnXdS(Nif0.10000000000000001(squeuesputspools connections TypeError((squeuespool(s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pys connectionïs(sThreadstargetf0.10000000000000001i(sPooledPgspoolsQueuesEmptysqueues connections threadingsThreadsrangesisstartsgetsdb1sdb2s TypeErrors_consdb1_consdb2_consselfsassertNotEquals assertRaisess assertEqual( sselfsqueuesThreadsisdb2_cons connectionsQueuespoolsdb1sdb2sEmptysdb1_con((squeuespools@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pys test6_ThreeThreadsTwoConnectionsës<     ( s__name__s __module__stest0_CheckVersionstest1_CreateConnectionstest2_CloseConnectionstest3_MinMaxCachedstest4_MaxConnectionsstest5_OneThreadTwoConnectionss test6_ThreeThreadsTwoConnections(((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pys TestPooledPgs  -  6 3 s__main__(s__doc__s __version__s __revision__s__date__ssyssunittestspathsinsertsDBUtils.Testings TestSteadyPgsDBUtils.PooledPgsPooledPgsTestCases TestPooledPgs__name__smain(ssyss __revision__s TestSteadyPgsunittests__date__sPooledPgs TestPooledPgs __version__((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPooledPg.pys? s    ó PK¼hç6…CêÙaa%DBUtils/Testing/TestSimplePooledDB.py"""Test the SimplePooledDB module. Note: We don't test performance here, so the test does not predicate whether SimplePooledDB actually will help in improving performance or not. We also do not test any real world DB-API 2 module, we just mock the basic connection functionality of an arbitrary module. Copyright and credit info: * This test was contributed by Christoph Zwerschke """ __version__ = '0.9.4' __revision__ = "$Rev: 6696 $" __date__ = "$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $" import sys # This module also serves as a mock object for an arbitrary DB-API 2 module: dbModule = sys.modules[__name__] threadsafety = 1 def connect(database, user): return Connection(database, user) class Connection: def __init__(self, database, user): self.database = database self.user = user self.open_cursors = 0 def close(self): self.open_cursors = 0 def cursor(self): self.open_cursors += 1 import unittest sys.path.insert(1, '../..') from DBUtils import SimplePooledDB class TestSimplePooledDB(unittest.TestCase): def my_dbpool(self, mythreadsafety, maxConnections): global threadsafety threadsafety = mythreadsafety return SimplePooledDB.PooledDB(dbModule, maxConnections, 'SimplePooledDBTestDB', 'SimplePooledDBTestUser') def test0_check_version(self): self.assertEqual(SimplePooledDB.__version__, __version__) def test1_no_threadsafety(self): for threadsafety in (None, -1, 0, 4): self.assertRaises(SimplePooledDB.NotSupportedError, self.my_dbpool, threadsafety, 1) def test2_create_connection(self): for threadsafety in (1, 2, 3): dbpool = self.my_dbpool(threadsafety, 1) db = dbpool.connection() self.assert_(hasattr(db, 'cursor')) self.assert_(hasattr(db, 'open_cursors')) self.assertEqual(db.open_cursors, 0) self.assert_(hasattr(db, 'database')) self.assertEqual(db.database, 'SimplePooledDBTestDB') self.assert_(hasattr(db, 'user')) self.assertEqual(db.user, 'SimplePooledDBTestUser') db.cursor() self.assertEqual(db.open_cursors, 1) def test3_close_connection(self): for threadsafety in (1, 2, 3): dbpool = self.my_dbpool(threadsafety, 1) db = dbpool.connection() self.assertEqual(db.open_cursors, 0) db.cursor() self.assertEqual(db.open_cursors, 1) db.close() self.assert_(not hasattr(db, 'open_cursors')) db = dbpool.connection() self.assert_(hasattr(db, 'database')) self.assertEqual(db.database, 'SimplePooledDBTestDB') self.assert_(hasattr(db, 'user')) self.assertEqual(db.user, 'SimplePooledDBTestUser') self.assertEqual(db.open_cursors, 1) db.cursor() self.assertEqual(db.open_cursors, 2) def test4_two_connections(self): for threadsafety in (1, 2, 3): dbpool = self.my_dbpool(threadsafety, 2) db1 = dbpool.connection() for i in range(5): db1.cursor() db2 = dbpool.connection() self.assertNotEqual(db1, db2) for i in range(7): db2.cursor() self.assertEqual(db1.open_cursors, 5) self.assertEqual(db2.open_cursors, 7) db1.close() db1 = dbpool.connection() self.assertNotEqual(db1, db2) self.assert_(hasattr(db1, 'cursor')) for i in range(3): db1.cursor() self.assertEqual(db1.open_cursors, 8) db2.cursor() self.assertEqual(db2.open_cursors, 8) def test5_threadsafety_1(self): dbpool = self.my_dbpool(1, 2) from Queue import Queue, Empty queue = Queue(3) def connection(): queue.put(dbpool.connection()) from threading import Thread thread1 = Thread(target=connection).start() thread2 = Thread(target=connection).start() thread3 = Thread(target=connection).start() try: db1 = queue.get(1, 1) db2 = queue.get(1, 1) except TypeError: db1 = queue.get(1) db2 = queue.get(1) self.assertNotEqual(db1, db2) self.assertNotEqual(db1._con, db2._con) try: self.assertRaises(Empty, queue.get, 1, 0.1) except TypeError: self.assertRaises(Empty, queue.get, 0) db2.close() try: db3 = queue.get(1, 1) except TypeError: db3 = queue.get(1) self.assertNotEqual(db1, db3) self.assertNotEqual(db1._con, db3._con) def test6_threadsafety_2(self): for threadsafety in (2, 3): dbpool = self.my_dbpool(threadsafety, 2) db1 = dbpool.connection() db2 = dbpool.connection() for i in xrange(100): dbpool.connection().cursor() self.assertEqual(db1.open_cursors, 50) self.assertEqual(db2.open_cursors, 50) if __name__ == '__main__': unittest.main() PK¼hç6ûÉ<‹¬ƒ¬ƒDBUtils/Testing/TestPooledDB.py"""Test the PooledDB module. Note: We don't test performance here, so the test does not predicate whether PooledDB actually will help in improving performance or not. We also assume that the underlying SteadyDB connections are tested. Copyright and credit info: * This test was contributed by Christoph Zwerschke """ __version__ = '0.9.4' __revision__ = "$Rev: 6696 $" __date__ = "$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $" import sys import unittest sys.path.insert(1, '../..') # The TestSteadyDB module serves as a mock object for the DB-API 2 module: from DBUtils.Testing import TestSteadyDB as dbapi from DBUtils.PooledDB import PooledDB class TestPooledDB(unittest.TestCase): def test00_CheckVersion(self): TestPooledDBVersion = __version__ from DBUtils.PooledDB import __version__ as PooledDBVersion self.assertEqual(PooledDBVersion, TestPooledDBVersion) def test01_NoThreadsafety(self): from DBUtils.PooledDB import NotSupportedError for threadsafety in (None, 0): dbapi.threadsafety = threadsafety self.assertRaises(NotSupportedError, PooledDB, dbapi) def test02_Threadsafety(self): for threadsafety in (1, 2, 3): dbapi.threadsafety = threadsafety pool = PooledDB(dbapi, 0, 0, 1) self.assert_(hasattr(pool, '_maxshared')) if threadsafety > 1: self.assertEqual(pool._maxshared, 1) self.assert_(hasattr(pool, '_shared_cache')) else: self.assertEqual(pool._maxshared, 0) self.assert_(not hasattr(pool, '_shared_cache')) def test03_CreateConnection(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 pool = PooledDB(dbapi, 1, 1, 1, 0, 0, 0, None, 'PooledDBTestDB', user='PooledDBTestUser') self.assert_(hasattr(pool, '_idle_cache')) self.assertEqual(len(pool._idle_cache), 1) if shareable: self.assert_(hasattr(pool, '_shared_cache')) self.assertEqual(len(pool._shared_cache), 0) else: self.assert_(not hasattr(pool, '_shared_cache')) self.assert_(hasattr(pool, '_maxusage')) self.assertEqual(pool._maxusage, 0) self.assert_(hasattr(pool, '_setsession')) self.assert_(pool._setsession is None) con = pool._idle_cache[0] from DBUtils.SteadyDB import SteadyDBConnection self.assert_(isinstance(con, SteadyDBConnection)) self.assert_(hasattr(con, '_maxusage')) self.assertEqual(con._maxusage, 0) self.assert_(hasattr(con, '_setsession_sql')) self.assert_(con._setsession_sql is None) db = pool.connection() self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 1) self.assert_(hasattr(db, '_con')) self.assertEqual(db._con, con) self.assert_(hasattr(db, 'cursor')) self.assert_(hasattr(db, '_usage')) self.assertEqual(db._usage, 0) self.assert_(hasattr(con, '_con')) db_con = con._con self.assert_(hasattr(db_con, 'database')) self.assertEqual(db_con.database, 'PooledDBTestDB') self.assert_(hasattr(db_con, 'user')) self.assertEqual(db_con.user, 'PooledDBTestUser') self.assert_(hasattr(db_con, 'open_cursors')) self.assertEqual(db_con.open_cursors, 0) self.assert_(hasattr(db_con, 'num_uses')) self.assertEqual(db_con.num_uses, 0) self.assert_(hasattr(db_con, 'num_queries')) self.assertEqual(db_con.num_queries, 0) cursor = db.cursor() self.assertEqual(db_con.open_cursors, 1) cursor.execute('select test') r = cursor.fetchone() cursor.close() self.assertEqual(db_con.open_cursors, 0) self.assertEqual(r, 'test') self.assertEqual(db_con.num_queries, 1) self.assertEqual(db._usage, 1) cursor = db.cursor() self.assertEqual(db_con.open_cursors, 1) cursor.execute('set sessiontest') cursor2 = db.cursor() self.assertEqual(db_con.open_cursors, 2) cursor2.close() self.assertEqual(db_con.open_cursors, 1) cursor.close() self.assertEqual(db_con.open_cursors, 0) self.assertEqual(db_con.num_queries, 1) self.assertEqual(db._usage, 2) self.assertEqual(db_con.session, ['rollback', 'sessiontest']) pool = PooledDB(dbapi, 1, 1, 1) db = pool.connection(0) self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 0) self.assertEqual(db._usage, 0) db_con = db._con._con self.assert_(db_con.database is None) self.assert_(db_con.user is None) pool = PooledDB(dbapi, 0, 0, 0, 0, 0, 3, ('set datestyle',),) self.assertEqual(pool._maxusage, 3) self.assertEqual(pool._setsession, ('set datestyle',)) con = pool.connection()._con self.assertEqual(con._maxusage, 3) self.assertEqual(con._setsession_sql, ('set datestyle',)) def test04_CloseConnection(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 pool = PooledDB(dbapi, 0, 1, 1, 0, 0, 0, None, 'PooledDBTestDB', user='PooledDBTestUser') self.assert_(hasattr(pool, '_idle_cache')) self.assertEqual(len(pool._idle_cache), 0) db = pool.connection() self.assert_(hasattr(db, '_con')) con = db._con self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 1) self.assert_(hasattr(db, '_shared_con')) shared_con = db._shared_con self.assertEqual(pool._shared_cache[0], shared_con) self.assert_(hasattr(shared_con, 'shared')) self.assertEqual(shared_con.shared, 1) self.assert_(hasattr(shared_con, 'con')) self.assertEqual(shared_con.con, con) from DBUtils.SteadyDB import SteadyDBConnection self.assert_(isinstance(con, SteadyDBConnection)) self.assert_(hasattr(con, '_con')) db_con = con._con self.assert_(hasattr(db_con, 'num_queries')) self.assertEqual(db._usage, 0) self.assertEqual(db_con.num_queries, 0) db.cursor().execute('select test') self.assertEqual(db._usage, 1) self.assertEqual(db_con.num_queries, 1) db.close() self.assertEqual(db._con, None) if shareable: self.assertEqual(db._shared_con, None) self.assertEqual(shared_con.shared, 0) self.assert_(not hasattr(db, '_usage')) self.assert_(not hasattr(db_con, '_num_queries')) self.assertEqual(len(pool._idle_cache), 1) self.assertEqual(pool._idle_cache[0]._con, db_con) if shareable: self.assertEqual(len(pool._shared_cache), 0) db.close() if shareable: self.assertEqual(shared_con.shared, 0) db = pool.connection() self.assertEqual(db._con, con) self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 1) shared_con = db._shared_con self.assertEqual(pool._shared_cache[0], shared_con) self.assertEqual(shared_con.con, con) self.assertEqual(shared_con.shared, 1) self.assertEqual(db._usage, 1) self.assertEqual(db_con.num_queries, 1) self.assert_(hasattr(db_con, 'database')) self.assertEqual(db_con.database, 'PooledDBTestDB') self.assert_(hasattr(db_con, 'user')) self.assertEqual(db_con.user, 'PooledDBTestUser') db.cursor().execute('select test') self.assertEqual(db_con.num_queries, 2) db.cursor().execute('select test') self.assertEqual(db_con.num_queries, 3) db.close() self.assertEqual(len(pool._idle_cache), 1) self.assertEqual(pool._idle_cache[0]._con, db_con) if shareable: self.assertEqual(len(pool._shared_cache), 0) db = pool.connection(0) self.assertEqual(db._con, con) self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 0) db.close() self.assertEqual(len(pool._idle_cache), 1) if shareable: self.assertEqual(len(pool._shared_cache), 0) def test05_CloseAll(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 pool = PooledDB(dbapi, 10) self.assertEqual(len(pool._idle_cache), 10) pool.close() self.assertEqual(len(pool._idle_cache), 0) pool = PooledDB(dbapi, 10) closed = ['no'] def close(what=closed): what[0] = 'yes' pool._idle_cache[7]._con.close = close self.assertEqual(closed, ['no']) del pool self.assertEqual(closed, ['yes']) pool = PooledDB(dbapi, 10, 10, 5) self.assertEqual(len(pool._idle_cache), 10) if shareable: self.assertEqual(len(pool._shared_cache), 0) cache = [] for i in range(5): cache.append(pool.connection()) self.assertEqual(len(pool._idle_cache), 5) if shareable: self.assertEqual(len(pool._shared_cache), 5) else: self.assertEqual(len(pool._idle_cache), 5) pool.close() self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 0) pool = PooledDB(dbapi, 10, 10, 5) closed = [] def close_idle(what=closed): what.append('idle') def close_shared(what=closed): what.append('shared') if shareable: cache = [] for i in range(5): cache.append(pool.connection()) pool._shared_cache[3].con.close = close_shared else: pool._idle_cache[7]._con.close = close_shared pool._idle_cache[3]._con.close = close_idle self.assertEqual(closed, []) del pool if shareable: del cache self.assertEqual(closed, ['idle', 'shared']) def test06_ShareableConnection(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 pool = PooledDB(dbapi, 0, 1, 2) self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 0) db1 = pool.connection() self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 1) db2 = pool.connection() self.assertNotEqual(db1._con, db2._con) self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 2) db3 = pool.connection() self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 2) self.assertEqual(db3._con, db1._con) self.assertEqual(db1._shared_con.shared, 2) self.assertEqual(db2._shared_con.shared, 1) else: self.assertNotEqual(db3._con, db1._con) self.assertNotEqual(db3._con, db2._con) db4 = pool.connection() self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 2) self.assertEqual(db4._con, db2._con) self.assertEqual(db1._shared_con.shared, 2) self.assertEqual(db2._shared_con.shared, 2) else: self.assertNotEqual(db4._con, db1._con) self.assertNotEqual(db4._con, db2._con) self.assertNotEqual(db4._con, db3._con) db5 = pool.connection(0) self.assertNotEqual(db5._con, db1._con) self.assertNotEqual(db5._con, db2._con) self.assertNotEqual(db5._con, db3._con) self.assertNotEqual(db5._con, db4._con) self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 2) self.assertEqual(db1._shared_con.shared, 2) self.assertEqual(db2._shared_con.shared, 2) db5.close() self.assertEqual(len(pool._idle_cache), 1) db5 = pool.connection() if shareable: self.assertEqual(len(pool._idle_cache), 1) self.assertEqual(len(pool._shared_cache), 2) self.assertEqual(db5._shared_con.shared, 3) else: self.assertEqual(len(pool._idle_cache), 0) pool = PooledDB(dbapi, 0, 0, 1) self.assertEqual(len(pool._idle_cache), 0) db1 = pool.connection(0) if shareable: self.assertEqual(len(pool._shared_cache), 0) db2 = pool.connection() if shareable: self.assertEqual(len(pool._shared_cache), 1) db3 = pool.connection() if shareable: self.assertEqual(len(pool._shared_cache), 1) self.assertEqual(db2._con, db3._con) else: self.assertNotEqual(db2._con, db3._con) del db3 if shareable: self.assertEqual(len(pool._idle_cache), 0) self.assertEqual(len(pool._shared_cache), 1) else: self.assertEqual(len(pool._idle_cache), 1) del db2 if shareable: self.assertEqual(len(pool._idle_cache), 1) self.assertEqual(len(pool._shared_cache), 0) else: self.assertEqual(len(pool._idle_cache), 2) del db1 if shareable: self.assertEqual(len(pool._idle_cache), 2) self.assertEqual(len(pool._shared_cache), 0) else: self.assertEqual(len(pool._idle_cache), 3) def test07_MinMaxCached(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 pool = PooledDB(dbapi, 3) self.assertEqual(len(pool._idle_cache), 3) cache = [pool.connection() for i in range(3)] self.assertEqual(len(pool._idle_cache), 0) del cache self.assertEqual(len(pool._idle_cache), 3) cache = [pool.connection() for i in range(6)] self.assertEqual(len(pool._idle_cache), 0) del cache self.assertEqual(len(pool._idle_cache), 6) pool = PooledDB(dbapi, 0, 3) self.assertEqual(len(pool._idle_cache), 0) cache = [pool.connection() for i in range(3)] self.assertEqual(len(pool._idle_cache), 0) del cache self.assertEqual(len(pool._idle_cache), 3) cache = [pool.connection() for i in range(6)] self.assertEqual(len(pool._idle_cache), 0) del cache self.assertEqual(len(pool._idle_cache), 3) pool = PooledDB(dbapi, 3, 3) self.assertEqual(len(pool._idle_cache), 3) cache = [pool.connection() for i in range(3)] self.assertEqual(len(pool._idle_cache), 0) del cache self.assertEqual(len(pool._idle_cache), 3) cache = [pool.connection() for i in range(6)] self.assertEqual(len(pool._idle_cache), 0) del cache self.assertEqual(len(pool._idle_cache), 3) pool = PooledDB(dbapi, 3, 2) self.assertEqual(len(pool._idle_cache), 3) cache = [pool.connection() for i in range(4)] self.assertEqual(len(pool._idle_cache), 0) del cache self.assertEqual(len(pool._idle_cache), 3) pool = PooledDB(dbapi, 2, 5) self.assertEqual(len(pool._idle_cache), 2) cache = [pool.connection() for i in range(10)] self.assertEqual(len(pool._idle_cache), 0) del cache self.assertEqual(len(pool._idle_cache), 5) pool = PooledDB(dbapi, 1, 2, 3) self.assertEqual(len(pool._idle_cache), 1) cache = [pool.connection(0) for i in range(4)] self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 0) del cache self.assertEqual(len(pool._idle_cache), 2) cache = [pool.connection() for i in range(10)] self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 3) del cache self.assertEqual(len(pool._idle_cache), 2) if shareable: self.assertEqual(len(pool._shared_cache), 0) pool = PooledDB(dbapi, 1, 3, 2) self.assertEqual(len(pool._idle_cache), 1) cache = [pool.connection(0) for i in range(4)] self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 0) del cache self.assertEqual(len(pool._idle_cache), 3) cache = [pool.connection() for i in range(10)] if shareable: self.assertEqual(len(pool._idle_cache), 1) self.assertEqual(len(pool._shared_cache), 2) else: self.assertEqual(len(pool._idle_cache), 0) del cache self.assertEqual(len(pool._idle_cache), 3) if shareable: self.assertEqual(len(pool._shared_cache), 0) def test08_MaxShared(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 pool = PooledDB(dbapi) self.assertEqual(len(pool._idle_cache), 0) cache = [pool.connection() for i in range(10)] self.assertEqual(len(pool._idle_cache), 0) pool = PooledDB(dbapi, 1, 1, 0) self.assertEqual(len(pool._idle_cache), 1) cache = [pool.connection() for i in range(10)] self.assertEqual(len(pool._idle_cache), 0) pool = PooledDB(dbapi, 0, 0, 1) cache = [pool.connection() for i in range(10)] self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 1) pool = PooledDB(dbapi, 1, 1, 1) self.assertEqual(len(pool._idle_cache), 1) cache = [pool.connection() for i in range(10)] self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 1) pool = PooledDB(dbapi, 0, 0, 7) cache = [pool.connection(0) for i in range(3)] self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 0) cache = [pool.connection() for i in range(10)] self.assertEqual(len(pool._idle_cache), 3) if shareable: self.assertEqual(len(pool._shared_cache), 7) def test09_EquallyShared(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 pool = PooledDB(dbapi, 5, 5, 5) self.assertEqual(len(pool._idle_cache), 5) for i in range(15): db = pool.connection(0) db.cursor().execute('select test') db.close() self.assertEqual(len(pool._idle_cache), 5) for i in range(5): con = pool._idle_cache[i] self.assertEqual(con._usage, 3) self.assertEqual(con._con.num_queries, 3) cache = [] for i in range(35): db = pool.connection() db.cursor().execute('select test') cache.append(db) del db self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 5) for i in range(5): con = pool._shared_cache[i] self.assertEqual(con.shared, 7) con = con.con self.assertEqual(con._usage, 10) self.assertEqual(con._con.num_queries, 10) del cache self.assertEqual(len(pool._idle_cache), 5) if shareable: self.assertEqual(len(pool._shared_cache), 0) def test10_SortShared(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 pool = PooledDB(dbapi, 0, 0, 5) cache = [] for i in range(35): db = pool.connection() db.cursor().execute('select test1') db.cursor().execute('select test2') db.cursor().callproc('test3') cache.append(db) del db self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 5) for i in range(5): con = pool._shared_cache[i] self.assertEqual(con.shared, 7) con = con.con self.assertEqual(con._usage, 21) self.assertEqual(con._con.num_queries, 14) cache[3] = cache[8] = cache[33] = None cache[12] = cache[17] = cache[34] = None self.assertEqual(len(pool._shared_cache), 5) self.assertEqual(pool._shared_cache[0].shared, 7) self.assertEqual(pool._shared_cache[1].shared, 7) self.assertEqual(pool._shared_cache[2].shared, 5) self.assertEqual(pool._shared_cache[3].shared, 4) self.assertEqual(pool._shared_cache[4].shared, 6) for db in cache: if db: db.cursor().callproc('test4') for i in range(6): db = pool.connection() db.cursor().callproc('test4') cache.append(db) del db for i in range(5): con = pool._shared_cache[i] self.assertEqual(con.shared, 7) con = con.con self.assertEqual(con._usage, 28) self.assertEqual(con._con.num_queries, 14) del cache if shareable: self.assertEqual(len(pool._idle_cache), 5) self.assertEqual(len(pool._shared_cache), 0) else: self.assertEqual(len(pool._idle_cache), 35) def test11_Rollback(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety pool = PooledDB(dbapi, 0, 1) self.assertEqual(len(pool._idle_cache), 0) db = pool.connection(0) self.assertEqual(len(pool._idle_cache), 0) self.assertEqual(db._con._con.open_cursors, 0) cursor = db.cursor() self.assertEqual(db._con._con.open_cursors, 1) cursor.execute('set doit1') db.commit() cursor.execute('set dont1') cursor.close() self.assertEqual(db._con._con.open_cursors, 0) del db self.assertEqual(len(pool._idle_cache), 1) db = pool.connection(0) self.assertEqual(len(pool._idle_cache), 0) self.assertEqual(db._con._con.open_cursors, 0) cursor = db.cursor() self.assertEqual(db._con._con.open_cursors, 1) cursor.execute('set doit2') cursor.close() self.assertEqual(db._con._con.open_cursors, 0) db.commit() session = db._con._con.session db.close() self.assertEqual(session, [ 'doit1', 'commit', 'dont1', 'rollback', 'doit2', 'commit', 'rollback']) def test12_MaxConnections(self): from DBUtils.PooledDB import TooManyConnections for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 pool = PooledDB(dbapi, 1, 2, 2, 3) self.assert_(hasattr(pool, '_maxconnections')) self.assertEqual(pool._maxconnections, 3) self.assert_(hasattr(pool, '_connections')) self.assertEqual(pool._connections, 0) self.assertEqual(len(pool._idle_cache), 1) cache = [] for i in range(3): cache.append(pool.connection(0)) self.assertEqual(pool._connections, 3) self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 0) self.assertRaises(TooManyConnections, pool.connection, 0) self.assertRaises(TooManyConnections, pool.connection) cache = [] self.assertEqual(pool._connections, 0) self.assertEqual(len(pool._idle_cache), 2) if shareable: self.assertEqual(len(pool._shared_cache), 0) for i in range(3): cache.append(pool.connection()) self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(pool._connections, 2) self.assertEqual(len(pool._shared_cache), 2) cache.append(pool.connection(0)) self.assertEqual(pool._connections, 3) self.assertEqual(len(pool._shared_cache), 2) else: self.assertEqual(pool._connections, 3) self.assertRaises(TooManyConnections, pool.connection, 0) if shareable: cache.append(pool.connection(1)) self.assertEqual(pool._connections, 3) else: self.assertRaises(TooManyConnections, pool.connection) del cache self.assertEqual(pool._connections, 0) self.assertEqual(len(pool._idle_cache), 2) pool = PooledDB(dbapi, 0, 1, 1, 1) self.assertEqual(pool._maxconnections, 1) self.assertEqual(pool._connections, 0) self.assertEqual(len(pool._idle_cache), 0) db = pool.connection(0) self.assertEqual(pool._connections, 1) self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 0) self.assertRaises(TooManyConnections, pool.connection, 0) self.assertRaises(TooManyConnections, pool.connection) del db self.assertEqual(pool._connections, 0) self.assertEqual(len(pool._idle_cache), 1) cache = [pool.connection()] self.assertEqual(pool._connections, 1) self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 1) cache.append(pool.connection()) self.assertEqual(pool._connections, 1) self.assertEqual(len(pool._shared_cache), 1) self.assertEqual(pool._shared_cache[0].shared, 2) else: self.assertRaises(TooManyConnections, pool.connection) self.assertRaises(TooManyConnections, pool.connection, 0) if shareable: cache.append(pool.connection(1)) self.assertEqual(pool._connections, 1) self.assertEqual(len(pool._shared_cache), 1) self.assertEqual(pool._shared_cache[0].shared, 3) else: self.assertRaises(TooManyConnections, pool.connection, 1) del cache self.assertEqual(pool._connections, 0) self.assertEqual(len(pool._idle_cache), 1) if shareable: self.assertEqual(len(pool._shared_cache), 0) db = pool.connection(0) self.assertEqual(pool._connections, 1) self.assertEqual(len(pool._idle_cache), 0) del db self.assertEqual(pool._connections, 0) self.assertEqual(len(pool._idle_cache), 1) pool = PooledDB(dbapi, 1, 2, 2, 1) self.assertEqual(pool._maxconnections, 2) self.assertEqual(pool._connections, 0) self.assertEqual(len(pool._idle_cache), 1) cache = [] cache.append(pool.connection(0)) self.assertEqual(pool._connections, 1) self.assertEqual(len(pool._idle_cache), 0) cache.append(pool.connection(0)) self.assertEqual(pool._connections, 2) self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 0) self.assertRaises(TooManyConnections, pool.connection, 0) self.assertRaises(TooManyConnections, pool.connection) pool = PooledDB(dbapi, 4, 3, 2, 1, 0) self.assertEqual(pool._maxconnections, 4) self.assertEqual(pool._connections, 0) self.assertEqual(len(pool._idle_cache), 4) cache = [] for i in range(4): cache.append(pool.connection(0)) self.assertEqual(pool._connections, 4) self.assertEqual(len(pool._idle_cache), 0) self.assertRaises(TooManyConnections, pool.connection, 0) self.assertRaises(TooManyConnections, pool.connection) pool = PooledDB(dbapi, 1, 2, 3, 4, 0) self.assertEqual(pool._maxconnections, 4) self.assertEqual(pool._connections, 0) self.assertEqual(len(pool._idle_cache), 1) for i in range(4): cache.append(pool.connection()) self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(pool._connections, 3) self.assertEqual(len(pool._shared_cache), 3) cache.append(pool.connection()) self.assertEqual(pool._connections, 3) cache.append(pool.connection(0)) self.assertEqual(pool._connections, 4) else: self.assertEqual(pool._connections, 4) self.assertRaises(TooManyConnections, pool.connection) self.assertRaises(TooManyConnections, pool.connection, 0) pool = PooledDB(dbapi, 0, 0, 3, 3, 0) self.assertEqual(pool._maxconnections, 3) self.assertEqual(pool._connections, 0) cache = [] for i in range(3): cache.append(pool.connection(0)) self.assertEqual(pool._connections, 3) self.assertRaises(TooManyConnections, pool.connection, 0) self.assertRaises(TooManyConnections, pool.connection, 1) cache = [] self.assertEqual(pool._connections, 0) for i in range(3): cache.append(pool.connection()) self.assertEqual(pool._connections, 3) if shareable: for i in range(3): cache.append(pool.connection()) self.assertEqual(pool._connections, 3) else: self.assertRaises(TooManyConnections, pool.connection) self.assertRaises(TooManyConnections, pool.connection, 0) pool = PooledDB(dbapi, 0, 0, 3) self.assertEqual(pool._maxconnections, 0) self.assertEqual(pool._connections, 0) cache = [] for i in range(10): cache.append(pool.connection(0)) cache.append(pool.connection()) if shareable: self.assertEqual(pool._connections, 13) self.assertEqual(len(pool._shared_cache), 3) else: self.assertEqual(pool._connections, 20) pool = PooledDB(dbapi, 1, 1, 1, 1, 1) self.assertEqual(pool._maxconnections, 1) self.assertEqual(pool._connections, 0) self.assertEqual(len(pool._idle_cache), 1) db = pool.connection(0) self.assertEqual(pool._connections, 1) self.assertEqual(len(pool._idle_cache), 0) def connection(): db = pool.connection() cursor=db.cursor() cursor.execute('set thread') cursor.close() db.close() from threading import Thread Thread(target=connection).start() from time import sleep sleep(0.1) self.assertEqual(pool._connections, 1) self.assertEqual(len(pool._idle_cache), 0) if shareable: self.assertEqual(len(pool._shared_cache), 0) session = db._con._con.session self.assertEqual(session, ['rollback']) del db sleep(0.1) self.assertEqual(pool._connections, 0) self.assertEqual(len(pool._idle_cache), 1) if shareable: self.assertEqual(len(pool._shared_cache), 0) db = pool.connection(0) self.assertEqual(pool._connections, 1) self.assertEqual(len(pool._idle_cache), 0) self.assertEqual(session, ['rollback', 'rollback', 'thread', 'rollback']) def test13_MaxUsage(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety for maxusage in (0, 3, 7): pool = PooledDB(dbapi, 0, 0, 0, 1, 0, maxusage) self.assertEqual(pool._maxusage, maxusage) self.assertEqual(len(pool._idle_cache), 0) db = pool.connection(0) self.assertEqual(db._con._maxusage, maxusage) self.assertEqual(len(pool._idle_cache), 0) self.assertEqual(db._con._con.open_cursors, 0) self.assertEqual(db._usage, 0) self.assertEqual(db._con._con.num_uses, 0) self.assertEqual(db._con._con.num_queries, 0) for i in range(20): cursor=db.cursor() self.assertEqual(db._con._con.open_cursors, 1) cursor.execute('select test%i' % i) r = cursor.fetchone() self.assertEqual(r, 'test%i' % i) cursor.close() self.assertEqual(db._con._con.open_cursors, 0) if maxusage: j = i % maxusage + 1 else: j = i + 1 self.assertEqual(db._usage, j) self.assertEqual(db._con._con.num_uses, j) self.assertEqual(db._con._con.num_queries, j) db.cursor().callproc('test') self.assertEqual(db._con._con.open_cursors, 0) self.assertEqual(db._usage, j + 1) self.assertEqual(db._con._con.num_uses, j + 1) self.assertEqual(db._con._con.num_queries, j) def test14_SetSession(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety setsession = ('set time zone', 'set datestyle') pool = PooledDB(dbapi, 0, 0, 0, 1, 0, 0, setsession) self.assertEqual(pool._setsession, setsession) db = pool.connection(0) self.assertEqual(db._setsession_sql, setsession) self.assertEqual(db._con._con.session, ['time zone', 'datestyle']) db.cursor().execute('select test') db.cursor().execute('set test1') self.assertEqual(db._usage, 2) self.assertEqual(db._con._con.num_uses, 4) self.assertEqual(db._con._con.num_queries, 1) self.assertEqual(db._con._con.session, ['time zone', 'datestyle', 'test1']) db.close() db = pool.connection(0) self.assertEqual(db._setsession_sql, setsession) self.assertEqual(db._con._con.session, ['time zone', 'datestyle', 'test1', 'rollback']) db._con._con.close() db.cursor().execute('select test') db.cursor().execute('set test2') self.assertEqual(db._con._con.session, ['time zone', 'datestyle', 'test2']) def test15_OneThreadTwoConnections(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 pool = PooledDB(dbapi, 2) db1 = pool.connection() for i in range(5): db1.cursor().execute('select test') db2 = pool.connection() self.assertNotEqual(db1, db2) self.assertNotEqual(db1._con, db2._con) for i in range(7): db2.cursor().execute('select test') self.assertEqual(db1._con._con.num_queries, 5) self.assertEqual(db2._con._con.num_queries, 7) del db1 db1 = pool.connection() self.assertNotEqual(db1, db2) self.assertNotEqual(db1._con, db2._con) for i in range(3): db1.cursor().execute('select test') self.assertEqual(db1._con._con.num_queries, 8) db2.cursor().execute('select test') self.assertEqual(db2._con._con.num_queries, 8) pool = PooledDB(dbapi, 0, 0, 2) db1 = pool.connection() for i in range(5): db1.cursor().execute('select test') db2 = pool.connection() self.assertNotEqual(db1, db2) self.assertNotEqual(db1._con, db2._con) for i in range(7): db2.cursor().execute('select test') self.assertEqual(db1._con._con.num_queries, 5) self.assertEqual(db2._con._con.num_queries, 7) del db1 db1 = pool.connection() self.assertNotEqual(db1, db2) self.assertNotEqual(db1._con, db2._con) for i in range(3): db1.cursor().execute('select test') self.assertEqual(db1._con._con.num_queries, 8) db2.cursor().execute('select test') self.assertEqual(db2._con._con.num_queries, 8) pool = PooledDB(dbapi, 0, 0, 1) db1 = pool.connection() db2 = pool.connection() self.assertNotEqual(db1, db2) if shareable: self.assertEqual(db1._con, db2._con) else: self.assertNotEqual(db1._con, db2._con) del db1 db1 = pool.connection(0) self.assertNotEqual(db1, db2) self.assertNotEqual(db1._con, db2._con) def test16_ThreeThreadsTwoConnections(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety pool = PooledDB(dbapi, 2, 2, 0, 2, 1) from Queue import Queue, Empty queue = Queue(3) def connection(): try: queue.put(pool.connection(), 1, 0.1) except Exception: queue.put(pool.connection(), 1) from threading import Thread for i in range(3): Thread(target=connection).start() try: db1 = queue.get(1, 0.1) db2 = queue.get(1, 0.1) except TypeError: db1 = queue.get(1) db2 = queue.get(1) self.assertNotEqual(db1, db2) db1_con = db1._con db2_con = db2._con self.assertNotEqual(db1_con, db2_con) try: self.assertRaises(Empty, queue.get, 1, 0.1) except TypeError: self.assertRaises(Empty, queue.get, 0) del db1 try: db1 = queue.get(1, 0.1) except TypeError: db1 = queue.get(1) self.assertNotEqual(db1, db2) self.assertNotEqual(db1._con, db2._con) self.assertEqual(db1._con, db1_con) pool = PooledDB(dbapi, 2, 2, 1, 2, 1) db1 = pool.connection(0) db2 = pool.connection(0) self.assertNotEqual(db1, db2) db1_con = db1._con db2_con = db2._con self.assertNotEqual(db1_con, db2_con) Thread(target=connection).start() try: self.assertRaises(Empty, queue.get, 1, 0.1) except TypeError: self.assertRaises(Empty, queue.get, 0) del db1 try: db1 = queue.get(1, 0.1) except TypeError: db1 = queue.get(1) self.assertNotEqual(db1, db2) self.assertNotEqual(db1._con, db2._con) self.assertEqual(db1._con, db1_con) if __name__ == '__main__': unittest.main() PKBM58JÈ…âGG DBUtils/Testing/TestSteadyDB.pyo;ò õÇFc@s8dZdZdZdZdkZeieZdZde fd„ƒYZ de fd „ƒYZ d e fd „ƒYZ d e fd „ƒYZ de fd„ƒYZeed„Zdfd„ƒYZdfd„ƒYZdkZeiiddƒdklZdeifd„ƒYZedjoeiƒndS(sÙTest the SteadyDB module. Note: We do not test any real DB-API 2 module, but we just mock the basic DB-API 2 connection functionality. Copyright and credit info: * This test was contributed by Christoph Zwerschke s0.9.4s $Rev: 6696 $s5$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $NisErrorcBstZRS(N(s__name__s __module__(((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysErrorss DatabaseErrorcBstZRS(N(s__name__s __module__(((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys DatabaseErrorssOperationalErrorcBstZRS(N(s__name__s __module__(((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysOperationalErrorss InternalErrorcBstZRS(N(s__name__s __module__(((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys InternalErrorssProgrammingErrorcBstZRS(N(s__name__s __module__(((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysProgrammingErrorscCst||ƒSdS(N(s Connectionsdatabasesuser(sdatabasesuser((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysconnect ss ConnectioncBs>tZeed„Zd„Zd„Zd„Zed„ZRS(NcCsc||_||_d|_d|_d|_g|_|djod|_t‚nd|_dS(Niserrori( sdatabasesselfsusers open_cursorssnum_usess num_queriesssessionsvalidsOperationalError(sselfsdatabasesuser((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys__init__%s         cCsF|i o t‚nd|_d|_d|_g|_d|_dS(Ni(sselfsvalids InternalErrors open_cursorssnum_usess num_queriesssession(sself((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysclose1s      cCs|iidƒdS(Nscommit(sselfssessionsappend(sself((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pyscommit:scCs|iidƒdS(Nsrollback(sselfssessionsappend(sself((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysrollback=scCs&|i o t‚nt||ƒSdS(N(sselfsvalids InternalErrorsCursorsname(sselfsname((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pyscursor@s  (s__name__s __module__sNones__init__sclosescommitsrollbackscursor(((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys Connection#s   sCursorcBsAtZed„Zd„Zd„Zd„Zd„Zd„ZRS(NcCsN||_t|_|djod|_t‚n|id7_d|_dS(Nserrorii(sconsselfsNonesresultsnamesvalidsOperationalErrors open_cursors(sselfsconsname((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys__init__Gs     cCs4|i o t‚n|iid8_d|_dS(Nii(sselfsvalids InternalErrorscons open_cursors(sself((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysclosePs  cCs¦|i p |ii o t‚n|iid7_|idƒo#|iid7_|d|_n;|idƒo$|ii i |dƒt |_nt ‚dS(Nisselect isset i( sselfsvalidscons InternalErrorsnum_usess operations startswiths num_queriessresultssessionsappendsNonesProgrammingError(sselfs operation((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysexecuteVs  cCs/|i o t‚n|i}t|_|SdS(N(sselfsvalids InternalErrorsresultsNone(sselfsresult((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysfetchonecs     cCs9|i p |ii o t‚n|iid7_dS(Ni(sselfsvalidscons InternalErrorsnum_uses(sselfsprocname((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pyscallprocjs cCs|io|iƒndS(N(sselfsvalidsclose(sself((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys__del__os ( s__name__s __module__sNones__init__sclosesexecutesfetchonescallprocs__del__(((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pysCursorEs    is../..(sconnects TestSteadyDBcBsPtZd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„Z RS( NcCs't}dkl}|i||ƒdS(N(s __version__(s __version__sTestSteadyDBVersionsDBUtils.SteadyDBsSteadyDBVersionsselfs assertEqual(sselfsSteadyDBVersionsTestSteadyDBVersion((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pystest0_CheckVersion{s cCstdddƒ}|it|dƒƒ|i|idƒ|it|dƒƒ|i|idƒ|it|dƒƒ|it|dƒƒ|it|dƒƒ|it|dƒƒ|it|d ƒƒ|it|d ƒƒ|it|d ƒƒ|i|iƒ|i|i d ƒxPt d ƒD]B}|i ƒ}|i|i dƒ|i ƒ|i|i d ƒq.Wg}x>t d ƒD]0}|i|i ƒƒ|i|i |dƒq‡W~|i|i d ƒ|i ƒ}|it|dƒƒ|it|dƒƒ|it|dƒƒ|it|dƒƒ|it|d ƒƒ|i|iƒ|i|i dƒxet d ƒD]W}|i|i|ƒ|i|i|ƒ|id|ƒ|i|iƒd|ƒq{W|i|iƒ|i|i dƒx!t dƒD]}|idƒqW|i ƒ|i|i ƒ|i|i d ƒ|i|idƒ|i|id ƒ|it|i ƒ|it|idƒ|i|iƒ|i ƒ|i|i ƒ|i|id ƒ|i|id ƒ|it|i ƒ|it|i ƒdS(NsSteadyDBTestDBsusersSteadyDBTestUsersdatabasescursorscloses open_cursorssnum_usess num_queriesssessionsvalidiiisexecutesfetchonescallprocs select test%dstest%distestis select test(sconnectsdbsselfsassert_shasattrs assertEqualsdatabasesusersvalids open_cursorssrangesiscursorsclosesappendsnum_usess num_queriessexecutesfetchonescallprocs assertRaisess InternalError(sselfsisdbscursor((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pystest1_MockedDBConnection€sz          cCsØttddƒ}xtdƒD]}|iƒqW~|itttddƒttddƒ}|i ƒ}xtdƒD]}|iƒqzW|i dƒ}xtdƒD]}|iƒqªW|it|i dƒdS(Nsdatabasesokiserror( sSteadyDBconnectsdbapisdbsrangesisclosesselfs assertRaisessOperationalErrorscursor(sselfsisdbscursor((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pystest2_BrokenDBConnection»s"      cCsÁxºddfD]¬}ttƒ}||_|i|iiƒ|i ƒ|i||iiAƒ|i ƒ|i||iiAƒ|i ƒ|i|ii ƒ|i ƒ|i|ii ƒq WdS(Nii( s closeablesSteadyDBconnectsdbapisdbs _closeablesselfsassert_s_consvalidscloses_close(sselfsdbs closeable((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pystest3_SteadyDBCloseËs       cCsHttdtdddƒ}|it|dƒƒ|it|dƒƒ|i|idƒ|it|i dƒƒ|i|i i ƒ|it|i dƒƒ|it|i d ƒƒ|it|i d ƒƒ|it|i d ƒƒ|it|i d ƒƒ|it|i d ƒƒ|it|i dƒƒ|i|i i dƒ|it|i dƒƒ|i|i i dƒ|it|dƒƒ|it|d ƒƒ|i|i i dƒxVtdƒD]H}|iƒ}|i|i i dƒ|iƒ|i|i i dƒqÉWg}xAtdƒD]3}|i|iƒƒ|i|i i |dƒq(W~|i|i i dƒ|iƒ}|it|dƒƒ|it|dƒƒ|it|dƒƒ|it|d ƒƒ|it|dƒƒ|i|i ƒ|i|i i dƒx~tdƒD]p}|i|i|ƒ|i|i i|ƒ|i|i i|ƒ|id|ƒ|i|iƒd|ƒq%W|i|i ƒ|i|i i dƒx!tdƒD]}|idƒqÌW|iƒ|i|i ƒ|i|i i dƒ|i|idƒ|i|i idƒ|i|i idƒ|iƒ|idƒ|i|i ƒ|i|i i dƒ|i|iƒdƒ|i|idƒ|i|i idƒ|i|i idƒ|i|i i ƒ|iƒ|i|i i ƒ|i|i i dƒ|i|idƒ|i|i idƒ|i|i idƒ|it|i iƒ|iƒ|it|i iƒ|iƒ}|i|i i ƒ|idƒ|i|iƒdƒ|idƒ|i|iƒdƒ|idƒ|i|idƒ|i|i idƒ|i|i id ƒ|iƒ}|i|i i d ƒ|id!ƒ|i|iƒd"ƒ|i|i idƒ|iƒ|i|i i dƒ|i|i idƒ|iƒ}|i|i ƒ|idƒd|i_ |i|i ƒ|it|iidƒ|idƒ|i|i ƒ|iidƒ|i|id ƒ|i|i idƒd|i _ |i_ |idƒ|i|i ƒ|i|idƒ|i|i idƒ|id#ƒ|iƒ|id$ƒ|iƒ|i|i id%d&d'd(gƒdS()NisSteadyDBTestDBsusersSteadyDBTestUsers_cons_usagesvalidscursorscloses open_cursorssnum_usess num_queriesssessionsdatabaseiisexecutesfetchonescallprocs select test%dstest%distestis select test8stest8is select test11stest11s select test12stest12is select test13stest13sset doitsset dontsdoitscommitsdontsrollback(sSteadyDBconnectsdbapisNonesdbsselfsassert_shasattrs assertEquals_usages_consvalidsdatabasesusers open_cursorssrangesiscursorsclosesappendsnum_usess num_queriessexecutesfetchonescallprocs assertRaisess InternalErrorscursor2s_cursorscommitsrollbackssession(sselfsisdbscursorscursor2((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pystest4_SteadyDBConnectionÙsê                             cCsÈttdtdddƒ}ttdtdddƒ}|i|iƒ|iƒƒ|i|iƒ|iƒƒ|i|i |i ƒ|i|i |i ƒ|i|i |i ƒ|i ƒ|i ƒdS(NisSteadyDBTestDBsusersSteadyDBTestUser( sSteadyDBconnectsdbapisNonesdb1sconnectsdb2sselfs assertEquals threadsafetys_creators_argss_kwargssclose(sselfsdb1sdb2((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys'test5_SteadyDBConnectionCreatorFunctionLs   cCsSttdƒ}|iƒ}x¥tdƒD]—}|id|ƒ|iƒ}|i |d|ƒ|i |i i ƒ|dd}|i |i|ƒ|i |i i|ƒ|i |i i|ƒq(W|i |i idƒxtdƒD]s}|idƒ|i |i i ƒ|dd}|i |i|ƒ|i |i i|ƒ|i |i idƒqæWx¹tdƒD]«}|djod|i _ |i_ n|id|ƒ|iƒ}|i |d|ƒ|dd}|i |i|ƒ|i |i i|ƒ|i |i i|ƒqjWxÇtdƒD]¹}|d jod|i _ |i_ n|idƒ||d jod pd dd}|i |i|ƒ|i |i i|ƒ|d jod pd}|i |i i|ƒq&W|iƒ|id ƒ|i |iƒd ƒ|i |idƒ|i |i idƒ|i |i idƒdS(Ni ids select test%dstest%distestiiiiiûÿÿÿs select test1stest1(sSteadyDBconnectsdbapisdbscursorsrangesisexecutesfetchonesrsselfs assertEqualsassert_s_consvalidsjs_usagesnum_usess num_queriess open_cursorsscallprocs_cursorsclose(sselfsisjsdbscursorsr((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys test6_SteadyDBConnectionMaxUsageYs`           &  cCsàttdddfƒ}|it|dƒƒ|i|idƒ|it|idƒƒ|i|ii dƒ|it|idƒƒ|i|ii dƒ|it|id ƒƒ|i|ii dƒ|it|id ƒƒ|it |ii ƒd d fƒx'td ƒD]}|iƒidƒqW|i|ii dƒ|i|idƒ|i|ii dƒ|i|ii dƒ|i|ii d d gƒ|iƒidƒ|i|ii dƒ|i|idƒ|i|ii dƒ|i|ii dƒ|i|ii d d dgƒ|iƒidƒ|i|ii dƒ|i|idƒ|i|ii dƒ|i|ii dƒ|i|ii d d gƒ|iƒidƒ|i|ii dƒ|i|idƒ|i|ii dƒ|i|ii dƒ|i|ii d d dgƒ|iƒidƒ|i|ii dƒ|i|idƒ|i|ii dƒ|i|ii dƒ|i|ii d d dgƒ|iƒ|iƒidƒ|i|ii dƒ|i|idƒ|i|ii dƒ|i|ii dƒ|i|ii d d dgƒ|iƒ|iƒidƒ|i|ii dƒ|i|idƒ|i|ii dƒ|i|ii dƒ|i|ii d d gƒdS(Nis set time zones set datestyles_usageis open_cursorssnum_usesis num_queriesssessions time zones datestylei s select testisset testistesti(sSteadyDBconnectsdbapisdbsselfsassert_shasattrs assertEquals_usages_cons open_cursorssnum_usess num_queriesstuplessessionsrangesiscursorsexecutesclose(sselfsisdb((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys"test7_SteadyDBConnectionSetSession‡sr"   ( s__name__s __module__stest0_CheckVersionstest1_MockedDBConnectionstest2_BrokenDBConnectionstest3_SteadyDBClosestest4_SteadyDBConnections'test5_SteadyDBConnectionCreatorFunctions test6_SteadyDBConnectionMaxUsages"test7_SteadyDBConnectionSetSession(((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys TestSteadyDBys  ;   s .s__main__(s__doc__s __version__s __revision__s__date__ssyssmoduless__name__sdbapis threadsafetys StandardErrorsErrors DatabaseErrorsOperationalErrors InternalErrorsProgrammingErrorsNonesconnects ConnectionsCursorsunittestspathsinsertsDBUtils.SteadyDBsSteadyDBconnectsTestCases TestSteadyDBsmain(sProgrammingErrorssyss __revision__s TestSteadyDBsconnects InternalErrors__date__sSteadyDBconnects Connections DatabaseErrorsOperationalErrorsErrors __version__sCursorsunittests threadsafetysdbapi((s@build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestSteadyDB.pys? s*  "/  ÿJ PKBM58ñ4ñ ñ $DBUtils/Testing/TestPersistentDB.pyo;ò õÇFc@sdZdZdZdZdkZdkZeiiddƒdkl Z dk l Z d ei fd „ƒYZed joeiƒndS( sBTest the PersistentDB module. Note: We don't test performance here, so the test does not predicate whether PersistentDB actually will help in improving performance or not. We also assume that the underlying SteadyDB connections are tested. Copyright and credit info: * This test was contributed by Christoph Zwerschke s0.9.4s $Rev: 6696 $s5$Date: 2007-07-07 11:02:24 -0600 (Sat, 07 Jul 2007) $Nis../..(s TestSteadyDB(s PersistentDBsTestPersistentDBcBsGtZd„Zd„Zd„Zd„Zd„Zd„Zd„ZRS(NcCs dt_dS(Ni(sdbapis threadsafety(sself((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pyssetUpscCs't}dkl}|i||ƒdS(N(s __version__(s __version__sTestPersistentDBVersionsDBUtils.PersistentDBsPersistentDBVersionsselfs assertEqual(sselfsPersistentDBVersionsTestPersistentDBVersion((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pystest0_CheckVersion!s cCs>dkl}x*tdfD]t_|i|ttƒqWdS(N(sNotSupportedErrori(sDBUtils.PersistentDBsNotSupportedErrorsNonesdbapis threadsafetysselfs assertRaisess PersistentDB(sselfsNotSupportedError((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pystest1_NoThreadsafety&s  cCsÍxÆddfD]¸}ttƒ}||_|iƒ}|i|i i ƒ|i ƒ|i||i i Aƒ|i ƒ|i||i i Aƒ|i ƒ|i|i i ƒ|i ƒ|i|i i ƒq WdS(Nii( s closeables PersistentDBsdbapispersists _closeables connectionsdbsselfsassert_s_consvalidscloses_close(sselfsdbs closeablespersist((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pystest2_PersistentDBClose+s        c s¸d}ttƒ‰dˆ_dkl}l‰ggf\‰‰x:t |ƒD],}ˆi |dƒƒˆi |dƒƒqMW‡‡‡‡d†}dk l}g} xCt |ƒD]5}|d|d|fƒ}| i |ƒ|iƒq²WxYt |ƒD]K}yˆ|iddd ƒWqøtj oˆ|iddƒqøXqøWx‚t |ƒD]t}yˆ|idd ƒ} Wn&tj oˆ|idƒ} nX|i| d |ƒ|i| |iƒƒqTWxÆt |ƒD]¸}x¯t |dƒD]}y5ˆ|id |dd ƒˆ|idd ƒ} Wn>tj o2ˆ|id |dƒˆ|idƒ} nX|i| d ||d|fƒqðWqÙWyˆdid dd ƒWn'tj oˆdid dƒnXyˆdidd ƒ} Wn&tj oˆdidƒ} nX|i| dƒy1ˆdiddd ƒˆdidd ƒ} Wn:tj o.ˆdiddƒˆdidƒ} nX|i| dƒx¨t dƒD]š}y5ˆdid |dd ƒˆdidd ƒ} Wn>tj o2ˆdid |dƒˆdidƒ} nX|i| d|d|fƒq¸Wxpt |ƒD]b}|i| |iƒƒyˆ|iddd ƒWqctj oˆ|iddƒqcXqcWxŒt |ƒD]~}yˆ|idd ƒ} Wn&tj oˆ|idƒ} nX|i| d||dfƒ|i| |iƒƒqÖWxYt |ƒD]K}yˆ|itddƒWqetj oˆ|itdƒqeXqeWdS(Nii(sQueuesEmptycs~ˆiƒ}xanoYyGyˆ|iddƒ}Wn&tj oˆ|idƒ}nXWnˆj o t }nX| oPnˆiƒ}||jo d}nh|djo d}nQ|djo|i ƒd}n0|i ƒ}|i|ƒ|iƒ}|i ƒd||i|f}yˆ|i|ddƒWqtj oˆ|i|dƒqXqW|i ƒdS( Niserror - not persistentspingsok - thread alivesclosesok - connection closeds %d(%d): %sf0.10000000000000001(spersists connectionsthis_dbs queryQueuesisgetsqs TypeErrorsEmptysNonesdbsrsclosescursorsexecutesfetchones_usages resultQueuesput(siscursorsdbsqsthis_dbsr(s resultQueues queryQueuespersistsEmpty(sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pys runQueriesCs<              (sThreadstargetsargsspingf0.10000000000000001s%d(0): ok - thread alives select test%ds%d(%d): test%ds select test4s 1(3): test4scloses1(3): ok - connection closedis 1(%d): test%ds%d(%d): ok - thread alive(s numThreadss PersistentDBsdbapispersists _closeablesQueuesEmptys queryQueues resultQueuesrangesisappends runQueriess threadingsThreadsthreadssthreadsstartsputs TypeErrorsgetsrsselfs assertEqualsassert_sisAlivesjsNone(sselfs runQueriessthreadsThreadsis numThreadss resultQueuesjsQueues queryQueuesthreadsspersistsrsEmpty((s resultQueues queryQueuespersistsEmptysDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pystest3_PersistentDBThreads:s°         ) "   cCsðttdƒ}|iƒ}|i|idƒx»tdƒD]­}|i ƒ}|i d|ƒ|i ƒ}|iƒ|i|d|ƒ|i|iiƒ|dd}|i|i|ƒ|i|ii|ƒ|i|ii|ƒq;WdS(Niids select test%dstest%di(s PersistentDBsdbapispersists connectionsdbsselfs assertEquals _maxusagesrangesiscursorsexecutesfetchonesrsclosesassert_s_consvalidsjs_usagesnum_usess num_queries(sselfsisjsdbscursorsrspersist((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pystest4_PersistentDBMaxUsage©s     cCs ttddfƒ}|iƒ}|i|idƒ|i|idfƒ|i|i i dgƒ|i ƒ}|i dƒ|i ƒ|iƒx]tdƒD]O}|i|i i ddgƒ|i ƒ}|i dƒ|i ƒ|iƒqW|i|i i dgƒdS(Nis set datestyles datestylesset teststests select test(s PersistentDBsdbapispersists connectionsdbsselfs assertEquals _maxusages_setsession_sqls_conssessionscursorsexecutesfetchonesclosesrangesi(sselfsisdbscursorspersist((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pystest5_PersistentDBSetSession¹s"         ( s__name__s __module__ssetUpstest0_CheckVersionstest1_NoThreadsafetystest2_PersistentDBClosestest3_PersistentDBThreadsstest4_PersistentDBMaxUsagestest5_PersistentDBSetSession(((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pysTestPersistentDBs     o s__main__(s__doc__s __version__s __revision__s__date__ssyssunittestspathsinsertsDBUtils.Testings TestSteadyDBsdbapisDBUtils.PersistentDBs PersistentDBsTestCasesTestPersistentDBs__name__smain(ssyss __revision__sunittestsTestPersistentDBs__date__s __version__s PersistentDBsdbapi((sDbuild/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/TestPersistentDB.pys? s    ° PK7M58h&IŒŒDBUtils/Testing/__init__.pyc;ò õÇFc@sdS(N((((s<build/bdist.darwin-8.0.1-x86/egg/DBUtils/Testing/__init__.pys?sPKBM58 æ²9²9 DBUtils/Testing/TestSteadyPg.pyo;ò õÇFc@sdZdZdZdZdkZeieeidMM ¤‹1DBUtils/Docs/RelNotes-0.9.3.htmlPK¼hç6/ó'] ] ¤6DBUtils/Docs/dbdep.gifPK¼hç6=ÙX< < <¤§@DBUtils/Docs/UsersGuide.zh.txtPK¼hç6`]@6„„¤ï|DBUtils/Docs/DocUtils.cssPK(tç6}Gì88 ¤ªŽDBUtils/Docs/RelNotes-0.9.4.htmlPK¼hç6¬©»Ëïï ¤ ’DBUtils/Docs/RelNotes-0.8.1.htmlPK¼hç6xÔô/¡¡ ¤M”DBUtils/Docs/RelNotes-0.9.1.htmlPK¼hç6Ñ,¢î¦x¦x¤,˜DBUtils/Docs/UsersGuide.htmlPK¼hç6E.™]‹]‹¤ DBUtils/Docs/UsersGuide.de.htmlPK¼hç6Vú•›ÄÄ ¤¦œDBUtils/Docs/RelNotes-0.9.2.htmlPK7M58”ªî¼’’&¤¨ŸDBUtils/Testing/TestSimplePooledPg.pycPK9M58íJÂ;K)K) ¤~¹DBUtils/Testing/TestPooledPg.pycPK¼hç6 Xˆ¤ãDBUtils/Testing/__init__.pyPK8M58Ï /Z Z &¤RãDBUtils/Testing/TestSimplePooledDB.pycPK¼hç6ÍùªÇ Ç %¤ðDBUtils/Testing/TestSimplePooledPg.pyPK¼hç6^ž¤À ( (¤úDBUtils/Testing/TestSteadyPg.pyPK8M58JÈ…âGG ¤D:DBUtils/Testing/TestSteadyDB.pycPKBM58¬ BÓôô$¤žDBUtils/Testing/TestPersistentPg.pyoPK¼hç6=&ƒýSS#¤ÔžDBUtils/Testing/TestPersistentPg.pyPKAM58h&IŒŒ¤h³DBUtils/Testing/__init__.pyoPK¼hç6ãe¹bb#¤.´DBUtils/Testing/TestPersistentDB.pyPK¼hç6¼˜J!7!7¤ÑÊDBUtils/Testing/TestSteadyDB.pyPK7M58ñ4ñ ñ $¤/ DBUtils/Testing/TestPersistentDB.pycPK7M58 æ²9²9 ¤b# DBUtils/Testing/TestSteadyPg.pycPKAM58”ªî¼’’&¤R] DBUtils/Testing/TestSimplePooledPg.pyoPK7M58¬ BÓôô$¤(w DBUtils/Testing/TestPersistentPg.pycPKBM58íJÂ;K)K) ¤^” DBUtils/Testing/TestPooledPg.pyoPK¼hç6…CêÙaa%¤ç½ DBUtils/Testing/TestSimplePooledDB.pyPK¼hç6ûÉ<‹¬ƒ¬ƒ¤‹Ï DBUtils/Testing/TestPooledDB.pyPKBM58JÈ…âGG ¤tS DBUtils/Testing/TestSteadyDB.pyoPKBM58ñ4ñ ñ $¤Îš DBUtils/Testing/TestPersistentDB.pyoPK7M58h&IŒŒ¤¼ DBUtils/Testing/__init__.pycPKBM58 æ²9²9 ¤Ç¼ DBUtils/Testing/TestSteadyPg.pyoPK8M58kYn6¥{¥{ ¤·ö DBUtils/Testing/TestPooledDB.pycPKBM58Ï /Z Z &¤šr DBUtils/Testing/TestSimplePooledDB.pyoPK¼hç6ƈàL!L!¤8“ DBUtils/Testing/TestPooledPg.pyPKBM58kYn6¥{¥{ ¤Á´ DBUtils/Testing/TestPooledDB.pyoPK%M58l¿Èˆþþ¤¤0 EGG-INFO/SOURCES.txtPK$M58“×2¤Ô5 EGG-INFO/dependency_links.txtPK#M58%Zq§::¤6 EGG-INFO/PKG-INFOPK#M58ƒáT¨¤y: EGG-INFO/top_level.txtPKÈhç6¤µ: EGG-INFO/not-zip-safePKXX3è: