Skip to main content

Enhanced Requests Library with Adaptive Rate Limit Estimation

Project description

SmartSurge: Intelligent HTTP Client with Adaptive Rate Limit Detection

SmartSurge logo

PyPI version Python versions License

SmartSurge is an intelligent HTTP client library that enhances the popular requests library with automatic rate limit detection, handling, and request throttling. Using statistical analysis and machine learning techniques, SmartSurge can automatically detect and adapt to rate limits without requiring any API-specific configuration.

🚀 Key Features

  • ⚡ Drop-in Replacement: Works seamlessly with your existing requests-based code
  • 🔄 Resumable Downloads: Stream large files with automatic resume capability on connection failures
  • 🔀 Async Support: Full support for asynchronous operations using aiohttp
  • 📊 Multi-Tiered Rate Limit Detection: Supports manual, server-provided, and HMM-based rate limit detection
  • 🧠 Intelligent Rate Limit Detection: Automatically detects rate limits using Hidden Markov Models (HMM)
  • 🛡️ Automatic Retries: Built-in retry logic with exponential backoff

IMPORTANT NOTE: The Hidden Markov Model component is currently under development and is not yet production-ready.

📦 Installation

pip install smartsurge

For development or additional features:

# Install with development tools
pip install smartsurge[dev]

# Install with benchmarking tools
pip install smartsurge[benchmark]

# Install with documentation tools
pip install smartsurge[docs]

# Install everything
pip install smartsurge[dev,benchmark,docs]

🎯 Quick Start

Basic Usage

from smartsurge import SmartSurgeClient

# Create a client - it works just like requests!
client = SmartSurgeClient()

# Make requests without worrying about rate limits
response = client.get("https://api.example.com/data")
print(response.json())

# Get response with request history for insights
response, history = client.get("https://api.example.com/data", return_history=True)

# Check detected rate limits
limits = client.list_rate_limits()
for (endpoint, method), limit in limits.items():
    if limit:
        print(f"{endpoint} {method}: {limit.max_requests} requests per {limit.time_period}s")

Configuration

from smartsurge import SmartSurgeClient

# Create a client with custom configuration
client = SmartSurgeClient(
    base_url="https://api.example.com",
    timeout=(10.0, 30.0),      # (connect, read) timeouts
    max_retries=3,             # Maximum retry attempts
    backoff_factor=0.3,        # Exponential backoff multiplier
    refit_every=20,            # Refit HMM every N requests
)

# All requests will use the base URL
response = client.get("/users")  # Requests https://api.example.com/users

Manual Rate Limit Configuration

# Set a known rate limit
client.set_rate_limit(
    endpoint="https://api.example.com/users",
    method="GET",
    max_requests=100,
    time_period=60.0  # 100 requests per minute
)

# Check current rate limit
rate_limit = client.get_rate_limit("https://api.example.com/users", "GET")
if rate_limit:
    print(f"Rate limit: {rate_limit.max_requests} per {rate_limit.time_period}s")
    print(f"Source: {rate_limit.source}")  # 'manual', 'header', or 'estimated'

Streaming Large Files

from smartsurge import JSONStreamingRequest

# Stream large files with automatic resume capability
result = client.stream_request(
    streaming_class=JSONStreamingRequest,
    endpoint="https://example.com/large-dataset.json",
    state_file="download_state.json",  # Automatically saves progress
    chunk_size=1024 * 1024  # 1MB chunks
)

# If interrupted, the download will resume from where it left off

Async Support

import asyncio

async def fetch_data():
    client = SmartSurgeClient()
    
    # Make async requests
    response = await client.async_get("https://api.example.com/data")
    data = await response.json()
    
    # Parallel requests
    tasks = [
        client.async_get(f"https://api.example.com/items/{i}")
        for i in range(10)
    ]
    responses = await asyncio.gather(*tasks)
    
    return responses

# Run the async function
results = asyncio.run(fetch_data())

🧠 How It Works

SmartSurge uses a three-tier approach to rate limiting:

  1. Manual Rate Limits (Highest Priority)

    • Explicitly set rate limits using set_rate_limit()
    • Useful when you know the API's limits
  2. Server-Provided Limits

    • Automatically reads standard rate limit headers:
      • X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
      • Retry-After headers from 429 responses
  3. HMM-Based Learning (Automatic)

    • Uses a 3-state Hidden Markov Model to detect patterns:
      • State 0: Normal operation
      • State 1: Approaching rate limit
      • State 2: Rate limited
    • Continuously adapts to changing patterns

📊 Advanced Features

Request History Analysis

# Get detailed request history
response, history = client.get("/api/data", return_history=True)

# Analyze the history
print(f"Total requests: {len(history.requests)}")

# Check if rate limit was detected
if history.rate_limit:
    print(f"Detected limit: {history.rate_limit}"))

Custom Configuration

from smartsurge import ClientConfig

# Create reusable configuration
config = ClientConfig(
    base_url="https://api.example.com",
    timeout=(5.0, 30.0),
    max_retries=5,
    backoff_factor=0.5,
    
    # HMM Configuration
    min_time_period=1.0,       # Minimum rate limit window (seconds)
    max_time_period=3600.0,    # Maximum rate limit window (1 hour)
    refit_every=20,            # Refit HMM every N requests
    
    # Other options
    verify_ssl=True,
    user_agent="MyApp/1.0 (SmartSurge)"
)

client = SmartSurgeClient(**config.model_dump())

Error Handling

from smartsurge import (
    RateLimitExceeded,
    StreamingError,
    ResumeError,
    ValidationError,
    ConfigurationError
)

try:
    response = client.get("/api/resource")
except RateLimitExceeded as e:
    print(f"Rate limit hit: {e.message}")
    if e.retry_after:
        print(f"Retry after {e.retry_after} seconds")
except StreamingError as e:
    print(f"Streaming failed: {e.message}")
except Exception as e:
    print(f"Unexpected error: {e}")

🔧 Utilities

SmartSurge includes helpful utilities:

from smartsurge import (
    SmartSurgeTimer,
    configure_logging,
    merge_histories,
    async_request_with_history
)

# Configure logging
configure_logging(level=logging.DEBUG)

# Time your requests
with SmartSurgeTimer() as timer:
    response = client.get("/api/data")
print(f"Request took {timer.duration:.3f} seconds")

# Merge multiple histories
history1 = client.get("/api/users", return_history=True)[1]
history2 = client.get("/api/posts", return_history=True)[1]
combined = merge_histories([history1, history2])

📈 Benchmarking

When installed with benchmark extras, you can test rate limit detection:

from smartsurge import create_benchmark_server, SmartSurgeClient

# Create a mock server with known rate limits
server = create_benchmark_server(
    max_requests=10,
    time_period=1.0  # 10 requests per second
)

# Test SmartSurge against it
client = SmartSurgeClient()
# ... run your tests

🤝 Contributing

We welcome contributions! Please see our Contributing Guidelines for details.

📄 License

SmartSurge is released under the Apache License 2.0. See the LICENSE file for details.

🔗 Links

📧 Contact

🏆 Credits

SmartSurge uses Hidden Markov Models for intelligent rate limit detection, leveraging the power of statistical learning to provide a truly adaptive HTTP client experience.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

smartsurge-0.0.7.tar.gz (1.0 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

smartsurge-0.0.7-py3-none-any.whl (135.0 kB view details)

Uploaded Python 3

File details

Details for the file smartsurge-0.0.7.tar.gz.

File metadata

  • Download URL: smartsurge-0.0.7.tar.gz
  • Upload date:
  • Size: 1.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for smartsurge-0.0.7.tar.gz
Algorithm Hash digest
SHA256 91da67055ab6f5cf21eac2f30e5374ff9529588291f016ee6efa5f24b43a01a3
MD5 aeb4e4ac3bfd0f7636979dbb85a7f535
BLAKE2b-256 3ce73e66f54996b3345381f3c46a90adebc6ff36db8d31d5902fba2731ab5ed8

See more details on using hashes here.

Provenance

The following attestation bundles were made for smartsurge-0.0.7.tar.gz:

Publisher: publish.yml on dingo-actual/smartsurge

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file smartsurge-0.0.7-py3-none-any.whl.

File metadata

  • Download URL: smartsurge-0.0.7-py3-none-any.whl
  • Upload date:
  • Size: 135.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for smartsurge-0.0.7-py3-none-any.whl
Algorithm Hash digest
SHA256 804ef2ecbe87a84be68971b6ea15e88ff5ce4de328d176e365e683685403a199
MD5 9462ba35bf075061e37d5b8a4109b9e9
BLAKE2b-256 b8e1ed2f958577adaed767ba798840bbf70dd58a85522b72db7e5531002034fb

See more details on using hashes here.

Provenance

The following attestation bundles were made for smartsurge-0.0.7-py3-none-any.whl:

Publisher: publish.yml on dingo-actual/smartsurge

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page