2
# -*- coding: utf-8 -*-
3
#-----------------------
6
# Author: Raymond Wagner
7
# Purpose: Caching framework to store TMDb API results
8
#-----------------------
13
from tmdb_exceptions import *
14
from cache_engine import Engines
19
class Cache( object ):
21
This class implements a persistent cache, backed in a file specified in
22
the object creation. The file is protected for safe, concurrent access
23
by multiple instances using flock.
24
This cache uses JSON for speed and storage efficiency, so only simple
25
data types are supported.
26
Data is stored in a simple format {key:(expiretimestamp, data)}
28
def __init__(self, engine=None, *args, **kwargs):
30
self.configure(engine, *args, **kwargs)
32
def configure(self, engine, *args, **kwargs):
35
elif engine not in Engines:
36
raise TMDBCacheError("Invalid cache engine specified: "+engine)
37
self._engine = Engines[engine](self)
38
self._engine.configure(*args, **kwargs)
40
def put(self, key, data, lifetime=3600):
41
# pull existing data, so cache will be fresh when written back out
42
if self._engine is None:
43
raise TMDBCacheError("No cache engine configured")
44
self._engine.put(key, data, lifetime)
47
if self._engine is None:
48
raise TMDBCacheError("No cache engine configured")
49
return self._engine.get(key)
52
if (key in self._cache) and (time.time() < self._cache[key][0]):
53
return self._cache[key][1]
56
def cached(self, callback):
58
Returns a decorator that uses a callback to specify the key to use
59
for caching the responses from the decorated function.
61
return self.Cached(self, callback)
63
class Cached( object ):
64
def __init__(self, cache, callback, func=None, inst=None):
66
self.callback = callback
71
self.__module__ = func.__module__
72
self.__name__ = func.__name__
73
self.__doc__ = func.__doc__
75
def __call__(self, *args, **kwargs):
76
if self.func is None: # decorator is waiting to be given a function
77
if len(kwargs) or (len(args) != 1):
78
raise TMDBCacheError('Cache.Cached decorator must be called '+\
79
'a single callable argument before it '+\
82
raise TMDBCacheError('Cache.Cached decorator called before '+\
83
'being given a function to wrap.')
84
elif not callable(args[0]):
85
raise TMDBCacheError('Cache.Cached must be provided a '+\
87
return self.__class__(self.cache, self.callback, args[0])
90
data = self.cache.get(key)
92
data = self.func(*args, **kwargs)
93
if hasattr(self.inst, 'lifetime'):
94
self.cache.put(key, data, self.inst.lifetime)
96
self.cache.put(key, data)
99
def __get__(self, inst, owner):
102
func = self.func.__get__(inst, owner)
103
callback = self.callback.__get__(inst, owner)
104
return self.__class__(self.cache, callback, func, inst)