Compatibility with other libraries#
This library works by patching and/or extending requests.Session
. Many other libraries
out there do the same thing, making it potentially difficult to combine them.
For that scenario, a mixin class is provided, so you can create a custom class with behavior from multiple Session-modifying libraries:
>>> from requests import Session
>>> from requests_cache import CacheMixin
>>> from some_other_lib import SomeOtherMixin
>>> class CustomSession(CacheMixin, SomeOtherMixin, Session):
... """Session class with features from both some_other_lib and requests-cache"""
Requests-HTML#
requests-html is one library that works with this method:
>>> import requests
>>> from requests_cache import CacheMixin, install_cache
>>> from requests_html import HTMLSession
>>> class CachedHTMLSession(CacheMixin, HTMLSession):
... """Session with features from both CachedSession and HTMLSession"""
>>> session = CachedHTMLSession()
>>> response = session.get('https://github.com/')
>>> print(response.from_cache, response.html.links)
Or if you are using install_cache()
, you can use the session_factory
argument:
>>> install_cache(session_factory=CachedHTMLSession)
>>> response = requests.get('https://github.com/')
>>> print(response.from_cache, response.html.links)
The same approach can be used with other libraries that subclass requests.Session
.
Requests-Futures#
Some libraries, including requests-futures, support wrapping an existing session object:
>>> from requests_cache import CachedSession
>>> from requests_futures.sessions import FuturesSession
>>> session = FuturesSession(session=CachedSession())
In this case, FuturesSession
must wrap CachedSession
rather than the other way around, since
FuturesSession
returns (as you might expect) futures rather than response objects.
See issue #135 for more notes on this.
Requests-OAuthlib#
Usage with requests-oauthlib is the same as other
libraries that subclass requests.Session
:
>>> from requests_cache import CacheMixin
>>> from requests_oauthlib import OAuth2Session
>>> class CachedOAuth2Session(CacheMixin, OAuth2Session):
... """Session with features from both CachedSession and OAuth2Session"""
>>> session = CachedOAuth2Session('my_client_id')
Requests-Ratelimiter#
requests-ratelimiter adds rate-limiting to requests via the pyrate-limiter library. It also provides a mixin, but note that the inheritance order is important: If rate-limiting is applied after caching, you get the added benefit of not counting cache hits against your rate limit.
>>> from pyrate_limiter import RedisBucket, RequestRate, Duration
>>> from requests import Session
>>> from requests_cache import CacheMixin, RedisCache
>>> from requests_ratelimiter import LimiterMixin
>>> class CachedLimiterSession(CacheMixin, LimiterMixin, Session):
... """Session class with caching and rate-limiting behavior. Accepts arguments for both
... LimiterSession and CachedSession.
... """
>>> # Limit non-cached requests to 5 requests per second, with unlimited cached requests
>>> # Optionally use Redis as both the bucket backend and the cache backend
>>> session = CachedLimiterSession(
... per_second=5,
... bucket_class=RedisBucket,
... backend=RedisCache(),
... )
Internet Archive#
Usage with internetarchive is the same as other libraries
that subclass requests.Session
:
>>> from requests_cache import CacheMixin
>>> from internetarchive.session import ArchiveSession
>>> class CachedArchiveSession(CacheMixin, ArchiveSession):
... """Session with features from both CachedSession and ArchiveSession"""
>>> session = CachedArchiveSession()
Requests-Mock#
requests-mock has multiple methods for mocking requests, including a contextmanager, decorator, fixture, and adapter. There are a few different options for using it with requests-cache, depending on how you want your tests to work.
Disabling requests-cache#
If you have an application that uses requests-cache and you just want to use requests-mock in your tests, the easiest thing to do is to disable requests-cache.
For example, if you are using install_cache()
in your application and the
requests-mock pytest fixture in your
tests, you could wrap it in another fixture that uses uninstall_cache()
or
disabled()
:
Or if you use a CachedSession
object, you could replace it with a regular Session
, for example:
>>> import unittest
>>> import pytest
>>> import requests
>>> @pytest.fixure(scope='function', autouse=True)
>>> def disable_requests_cache():
... """Replace CachedSession with a regular Session for all test functions"""
... with unittest.mock.patch('requests_cache.CachedSession', requests.Session):
... yield
Combining requests-cache with requests-mock#
If you want both caching and mocking features at the same time, you can attach requests-mock’s
adapter to a CachedSession
:
Building a mocker using requests-cache data#
Another approach is to use cached data to dynamically define mock requests + responses. This has the advantage of only using request-mock’s behavior for request matching.
@pytest.fixture(scope='session')
def mock_session():
"""Fixture that provides a session with mocked URLs and responses based on cache data"""
adapter = Adapter()
cache = CachedSession(TEST_DB).cache
for response in cache.responses.values():
adapter.register_uri(
response.request.method,
response.request.url,
content=response.content,
headers=response.headers,
status_code=response.status_code,
)
print(f'Added mock response: {response}')
session = Session()
session.mount('http://', adapter)
session.mount('https://', adapter)
yield session
To turn that into a complete example:
Responses#
Usage with the responses library is similar to the requests-mock examples above.
VCR#
If you would like to reuse your cached response data for unit tests, one option is to convert your cache into a format compatible with VCR-vased libraries like vcrpy and betamax.