# resilient-result
[](https://badge.fury.io/py/resilient-result)
[](https://www.python.org/downloads/)
[](https://opensource.org/licenses/MIT)
**Resilience mechanisms with Result types.**
```python
from resilient_result import retry, timeout, Result
@retry(attempts=3)
@timeout(10.0)
async def call_api(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?** Pure mechanisms over domain patterns, Result types over exceptions, orthogonal composition.
**π [Result API](docs/result.md) | π§ [Resilience Patterns](docs/resilient.md)**
## Installation
```bash
pip install resilient-result
```
## Core Features
### Pure Mechanism Composition
```python
from resilient_result import retry, timeout, circuit, rate_limit
# Orthogonal composition - each decorator handles one concern
@retry(attempts=3) # Retry mechanism
@timeout(10.0) # Time-based protection
@circuit(failures=5) # Circuit breaker protection
@rate_limit(rps=100) # Rate limiting mechanism
async def critical_operation():
return await external_service()
```
### Result Usage
```python
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)
```
### Advanced Composition
```python
from resilient_result import compose, resilient
# Manual composition - right to left
@compose(
circuit(failures=3),
timeout(10.0),
retry(attempts=3)
)
async def robust_operation():
return await external_service()
# Pre-built patterns
@resilient.api() # timeout(30) + retry(3)
@resilient.db() # timeout(60) + retry(5)
@resilient.protected() # circuit + retry
```
### Parallel Operations
```python
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
```python
# 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](docs/dev/roadmap.md)**
Raw data
{
"_id": null,
"home_page": "https://github.com/iteebz/resilient-result",
"name": "resilient-result",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.8",
"maintainer_email": null,
"keywords": "result, error-handling, resilient, retry, timeout, async",
"author": "resilient-result contributors",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/a4/3c/b42c88ba1224e819993709fa96f81e0dbbef14ec65e9d5a4683c6b28e5cf/resilient_result-0.4.0.tar.gz",
"platform": null,
"description": "# resilient-result\n\n[](https://badge.fury.io/py/resilient-result)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n\n**Resilience mechanisms with Result types.**\n\n```python\nfrom resilient_result import retry, timeout, Result\n\n@retry(attempts=3)\n@timeout(10.0)\nasync def call_api(url: str) -> str:\n return await http.get(url)\n\nresult: Result[str, Exception] = await call_api(\"https://api.example.com\")\nif result.success:\n data = result.unwrap() # Extract data safely\n print(data)\nelse:\n print(f\"Failed: {result.error}\") # Inspect error directly\n```\n\n**Why resilient-result?** Pure mechanisms over domain patterns, Result types over exceptions, orthogonal composition.\n\n**\ud83d\udcd6 [Result API](docs/result.md) | \ud83d\udd27 [Resilience Patterns](docs/resilient.md)**\n\n## Installation\n\n```bash\npip install resilient-result\n```\n\n## Core Features\n\n### Pure Mechanism Composition\n```python\nfrom resilient_result import retry, timeout, circuit, rate_limit\n\n# Orthogonal composition - each decorator handles one concern\n@retry(attempts=3) # Retry mechanism\n@timeout(10.0) # Time-based protection \n@circuit(failures=5) # Circuit breaker protection\n@rate_limit(rps=100) # Rate limiting mechanism\nasync def critical_operation():\n return await external_service()\n```\n\n### Result Usage\n```python\nfrom resilient_result import Result, Ok, Err\n\n# Pattern 1: Check then unwrap\nresult = await call_api(\"https://api.example.com\")\nif result.success:\n data = result.unwrap()\n process(data)\n\n# Pattern 2: Error inspection for conditional logic\nresult = await call_api(\"https://api.example.com\")\nif result.failure and \"rate_limit\" in result.error:\n await asyncio.sleep(60) # Backoff on rate limit\n retry()\nelif result.failure:\n log_error(result.error)\n\n# Pattern 3: Direct unwrap (raises exception on failure)\ntry:\n data = result.unwrap()\n process(data)\nexcept ApiError as e:\n log_error(e)\n```\n\n### Advanced Composition\n```python\nfrom resilient_result import compose, resilient\n\n# Manual composition - right to left\n@compose(\n circuit(failures=3),\n timeout(10.0), \n retry(attempts=3)\n)\nasync def robust_operation():\n return await external_service()\n\n# Pre-built patterns\n@resilient.api() # timeout(30) + retry(3)\n@resilient.db() # timeout(60) + retry(5)\n@resilient.protected() # circuit + retry\n```\n\n### Parallel Operations\n```python\nfrom resilient_result import Result\n\n# Collect multiple async operations\noperations = [fetch_user(1), fetch_user(2), fetch_user(3)]\nresult = await Result.collect(operations)\n\nif result.success:\n users = result.unwrap() # All succeeded\nelse:\n try:\n result.unwrap() # Raises first failure\n except Exception as e:\n print(f\"First failure: {e}\")\n```\n\n### Error Inspection Patterns\n```python\n# Canonical API: 3 ways to work with Results\nresult = await call_api(\"https://api.example.com\")\n\n# 1. Status checking\nif result.success:\n print(\"Success!\")\nif result.failure:\n print(\"Failed!\")\n\n# 2. Error inspection (without exceptions)\nif result.failure:\n error_msg = result.error\n if \"network\" in str(error_msg):\n retry_with_backoff()\n elif \"auth\" in str(error_msg):\n refresh_token()\n\n# 3. Value extraction (raises on failure)\ntry:\n data = result.unwrap() \n process(data)\nexcept Exception as e:\n handle_error(e)\n```\n\n## License\n\nMIT - Build amazing resilient systems! \ud83d\ude80\n\n---\n\n**\ud83d\uddfa\ufe0f [Roadmap](docs/dev/roadmap.md)**",
"bugtrack_url": null,
"license": "MIT",
"summary": "Resilient decorators that return Result types instead of throwing exceptions",
"version": "0.4.0",
"project_urls": {
"Homepage": "https://github.com/iteebz/resilient-result",
"Repository": "https://github.com/iteebz/resilient-result"
},
"split_keywords": [
"result",
" error-handling",
" resilient",
" retry",
" timeout",
" async"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "e5f1cf50d7dabb46fd62495d5f5d0ea803bb7c13a1298fb43f9f1e2deb4b8a72",
"md5": "a4bfcd5a123b36b91dbd88d18a03c0d1",
"sha256": "f40dcdb466ef1c7122091b0f73dac2271db82fe9560200b71913d4d6f7a98489"
},
"downloads": -1,
"filename": "resilient_result-0.4.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "a4bfcd5a123b36b91dbd88d18a03c0d1",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.8",
"size": 11255,
"upload_time": "2025-08-13T07:35:32",
"upload_time_iso_8601": "2025-08-13T07:35:32.091446Z",
"url": "https://files.pythonhosted.org/packages/e5/f1/cf50d7dabb46fd62495d5f5d0ea803bb7c13a1298fb43f9f1e2deb4b8a72/resilient_result-0.4.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "a43cb42c88ba1224e819993709fa96f81e0dbbef14ec65e9d5a4683c6b28e5cf",
"md5": "96e5d89fe92c567bae8ad3925533750b",
"sha256": "b11ddd8f758027f26e5a951b84607f0fea75ce460587a12b9ede8b881040b732"
},
"downloads": -1,
"filename": "resilient_result-0.4.0.tar.gz",
"has_sig": false,
"md5_digest": "96e5d89fe92c567bae8ad3925533750b",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.8",
"size": 9756,
"upload_time": "2025-08-13T07:35:33",
"upload_time_iso_8601": "2025-08-13T07:35:33.477346Z",
"url": "https://files.pythonhosted.org/packages/a4/3c/b42c88ba1224e819993709fa96f81e0dbbef14ec65e9d5a4683c6b28e5cf/resilient_result-0.4.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-13 07:35:33",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "iteebz",
"github_project": "resilient-result",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "resilient-result"
}