1
# Copyright (C) 2009, 2010 Canonical Ltd
1
# Copyright (C) 2009 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
31
31
If you want to be certain that the first, and only the first, error is raised,
34
operation = OperationWithCleanups(do_something)
34
operation = OperationWithCleanups(lambda operation: do_something())
35
35
operation.add_cleanup(cleanup_something)
36
operation.run_simple()
38
38
This is more inconvenient (because you need to make every try block a
39
39
function), but will ensure that the first error encountered is the one raised,
78
78
_run_cleanup(func, *args, **kwargs)
81
class ObjectWithCleanups(object):
82
"""A mixin for objects that hold a cleanup list.
84
Subclass or client code can call add_cleanup and then later `cleanup_now`.
87
self.cleanups = deque()
89
def add_cleanup(self, cleanup_func, *args, **kwargs):
90
"""Add a cleanup to run.
92
Cleanups may be added at any time.
93
Cleanups will be executed in LIFO order.
95
self.cleanups.appendleft((cleanup_func, args, kwargs))
97
def cleanup_now(self):
98
_run_cleanups(self.cleanups)
102
class OperationWithCleanups(ObjectWithCleanups):
81
class OperationWithCleanups(object):
103
82
"""A way to run some code with a dynamic cleanup list.
105
84
This provides a way to add cleanups while the function-with-cleanups is
113
92
where `some_func` is::
115
def some_func(operation, args, ...):
94
def some_func(operation, args, ...)
117
96
operation.add_cleanup(something)
120
99
Note that the first argument passed to `some_func` will be the
121
OperationWithCleanups object. To invoke `some_func` without that, use
122
`run_simple` instead of `run`.
100
OperationWithCleanups object.
125
103
def __init__(self, func):
126
super(OperationWithCleanups, self).__init__()
105
self.cleanups = deque()
107
def add_cleanup(self, cleanup_func, *args, **kwargs):
108
"""Add a cleanup to run.
110
Cleanups may be added at any time before or during the execution of
111
self.func. Cleanups will be executed in LIFO order.
113
self.cleanups.appendleft((cleanup_func, args, kwargs))
129
115
def run(self, *args, **kwargs):
130
116
return _do_with_cleanups(
131
117
self.cleanups, self.func, self, *args, **kwargs)
133
def run_simple(self, *args, **kwargs):
134
return _do_with_cleanups(
135
self.cleanups, self.func, *args, **kwargs)
138
120
def _do_with_cleanups(cleanup_funcs, func, *args, **kwargs):
139
121
"""Run `func`, then call all the cleanup_funcs.
188
170
# but don't propagate them.
189
171
_run_cleanup(cleanup, *c_args, **kwargs)
190
172
if exc_info is not None:
192
raise exc_info[0], exc_info[1], exc_info[2]
173
raise exc_info[0], exc_info[1], exc_info[2]
195
174
# No error, so we can return the result