from models import *
from error import TweepError
from api import API
+from cache import *
# Global, unauthenticated instance of API
api = API()
"""Twitter API"""
class API(object):
- def __init__(self, username=None, password=None, host='twitter.com', secure=False,
+ def __init__(self, username=None, password=None, host='twitter.com',
+ cache=None, secure=False,
classes={'user': User, 'status': Status,
'direct_message': DirectMessage, 'friendship': Friendship,
'saved_search': SavedSearch, 'search_result': SearchResult}):
else:
self._b64up = None
self.host = host
+ self.cache = cache
self.secure = secure
self.classes = classes
self.username = username
else:
parameters = None
+ # Build url with parameters
+ if parameters:
+ url = '%s?%s' % (path, urllib.urlencode(parameters))
+ else:
+ url = path
+
+ # Check cache if caching enabled and method is GET
+ if api.cache and method == 'GET':
+ cache_result = api.cache.get(url)
+ if cache_result:
+ # if cache result found and not expired, return it
+ print 'hit!'
+ return cache_result
+
# Open connection
if host:
_host = host
else:
conn = httplib.HTTPConnection(_host)
- # Build url with parameters
- if parameters:
- url = '%s?%s' % (path, urllib.urlencode(parameters))
- else:
- url = path
-
# Assemble headers
headers = {
'User-Agent': 'tweepy'
# Pass returned body into parser and return parser output
out = parser(resp.read(), api)
+ # store result in cache
+ if api.cache and method == 'GET':
+ api.cache.store(url, out)
+
# close connection and return data
conn.close()
return out
--- /dev/null
+# Tweepy
+# Copyright 2009 Joshua Roesslein
+# See LICENSE
+
+import time
+import threading
+
+"""Cache interface"""
+class Cache(object):
+
+ def __init__(self, timeout=60):
+ """Init the cache
+ timeout: number of seconds to keep a cached entry
+ """
+ self.timeout = timeout
+
+ def store(self, key, value):
+ """Add new record to cache
+ key: entry key
+ value: data of entry
+ """
+ raise NotImplemented
+
+ def get(self, key):
+ """Get cached entry if exists and not expired
+ key: which entry to get
+ """
+ raise NotImplemented
+
+ def cleanup(self):
+ """Delete any expired entries in cache."""
+ raise NotImplemented
+
+ def flush(self):
+ """Delete all cached entries"""
+ raise NotImplemented
+
+"""In-memory cache"""
+class MemoryCache(Cache):
+
+ def __init__(self, timeout=60):
+ Cache.__init__(self, timeout)
+ self._entries = {}
+ self.lock = threading.Lock()
+
+ def _is_expired(self, entry):
+ return (time.time() - entry[0]) >= self.timeout
+
+ def store(self, key, value):
+ with self.lock:
+ self._entries[key] = (time.time(), value)
+
+ def get(self, key):
+ with self.lock:
+ # check to see if we have this key
+ entry = self._entries.get(key)
+ if not entry:
+ # no hit, return nothing
+ return None
+
+ # make sure entry is not expired
+ if self._is_expired(entry):
+ # entry expired, delete and return nothing
+ del self._entries[key]
+ return None
+
+ # entry found and not expired, return it
+ return entry[1]
+
+ def cleanup(self):
+ with self.lock:
+ for k,v in self._entries.items():
+ if self._is_expired(v):
+ del self._entries[k]
+
+ def flush(self):
+ with self.lock:
+ self._entries.clear()
+