Files
2012-06-27 11:30:37 -04:00

127 lines
3.7 KiB
Python

# -*- coding: utf-8 -*-
"""
This module contains the primary objects for caching responses
for the Python Requests library.
:copyright: (c) 2012 by Kyle Jensen.
:license: ISC, see LICENSE for more details.
"""
import hashlib
import datetime
import requests
from requests_cache import backends
class ReqCache(object):
def __init__(self, cache_name, backend,
allowable_codes=(200,),
allowable_methods=('GET',),
expire_after=None,
**backend_options):
super(ReqCache, self).__init__()
self.cache_name = cache_name
self.backend = backend
self.allowable_codes = allowable_codes
self.allowable_methods = allowable_methods
self.expire_after = expire_after
try:
self.cache = backends.registry[self.backend](
cache_name,
**backend_options
)
except KeyError:
raise ValueError('Unsupported backend "%s" try one of: %s' %
(backend, ', '.join(backends.registry.keys())))
@staticmethod
def reqresp_to_key(r):
"""
Accepts a Request or Reponse object, returns a string key for
storing the cached response in a dictionary-like object.
"""
if isinstance(r, requests.Response):
request = r.request
else:
request = r
key = "method={0} url={1}".format(
request.method,
request.full_url,
)
if request.method in ("POST", "PUT"):
data = request._encode_params(getattr(r, 'data', {}))
key = "{0} datahash={2}".format(
key,
hashlib.sha224(data).hexdigest(),
)
return key
def to_cache(self, response):
"""
Save a response to the cache.
"""
if (response.status_code in self.allowable_codes
and response.request.method in self.allowable_methods
and not hasattr(response, 'from_cache')):
key = self.reqresp_to_key(response)
self.cache.save_response(key, response)
return response
def from_cache(self, request):
"""
Retrieve a response from the cache given a request.
"""
if request.method in self.allowable_methods:
key = self.reqresp_to_key(request)
response, timestamp = self.cache.get_response_and_time(key)
if response:
difference = datetime.datetime.now() - timestamp
if (self.expire_after is not None
and difference >
datetime.timedelta(minutes=self.expire_after)):
self.cache.del_cached_url(key)
else:
request.sent = True
request.response = response
request.response.request = request
request.response.from_cache = True
return request
@property
def hooks(self):
return {
"pre_request": self.from_cache,
"response": self.to_cache,
}
if __name__ == '__main__':
def explain_cache_result(response):
was_cached = getattr(response, "from_cache", False)
if was_cached:
source = "cache"
else:
source = "interwebs"
msg = "Got response from {0} for {1}".format(
source,
ReqCache.reqresp_to_key(response.request),
)
print msg
mycache = ReqCache("test", "memory")
r = requests.get('http://github.com', hooks=mycache.hooks)
explain_cache_result(r)
r = requests.get('http://github.com', hooks=mycache.hooks)
explain_cache_result(r)