Imported from SVN by Bitbucket
This commit is contained in:
120
Paste-1.7.5.1-py2.6.egg/paste/transaction.py
Executable file
120
Paste-1.7.5.1-py2.6.egg/paste/transaction.py
Executable file
@@ -0,0 +1,120 @@
|
||||
# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
|
||||
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
|
||||
# (c) 2005 Clark C. Evans
|
||||
# This module is part of the Python Paste Project and is released under
|
||||
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
"""
|
||||
Middleware related to transactions and database connections.
|
||||
|
||||
At this time it is very basic; but will eventually sprout all that
|
||||
two-phase commit goodness that I don't need.
|
||||
|
||||
.. note::
|
||||
|
||||
This is experimental, and will change in the future.
|
||||
"""
|
||||
from paste.httpexceptions import HTTPException
|
||||
from wsgilib import catch_errors
|
||||
|
||||
class TransactionManagerMiddleware(object):
|
||||
|
||||
def __init__(self, application):
|
||||
self.application = application
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
environ['paste.transaction_manager'] = manager = Manager()
|
||||
# This makes sure nothing else traps unexpected exceptions:
|
||||
environ['paste.throw_errors'] = True
|
||||
return catch_errors(self.application, environ, start_response,
|
||||
error_callback=manager.error,
|
||||
ok_callback=manager.finish)
|
||||
|
||||
class Manager(object):
|
||||
|
||||
def __init__(self):
|
||||
self.aborted = False
|
||||
self.transactions = []
|
||||
|
||||
def abort(self):
|
||||
self.aborted = True
|
||||
|
||||
def error(self, exc_info):
|
||||
self.aborted = True
|
||||
self.finish()
|
||||
|
||||
def finish(self):
|
||||
for trans in self.transactions:
|
||||
if self.aborted:
|
||||
trans.rollback()
|
||||
else:
|
||||
trans.commit()
|
||||
|
||||
|
||||
class ConnectionFactory(object):
|
||||
"""
|
||||
Provides a callable interface for connecting to ADBAPI databases in
|
||||
a WSGI style (using the environment). More advanced connection
|
||||
factories might use the REMOTE_USER and/or other environment
|
||||
variables to make the connection returned depend upon the request.
|
||||
"""
|
||||
def __init__(self, module, *args, **kwargs):
|
||||
#assert getattr(module,'threadsaftey',0) > 0
|
||||
self.module = module
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
|
||||
# deal with database string quoting issues
|
||||
self.quote = lambda s: "'%s'" % s.replace("'","''")
|
||||
if hasattr(self.module,'PgQuoteString'):
|
||||
self.quote = self.module.PgQuoteString
|
||||
|
||||
def __call__(self, environ=None):
|
||||
conn = self.module.connect(*self.args, **self.kwargs)
|
||||
conn.__dict__['module'] = self.module
|
||||
conn.__dict__['quote'] = self.quote
|
||||
return conn
|
||||
|
||||
def BasicTransactionHandler(application, factory):
|
||||
"""
|
||||
Provides a simple mechanism for starting a transaction based on the
|
||||
factory; and for either committing or rolling back the transaction
|
||||
depending on the result. It checks for the response's current
|
||||
status code either through the latest call to start_response; or
|
||||
through a HTTPException's code. If it is a 100, 200, or 300; the
|
||||
transaction is committed; otherwise it is rolled back.
|
||||
"""
|
||||
def basic_transaction(environ, start_response):
|
||||
conn = factory(environ)
|
||||
environ['paste.connection'] = conn
|
||||
should_commit = [500]
|
||||
def finalizer(exc_info=None):
|
||||
if exc_info:
|
||||
if isinstance(exc_info[1], HTTPException):
|
||||
should_commit.append(exc_info[1].code)
|
||||
if should_commit.pop() < 400:
|
||||
conn.commit()
|
||||
else:
|
||||
try:
|
||||
conn.rollback()
|
||||
except:
|
||||
# TODO: check if rollback has already happened
|
||||
return
|
||||
conn.close()
|
||||
def basictrans_start_response(status, headers, exc_info = None):
|
||||
should_commit.append(int(status.split(" ")[0]))
|
||||
return start_response(status, headers, exc_info)
|
||||
return catch_errors(application, environ, basictrans_start_response,
|
||||
finalizer, finalizer)
|
||||
return basic_transaction
|
||||
|
||||
__all__ = ['ConnectionFactory', 'BasicTransactionHandler']
|
||||
|
||||
if '__main__' == __name__ and False:
|
||||
from pyPgSQL import PgSQL
|
||||
factory = ConnectionFactory(PgSQL, database="testing")
|
||||
conn = factory()
|
||||
curr = conn.cursor()
|
||||
curr.execute("SELECT now(), %s" % conn.quote("B'n\\'gles"))
|
||||
(time, bing) = curr.fetchone()
|
||||
print bing, time
|
||||
|
||||
Reference in New Issue
Block a user