[RFC/MERGE][#243391] _run_and_cleanup helper (alternative to try/finally)
Andrew Bennetts
andrew.bennetts at canonical.com
Wed Oct 8 07:07:05 BST 2008
Hi all,
This patch is an extension of my fix for bug 230902 at
<http://bundlebuggy.aaronbentley.com/request/%3C20081008054310.GC19754@steerpike.home.puzzling.org%3E>.
I'm looking for opinions on the API defined by the attached patch. I'm
especially interested in ideas for a more convenient alternative. I'm
also interested ideas for a better home for this function than
bzrlib/branch.py :)
The patch defines a function, _run_and_cleanup:
def _run_and_cleanup(cleanup, callable, *args, **kwargs):
"""Like ``callable(*args, **kwargs); cleanup()``, but errors from callable.
e.g.::
branch.lock_write()
_run_and_cleanup(branch.unlock, branch.push, ...)
If an exception is raised by callable, then that exception *will* be
propagated, even if the cleanup function raises its own error.
"""
# This is very similar to bzrlib.decorators.needs_write_lock. Perhaps they
# should share code?
try:
result = callable(*args, **kwargs)
except:
exc_info = sys.exc_info()
try:
cleanup()
finally:
raise exc_info[0], exc_info[1], exc_info[2]
else:
cleanup()
return result
This is a little more flexible than the _run_with_write_locked_target
helper in my previous patch, because it doesn't assume that you want to
call foo.lock_write before the callable or foo.unlock after.
So for instance, _run_with_write_locked_target is now implemented as:
def _run_with_write_locked_target(target, callable, *args, **kwargs):
# [docstring snipped]
target.lock_write()
return _run_and_cleanup(target.unlock, callable, *args, **kwargs)
The idea is that anywhere where we have a finally block where we
*don't* want an exception from the corresponding try block to be
squashed, we should use _run_and_cleanup instead of try/finally.
A quick grep of finally blocks in the codebase (try “grep -A1 -Irn
finally: bzrlib/ | grep -B1 unlock | less” for example) suggests that we
have lots of places in the code that may need changing one way or other.
This patch also updates bzrlib/commit.py to use this to run its cleanup
function, to demonstrate how it looks to use in real code. This should
fix <https://bugs.launchpad.net/bzr/+bug/243391>! But this demonstrates
the main drawback of this approach: it typically requires defining a new
function for no purpose other than to have code run from within
_run_and_cleanup. This tends to make code be littered with “_foo_inner”
methods with fairly arbitrary arguments. It may be that this is the
price we have to pay — it certainly seems better than embedding the
eleven lines of _run_and_cleanup directly into the function.
So, feedback sought.
-Andrew.
More information about the bazaar
mailing list