Skip to main content

Simple Parallel Asynchronous Requests for Python

Project description

SPARP: Simple Parallel Async Requests for Python

This library enables you to turn: responses = [requests.post(url) for url in urls] into concurrent requests without you needing to write any async/await code.

Installation

python3 -m pip install sparp

Basic Usage

This example shows how to process 100 concurrent requests with a progress bar:

# examples/basic_example.py
import aiohttp
from sparp.sparp import SPARP, ResponseState
import json


def inspect_response(response: aiohttp.ClientResponse) -> ResponseState:
    if response.status == 200:
        return ResponseState.SUCCESS
    if response.status == 429 or response.status == 502:
        return ResponseState.SOFT_FAIL
    return ResponseState.HARD_FAIL


def main():
    requests = [{
        "method": "GET",
        "url": f"https://httpbin.org/get?item={i}"}
    for i in range(100)]

    result = SPARP(
        requests, inspect_response=inspect_response, concurrency=20, show_progress_bar=True
    ).main()

    for item in result.success:
        print(
            f"data sent: {item['input']['url']},
            data received: {json.loads(item['text'])['args']['item']}"
        )
    print(f"Completed {result.stats.success} requests")
    print(f"Retried {result.stats.soft_retries} times")


if __name__ == "__main__":
    main()

Running Examples

make run-basic-usage
make run-example EXAMPLE=input_collection
make run-example EXAMPLE=callbacks
make run-example EXAMPLE=custom_parser
make run-example EXAMPLE=retry_exhaustion
make run-example EXAMPLE=stop_condition
make run-example EXAMPLE=timeouts

Features

  • Generator Support: Takes a generator as input to generate request data on the fly.
  • Smart Retries: Separate logic for retrying based on request timeouts versus server information (like a 429 - Too Many Requests).
  • Custom Parsing: Decide exactly what data to keep from the response (headers, body, or status) before the final list is returned.
  • Progress Tracking: A nice progress bar that tracks successes, failures, and retries in real-time.

API Reference

Initialization

All configurations are passed during the initialization of the SPARP class:

class SPARP:
    def __init__(
        self: Self,
        input_collection: Iterable[Dict[str, Any]],             # Iterable of request configurations
        inspect_response: Callable[[aiohttp.ClientResponse], ResponseState], # Logic to categorize response status
        callbacks: Callbacks = Callbacks(),                      # Hooks for success, fail, and retry events
        concurrency: int = 100,                                 # Maximum number of simultaneous requests
        max_retries_by_soft_fail: int = 20,                     # Retry limit for server-side errors (e.g. 429)
        max_retries_by_timeout: int = 20,                       # Retry limit for connection or read timeouts
        parse_response: Callable[                               # Logic to extract data from the response
            [dict[str, Any], aiohttp.ClientResponse], Awaitable[Any]
        ] = default_parse_response,
        stop_conditions: StopConditions = StopConditions(),      # Thresholds to halt the entire process
        input_buffer_size: int = 100,                           # Items to pre-fetch from generator into memory
        show_progress_bar: bool = False,                        # Toggle the terminal progress UI
        estimated_input_collection_size: int | None = None,     # Total count for accurate progress percentage
        timeout_s: float = 30.0,                                # Seconds before a request attempt times out
        progress_bar_requests_threshold: int = 1,               # Min requests finished before UI updates
        progress_bar_time_threshold: datetime.timedelta =       # Min time elapsed before UI updates
            datetime.timedelta(seconds=0.5),
    ) -> None:
    ...

    def main() -> 

# Input classes

class ResponseState(Enum):
    HARD_FAIL = "HARD_FAIL"
    SOFT_FAIL = "SOFT_FAIL"
    SUCCESS = "SUCCESS"


class Callbacks:
    def __init__(
        self: Self,
        on_success: Callable[[dict[str, Any], aiohttp.ClientResponse], None] | None = None,
        on_hard_fail: Callable[[dict[str, Any], aiohttp.ClientResponse], None] | None = None,
        on_soft_fail: Callable[[dict[str, Any], int], None] | None = None,
        on_timeout: Callable[[dict[str, Any], int], None] | None = None,
        on_max_retries_by_soft_fail_reached: Callable[[dict[str, Any]], None] | None = None,
        on_max_retries_by_timeout_reached: Callable[[dict[str, Any]], None] | None = None,
    ) -> None:
    ...


# Output classes
@dataclass(frozen=True)
class SparpStats:
    success: int
    failed: int
    soft_retries: int
    timeout_retries: int


@dataclass(frozen=True)
class SparpResult:
    stats: SparpStats
    success: list[Any]
    failed: list[Any]
    max_retries_soft_fail_reached: list[dict[str, Any]]
    max_retries_timeout_reached: list[dict[str, Any]]

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

sparp-1.11.0.tar.gz (9.4 kB view details)

Uploaded Source

Built Distribution

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

sparp-1.11.0-py3-none-any.whl (9.5 kB view details)

Uploaded Python 3

File details

Details for the file sparp-1.11.0.tar.gz.

File metadata

  • Download URL: sparp-1.11.0.tar.gz
  • Upload date:
  • Size: 9.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for sparp-1.11.0.tar.gz
Algorithm Hash digest
SHA256 f23ccdd8a0f472f7b27eb3832bbeea56513b25c71bfbdcd8c81191e94832d661
MD5 d45bc5a5a92df5c4ab0c8217c03d6738
BLAKE2b-256 178b6d5dd4111e28cad57105d1c9cfc692115606a9eeffb2da865dd798df4331

See more details on using hashes here.

Provenance

The following attestation bundles were made for sparp-1.11.0.tar.gz:

Publisher: release.yml on fredo838/sparp

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

File details

Details for the file sparp-1.11.0-py3-none-any.whl.

File metadata

  • Download URL: sparp-1.11.0-py3-none-any.whl
  • Upload date:
  • Size: 9.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for sparp-1.11.0-py3-none-any.whl
Algorithm Hash digest
SHA256 01843392d21f0d4f5b1c7116fd3cced064dbc85c825022e17c805e8435b617a0
MD5 18fe614942f1aedb9ca3fa67c2992848
BLAKE2b-256 94bd4fef541a1ff17ac4e57ba112f7487c27fa04e5e6a4e6da620f887eddca2f

See more details on using hashes here.

Provenance

The following attestation bundles were made for sparp-1.11.0-py3-none-any.whl:

Publisher: release.yml on fredo838/sparp

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