guneysus
12/1/2014 - 11:59 AM

From https://guneysu.firebaseapp.com/node/2404/ (http://blog.teknikprogramlama.net/en/node/2404 is broken)

def func_hash(*args, **kwargs):

    def hash_args(*args):
        """docstring for main"""
        hlist = []
        for v in sorted(args):
            if hasattr(v, '__iter__'):
                result = {
                    'tuple': lambda: v,
                    'list': lambda: tuple(sorted(v)),
                    'dict': lambda: tuple(sorted(v.items()))
                }[type(v).__name__]()
                hlist.append(result)
            else:
                hlist.append(v)
        return hash(tuple(hlist))

    def hash_kwargs(**kwargs):
        """docstring for main"""
        hlist = []
        for k, v in sorted(kwargs.iteritems()):
            if hasattr(v, '__iter__'):
                result = {
                    'tuple': lambda: v,
                    'list': lambda: tuple(sorted(v)),
                    'dict': lambda: tuple(sorted(v.items()))
                }[type(v).__name__]()
                hlist.append(result)
            else:
                hlist.append((k, v))
        return hash(tuple(hlist))

    return str(hash_kwargs(**kwargs) + hash_args(*args))


class cache(object):
    # TODO expire='1d at 00:00' 
    # call with @cache(expire=\d+s|m|h|d|w @00:00)

    def __init__(self, func, expire=None):
        self.func = func

        for name in set(dir(func)) - set(dir(self)):
            setattr(self, name, getattr(func, name))

    def __call__(self, *args, **kwargs):
        self.key = func_hash(*args, **kwargs)
        if self.is_cached():
            logging.warning(
                '>>>>> Serving from cache for key :\t %s' % self.key)
            return self.cache_data()
        else:
            # call function to get data
            data = self.func(*args, **kwargs)
            # Put this data to memcache
            memcache.set(self.key, data, time=60 * 60 * 24)
            # Return function
            return self.func(*args, **kwargs)
        return self.func(*args, **kwargs)  # OK

    def is_cached(self):
        data = memcache.get(self.key)
        return data is not None

    def cache_data(self, *args, **kwargs):
        # data = self.func(*args, **kwargs)
        return memcache.get(self.key)