resilient-result
Resilience mechanisms with Result types.
from resilient_result import resilient, Result
# Simple: perfect defaults for most cases
@resilient()
async def call_api(url: str) -> str:
return await http.get(url)
# Advanced: compose individual mechanisms
@timeout(seconds=10)
@retry(attempts=5)
async def robust_call(url: str) -> str:
return await http.get(url)
result: Result[str, Exception] = await call_api("https://api.example.com")
if result.success:
data = result.unwrap() # Extract data safely
print(data)
else:
print(f"Failed: {result.error}") # Inspect error directly
Why resilient-result? Network calls fail. Databases timeout. APIs rate limit. Handle it cleanly without exception soup.
Observability built-in: Enable logging.getLogger('resilient_result').setLevel(logging.DEBUG) to see retry attempts and recovery.
📖 Result API | 🔧 Resilience Patterns
Installation
pip install resilient-result
Core Features
Progressive Disclosure
from resilient_result import resilient, retry, timeout, circuit, rate_limit
# Simple: Just works with reasonable defaults
@resilient() # 2 attempts, 1s backoff, 30s timeout
async def simple_operation():
return await external_service()
# Advanced: Compose individual mechanisms
@rate_limit(rps=100) # Rate limiting (100 rps default)
@circuit(failures=3) # Circuit breaker (1 minute window)
@timeout(seconds=10) # Time-based protection
@retry(attempts=5) # Retry mechanism
async def critical_operation():
return await external_service()
Result Usage
from resilient_result import Result, Ok, Err
# Pattern 1: Check then unwrap
result = await call_api("https://api.example.com")
if result.success:
data = result.unwrap()
process(data)
# Pattern 2: Error inspection for conditional logic
result = await call_api("https://api.example.com")
if result.failure and "rate_limit" in result.error:
await asyncio.sleep(60) # Backoff on rate limit
retry()
elif result.failure:
log_error(result.error)
# Pattern 3: Direct unwrap (raises exception on failure)
try:
data = result.unwrap()
process(data)
except ApiError as e:
log_error(e)
Policy Configuration
from resilient_result import Retry, Backoff, Circuit, resilient
# Explicit policy configuration
@resilient(
retry=Retry(attempts=5, timeout=60),
backoff=Backoff.exp(delay=0.1, max_delay=10), # Jitter enabled by default
circuit=Circuit(failures=3, window=60) # 1 minute window
)
async def custom_operation():
return await external_service()
# Shorthand for common patterns
@resilient(retry=Retry(attempts=5)) # Just more attempts
@resilient(timeout=60) # Just longer timeout
async def database_operation():
return await db.query()
Parallel Operations
from resilient_result import Result
# Collect multiple async operations
operations = [fetch_user(1), fetch_user(2), fetch_user(3)]
result = await Result.collect(operations)
if result.success:
users = result.unwrap() # All succeeded
else:
try:
result.unwrap() # Raises first failure
except Exception as e:
print(f"First failure: {e}")
Error Inspection Patterns
# Canonical API: 3 ways to work with Results
result = await call_api("https://api.example.com")
# 1. Status checking
if result.success:
print("Success!")
if result.failure:
print("Failed!")
# 2. Error inspection (without exceptions)
if result.failure:
error_msg = result.error
if "network" in str(error_msg):
retry_with_backoff()
elif "auth" in str(error_msg):
refresh_token()
# 3. Value extraction (raises on failure)
try:
data = result.unwrap()
process(data)
except Exception as e:
handle_error(e)
License
MIT - Build amazing resilient systems! 🚀
🗺️ Roadmap
Metadata
Release files for resilient-result 0.4.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| resilient_result-0.4.1.tar.gz | 10.5 kB | Without provenance | Details for resilient_result-0.4.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| resilient_result-0.4.1-py3-none-any.whl | Python 3 | none | any | Details for resilient_result-0.4.1-py3-none-any.whl |
Total release size: 22.5 kB
Release files / resilient_result-0.4.1.tar.gz
| Download URL | resilient_result-0.4.1.tar.gz |
|---|---|
| Size | 10.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6f7f3d8f1e513058790ba415ed519e82f81d1e4aa2ed4f32a16ee158ea3fa8c7
|
|
BLAKE2b-256 checksum How to use checksums |
68190dea2f5095d26aa6d4aa496d1945531893b7d8eaf9f2691ce410c0648376
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.1.3 CPython/3.12.10 Darwin/24.5.0
|
Release files / resilient_result-0.4.1-py3-none-any.whl
| Download URL | resilient_result-0.4.1-py3-none-any.whl |
|---|---|
| Size | 12.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
31edb802ea60a313c7fbf15a501bc2aec023794a2b64ffa5e7424684687603df
|
|
BLAKE2b-256 checksum How to use checksums |
dcb0abf94b578d042ba11936c2239746c8ee835007e86e35b78f225cf09d0612
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.1.3 CPython/3.12.10 Darwin/24.5.0
|
Security for resilient-result 0.4.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.