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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f23ccdd8a0f472f7b27eb3832bbeea56513b25c71bfbdcd8c81191e94832d661
|
|
| MD5 |
d45bc5a5a92df5c4ab0c8217c03d6738
|
|
| BLAKE2b-256 |
178b6d5dd4111e28cad57105d1c9cfc692115606a9eeffb2da865dd798df4331
|
Provenance
The following attestation bundles were made for sparp-1.11.0.tar.gz:
Publisher:
release.yml on fredo838/sparp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sparp-1.11.0.tar.gz -
Subject digest:
f23ccdd8a0f472f7b27eb3832bbeea56513b25c71bfbdcd8c81191e94832d661 - Sigstore transparency entry: 2143340897
- Sigstore integration time:
-
Permalink:
fredo838/sparp@075280b28bcf09b1f5925fffaab2bfa68dae0697 -
Branch / Tag:
refs/tags/v1.11.0 - Owner: https://github.com/fredo838
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@075280b28bcf09b1f5925fffaab2bfa68dae0697 -
Trigger Event:
push
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
01843392d21f0d4f5b1c7116fd3cced064dbc85c825022e17c805e8435b617a0
|
|
| MD5 |
18fe614942f1aedb9ca3fa67c2992848
|
|
| BLAKE2b-256 |
94bd4fef541a1ff17ac4e57ba112f7487c27fa04e5e6a4e6da620f887eddca2f
|
Provenance
The following attestation bundles were made for sparp-1.11.0-py3-none-any.whl:
Publisher:
release.yml on fredo838/sparp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sparp-1.11.0-py3-none-any.whl -
Subject digest:
01843392d21f0d4f5b1c7116fd3cced064dbc85c825022e17c805e8435b617a0 - Sigstore transparency entry: 2143340933
- Sigstore integration time:
-
Permalink:
fredo838/sparp@075280b28bcf09b1f5925fffaab2bfa68dae0697 -
Branch / Tag:
refs/tags/v1.11.0 - Owner: https://github.com/fredo838
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@075280b28bcf09b1f5925fffaab2bfa68dae0697 -
Trigger Event:
push
-
Statement type: