resilient-result


Nameresilient-result JSON
Version 0.4.0 PyPI version JSON
download
home_pagehttps://github.com/iteebz/resilient-result
SummaryResilient decorators that return Result types instead of throwing exceptions
upload_time2025-08-13 07:35:33
maintainerNone
docs_urlNone
authorresilient-result contributors
requires_python<4.0,>=3.8
licenseMIT
keywords result error-handling resilient retry timeout async
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # resilient-result

[![PyPI version](https://badge.fury.io/py/resilient-result.svg)](https://badge.fury.io/py/resilient-result)
[![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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[![PyPI version](https://badge.fury.io/py/resilient-result.svg)](https://badge.fury.io/py/resilient-result)\n[![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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"
}
        
Elapsed time: 2.60388s