Remy Blank wrote:
> Christian Boos wrote:
>
>> Rather, the comparison with the "with" approach made me think we should
>> instead propagate the value returned by the implementation function,
>> otherwise we would have no way to communicate something from there to
>> the outside.
>>
>
> Not quite true. The usual trick is to allocate a list in the surrounding
> scope, and to mutate the array in the transaction function.
>
> retval = [0]
>
> @with_transaction(env, db)
> def renamne(db):
> # ... transaction body ...
> retval[0] = 1
>
Ah yes ;-)
That's more explicit than the return trick, and when switching to
"with", we'll just have to remove the list.
> (snip)
> Could we start with as little magic as possible, and only add the magic
> if/when we really need it?
>
Ok, reading more about context managers show that swallowing exceptions
should be ... the exception.
Updated sample code accordingly.
-- Christian
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Trac
Development" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/trac-dev?hl=en
-~----------~----~----~----~------~----~------~--~---
from __future__ import with_statement # this requires Python 2.5 or 2.6
class Connection(object):
def __init__(self, fail):
self._fail = fail
def execute(self):
if self._fail:
print '>> arghh!'
a = int('')
else:
print '>> execute something successfully...'
def commit(self):
print '>> commit transaction'
def rollback(self):
print '>> rollback transaction'
class Environment(object):
def __init__(self, fail):
self._fail = fail
def get_db_cnx(self):
print ">> Environment.get_db_cnx"
return Connection(self._fail)
def with_transaction(env, db):
""" ... """
def wrap(fn):
if db:
fn(db)
else:
tmpdb = env.get_db_cnx()
try:
fn(tmpdb)
tmpdb.commit()
except Exception:
tmpdb.rollback()
raise
return wrap
class transaction(object):
def __init__(self, env, db):
self._env = env
self._db = db
def __enter__(self):
if not self._db:
self._db = self._env.get_db_cnx()
self._env = None
return self._db
def __exit__(self, et, ev, tb):
if self._env is None:
if et is None:
self._db.commit()
else:
self._db.rollback()
# Trac 0.12
def do_rename_deco(env, db=None):
new_name = [None]
@with_transaction(env, db)
def rename(db):
db.execute()
new_name[0] = 'renamed'
if new_name[0]:
print '> it worked:', new_name[0]
return True
else:
print '> rename failed'
# Trac 0.13
def do_rename_with(env, db=None):
new_name = None
with transaction(env, db) as db:
db.execute()
new_name = 'renamed' # modifies `new_name` above
if new_name:
print '> it worked:', new_name
return True
else:
print '> rename failed'
if __name__ == '__main__':
for do_rename in (do_rename_deco, do_rename_with):
for fail in (False, True):
env = Environment(fail)
print
print '== (fail=%r, do_rename=%r)' % (fail, do_rename)
print
print '-- testing automatic transaction'
try:
do_rename(env)
except:
pass
print
print '-- testing explicit transaction'
db = env.get_db_cnx()
try:
if do_rename(env, db) and do_rename(env, db):
db.commit()
else:
db.rollback()
except:
db.rollback()