diff options
Diffstat (limited to 'odoo/tools')
| -rw-r--r-- | odoo/tools/misc.py | 96 |
1 files changed, 57 insertions, 39 deletions
diff --git a/odoo/tools/misc.py b/odoo/tools/misc.py index 31e391fe30e..5173e046467 100644 --- a/odoo/tools/misc.py +++ b/odoo/tools/misc.py @@ -1084,54 +1084,72 @@ class LastOrderedSet(OrderedSet): OrderedSet.add(self, elem) -class GroupCalls: - """ A collection of callbacks with support for aggregated arguments. Upon - call, every registered function is called once with positional arguments. - When registering a function, a tuple of positional arguments is returned, so - that the caller can modify the arguments in place. This allows to - accumulate some data to process once:: +class Callbacks: + """ A simple queue of callback functions. Upon run, every function is + called (in addition order), and the queue is emptied. - callbacks = GroupCalls() + callbacks = Callbacks() - # register print (by default with a list) - [args] = callbacks.register(print, list) - args.append(42) + # add foo + def foo(): + print("foo") - # add an element to the list to print - [args] = callbacks.register(print, list) - args.append(43) + callbacks.add(foo) - # print "[42, 43]" - callbacks() + # add bar + callbacks.add + def bar(): + print("bar") + + # add foo again + callbacks.add(foo) + + # call foo(), bar(), foo(), then clear the callback queue + callbacks.run() + + The queue also provides a ``data`` dictionary, that may be freely used to + store anything, but is mostly aimed at aggregating data for callbacks. The + dictionary is automatically cleared by ``run()`` once all callback functions + have been called. + + # register foo to process aggregated data + @callbacks.add + def foo(): + print(sum(callbacks.data['foo'])) + + callbacks.data.setdefault('foo', []).append(1) + ... + callbacks.data.setdefault('foo', []).append(2) + ... + callbacks.data.setdefault('foo', []).append(3) + + # call foo(), which prints 6 + callbacks.run() + + Given the global nature of ``data``, the keys should identify in a unique + way the data being stored. It is recommended to use strings with a + structure like ``"{module}.{feature}"``. """ + __slots__ = ['_funcs', 'data'] + def __init__(self): - self._func_args = {} # {func: args} + self._funcs = [] + self.data = {} - def __call__(self): - """ Call all the registered functions (in first addition order) with - their respective arguments. Only recurrent functions remain registered - after the call. - """ - func_args = self._func_args - while func_args: - func = next(iter(func_args)) - args = func_args.pop(func) - func(*args) - - def add(self, func, *types): - """ Register the given function, and return the tuple of positional - arguments to call the function with. If the function is not registered - yet, the list of arguments is made up by invoking the given types. - """ - try: - return self._func_args[func] - except KeyError: - args = self._func_args[func] = [type_() for type_ in types] - return args + def add(self, func): + """ Add the given function. """ + self._funcs.append(func) + + def run(self): + """ Call all the functions (in addition order), then clear. """ + for func in self._funcs: + func() + self.clear() def clear(self): - """ Remove all callbacks from self. """ - self._func_args.clear() + """ Remove all callbacks and data from self. """ + self._funcs.clear() + self.data.clear() class IterableGenerator: |
