Hello again,

I have installed a python2.4 again, and created two implementations of  
the transaction scheme, one for 2.4, which uses decorators, and one  
for 2.5, which uses with statements. In both cases I converted the  
WikiPage class to use the scheme, and both pass the complete unit test  
and functional test suits in the python versions they are supposed to  
work in.

Both are very very similar in their use, but I do think now, it would  
be unwise to have both implementations present at the same time in the  
code. Whether both implementations are present or not, it wold need  
need cleanup, once 2.4 support is dropped, and in the case of just  
having to replace the decorators with with-statements and the context  
managers, without all that version check code, this could be done with  
a quite simple sed script ...

What I did notice though is, that you can't get variables out of the  
with block. The overwriting of the new_name variable in the Trac 0.13  
example by Christian below isn't visible outside the with block. At  
least that is what the unit tests told me when I tried it. Maybe I'm  
not aware of something here.

If this proposal gets accepted, I would start converting all code to  
use the new scheme, as I have stated before.
If there are still objections, I would like to hear them.

Regards

Jan Schukat


--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---

Attachment: transactions_py2.5.diff
Description: Binary data

Attachment: transactions_py2.4.diff
Description: Binary data


On 08.10.2009, at 18:03, Christian Boos wrote:

> 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()
>

Reply via email to