Added module gaphor.transaction

git-svn-id: file:///Users/arjan/backup/gaphor/gaphor/trunk@1204 a8418922-720d-0410-834f-a69b97ada669
This commit is contained in:
Arjan Molenaar 2007-04-10 06:58:03 +00:00
parent e621eede0f
commit 65d8c5c389
2 changed files with 171 additions and 0 deletions

63
gaphor/transaction.py Normal file
View File

@ -0,0 +1,63 @@
"""
Transation support for Gaphor
"""
from zope import interface, component
from gaphor.interfaces import ITransaction
from gaphor.event import TransactionBegin, TransactionCommit, TransactionRollback
def transactional(func):
def _transactional(*args, **kwargs):
tx = Transaction()
try:
func(*args, **kwargs)
except:
tx.rollback()
raise
else:
tx.commit()
return _transactional
class TransactionError(Exception):
"""
Errors related to the transaction module.
"""
class Transaction(object):
interface.implements(ITransaction)
_stack= []
def __init__(self):
self._need_rollback = False
if not self._stack:
component.handle(TransactionBegin())
self._stack.append(self)
def commit(self):
self._close()
# if self._need_rollback:
# log.warning('Tried to commit a transaction already marked for rollback.')
if not self._stack:
if self._need_rollback:
component.handle(TransactionRollback())
else:
component.handle(TransactionCommit())
def rollback(self):
self._close()
# Mark every tx on the stack for rollback
for tx in self._stack:
tx._need_rollback = True
if not self._stack:
component.handle(TransactionRollback())
def _close(self):
try:
last = self._stack.pop()
except IndexError:
raise TransactionError, 'No Transaction on stack.'
if last is not self:
self._stack.append(last)
raise TransactionError, 'Transaction on stack is not the transaction being closed.'

108
gaphor/transaction.txt Normal file
View File

@ -0,0 +1,108 @@
Transaction support for Gaphor
==============================
Transaction support is located in module gaphor.transaction:
>>> from gaphor import transaction
The Transaction class is used mainly to signal the begin and end of a transaction. This is done by the TransactionBegin, TransactionCommit and TransactionRollback events:
>>> from zope import component
>>> @component.adapter(transaction.TransactionBegin)
... def transaction_begin_handler(event):
... print 'tx begin'
>>> component.provideHandler(transaction_begin_handler)
Same goes for commit and rollback events:
>>> @component.adapter(transaction.TransactionCommit)
... def transaction_commit_handler(event):
... print 'tx commit'
>>> component.provideHandler(transaction_commit_handler)
>>> @component.adapter(transaction.TransactionRollback)
... def transaction_rollback_handler(event):
... print 'tx rollback'
>>> component.provideHandler(transaction_rollback_handler)
A Transaction is started by initiating a Transaction instance:
>>> tx = transaction.Transaction()
tx begin
On success, a transaction can be committed:
>>> tx.commit()
tx commit
After a commit, a rollback is no longer allowed (the transaction is closed):
>>> tx.rollback()
... # doctest: +ELLIPSIS
Traceback (most recent call last):
...
TransactionError: No Transaction on stack.
Transactions may be nested:
>>> tx = transaction.Transaction()
tx begin
>>> tx2 = transaction.Transaction()
>>> tx2.commit()
>>> tx.commit()
tx commit
Transactions should be closed in the right order (subtransactions first):
>>> tx = transaction.Transaction()
tx begin
>>> tx2 = transaction.Transaction()
>>> tx.commit()
... # doctest: +ELLIPSIS
Traceback (most recent call last):
...
TransactionError: Transaction on stack is not the transaction being closed.
>>> tx2.commit()
>>> tx.commit()
tx commit
The transactional decorator can be used to mark functions as transactional:
>>> @transaction.transactional
... def a():
... print 'do something'
>>> a()
tx begin
do something
tx commit
If an exception is raised from within the decorated function a rollback is
performed:
>>> @transaction.transactional
... def a():
... raise IndexError, 'bla'
>>> a()
... # doctest: +ELLIPSIS
Traceback (most recent call last):
...
IndexError: bla
>>> transaction.Transaction._stack
[]
All transactions are marked for rollback once an exception is raised:
>>> tx = transaction.Transaction()
tx begin
>>> a()
... # doctest: +ELLIPSIS
Traceback (most recent call last):
...
IndexError: bla
>>> tx._need_rollback
True
>>> tx.commit()
tx rollback