"""Later: Go-like execution deferral for python This module provides Go-like execution deferral for Python. A call may be deferred, meaning that it is executed once the context of the deferral closes. Several calls may be deferred, in which case they are all executed in LIFO order as the context closes. A deferral needs only to happen within a deferral context. The context stores the deferred calls and invokes them as the context is closed. Contexts may be shared and nested, but Later instances and their contexts are not thread safe. The purpose of the module is to avoid common headaches when untangling resources after an exception, error or finishing business as usual, and to avoid the pyramidic indentation that nested "with" contexts may result in. Example: from later import Later # Using the decorator l = Later() @l.context def copy(filename): f = open(filename) l.defer(f.close) f2 = open(filename + '.copy', 'wb') l.defer(f2.close) f2.write(f.read()) # Using the context manager with Later() as l: f = open('a') l.defer(f.close) f2 = open('b', 'wb') l.defer(f2.close) f2.write(f.read()) """ class Later(object): """Later represents a stack of deferral contexts.""" def __init__(self): """Create a Later instance""" self.contexts = [] def __enter__(self): """Opens a new deferral context.""" self.contexts.append([]) return self def __exit__(self, exc_type, exc_value, traceback): """Closes a deferral context, executing any deferred calls in LIFO order.""" ctx = self.contexts.pop() while ctx: call = ctx.pop() call[0](*call[1], **call[2]) def context(self, func): """context is used as a decorator to wrap functions that may use the defer method. It wraps the function in a deferral context manager.""" def ret(*args, **kwargs): """function wrapper for managing the context of the wrapped function""" with self: return func(*args, **kwargs) return ret def defer(self, func, *args, **kwargs): """defer stores a function and an optional set of arguments in the active context, to be invoked when the active context is finished.""" self.contexts[-1].append((func, args, kwargs))