# # Copyright (c) 2007 Helmut Merz helmutm@cy55.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # """ $Id$ """ def getNotifier(method): if isinstance(method, (Notifier, BoundNotifier)): # already wrapped return method if method.im_self is not None: # wrapping instance method - let's also wrap the class-level method classNotifier = getNotifier(getattr(method.im_class, method.im_func.func_name)) return BoundNotifier(classNotifier, method.im_self) return Notifier(method) class Notifier(object): def __init__(self, method): self.method = method obj = method.im_self or method.im_class name = self.name = method.im_func.func_name setattr(obj, name, self) self.beforeSubs = [] self.afterSubs = [] def __get__(self, instance, cls=None): if instance is None: # class-level access return self existing = instance.__dict__.get(self.name) if isinstance(existing, BoundNotifier): # the instance's method is already wrapped return existing return BoundNotifier(self, instance) def __call__(self, *args, **kw): for sub, sargs, skw in self.beforeSubs: sub(None, *sargs, **skw) result = self.method(*args, **kw) for sub, aargs, akw in self.afterSubs: sub(result, *aargs, **akw) return result def subscribe(self, before, after, *args, **kw): if before is not None: self.beforeSubs.append((before, args, kw)) if after is not None: self.afterSubs.append((after, args, kw)) class BoundNotifier(object): def __init__(self, context, instance): self.context = context self.instance = instance setattr(instance, context.name, self) self.beforeSubs = [] self.afterSubs = [] def __call__(self, *args, **kw): context = self.context for sub, sargs, skw in self.beforeSubs + context.beforeSubs: sub(None, *sargs, **skw) result = context.method(self.instance, *args, **kw) for sub, aargs, akw in self.afterSubs + context.afterSubs: sub(result, *aargs, **akw) return result def subscribe(self, before, after, *args, **kw): if before is not None: self.beforeSubs.append((before, args, kw)) if after is not None: self.afterSubs.append((after, args, kw))