import warnings class DecoratorBase(object): """The common parent of Decorator and Wrapper.""" @classmethod def depends(cls): return [] @classmethod def picklable(cls): """Can the decorator be pickled?""" return True @classmethod def idempotent(cls, info): """Can the decorator be instantiated twice on the same wrapper with the same results, given that the members of info (the parameter here) will be passed into the constructor as they were before.""" return True def fail(self, type): """Warn that "type" couldn't be used as a decorator.""" warnings.warn( "Couldn't use " + str(type) + " as a decorator", Failure) def picklable_part(self): """Returns a decorated wrapper for this object which can be pickled.""" if self.picklable(): return self else: return self.wrapper.picklable_part() def idempotent_part(self, info): """Return a decorated wrapper for this object which will give the same results when instantiated under info twice.""" if self.idempotent(): return self else: return self.wrapper.idempotent_part() class Decorator(DecoratorBase): """The base class for all decorators. Thanks to melt.py, there should be only one of these in each group of decorators. Handles tedious tasks like moving requests forward to the next group in line, and defines default versions of methods.""" __slots__ = ["wrapper"] def __init__(self, wrapper, info): # wrapper may be an actual wrapper or another decorator. # info is discarded once the decorator has been constructed, # so it shouldn't be kept around. self.wrapper = wrapper def __getattr__(self, name, default = None): return getattr(self.wrapper, name, default) def __setattr__(self, name, val): setattr(self.wrapper, name, val) def __delattr__(self, name): delattr(self.wrapper, name) class Failure(Warning): pass