Persistent cache implementation for httpx and httpcore following RFC 9111 specification
npx @tessl/cli install tessl/pypi-hishel@0.1.0An elegant HTTP caching library that implements RFC 9111 caching specification for HTTPX and HTTP Core libraries. Hishel provides persistent memory caching with smart cache management, understanding HTTP headers like Vary, Etag, Last-Modified, Cache-Control, and Expires for automatic response re-validation.
pip install hishelimport hishelFor direct access to main components:
from hishel import CacheClient, AsyncCacheClient, Controller, FileStorageimport hishel
# Replace httpx.Client with hishel.CacheClient
with hishel.CacheClient() as client:
response = client.get("https://httpbin.org/get")
print(response.status_code) # 200, fetched from server
# Second request is served from cache
response = client.get("https://httpbin.org/get")
print(response.status_code) # 200, served from cache
# Async version
import asyncio
async def main():
async with hishel.AsyncCacheClient() as client:
response = await client.get("https://httpbin.org/get")
print(response.status_code)
asyncio.run(main())import hishel
import httpx
# Monkey-patch httpx to use caching globally
hishel.install_cache()
# Now all httpx clients automatically use caching
with httpx.Client() as client:
response = client.get("https://httpbin.org/get")Hishel follows a modular architecture with four main components:
This design provides complete compatibility with existing HTTPX workflows while adding transparent HTTP caching capabilities.
Drop-in replacements for httpx.Client and httpx.AsyncClient that provide transparent HTTP caching with configurable storage backends and caching policies.
class CacheClient(httpx.Client):
def __init__(self, *, storage=None, controller=None, **kwargs): ...
class AsyncCacheClient(httpx.AsyncClient):
def __init__(self, *, storage=None, controller=None, **kwargs): ...Pluggable storage implementations for persisting cached HTTP responses across various backends including file system, Redis, SQLite, AWS S3, and in-memory storage.
class FileStorage(BaseStorage):
def __init__(self, *, serializer=None, base_path=None, ttl=None, check_ttl_every=60): ...
class AsyncFileStorage(AsyncBaseStorage):
def __init__(self, *, serializer=None, base_path=None, ttl=None, check_ttl_every=60): ...RFC 9111 compliant cache controller that determines cacheability, validates cached responses, and handles cache directives from HTTP headers.
class Controller:
def __init__(self, *, cacheable_methods=None, cacheable_status_codes=None,
cache_private=True, allow_heuristics=False, clock=None,
allow_stale=False, always_revalidate=False, force_cache=False,
key_generator=None): ...
def is_cachable(self, request: Request, response: Response) -> bool: ...
def construct_response_from_cache(self, request: Request, response: Response,
original_request: Request): ...Serialization formats for persisting HTTP request/response pairs including Pickle, JSON, and YAML serializers with metadata support.
class PickleSerializer(BaseSerializer):
def dumps(self, response: Response, request: Request, metadata: Metadata) -> bytes: ...
def loads(self, data: bytes) -> tuple[Response, Request, Metadata]: ...
class JSONSerializer(BaseSerializer):
def dumps(self, response: Response, request: Request, metadata: Metadata) -> str: ...
def loads(self, data: str) -> tuple[Response, Request, Metadata]: ...HTTPX transport implementations that add caching layer on top of existing transports, handling cache lookups, storage, and validation.
class CacheTransport(httpx.BaseTransport):
def __init__(self, *, transport: httpx.BaseTransport, storage=None, controller=None): ...
class AsyncCacheTransport(httpx.AsyncBaseTransport):
def __init__(self, *, transport: httpx.AsyncBaseTransport, storage=None, controller=None): ...Cache-Control and Vary header parsing and representation with RFC 9111 compliant validation and directive handling.
class CacheControl:
def __init__(self, *, immutable=False, max_age=None, max_stale=None,
min_fresh=None, must_revalidate=False, must_understand=False,
no_cache=False, no_store=False, no_transform=False,
only_if_cached=False, private=False, proxy_revalidate=False,
public=False, s_maxage=None): ...
def parse_cache_control(cache_control_values: list[str]) -> CacheControl: ...Testing utilities including mock connection pools and transports for unit testing cached HTTP interactions.
class MockTransport(httpx.BaseTransport):
def add_responses(self, responses: list[httpx.Response]) -> None: ...
class MockAsyncTransport(httpx.AsyncBaseTransport):
def add_responses(self, responses: list[httpx.Response]) -> None: ...def install_cache() -> None:
"""Monkey-patch httpx to use Hishel caching globally"""class LFUCache:
def __init__(self, capacity: int): ...
def get(self, key) -> Any: ...
def put(self, key, value) -> None: ...
def remove_key(self, key) -> None: ...Least Frequently Used cache implementation for internal use and advanced caching scenarios.
class CacheControlError(Exception): ...
class ParseError(CacheControlError): ...
class ValidationError(CacheControlError): ...