def cache(time_to_wait = None, resource_manager = None):
    """ cache(time in float seconds) -> decorator

    Given "time" seconds (float), this decorator will cache during that
    time the output of the decorated function. This way, if someone calls
    the cache object with the same input within the next "time" time, the
    function will not be called and the output will be returned instead.
    """
    class cache_obj(object):
        def __init__(self, func):
            super(cache_obj,self).__init__()
            self.func         = (func,)
            self.lock         = threading.RLock()
            self.dictionaries_per_inst = {
                    # inst : { # if it's not an inst, None is the key
                    #   'dict': {},
                    #   'list': []
                    # }
                 }
            self._time        = time_to_wait
            self._inst        = None
            _cache_registry.append(self)

        def __get__(self, inst, owner):
            if inst is not None:
                self._inst = weakref.ref(inst)
            return self

        def _generate_key(self, args, kargs):
            if kargs == {}:
                try:
                    hash(args)
                except TypeError:
                    pass
                else:
                    key = _HasheableKey(args)
                    return key
            try:
                pickled_key = pickle.dumps((args,kargs))
            except:
                key = _NotPicklableKey((args,kargs))
            else:
                key = _PicklableKey(pickled_key)
            return key

        def _get_time(self):
            # For testing purposes
            return time_module.time()

        def __call__(self, *args, **kargs):
            key = self._generate_key(args, kargs)
            current_time = self._get_time()

            found, (obj, storage_time) = key.load(self._get_dictionaries())
            if found:
                if self.time is None or current_time - storage_time < self.time:
                    return obj

            if self._inst != None:
                args = (self._inst(),) + args
            return_value = self.func[0](*args, **kargs)

            key.save(
                    self._get_dictionaries(),
                    ( return_value, current_time)
                )

            return return_value

        def _save_to_cache(self, key, value):
            return_value, current_time = value
            key.save(self._get_dictionaries(), (return_value, current_time))

        def _get_dictionaries(self, inst = "this.is.not.an.instance"):
            if inst == "this.is.not.an.instance":
                inst = self._inst
            if not inst in self.dictionaries_per_inst:
                self.lock.acquire()
                try:
                    # Double ask, just to avoid acquiring and releasing
                    # without need
                    if not inst in self.dictionaries_per_inst:
                        self.dictionaries_per_inst[inst] = {
                            'dict' : {},
                            'list' : []
                        }
                finally:
                    self.lock.release()
            return self.dictionaries_per_inst[inst]

        def get_time(self):
            return self._time

        def set_time(self, value):
            self._time = value

        time = property(get_time, set_time)

        def _remove_obj(self, key, inst):
            try:
                returnValue, _ = key.pop(self._get_dictionaries(inst))
            except __HOLE__:
                return

    def wrapped_decorator(func):
        o = cache_obj(func)
        o.__name__ = func.__name__
        o.__doc__  = func.__doc__
        return o

    return wrapped_decorator
dataset/ETHPy150Open weblabdeusto/weblabdeusto/server/src/voodoo/cache.py/cache