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.10.2.tar.gz (8.8 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.10.2-py3-none-any.whl (7.8 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for sparp-1.10.2.tar.gz
Algorithm Hash digest
SHA256 913a03d5c2a44c790131c2b12f316bc5385f67a4f2e6fa818a14df6c6fe13662
MD5 7048ea23ba0ce6bfcdc367b5093f8bfe
BLAKE2b-256 2595ee037bd3d5a4bc400b730261c2914ea44a3634d30439d14c8604b303ff80

See more details on using hashes here.

Provenance

The following attestation bundles were made for sparp-1.10.2.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.10.2-py3-none-any.whl.

File metadata

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

File hashes

Hashes for sparp-1.10.2-py3-none-any.whl
Algorithm Hash digest
SHA256 eb3be260988a50131729964fc8011a96e49ac18feadcfb4b12e42d69a785ee21
MD5 65d0415d9f09517f92f38d6a26f16826
BLAKE2b-256 4ef5154fafd7e56f8009d2628b0a6e81692ec70e060bb95cac14b0d510d127b3

See more details on using hashes here.

Provenance

The following attestation bundles were made for sparp-1.10.2-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