Metadata-Version: 2.4
Name: smartcatch
Version: 0.1.0
Summary: AI-powered try/catch: explains unexpected errors and generates ready-to-paste fixes using OpenAI.
License: MIT
Project-URL: Homepage, https://github.com/yourname/smartcatch
Project-URL: Issues, https://github.com/yourname/smartcatch/issues
Keywords: debugging,exception,openai,ai,error-handling
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Debuggers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: pytest-mock; extra == "dev"

# SmartCatch 🚨🤖

**AI-powered exception handling for Python.**  
SmartCatch wraps your code in a smart try/catch that, when an *unexpected* error slips through, automatically:

1. **Explains** exactly which line caused the error and why.
2. **Generates** a ready-to-paste fix snippet you can drop straight into your code.
3. **Advises** on how to prevent that class of error in the future.

It uses the OpenAI API (zero extra dependencies — pure stdlib) and works as a **decorator**, a **context manager**, or a **global exception hook**.

---

## Installation

```bash
pip install smartcatch
```

Set your OpenAI key once (or pass it via `SmartCatchConfig`):

```bash
export OPENAI_API_KEY="sk-..."
```

---

## Quick start

### 1 — Decorator

```python
from smartcatch import smartcatch

@smartcatch
def load_config(path):
    with open(path) as f:
        return json.load(f)   # FileNotFoundError? JSONDecodeError? SmartCatch handles it.

load_config("settings.json")
```

### 2 — Context manager

```python
from smartcatch import SmartCatchContext

with SmartCatchContext():
    result = int(user_input) / divisor   # ZeroDivisionError? ValueError? Caught + explained.
```

### 3 — Global hook (catch everything)

Put this at the very top of your `main.py` or entry point:

```python
import smartcatch
smartcatch.install_global_handler()

# … rest of your app …
```

Any unhandled exception anywhere in the process will be analysed automatically.

---

## What the output looks like

```
════════════════════════════════════════════════════════════════════════
  🚨  SMARTCATCH — Unexpected Error Detected
════════════════════════════════════════════════════════════════════════

  Exception : ZeroDivisionError: division by zero

────────────────────────────────────────────────────────────────────────
  📌  What happened
────────────────────────────────────────────────────────────────────────

  Division by zero occurred on line 12 of app.py.

────────────────────────────────────────────────────────────────────────
  🔍  Root cause
────────────────────────────────────────────────────────────────────────

  The variable `divisor` is 0 at line 12 because no guard is in place
  before the division `value / divisor`.

────────────────────────────────────────────────────────────────────────
  🛠️   Ready-to-integrate fix
────────────────────────────────────────────────────────────────────────

    # Guard against zero divisor before performing division
    if divisor == 0:
        raise ValueError("divisor must not be zero")
    result = value / divisor

────────────────────────────────────────────────────────────────────────
  💡  Prevention advice
────────────────────────────────────────────────────────────────────────

  Always validate numeric inputs before performing arithmetic. Consider
  using a helper function that raises a descriptive error on bad values.

════════════════════════════════════════════════════════════════════════
```

---

## Configuration

All behaviour is controlled via `SmartCatchConfig`:

```python
from smartcatch import SmartCatchConfig, smartcatch, SmartCatchContext, install_global_handler

cfg = SmartCatchConfig(
    api_key="sk-...",          # or set OPENAI_API_KEY env var
    model="gpt-4o",            # any OpenAI chat model
    max_source_lines=30,       # lines of source context sent to the model
    show_fix=True,             # print the fix snippet
    show_explanation=True,     # print the root-cause explanation
    reraise=True,              # re-raise after analysis (default True)
    output_file="errors.log",  # write report to a file instead of stderr
    silent=False,              # suppress all output (useful with output_file)
)

@smartcatch(config=cfg)
def my_function():
    ...

with SmartCatchContext(config=cfg):
    ...

install_global_handler(config=cfg)
```

### Catch only specific exception types

```python
@smartcatch(catch=(ValueError, KeyError))
def parse(data):
    ...

with SmartCatchContext(catch=(IOError,)):
    ...
```

---

## How it works

1. The handler intercepts the exception **before Python unwinds the stack**.
2. It extracts the full traceback + annotated source lines around each frame using `linecache`.
3. It sends that context to `gpt-4o` via a single structured prompt that demands a JSON response.
4. The JSON is parsed into an `AnalysisResult` and printed (or written to a file).
5. The original exception is re-raised (unless `reraise=False`).

**No third-party libraries are required** — only `urllib`, `json`, `traceback`, and `linecache` from the Python standard library.

## License

MIT
