requests-cache CachedSession with sqlite backend and expiry: working versions (tested 2026-10-15)
A requests session backed by a persistent sqlite cache with TTL expiry and 200-only caching, tested offline with responses mocks.
passed4 passed · 0 failed2026-10-15 13:33 UTC- Status
- passed
- Last passed
- 2026-10-15 13:33 UTC
- Tests
- 4 / 4
- Language
- Python
- Runtime
- Python 3.13.16
pinned versions4
requests@2.34.2requests-cache@1.3.3responses@0.26.3pytest@9.1.1
run it
uv venv -q .venv && uv pip install -q --python .venv/bin/python -r requirements.txt .venv/bin/python -m pytest -q
test environment
Python 3.13.16 linux 6.17.0-1022-azure x64 runner: github-actions 38742087302
The code
Exactly the files that passed. Your agent can pull them with get_recipe("requests-cache-sqlite-backend") (install), or see them on GitHub.
requirements.txt
requests==2.34.2 requests-cache==1.3.3 responses==0.26.3 pytest==9.1.1
cache_session.py
from datetime import timedelta
from pathlib import Path
import requests_cache
def make_session(db_path: Path, ttl: timedelta | None = timedelta(minutes=5)) -> requests_cache.CachedSession:
# Only 200 responses are cached; errors always hit the network.
return requests_cache.CachedSession(
cache_name=str(db_path),
backend="sqlite",
expire_after=ttl,
allowable_codes=(200,),
)
tests/test_cache.py
import time
from datetime import timedelta
import pytest
import responses
from cache_session import make_session
URL = "https://api.example.com/items/1"
@pytest.fixture
def rsps():
with responses.RequestsMock() as m:
yield m
def test_second_get_served_from_sqlite(tmp_path, rsps):
rsps.get(URL, json={"id": 1})
with make_session(tmp_path / "http.sqlite") as s:
first = s.get(URL)
second = s.get(URL)
assert not first.from_cache
assert second.from_cache
assert second.json() == {"id": 1}
assert len(rsps.calls) == 1
def test_cache_survives_new_session(tmp_path, rsps):
# The sqlite file is the cache, so a fresh session on the same path reuses it.
db = tmp_path / "http.sqlite"
rsps.get(URL, json={"id": 1})
with make_session(db) as s:
s.get(URL)
with make_session(db) as s:
assert s.get(URL).from_cache
assert len(rsps.calls) == 1
def test_entry_expires(tmp_path, rsps):
rsps.get(URL, json={"id": 1})
with make_session(tmp_path / "http.sqlite", ttl=timedelta(seconds=1)) as s:
s.get(URL)
time.sleep(1.1)
assert not s.get(URL).from_cache
assert len(rsps.calls) == 2
def test_server_errors_not_cached(tmp_path, rsps):
rsps.get(URL, status=500)
rsps.get(URL, json={"id": 1})
with make_session(tmp_path / "http.sqlite") as s:
assert s.get(URL).status_code == 500
r = s.get(URL)
assert r.status_code == 200 and not r.from_cache
assert len(rsps.calls) == 2
pytest.ini
[pytest] pythonpath = .
Connect to ProvenPin
Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.
terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp
~/.cursor/mcp.json
{ "mcpServers": { "provenpin": { "url": "https://mcp.provenpin.com/mcp" } } }.vscode/mcp.json
{ "servers": { "provenpin": { "type": "http", "url": "https://mcp.provenpin.com/mcp" } } }~/.codeium/windsurf/mcp_config.json
{ "mcpServers": { "provenpin": { "serverUrl": "https://mcp.provenpin.com/mcp" } } }MCP settings
{ "mcpServers": { "provenpin": { "type": "streamableHttp", "url": "https://mcp.provenpin.com/mcp" } } }Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.