Metadata-Version: 2.5
Name: pydd-web
Version: 0.2.2
Summary: Dump-and-die for web frameworks (FastAPI, Flask, Django) — HTML dumps on top of pydump-dd
Project-URL: Homepage, https://github.com/ardavanshamroshan/pydd
Project-URL: Repository, https://github.com/ardavanshamroshan/pydd
Project-URL: Issues, https://github.com/ardavanshamroshan/pydd/issues
Author: Ardavan
License: MIT
License-File: LICENSE
Keywords: dd,debug,django,dump,fastapi,flask
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: Django
Classifier: Framework :: FastAPI
Classifier: Framework :: Flask
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Debuggers
Requires-Python: >=3.10
Requires-Dist: pydump-dd>=0.2.2
Provides-Extra: all
Requires-Dist: django>=4.2; extra == 'all'
Requires-Dist: fastapi>=0.100.0; extra == 'all'
Requires-Dist: flask>=2.3.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: fastapi[standard]>=0.100.0; extra == 'dev'
Requires-Dist: httpx>=0.27.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Provides-Extra: django
Requires-Dist: django>=4.2; extra == 'django'
Provides-Extra: fastapi
Requires-Dist: fastapi>=0.100.0; extra == 'fastapi'
Provides-Extra: flask
Requires-Dist: flask>=2.3.0; extra == 'flask'
Description-Content-Type: text/markdown

# pydd

**Dump and die for Python web apps.** HTML dumps in the browser during HTTP requests; terminal output everywhere else.

Built on **[pydump](../pydump)** (installed automatically). One install gives you both packages:

```python
import pydd  # installs dd/dump as builtins + FastAPI patch

dd(user)     # no from-import needed in this file
dump(data)
```

Explicit import still works: `from pydd import dd, dump, render_html, render_text`.

## Preview

### In a web request (HTML)

Visiting a debug route returns a **500** response with an interactive dark-theme dump:

```text
dict:4 [▼ // views.py:18
  "id" => 1
  "author" => "Jane Doe"
  "title" => "Hello world"
  "tags" => list:3 [▶]
]
```

Click `list:3 [▶]` (or the whole header) to expand nested data in the browser.

### Outside a request (terminal)

Same data falls back to **pydump** text on stderr — fully expanded, no collapse:

```text
dict:4 [
  "id" => 1
  ...
] // script.py:10
```

### Boot-time dump (`dd(app)`)

Pass your FastAPI app at import time to arm a dump while the server keeps running. Refresh the existing tab (or visit the printed URL) to see it — no auto-open:

```python
app = FastAPI()
dd(app)  # every request serves dump HTML until restart
```

## Introduction

`pydd` wires `pydump` into popular Python web frameworks:

| Framework | Setup |
|-----------|--------|
| **FastAPI** | Auto-wired on `import pydd` |
| **Flask** | `install_flask(app)` |
| **Django** | `PyddMiddleware` in `MIDDLEWARE` |

Inside an HTTP request, `dd()` raises `DdException` with HTML; the framework returns it as a 500 page. Outside a request, behavior matches `pydump`.

## Installation

Assume your web app and `pydd` live side by side. Installing `pydd` also installs **pydump** — no separate `pydump` step.

```text
PythonProjects/
├── pydump/         # dependency of pydd
├── pydd/
└── myapp/          # FastAPI, Flask, or Django project
```

### pip + venv

```bash
cd myapp
python -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate

pip install -e ../pydd/
```

With a framework extra (when you do not already have it installed):

```bash
pip install -e "../pydd[fastapi]"
pip install -e "../pydd[flask]"
pip install -e "../pydd[django]"
pip install -e "../pydd[all]"
```

| Extra | Adds |
|-------|------|
| `fastapi` | FastAPI |
| `flask` | Flask |
| `django` | Django |
| `all` | All three |

### uv

New project:

```bash
cd myapp
uv init
uv add ../pydd
uv sync
```

FastAPI app (typical):

```bash
uv add fastapi[standard]
uv add ../pydd
```

`pyproject.toml`:

```toml
[project]
dependencies = [
    "fastapi[standard]",
    "pydd",
]

[tool.uv.sources]
pydd = { path = "../pydd", editable = true }
```

Run:

```bash
uv run uvicorn main:app --reload
```

`pydump` is pulled in automatically as a dependency of `pydd`.

### Install into the pydd repo itself (development)

```bash
cd /path/to/pydd
pip install -e ".[dev]"
# or
uv sync --extra dev
uv run pytest -q
```

### Test projects

| Project | Stack |
|---------|--------|
| FastAPI | `../blog` |
| Django | `../testDDInDjango` |
| Flask | `../testDDInFlask` |
| Terminal only | `../pyexample` (uses `pydump` directly) |

---

## FastAPI

### Install and run

```bash
cd myapp
uv init                    # skip if project exists
uv add fastapi[standard]
uv add ../pydd
uv run uvicorn main:app --reload
```

Or with pip:

```bash
pip install -e "../pydd[fastapi]"
uvicorn main:app --reload
```

`pyproject.toml` (uv):

```toml
dependencies = ["fastapi[standard]", "pydd"]

[tool.uv.sources]
pydd = { path = "../pydd", editable = true }
```

### Code

```python
from pathlib import Path
from fastapi import FastAPI
from pydd import configure, dd

configure(project_root=Path(__file__).resolve().parent)

app = FastAPI()

@app.get("/posts/{post_id}")
def show_post(post_id: int):
    post = load_post(post_id)
    dd(post)   # HTML 500 in browser
```

Importing `pydd` patches `FastAPI.__init__` to register middleware and a `DdException` handler. No manual `install()` call.

### Boot dump

```python
app = FastAPI()
dd(app)   # arms HTML on app; refresh http://127.0.0.1:8000/
```

Useful when debugging app wiring at startup. **Every request** returns the dump until you remove `dd(app)` and restart. No browser is opened automatically.

### Verify

```bash
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8000/posts/1
# 500 when dd() runs in route
```

---

## Flask

### Install and run

```bash
cd myapp
uv init
uv add flask
uv add ../pydd
uv run python app.py
```

Or with pip:

```bash
pip install -e "../pydd[flask]"
python app.py
```

### Code

```python
from pathlib import Path
from flask import Flask, request
from pydd import configure, dd
from pydd.integrations import install_flask

configure(project_root=Path(__file__).resolve().parent)

app = Flask(__name__)
install_flask(app)

@app.get("/dd")
def debug_dump():
    dd({
        "title": "Flask dd test",
        "query": dict(request.args),
    })
```

`install_flask` registers `before_request` / `teardown_request` for the request flag and an error handler for `DdException`.

---

## Django

### Install and run

```bash
cd myapp
uv init
uv add django
uv add ../pydd
uv run python manage.py migrate
uv run python manage.py runserver
```

Or with pip:

```bash
pip install -e "../pydd[django]"
python manage.py migrate
python manage.py runserver
```

### Settings

```python
# config/settings.py
from pathlib import Path
from pydd import configure

BASE_DIR = Path(__file__).resolve().parent.parent
configure(project_root=BASE_DIR)

MIDDLEWARE = [
    # ...
    "pydd.integrations.django.PyddMiddleware",
]
```

### View

```python
# debugapp/views.py
from django.http import HttpResponse
from pydd import dd

def home(request):
    return HttpResponse('<a href="/dd/">/dd/</a>')

def debug_dump(request):
    dd({
        "title": "Django dd test",
        "query": dict(request.GET),
    })
```

`PyddMiddleware` sets the request context and catches `DdException` in `__call__`, returning `HttpResponse(status=500)`.

---

## Usage reference

### API

| Call | In HTTP request | CLI / script | `dd(app)` boot |
|------|-----------------|----------------|----------------|
| `dd(x)` | HTML 500 | stderr + exit 1 | arm HTML (refresh tab) |
| `dump(x)` | stderr only | stderr only | stderr only |
| `render_html(x)` | string | string | string |
| `render_text(x)` | string | string | string |
| `install_helpers()` | inject builtins (auto on `import pydd`; overrides pydump) | | |

After `import pydd` once (e.g. in `main.py`), use `dd` / `dump` in any module without importing them again.

### Editor / linter (Ruff, Pyright, PyCharm)

Runtime inject ≠ static name. Ruff / basedpyright / Pylance / PyCharm do **not** see `builtins.dd` from `install_helpers()`. Runtime works; the editor stays blind unless you configure or import.

**Ruff** — treat helpers like real builtins in the consumer `pyproject.toml`:

```toml
[tool.ruff]
builtins = ["dd", "dump"]
```

**Cursor / VS Code / basedpyright / Pylance** — prefer an explicit import (cleanest for the IDE):

```python
from pydd import dd, dump

dd(user)
```

Same functions as the builtins path. Still fine to keep `import pydd` in `main.py` for FastAPI patch + runtime inject.

Type-only alternative (bare `dd()` at runtime, import for the checker only):

```python
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from pydd import dd, dump

dd(user)
```

**PyCharm** — Inspections → Python → Unresolved references → ignored identifiers: `dd`, `dump` — or use `from pydd import dd`.

Do **not** ship a full `typings/builtins.pyi` to fake these names: a complete `builtins.pyi` can replace typeshed stubs and break typing for the whole project.

### Multiple values

```python
dd(user, post, filters=query_params)
```

### Configure tips

```python
from pathlib import Path
from pydd import configure

configure(project_root=Path(__file__).resolve().parent)
```

## Advantages

- **Two modes, one API** — HTML in requests, text elsewhere
- **FastAPI zero-config** — import and use
- **Laravel-style helpers** — `import pydd` once, then `dd` / `dump` as builtins
- **Includes pydump** — terminal debugging without a second dependency
- **Interactive HTML** — expand/collapse nested structures in the browser
- **Boot mode** — inspect a FastAPI app at startup without killing the server
- **Framework hooks** — Flask and Django supported explicitly
- **Shared inspection** — same `DumpNode` tree as `pydump`

## Disadvantages

- **Not for production** — `dd()` is a debugger; it stops the request with HTTP 500
- **Boot mode hijacks all routes** — while armed, every URL serves the dump
- **HTML collapse does not exist in terminal** — use `render_text` / `pydump` for full CLI trees
- **Dynamic builtins vs checkers** — Ruff needs `builtins = ["dd", "dump"]`; Pyright/Pylance need an explicit or `TYPE_CHECKING` import (see Editor / linter)
- **FastAPI monkey-patch** — patches `FastAPI.__init__`; avoid if you need strict import side-effect control (call `install_fastapi` manually instead and skip auto-patch — advanced)
- **Limited object dumping** — same introspection limits as `pydump`
- **Django** — requires middleware entry in `settings.py` (not automatic)

## pydump vs pydd

| Need | Package |
|------|---------|
| Scripts, CLI, tests, notebooks | `pydump` |
| FastAPI / Flask / Django | `pydd` |
| Both | `pydd` only |

## License

MIT
