CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-requests-cache

A persistent cache for python requests

76

1.26x
Overview
Eval results
Files

models.mddocs/

Response and Request Models

Response and request models provide cached versions of HTTP requests and responses that maintain compatibility with the standard requests library while adding cache-specific metadata and functionality. These models handle serialization, deserialization, and provide cache status information.

Capabilities

Cached Response Model

The main response object returned by cached requests, providing full compatibility with requests.Response while adding cache-specific properties and methods.

class CachedResponse:
    """
    Cached response object that emulates requests.Response.
    
    Provides all standard Response properties and methods plus
    cache-specific functionality and metadata.
    """
    
    def __init__(
        self,
        url: str = '',
        status_code: int = 200,
        reason: str = 'OK',
        headers: Optional[Mapping[str, str]] = None,
        content: bytes = b'',
        encoding: Optional[str] = None,
        history: Optional[List] = None,
        request: Optional[AnyRequest] = None,
        cookies: Optional[RequestsCookieJar] = None,
        elapsed: Optional[timedelta] = None,
        expires: Optional[datetime] = None,
        **kwargs
    ):
        """
        Create cached response object.

        Parameters mirror requests.Response constructor plus:
        - expires: When this cached response expires
        """
    
    # Cache-specific properties
    @property
    def from_cache(self) -> bool:
        """True if response was served from cache, False if fresh."""
    
    @property
    def is_expired(self) -> bool:
        """True if cached response has expired."""
    
    @property
    def expires_delta(self) -> Optional[timedelta]:
        """Time until expiration (positive) or since expiration (negative)."""
    
    @property
    def expires_unix(self) -> Optional[float]:
        """Expiration time as Unix timestamp."""
    
    @property
    def size(self) -> int:
        """Size of cached response in bytes."""
    
    # Cache management methods
    def is_older_than(self, time: ExpirationTime) -> bool:
        """
        Check if response is older than specified time.

        Parameters:
        - time: Time threshold in various formats (int, timedelta, datetime, str)

        Returns:
        True if response age exceeds threshold
        """
    
    def reset_expiration(self, expire_after: ExpirationTime = None) -> None:
        """
        Reset expiration time for cached response.

        Parameters:
        - expire_after: New expiration time (None for no expiration)
        """
    
    # Standard requests.Response interface
    @property
    def text(self) -> str:
        """Response body as text."""
    
    @property
    def content(self) -> bytes:
        """Response body as bytes."""
    
    def json(self, **kwargs) -> Any:
        """Parse response body as JSON."""
    
    def iter_content(self, chunk_size: int = 1) -> Iterator[bytes]:
        """Iterate over response content in chunks."""
    
    def iter_lines(self, **kwargs) -> Iterator[str]:
        """Iterate over response content line by line."""
    
    def raise_for_status(self) -> None:
        """Raise HTTPError for bad status codes."""
    
    # Standard response attributes
    status_code: int
    reason: str
    url: str
    headers: CaseInsensitiveDict
    cookies: RequestsCookieJar
    history: List
    request: AnyRequest
    elapsed: timedelta
    encoding: Optional[str]
    apparent_encoding: str
    ok: bool

Usage Examples

Basic cached response usage:

from requests_cache import CachedSession

session = CachedSession('demo_cache', expire_after=3600)

# First request - fetched from server
response = session.get('https://httpbin.org/json')
print(f"From cache: {response.from_cache}")  # False
print(f"Status: {response.status_code}")     # 200
print(f"Size: {response.size} bytes")

# Second request - served from cache  
response = session.get('https://httpbin.org/json')
print(f"From cache: {response.from_cache}")  # True
print(f"Expires in: {response.expires_delta}")

# Check expiration status
if not response.is_expired:
    data = response.json()
    print("Using cached data:", data)

# Reset expiration 
response.reset_expiration(expire_after=7200)  # 2 hours from now

Cache metadata inspection:

import requests_cache
from datetime import datetime, timedelta

session = requests_cache.CachedSession('cache')

response = session.get('https://api.example.com/data')

# Cache status
print(f"From cache: {response.from_cache}")
print(f"Expired: {response.is_expired}")  
print(f"Size: {response.size} bytes")

# Expiration info
if response.expires_delta:
    if response.expires_delta.total_seconds() > 0:
        print(f"Expires in: {response.expires_delta}")
    else:
        print(f"Expired {abs(response.expires_delta)} ago")

# Age checking
if response.is_older_than('1 hour'):
    print("Response is older than 1 hour")

if response.is_older_than(timedelta(minutes=30)):
    print("Response is older than 30 minutes")

Original Response Wrapper

Wrapper for non-cached responses that provides cache-related properties for consistency.

class OriginalResponse:
    """
    Wrapper for requests.Response that adds cache-related properties.
    
    Used for responses that bypass caching or are fetched fresh
    from the server.
    """
    
    @classmethod
    def wrap_response(
        cls,
        response: Response,
        actions: CacheActions
    ) -> 'OriginalResponse':
        """
        Wrap a requests.Response with cache metadata.

        Parameters:
        - response: Original requests.Response
        - actions: Cache actions that determined response handling

        Returns:
        OriginalResponse with cache properties
        """
    
    @property
    def from_cache(self) -> bool:
        """Always False for original responses."""
    
    # Delegates all other attributes to wrapped response

Cached Request Model

Cached version of HTTP requests that can be serialized and stored with responses.

class CachedRequest:
    """
    Serializable request object that emulates requests.PreparedRequest.
    
    Stores request data alongside cached responses for cache key
    generation and request matching.
    """
    
    def __init__(
        self,
        method: Optional[str] = None,
        url: Optional[str] = None,
        headers: Optional[CaseInsensitiveDict] = None,
        body: Optional[bytes] = None,
        **kwargs
    ):
        """
        Create cached request object.

        Parameters mirror requests.PreparedRequest constructor.
        """
    
    def copy(self) -> 'CachedRequest':
        """Create a copy of the cached request."""
    
    # Standard PreparedRequest interface
    method: Optional[str]
    url: Optional[str] 
    headers: CaseInsensitiveDict
    body: Optional[bytes]
    hooks: Dict[str, List]

HTTP Response Model

Low-level cached HTTP response for urllib3 compatibility.

class CachedHTTPResponse:
    """
    Cached HTTP response that provides urllib3.HTTPResponse compatibility.
    
    Used internally by the caching system to maintain compatibility
    with the requests library's response processing pipeline.
    """
    
    def __init__(
        self,
        body: bytes = b'',
        headers: Optional[Mapping[str, str]] = None,
        status: int = 200,
        reason: Optional[str] = None,
        version: int = 11,
        **kwargs
    ):
        """Create cached HTTP response for urllib3 compatibility."""
    
    def read(self, amt: Optional[int] = None) -> bytes:
        """Read response body."""
    
    def stream(self, amt: int = 1024) -> Iterator[bytes]:
        """Stream response body in chunks."""
    
    def close(self) -> None:
        """Close response (no-op for cached responses)."""

Base Classes and Mixins

Foundation classes providing common functionality for all model objects.

class RichMixin:
    """
    Mixin providing rich repr formatting for model objects.
    
    Adds pretty-printed string representations with syntax
    highlighting when used in rich-enabled environments.
    """
    
    def __rich_repr__(self):
        """Rich representation for pretty printing."""
    
    def __repr__(self) -> str:
        """Standard string representation."""

Type Aliases and Unions

# Response type unions
AnyResponse = Union[OriginalResponse, CachedResponse]
"""Union type representing any response object (cached or original)."""

AnyRequest = Union[Request, PreparedRequest, CachedRequest]  
"""Union type representing any request object."""

AnyPreparedRequest = Union[PreparedRequest, CachedRequest]
"""Union type for prepared request objects."""

# Content type for JSON-compatible data
DecodedContent = Union[str, bytes, int, float, bool, None, Dict, List]
"""JSON-compatible content types for serialization."""

Response Lifecycle

Understanding how responses flow through the caching system:

  1. Request Creation: User makes request through CachedSession
  2. Cache Lookup: System checks for existing cached response
  3. Cache Hit: Return CachedResponse with from_cache=True
  4. Cache Miss: Make HTTP request, get standard Response
  5. Response Wrapping: Wrap as OriginalResponse with from_cache=False
  6. Response Storage: Serialize and store as CachedResponse for future use
# Example showing response lifecycle
from requests_cache import CachedSession

session = CachedSession('demo')

# First request - cache miss
response1 = session.get('https://httpbin.org/json')
print(type(response1))  # <class 'OriginalResponse'>
print(response1.from_cache)  # False

# Second request - cache hit  
response2 = session.get('https://httpbin.org/json')
print(type(response2))  # <class 'CachedResponse'>
print(response2.from_cache)  # True

# Both provide same interface
print(response1.json() == response2.json())  # True

Serialization Integration

Response models integrate seamlessly with the serialization system:

from requests_cache import CachedSession

# Different serializers handle response data differently
json_session = CachedSession('json_cache', serializer='json')
pickle_session = CachedSession('pickle_cache', serializer='pickle')

# All serializers preserve response properties and methods
response = json_session.get('https://httpbin.org/json')
print(f"From cache: {response.from_cache}")
print(f"Data: {response.json()}")

Install with Tessl CLI

npx tessl i tessl/pypi-requests-cache

docs

backends.md

expiration.md

index.md

models.md

patching.md

serialization.md

sessions.md

tile.json