Metadata-Version: 2.4
Name: crash_sight
Version: 1.1.0
Summary: A zero-dependency debugging engine for Python that intercepts unhandled exceptions, extracts post-mortem state, masks sensitive data, and provides formatted crash reports with an interactive debugging REPL.
Home-page: https://github.com/annaqibz01/crash_sight
Author: crash_sight Team
Author-email: nagibmnagib01@gmail.com
License: MIT
Project-URL: Documentation, https://crash-sight.readthedocs.io/
Project-URL: Source Code, https://github.com/annaqibz01/crash_sight
Project-URL: Bug Tracker, https://github.com/annaqibz01/crash_sight/issues
Keywords: debugging,debugger,exception,crash,post-mortem,repl,error-handling,developer-tools,zero-dependency
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Topic :: Software Development :: Debuggers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Monitoring
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Operating System :: OS Independent
Classifier: Environment :: Console
Classifier: Typing :: Typed
Requires-Python: >=3.8, <3.15
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: license-file
Dynamic: project-url
Dynamic: requires-python
Dynamic: summary

# crash_sight

[![Python 3.8 - 3.14](https://img.shields.io/badge/Python-3.8%20--%203.14-blue.svg)](https://www.python.org/)
[![Zero Dependencies](https://img.shields.io/badge/Dependencies-0-brightgreen.svg)](https://pypi.org/project/crash_sight/)
[![MIT License](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Tests Passing](https://img.shields.io/badge/Tests-90%20Passing-success.svg)](tests/)

> **Production-Grade Debugging Engine** · A zero-dependency runtime exception interceptor that hijacks `sys.excepthook` to maximize Developer Experience (DX).

**crash_sight** is a post-mortem debugging engine for Python 3.8+ that operates at the runtime interceptor level. When an unhandled exception escapes your application, crash_sight captures the precise execution context, scrubs sensitive data, generates a beautifully formatted ANSI terminal report, exports a clean Markdown log, and drops you into an interactive REPL at the exact crash site — all with **zero external dependencies**.

---

## Core Pillars

crash_sight's architecture is composed of five tightly integrated modules, each responsible for a critical stage of the post-mortem pipeline:

| Module | Responsibility |
|--------|----------------|
| **Core Interceptor** (`crash_sight.core.interceptor`) | Registers a global hook on `sys.excepthook`, traverses the stack frame window to the deepest frame, and orchestrates the entire pipeline. |
| **Security Data Scrubber** (`crash_sight.security.masker`) | Scans local and global variables using case-insensitive regex pattern matching, replacing sensitive values (e.g., `password`, `secret`, `token`, `apiKey`, `credential`) with `"******** (SECURED)"`. Supports nested dictionaries, lists, and tuples with infinite recursion depth. |
| **Terminal Formatter** (`crash_sight.formatter.terminal`) | Renders a visually stunning ANSI-colored crash report complete with source code context, variable dump, and precise arrow markers — all using only standard library `linecache`. |
| **Post-Mortem REPL** (`crash_sight.repl.console`) | Launches an interactive Python shell (`code.InteractiveConsole`) injected with the exact masked locals and globals from the crash frame, allowing real-time forensic inspection. |
| **Markdown Exporter** (`crash_sight.exporter.markdown`) | Strips ANSI color codes and writes a pristine Markdown version of the crash report to `crash_report_[YYYYMMDD_HHMMSS].md` for logging, CI/CD, or team sharing. |

---

## Installation

Install crash_sight locally in development/editable mode from the project root:

```bash
pip install -e .
```

> **Zero Dependencies Guarantee** – `pip freeze` will show zero additional packages. crash_sight uses **only Python Standard Library** modules: `sys`, `inspect`, `linecache`, `code`, `os`, `re`, `datetime`, `typing`.

---

## Quick Start

Create a file called `test_crash.py` with the following content:

```python
import crash_sight

crash_sight.install()

def risky_function(user_input):
    user_password = "sup3rS3cr3t!"
    apiKey = "AIzaSyD-abc123def456"
    my_secret_token = "ghp_xxxxxxxxxxxx"
    ratio = 100 / user_input  # will trigger ZeroDivisionError when user_input = 0

risky_function(0)
```

Then run it:

```bash
python test_crash.py
```

That's it — **two lines** to activate crash_sight. The rest is automatic.

---

## Aesthetic Terminal Preview

When you run the example above, crash_sight will print a report like this to stderr:

```
🔍 crash_sight — Post-Mortem Report
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

⚡ ZeroDivisionError: division by zero

📍 Location:
   📄 File: /path/to/test_crash.py
   🔧 Function: risky_function
   ⏰ Line: 8

📄 Code Context:
   5  | def risky_function(user_input):
   6  |     user_password = "sup3rS3cr3t!"
   7  |     apiKey = "AIzaSyD-abc123def456"
   8  ───> ratio = 100 / user_input
   9  | 
  10  | risky_function(0)

🔍 Local Variables (Masked):
   user_input        = 0
   user_password     = ******** (SECURED)
   apiKey            = ******** (SECURED)
   my_secret_token   = ******** (SECURED)
   ratio             = <not defined>

📁 Report saved to: crash_report_20250320_143022.md

💻 Opening interactive REPL at crash site...
   Type 'exit()' or 'quit()' to return to the shell.
```

---

## Security & Masking Specifications

The security engine (`crash_sight.security.masker`) applies a deterministic, pattern-based masking algorithm with the following rules:

### Pattern Matching (Case-Insensitive)

Any variable **key** containing any of these substrings (case-insensitive) will have its **value** replaced:

| Keyword | Example Keys That Trigger Masking |
|---------|-----------------------------------|
| `password` | `password`, `userPassword`, `PASSWORD`, `passwords_list` |
| `secret` | `secret`, `my_secret_token`, `SECRET_KEY`, `secret_answer` |
| `token` | `token`, `api_token`, `TOKEN`, `auth_tokens` |
| `apikey` | `apiKey`, `API_KEY`, `apikey`, `api_key_v2` |
| `credential` | `credential`, `credentials`, `CREDENTIALS` |

### Recursive Scrubbing — Full Nested Support

Masking is applied **recursively** to arbitrary-depth data structures:

- **Nested dictionaries**: `{"db": {"password": "s3cr3t"}}` → `{"db": {"password": "******** (SECURED)"}}`
- **Lists of dictionaries**: `[{"apiKey": "xyz"}, {"other": 42}]` → `[{"apiKey": "******** (SECURED)"}, {"other": 42}]`
- **Tuples**: `("user", {"token": "abc"})` → `("user", {"token": "******** (SECURED)"})`
- Mixed nesting is fully supported.

### False-Positive Guard

Variables whose keys contain certain "safe" substrings are intelligently bypassed:

- `not_secret` → **NOT masked** (contains "secret" but guarded)
- `public_token_id` → **NOT masked** (contains "token" but guarded)

Built-in exception list: `not_secret`, `not_password`, `public_token`, `non_credential`, and equivalents are safely ignored.

---

## Python 3.14 Compatibility Note

crash_sight is fully compliant with **PEP 667** (introduced in Python 3.13, standard in 3.14). The `extract_deepest_context()` function explicitly converts `frame.f_locals` and `frame.f_globals` to standard `dict` objects using `dict()` constructor, ensuring seamless compatibility with Python 3.13+ where `FrameLocalsProxy` is returned instead of a plain dictionary.

This safeguard is encapsulated in the core interceptor:

```python
# In Python 3.13+, frame.f_locals returns FrameLocalsProxy, not a plain dict
f_locals: Dict[str, Any] = dict(frame.f_locals)
f_globals: Dict[str, Any] = dict(frame.f_globals)
```

Tested and verified across Python 3.8 through 3.14-pre release.

---

## Testing

crash_sight ships with a comprehensive test suite (90+ tests covering unit, integration, and edge-case scenarios). Run the full suite with:

```bash
python -m unittest discover -s tests -p "test_*.py" -v
```

Test categories include:
- Core interceptor installation/idempotency/uninstallation
- Deepest frame extraction (including chain tracebacks)
- Security masker — pattern matching, nested structures, false-positive guard
- Terminal formatter (ANSI rendering, code context windows)
- Markdown exporter (cleaning, naming conventions)
- REPL initialization and context injection
- Cross-version compatibility (Python 3.8–3.14)

---

## Development & Contributing

1. Clone the repository:
   ```bash
   git clone https://github.com/annaqibz01/crash_sight.git
   cd crash_sight
   ```

2. Install in editable mode:
   ```bash
   pip install -e .
   ```

3. Run the tests:
   ```bash
   python -m unittest discover -s tests -p "test_*.py" -v
   ```

4. Submit a pull request or open an issue on [GitHub Issues](https://github.com/annaqibz01/crash_sight/issues).

---

## License

Distributed under the **MIT License**. See [LICENSE](LICENSE) for more information.

---

**crash_sight** — Zero-dependency debugging. Precision post-mortem. Maximum DX.
