from spectate import expose, watch


@expose('__setattr__', '__delattr__')
class Data(object):

    def __init__(self):
        self._callbacks = []
        spectator = watch(self)
        spectator.callback(
            '__setattr__',
            self._before_update,
            self._after_update,
        )
        spectator.callback(
            '__delattr__',
            self._before_update,
            self._after_update,
        )

    @staticmethod
    def _before_update(data, call):
        key = call.args[0]
        old = data.__dict__.get(key)
        return key, old

    @staticmethod
    def _after_update(data, answer):
        key, old = answer.before
        new = data.__dict__.get(key)
        for c in data._callbacks:
            c(key=key, old=old, new=new)

    def watch(self, function):
        self._callbacks.append(function)
        return function


class User(Data):

    def __init__(self, name, description):
        super(User, self).__init__()
        self.name = name
        self.description = description


user = User('Paul', 'a new user')


@user.watch
def printer(key, old, new):
    print('%s : %r -> %r' % (key, old, new))


user.name = 'Paul Jones'
user.description = 'updated user description'
