dhrupad-sah-exception-catcher


Namedhrupad-sah-exception-catcher JSON
Version 1.0.4 PyPI version JSON
download
home_pageNone
SummaryAutomatically catch and report exceptions to Mira Sentinel with rich context and log integration for AI-powered debugging and automatic fix generation
upload_time2025-07-24 15:53:47
maintainerNone
docs_urlNone
authorNone
requires_python>=3.8
licenseMIT
keywords exception error-handling monitoring observability logging automation claude ai-fixing fastapi flask django
VCS
bugtrack_url
requirements httpx pydantic psutil
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # dhrupad-sah-exception-catcher

Automatically catch and report exceptions to Mira Sentinel with rich context and log integration for AI-powered debugging and automatic fix generation.

## Features

- 🚨 **Automatic Exception Catching** - Monitors uncaught exceptions and unhandled rejections
- 📊 **Rich Context** - Collects system info, memory usage, and custom context
- 🔍 **Log Integration** - Correlates exceptions with log data for enhanced debugging
- 🤖 **AI-Powered Fixes** - Integrates with Claude Code for automatic issue resolution
- 📋 **GitHub Integration** - Automatically creates issues and pull requests
- 🔄 **Retry Logic** - Robust error reporting with configurable retries
- 🎯 **Flexible Filtering** - Custom error filtering and context enrichment

## Installation

```bash
# Using PDM (recommended)
pdm add dhrupad-sah-exception-catcher

# Using pip
pip install dhrupad-sah-exception-catcher

# With FastAPI support
pdm add dhrupad-sah-exception-catcher[fastapi]

# With Flask support  
pdm add dhrupad-sah-exception-catcher[flask]

# With all framework support
pdm add dhrupad-sah-exception-catcher[fastapi,flask]
```

## Quick Start

### FastAPI Integration (Recommended for APIs)

```python
from fastapi import FastAPI
from exception_catcher import setup_fastapi_mira_sentinel, MiraSentinelConfig
import os

app = FastAPI()

# Set up Mira Sentinel with environment variables
config = MiraSentinelConfig(
    sentinel_url=os.getenv("MIRA_SENTINEL_URL"),
    service_name=os.getenv("MIRA_SERVICE_NAME", "fastapi-service"),
    repo=os.getenv("MIRA_REPO", "company/fastapi-service")
)

# Set up automatic exception catching
sentinel = setup_fastapi_mira_sentinel(
    app,
    config,
    
    # Optional: Skip client errors
    skip_status_codes=[400, 401, 403, 404],
    
    # Optional: Extract custom context
    extract_request_context=lambda request: {
        "user_id": request.headers.get("x-user-id"),
        "trace_id": request.headers.get("x-trace-id")
    }
)

# Your routes - exceptions are automatically caught and reported
@app.get("/users/{user_id}")
async def get_user(user_id: int):
    user = await get_user_from_db(user_id)  # Any error here is caught
    return user

# Manual exception reporting is also available  
@app.get("/manual-report")
async def manual_report():
    try:
        await risky_operation()
    except Exception as error:
        await app.state.mira_sentinel.report_exception(error, {
            "context": {"operation": "risky"}
        })
        raise  # Re-raise to send HTTP error response

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
```

### Basic Usage (Non-Framework Apps)

```python
from exception_catcher import MiraSentinelExceptionCatcher, MiraSentinelConfig

config = MiraSentinelConfig(
    sentinel_url="https://your-sentinel-instance.com",
    service_name="python-service",
    repo="company/python-service"
)

catcher = MiraSentinelExceptionCatcher(config)
catcher.initialize()

# That's it! All exceptions are now automatically caught and reported
```

### Environment-Based Auto-Initialization

```python
from exception_catcher import auto_initialize

# Set environment variables:
# MIRA_SENTINEL_URL=https://your-sentinel-instance.com
# MIRA_SERVICE_NAME=python-service
# MIRA_REPO=company/python-service

catcher = auto_initialize()
# Automatically initializes if environment variables are set
```

### Advanced Configuration

```python
from exception_catcher import MiraSentinelExceptionCatcher, MiraSentinelConfig

config = MiraSentinelConfig(
    sentinel_url="https://your-sentinel-instance.com",
    service_name="python-service", 
    repo="company/python-service",
    api_key="your-api-key",  # Optional authentication
    timeout=15.0,  # HTTP timeout in seconds
    retry_attempts=5,
    retry_delay=2.0
)

catcher = MiraSentinelExceptionCatcher(config)

# Custom error filtering
catcher.set_error_filter(lambda error: 
    # Skip test errors
    "test" not in str(error).lower()
)

# Enrich context with custom data
catcher.set_context_enricher(lambda error, context: {
    "user_id": get_current_user_id(),
    "request_id": get_current_request_id(),
    "version": os.getenv("APP_VERSION")
})

catcher.initialize()
```

## Manual Exception Reporting

```python
import asyncio
from exception_catcher import ReportOptions

try:
    # Some risky operation
    await process_payment(payment_data)
except Exception as error:
    # Manually report with additional context
    await catcher.report_exception(error, ReportOptions(
        context={
            "payment_id": payment_data.id,
            "user_id": payment_data.user_id,
            "amount": payment_data.amount
        },
        tags=["payment", "critical"],
        severity="high"
    ))
    
    raise  # Re-throw if needed
```

## Integration with Flask

```python
from flask import Flask
from exception_catcher import setup_flask_mira_sentinel, MiraSentinelConfig
import os

app = Flask(__name__)

config = MiraSentinelConfig(
    sentinel_url=os.getenv("MIRA_SENTINEL_URL"),
    service_name="flask-api",
    repo="company/flask-api"
)

# Set up automatic exception catching
sentinel = setup_flask_mira_sentinel(
    app,
    config,
    include_headers=True,
    skip_status_codes=[400, 401, 403, 404],
    extract_request_context=lambda request: {
        "user_id": request.headers.get("X-User-ID"),
        "session_id": request.headers.get("X-Session-ID")
    }
)

@app.route("/users/<int:user_id>")
def get_user(user_id):
    user = get_user_from_db(user_id)  # Any error here is caught
    return jsonify(user)

# Manual exception reporting
@app.route("/manual-report")
def manual_report():
    try:
        risky_operation()
    except Exception as error:
        # Note: Flask integration runs async in sync context
        import asyncio
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        try:
            loop.run_until_complete(
                app.mira_sentinel.report_exception(error, {
                    "context": {"operation": "risky"}
                })
            )
        finally:
            loop.close()
        raise

if __name__ == "__main__":
    app.run(debug=True)
```

## Environment Variables

| Variable | Description | Required |
|----------|-------------|----------|
| `MIRA_SENTINEL_URL` | URL of your Mira Sentinel instance | Yes |
| `MIRA_SERVICE_NAME` | Name of your service | Yes |
| `MIRA_REPO` | GitHub repository (owner/repo) | Yes |
| `MIRA_API_KEY` | API key for authentication | No |
| `MIRA_ENABLED` | Enable/disable (default: true) | No |

## Configuration Options

| Option | Type | Description | Default |
|--------|------|-------------|---------|
| `sentinel_url` | str | Mira Sentinel instance URL | Required |
| `service_name` | str | Service name for log correlation | Required |
| `repo` | str | GitHub repository (owner/repo) | Required |
| `api_key` | str | Optional API key | None |
| `enabled` | bool | Enable/disable catching | True |
| `timeout` | float | HTTP timeout (seconds) | 10.0 |
| `retry_attempts` | int | Retry attempts | 3 |
| `retry_delay` | float | Retry delay (seconds) | 1.0 |

## How It Works

1. **Exception Occurs** - Your service throws an exception
2. **Context Collection** - Rich context is automatically collected:
   - Error message and stack trace
   - System information (Python version, memory, CPU)
   - Timestamp for log correlation
   - Custom context from your application
3. **Sent to Mira Sentinel** - Exception data is sent to your Sentinel instance
4. **Log Integration** - Sentinel queries logs around the exception time
5. **AI Analysis** - Claude Code analyzes the exception + log context
6. **GitHub Integration** - Issue and PR are automatically created
7. **Timeline Analysis** - Full timeline of events leading to the exception

## Best Practices

### 1. Service Naming
Use consistent service names that match your log labels:

```python
# Good - matches log service label
service_name="api-gateway"

# Bad - doesn't match logs
service_name="my-awesome-service"
```

### 2. Error Filtering
Filter out noise to focus on actionable exceptions:

```python
def should_catch_error(error):
    # Skip test environments
    if os.getenv("ENV") == "test":
        return False
    
    # Skip known non-critical errors
    if "ConnectionResetError" in str(error):
        return False
    
    # Skip client errors for HTTP frameworks
    if hasattr(error, 'status_code') and 400 <= error.status_code < 500:
        return False
    
    return True

catcher.set_error_filter(should_catch_error)
```

### 3. Context Enrichment
Add meaningful context for better debugging:

```python
def enrich_context(error, context):
    return {
        # Business context
        "tenant_id": get_current_tenant(),
        "feature": get_current_feature(),
        
        # Technical context
        "version": os.getenv("APP_VERSION"),
        "deployment": os.getenv("DEPLOYMENT_ID"),
        
        # Performance context
        "response_time": get_response_time(),
        "queue_size": get_queue_size()
    }

catcher.set_context_enricher(enrich_context)
```

### 4. Graceful Shutdown
Always clean up on process exit:

```python
import atexit

catcher = MiraSentinelExceptionCatcher(config)
catcher.initialize()

def cleanup():
    catcher.shutdown()

atexit.register(cleanup)
```

## Testing

Test your integration:

```python
import asyncio
from exception_catcher import auto_initialize

async def test_integration():
    catcher = auto_initialize()
    
    if catcher:
        print("✅ Configuration loaded successfully")
        
        # Test connection
        is_connected = await catcher.test_connection()
        if is_connected:
            print("✅ Connection to Mira Sentinel successful")
        else:
            print("❌ Connection failed - check your MIRA_SENTINEL_URL")
    else:
        print("❌ Missing required environment variables")
        print("Required: MIRA_SENTINEL_URL, MIRA_SERVICE_NAME, MIRA_REPO")

# Run test
asyncio.run(test_integration())
```

## Development

```bash
# Clone the repository
git clone https://github.com/dhrupad-sah/python-exception-catcher
cd python-exception-catcher

# Install dependencies with PDM
pdm install

# Install with development dependencies
pdm install -d

# Run tests
pdm run pytest

# Format code
pdm run black src/
pdm run isort src/

# Type checking
pdm run mypy src/
```

## License

MIT

## Support

For support, please create an issue in the [GitHub repository](https://github.com/dhrupad-sah/python-exception-catcher).
            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "dhrupad-sah-exception-catcher",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "exception, error-handling, monitoring, observability, logging, automation, claude, ai-fixing, fastapi, flask, django",
    "author": null,
    "author_email": "Mira Sentinel Team <noreply@example.com>",
    "download_url": "https://files.pythonhosted.org/packages/c5/1a/27065fa9aa2ac6f8ede667ea32100761c18383c0f1bda991b7bbf375ed19/dhrupad_sah_exception_catcher-1.0.4.tar.gz",
    "platform": null,
    "description": "# dhrupad-sah-exception-catcher\n\nAutomatically catch and report exceptions to Mira Sentinel with rich context and log integration for AI-powered debugging and automatic fix generation.\n\n## Features\n\n- \ud83d\udea8 **Automatic Exception Catching** - Monitors uncaught exceptions and unhandled rejections\n- \ud83d\udcca **Rich Context** - Collects system info, memory usage, and custom context\n- \ud83d\udd0d **Log Integration** - Correlates exceptions with log data for enhanced debugging\n- \ud83e\udd16 **AI-Powered Fixes** - Integrates with Claude Code for automatic issue resolution\n- \ud83d\udccb **GitHub Integration** - Automatically creates issues and pull requests\n- \ud83d\udd04 **Retry Logic** - Robust error reporting with configurable retries\n- \ud83c\udfaf **Flexible Filtering** - Custom error filtering and context enrichment\n\n## Installation\n\n```bash\n# Using PDM (recommended)\npdm add dhrupad-sah-exception-catcher\n\n# Using pip\npip install dhrupad-sah-exception-catcher\n\n# With FastAPI support\npdm add dhrupad-sah-exception-catcher[fastapi]\n\n# With Flask support  \npdm add dhrupad-sah-exception-catcher[flask]\n\n# With all framework support\npdm add dhrupad-sah-exception-catcher[fastapi,flask]\n```\n\n## Quick Start\n\n### FastAPI Integration (Recommended for APIs)\n\n```python\nfrom fastapi import FastAPI\nfrom exception_catcher import setup_fastapi_mira_sentinel, MiraSentinelConfig\nimport os\n\napp = FastAPI()\n\n# Set up Mira Sentinel with environment variables\nconfig = MiraSentinelConfig(\n    sentinel_url=os.getenv(\"MIRA_SENTINEL_URL\"),\n    service_name=os.getenv(\"MIRA_SERVICE_NAME\", \"fastapi-service\"),\n    repo=os.getenv(\"MIRA_REPO\", \"company/fastapi-service\")\n)\n\n# Set up automatic exception catching\nsentinel = setup_fastapi_mira_sentinel(\n    app,\n    config,\n    \n    # Optional: Skip client errors\n    skip_status_codes=[400, 401, 403, 404],\n    \n    # Optional: Extract custom context\n    extract_request_context=lambda request: {\n        \"user_id\": request.headers.get(\"x-user-id\"),\n        \"trace_id\": request.headers.get(\"x-trace-id\")\n    }\n)\n\n# Your routes - exceptions are automatically caught and reported\n@app.get(\"/users/{user_id}\")\nasync def get_user(user_id: int):\n    user = await get_user_from_db(user_id)  # Any error here is caught\n    return user\n\n# Manual exception reporting is also available  \n@app.get(\"/manual-report\")\nasync def manual_report():\n    try:\n        await risky_operation()\n    except Exception as error:\n        await app.state.mira_sentinel.report_exception(error, {\n            \"context\": {\"operation\": \"risky\"}\n        })\n        raise  # Re-raise to send HTTP error response\n\nif __name__ == \"__main__\":\n    import uvicorn\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\n### Basic Usage (Non-Framework Apps)\n\n```python\nfrom exception_catcher import MiraSentinelExceptionCatcher, MiraSentinelConfig\n\nconfig = MiraSentinelConfig(\n    sentinel_url=\"https://your-sentinel-instance.com\",\n    service_name=\"python-service\",\n    repo=\"company/python-service\"\n)\n\ncatcher = MiraSentinelExceptionCatcher(config)\ncatcher.initialize()\n\n# That's it! All exceptions are now automatically caught and reported\n```\n\n### Environment-Based Auto-Initialization\n\n```python\nfrom exception_catcher import auto_initialize\n\n# Set environment variables:\n# MIRA_SENTINEL_URL=https://your-sentinel-instance.com\n# MIRA_SERVICE_NAME=python-service\n# MIRA_REPO=company/python-service\n\ncatcher = auto_initialize()\n# Automatically initializes if environment variables are set\n```\n\n### Advanced Configuration\n\n```python\nfrom exception_catcher import MiraSentinelExceptionCatcher, MiraSentinelConfig\n\nconfig = MiraSentinelConfig(\n    sentinel_url=\"https://your-sentinel-instance.com\",\n    service_name=\"python-service\", \n    repo=\"company/python-service\",\n    api_key=\"your-api-key\",  # Optional authentication\n    timeout=15.0,  # HTTP timeout in seconds\n    retry_attempts=5,\n    retry_delay=2.0\n)\n\ncatcher = MiraSentinelExceptionCatcher(config)\n\n# Custom error filtering\ncatcher.set_error_filter(lambda error: \n    # Skip test errors\n    \"test\" not in str(error).lower()\n)\n\n# Enrich context with custom data\ncatcher.set_context_enricher(lambda error, context: {\n    \"user_id\": get_current_user_id(),\n    \"request_id\": get_current_request_id(),\n    \"version\": os.getenv(\"APP_VERSION\")\n})\n\ncatcher.initialize()\n```\n\n## Manual Exception Reporting\n\n```python\nimport asyncio\nfrom exception_catcher import ReportOptions\n\ntry:\n    # Some risky operation\n    await process_payment(payment_data)\nexcept Exception as error:\n    # Manually report with additional context\n    await catcher.report_exception(error, ReportOptions(\n        context={\n            \"payment_id\": payment_data.id,\n            \"user_id\": payment_data.user_id,\n            \"amount\": payment_data.amount\n        },\n        tags=[\"payment\", \"critical\"],\n        severity=\"high\"\n    ))\n    \n    raise  # Re-throw if needed\n```\n\n## Integration with Flask\n\n```python\nfrom flask import Flask\nfrom exception_catcher import setup_flask_mira_sentinel, MiraSentinelConfig\nimport os\n\napp = Flask(__name__)\n\nconfig = MiraSentinelConfig(\n    sentinel_url=os.getenv(\"MIRA_SENTINEL_URL\"),\n    service_name=\"flask-api\",\n    repo=\"company/flask-api\"\n)\n\n# Set up automatic exception catching\nsentinel = setup_flask_mira_sentinel(\n    app,\n    config,\n    include_headers=True,\n    skip_status_codes=[400, 401, 403, 404],\n    extract_request_context=lambda request: {\n        \"user_id\": request.headers.get(\"X-User-ID\"),\n        \"session_id\": request.headers.get(\"X-Session-ID\")\n    }\n)\n\n@app.route(\"/users/<int:user_id>\")\ndef get_user(user_id):\n    user = get_user_from_db(user_id)  # Any error here is caught\n    return jsonify(user)\n\n# Manual exception reporting\n@app.route(\"/manual-report\")\ndef manual_report():\n    try:\n        risky_operation()\n    except Exception as error:\n        # Note: Flask integration runs async in sync context\n        import asyncio\n        loop = asyncio.new_event_loop()\n        asyncio.set_event_loop(loop)\n        try:\n            loop.run_until_complete(\n                app.mira_sentinel.report_exception(error, {\n                    \"context\": {\"operation\": \"risky\"}\n                })\n            )\n        finally:\n            loop.close()\n        raise\n\nif __name__ == \"__main__\":\n    app.run(debug=True)\n```\n\n## Environment Variables\n\n| Variable | Description | Required |\n|----------|-------------|----------|\n| `MIRA_SENTINEL_URL` | URL of your Mira Sentinel instance | Yes |\n| `MIRA_SERVICE_NAME` | Name of your service | Yes |\n| `MIRA_REPO` | GitHub repository (owner/repo) | Yes |\n| `MIRA_API_KEY` | API key for authentication | No |\n| `MIRA_ENABLED` | Enable/disable (default: true) | No |\n\n## Configuration Options\n\n| Option | Type | Description | Default |\n|--------|------|-------------|---------|\n| `sentinel_url` | str | Mira Sentinel instance URL | Required |\n| `service_name` | str | Service name for log correlation | Required |\n| `repo` | str | GitHub repository (owner/repo) | Required |\n| `api_key` | str | Optional API key | None |\n| `enabled` | bool | Enable/disable catching | True |\n| `timeout` | float | HTTP timeout (seconds) | 10.0 |\n| `retry_attempts` | int | Retry attempts | 3 |\n| `retry_delay` | float | Retry delay (seconds) | 1.0 |\n\n## How It Works\n\n1. **Exception Occurs** - Your service throws an exception\n2. **Context Collection** - Rich context is automatically collected:\n   - Error message and stack trace\n   - System information (Python version, memory, CPU)\n   - Timestamp for log correlation\n   - Custom context from your application\n3. **Sent to Mira Sentinel** - Exception data is sent to your Sentinel instance\n4. **Log Integration** - Sentinel queries logs around the exception time\n5. **AI Analysis** - Claude Code analyzes the exception + log context\n6. **GitHub Integration** - Issue and PR are automatically created\n7. **Timeline Analysis** - Full timeline of events leading to the exception\n\n## Best Practices\n\n### 1. Service Naming\nUse consistent service names that match your log labels:\n\n```python\n# Good - matches log service label\nservice_name=\"api-gateway\"\n\n# Bad - doesn't match logs\nservice_name=\"my-awesome-service\"\n```\n\n### 2. Error Filtering\nFilter out noise to focus on actionable exceptions:\n\n```python\ndef should_catch_error(error):\n    # Skip test environments\n    if os.getenv(\"ENV\") == \"test\":\n        return False\n    \n    # Skip known non-critical errors\n    if \"ConnectionResetError\" in str(error):\n        return False\n    \n    # Skip client errors for HTTP frameworks\n    if hasattr(error, 'status_code') and 400 <= error.status_code < 500:\n        return False\n    \n    return True\n\ncatcher.set_error_filter(should_catch_error)\n```\n\n### 3. Context Enrichment\nAdd meaningful context for better debugging:\n\n```python\ndef enrich_context(error, context):\n    return {\n        # Business context\n        \"tenant_id\": get_current_tenant(),\n        \"feature\": get_current_feature(),\n        \n        # Technical context\n        \"version\": os.getenv(\"APP_VERSION\"),\n        \"deployment\": os.getenv(\"DEPLOYMENT_ID\"),\n        \n        # Performance context\n        \"response_time\": get_response_time(),\n        \"queue_size\": get_queue_size()\n    }\n\ncatcher.set_context_enricher(enrich_context)\n```\n\n### 4. Graceful Shutdown\nAlways clean up on process exit:\n\n```python\nimport atexit\n\ncatcher = MiraSentinelExceptionCatcher(config)\ncatcher.initialize()\n\ndef cleanup():\n    catcher.shutdown()\n\natexit.register(cleanup)\n```\n\n## Testing\n\nTest your integration:\n\n```python\nimport asyncio\nfrom exception_catcher import auto_initialize\n\nasync def test_integration():\n    catcher = auto_initialize()\n    \n    if catcher:\n        print(\"\u2705 Configuration loaded successfully\")\n        \n        # Test connection\n        is_connected = await catcher.test_connection()\n        if is_connected:\n            print(\"\u2705 Connection to Mira Sentinel successful\")\n        else:\n            print(\"\u274c Connection failed - check your MIRA_SENTINEL_URL\")\n    else:\n        print(\"\u274c Missing required environment variables\")\n        print(\"Required: MIRA_SENTINEL_URL, MIRA_SERVICE_NAME, MIRA_REPO\")\n\n# Run test\nasyncio.run(test_integration())\n```\n\n## Development\n\n```bash\n# Clone the repository\ngit clone https://github.com/dhrupad-sah/python-exception-catcher\ncd python-exception-catcher\n\n# Install dependencies with PDM\npdm install\n\n# Install with development dependencies\npdm install -d\n\n# Run tests\npdm run pytest\n\n# Format code\npdm run black src/\npdm run isort src/\n\n# Type checking\npdm run mypy src/\n```\n\n## License\n\nMIT\n\n## Support\n\nFor support, please create an issue in the [GitHub repository](https://github.com/dhrupad-sah/python-exception-catcher).",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Automatically catch and report exceptions to Mira Sentinel with rich context and log integration for AI-powered debugging and automatic fix generation",
    "version": "1.0.4",
    "project_urls": {
        "Documentation": "https://github.com/dhrupad-sah/python-exception-catcher#readme",
        "Homepage": "https://github.com/dhrupad-sah/python-exception-catcher",
        "Issues": "https://github.com/dhrupad-sah/python-exception-catcher/issues",
        "Repository": "https://github.com/dhrupad-sah/python-exception-catcher"
    },
    "split_keywords": [
        "exception",
        " error-handling",
        " monitoring",
        " observability",
        " logging",
        " automation",
        " claude",
        " ai-fixing",
        " fastapi",
        " flask",
        " django"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "8a73e1392e2c61a79d2cd7a4d990bcb7e364ef6a198ba2ad089859e59ba384fc",
                "md5": "35d99747d0cebb25e6dc78fa6fc83e69",
                "sha256": "220a10ac133b228d8e77dcb65ded75b071baa36127c07e0cd995cd5ad5519dc7"
            },
            "downloads": -1,
            "filename": "dhrupad_sah_exception_catcher-1.0.4-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "35d99747d0cebb25e6dc78fa6fc83e69",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 15942,
            "upload_time": "2025-07-24T15:53:46",
            "upload_time_iso_8601": "2025-07-24T15:53:46.202243Z",
            "url": "https://files.pythonhosted.org/packages/8a/73/e1392e2c61a79d2cd7a4d990bcb7e364ef6a198ba2ad089859e59ba384fc/dhrupad_sah_exception_catcher-1.0.4-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "c51a27065fa9aa2ac6f8ede667ea32100761c18383c0f1bda991b7bbf375ed19",
                "md5": "58f92e6db0f87911b8297ca4158ca678",
                "sha256": "5182bfdf8405193872f797e7f001a7544d8e96b72cccbb8867d1fac71d2f84b5"
            },
            "downloads": -1,
            "filename": "dhrupad_sah_exception_catcher-1.0.4.tar.gz",
            "has_sig": false,
            "md5_digest": "58f92e6db0f87911b8297ca4158ca678",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 15175,
            "upload_time": "2025-07-24T15:53:47",
            "upload_time_iso_8601": "2025-07-24T15:53:47.440643Z",
            "url": "https://files.pythonhosted.org/packages/c5/1a/27065fa9aa2ac6f8ede667ea32100761c18383c0f1bda991b7bbf375ed19/dhrupad_sah_exception_catcher-1.0.4.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-24 15:53:47",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "dhrupad-sah",
    "github_project": "python-exception-catcher#readme",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [
        {
            "name": "httpx",
            "specs": [
                [
                    ">=",
                    "0.25.0"
                ]
            ]
        },
        {
            "name": "pydantic",
            "specs": [
                [
                    ">=",
                    "2.0.0"
                ]
            ]
        },
        {
            "name": "psutil",
            "specs": [
                [
                    ">=",
                    "5.9.0"
                ]
            ]
        }
    ],
    "lcname": "dhrupad-sah-exception-catcher"
}
        
Elapsed time: 1.67239s