Persistent cache implementation for httpx and httpcore following RFC 9111 specification
74
Cache-Control and Vary header parsing and representation with RFC 9111 compliant validation and directive handling. These classes provide structured access to HTTP caching headers.
Class representing Cache-Control header directives with validation and parsing functionality.
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):
"""
Represent Cache-Control header directives.
Parameters:
- immutable: Response will not change over time (RFC 8246)
- max_age: Maximum age in seconds for cached response
- max_stale: Client will accept stale response up to specified seconds
- min_fresh: Client wants response fresh for at least specified seconds
- must_revalidate: Must revalidate stale responses
- must_understand: Override no-store under certain circumstances
- no_cache: Must revalidate before using cached response
- no_store: Must not store request or response
- no_transform: Must not transform response content
- only_if_cached: Only use cached response, don't contact server
- private: Response is private to single user
- proxy_revalidate: Shared caches must revalidate
- public: Response may be cached by any cache
- s_maxage: Maximum age for shared caches
"""Usage Examples:
import hishel
# Create Cache-Control directives
cache_control = hishel.CacheControl(
max_age=3600, # 1 hour
public=True, # Can be cached by any cache
must_revalidate=True # Must revalidate when stale
)
# Access individual directives
print(cache_control.max_age) # 3600
print(cache_control.public) # True
print(cache_control.no_cache) # False
# Private cache directives
private_cache = hishel.CacheControl(
max_age=1800, # 30 minutes
private=True, # Private to single user
no_store=False # Can be stored
)Class method for validating and normalizing Cache-Control directives from parsed headers.
@classmethod
def validate(cls, directives: dict[str, Any]) -> dict[str, Any]:
"""
Validate and normalize Cache-Control directives.
Parameters:
- directives: Dictionary of directive names to values
Returns:
- Validated and normalized directives dictionary
Raises:
- ValidationError: If directive values are invalid
"""Function to parse Cache-Control header values into a CacheControl object.
def parse_cache_control(cache_control_values: list[str]) -> CacheControl:
"""
Parse Cache-Control header values into structured representation.
Parameters:
- cache_control_values: List of Cache-Control header value strings
Returns:
- CacheControl object with parsed directives
Raises:
- ParseError: If header values cannot be parsed
"""Usage Examples:
import hishel
# Parse Cache-Control header
header_values = ["max-age=3600, public", "must-revalidate"]
cache_control = hishel.parse_cache_control(header_values)
print(cache_control.max_age) # 3600
print(cache_control.public) # True
print(cache_control.must_revalidate) # True
# Parse complex directives
complex_header = ['no-cache="Set-Cookie, Authorization", max-age=0']
cache_control = hishel.parse_cache_control([complex_header])
print(cache_control.no_cache) # ['Set-Cookie', 'Authorization']
# Handle quoted values
quoted_header = ['private="user-info", s-maxage=7200']
cache_control = hishel.parse_cache_control([quoted_header])
print(cache_control.private) # ['user-info']
print(cache_control.s_maxage) # 7200Class representing HTTP Vary header for content negotiation caching.
class Vary:
def __init__(self, values: list[str]):
"""
Represent Vary header field names.
Parameters:
- values: List of header field names that affect response content
"""
@classmethod
def from_value(cls, vary_values: list[str]) -> "Vary":
"""
Create Vary object from header value strings.
Parameters:
- vary_values: List of Vary header value strings
Returns:
- Vary object with parsed field names
"""Usage Examples:
import hishel
# Create Vary header from field names
vary = hishel.Vary(values=["Accept", "Accept-Encoding", "User-Agent"])
# Parse from header values
vary_headers = ["Accept, Accept-Encoding", "User-Agent"]
vary = hishel.Vary.from_value(vary_headers)
# Access field names
print(vary._values) # ['Accept', 'Accept-Encoding', 'User-Agent']
# Handle wildcard
wildcard_vary = hishel.Vary.from_value(["*"])
print(wildcard_vary._values) # ['*']Time values are specified in seconds:
Directives that are either present (True) or absent (False):
Directives that can have optional field name lists:
Header parsing can raise specific exceptions:
class CacheControlError(Exception):
"""Base exception for Cache-Control processing"""
class ParseError(CacheControlError):
"""Exception raised when parsing Cache-Control header fails"""
class ValidationError(CacheControlError):
"""Exception raised when validating Cache-Control directives fails"""Usage Examples:
import hishel
try:
# Invalid directive value
cache_control = hishel.parse_cache_control(["max-age=invalid"])
except hishel.ValidationError as e:
print(f"Validation error: {e}")
try:
# Malformed header
cache_control = hishel.parse_cache_control(['max-age="unclosed quote'])
except hishel.ParseError as e:
print(f"Parse error: {e}")import hishel
# Parse headers and inspect all directives
cache_control = hishel.parse_cache_control([
"max-age=3600, public, custom-directive=value"
])
# Access standard directives
print(cache_control.max_age) # 3600
print(cache_control.public) # True
# Custom directives are not directly accessible
# but are preserved in the parsing processimport httpx
import hishel
# Extract Cache-Control from response
response = httpx.get("https://api.example.com/data")
cache_control_headers = [
value.decode() for key, value in response.headers.raw
if key.lower() == b'cache-control'
]
if cache_control_headers:
cache_control = hishel.parse_cache_control(cache_control_headers)
print(f"Max age: {cache_control.max_age}")
print(f"Public: {cache_control.public}")import hishel
# Handle content negotiation caching
vary = hishel.Vary.from_value(["Accept", "Accept-Language"])
# In cache key generation, these headers would be considered:
# - Accept: application/json vs text/html
# - Accept-Language: en-US vs fr-FR
# Each combination gets its own cache entryInstall with Tessl CLI
npx tessl i tessl/pypi-hisheldocs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10