# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import sys from util.decorators import DecoratorWithArgs class Persistent(type): '''Metaclass providing object persistence''' def __init__(cls, name, bases, dct): super(Persistent, cls).__init__(name, bases, dct) setattr(cls, '__dirty__', False) setattr(cls, '__properties__', filter(_is_persistent, dct.iteritems())) from util.journalpickler import dumps, loads setattr(cls, 'dumps', dumps) setattr(cls, 'loads', loads) @DecoratorWithArgs def PersistentProperty(function, default = None): '''Decorator to set persistent properties''' keys = 'fset', 'fdel' func_locals = {'doc':function.__doc__} def fgetter(obj, name, getter, default_value): attr_name = '_' + obj.__class__.__name__ + '__' + name if not hasattr(obj, attr_name): setattr(obj, attr_name, default_value(obj)) return getter(obj) def fsetter(obj, name, setter, value): setattr(obj, '__dirty__', True) return setter(obj, value) def introspect(frame, event, arg): if event == 'return': locals = frame.f_locals func_locals.update(dict((k,locals.get(k)) for k in keys)) if locals.has_key('fset'): func_locals['fset'] = \ lambda obj, value : fsetter(obj, function.__name__, locals['fset'], value) if default != None: get_function = \ lambda obj : fgetter(obj, function.__name__, locals['fget'], lambda x : default) else: get_function = \ lambda obj : fgetter(obj, function.__name__, locals['fget'], lambda x : None) get_function.decorator = PersistentProperty # tag the getter so we can id # the decorator. Yeah, it's ugly. func_locals['fget'] = get_function sys.settrace(None) return introspect sys.settrace(introspect) function() return property(**func_locals) # a wee bit ugly def _is_persistent(item): '''check if property is decorated with PersistentProperty decorator''' prop = item[1] return type(prop) is property and \ hasattr(prop.fget, 'decorator') and \ prop.fget.decorator is PersistentProperty