Metadata-Version: 2.4
Name: pdfox
Version: 0.1.0
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Multimedia :: Graphics
Classifier: Topic :: Text Processing :: Markup :: HTML
Requires-Dist: pytest>=7 ; extra == 'test'
Provides-Extra: test
Summary: Native HTML-to-PDF engine (no Chromium, no headless browser). Python bindings.
Keywords: pdf,html,css,rendering,document
Author: Saurav Rao
License: MIT
Requires-Python: >=3.8
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Issues, https://github.com/sauravrao637/pdfox/issues
Project-URL: Repository, https://github.com/sauravrao637/pdfox

# pdfox (Python)

Native HTML-to-PDF rendering for Python — no Chromium, no headless browser, no
external binary. A thin [PyO3](https://pyo3.rs) wrapper over the Rust
`pdfox-core` engine.

## Install

```sh
pip install pdfox
```

Wheels are abi3 (`abi3-py38`), so a single wheel per platform works on CPython
3.8 and newer.

## Usage

```python
import pdfox

# Simplest: HTML string in, PDF bytes out.
pdf: bytes = pdfox.render_html("<h1>Hello</h1>")

# Resolve relative <img>/<link> paths against a directory.
pdf = pdfox.render_html(html, base_dir="./assets")

# Full control — returns an object with .pdf and .diagnostics.
result = pdfox.render(
    html,
    base_dir="./assets",
    allow_remote=True,
    deny_list=["internal.corp"],
    pdf_a=True,
    template_vars={"customer": "Acme Inc."},
)
result.pdf            # bytes
result.diagnostics    # list[Diagnostic]
result.has_errors()   # bool

# Convenience: write straight to a file.
pdfox.render_to_file(html, "out.pdf", base_dir="./assets")
```

### Diagnostics

`render()` never raises for a missing asset or an unsupported CSS feature — it
degrades gracefully and records a `Diagnostic`:

```python
for d in result.diagnostics:
    print(d.severity, d.kind, d.url, "—", d.reason)
```

`kind` ∈ `{"image", "font", "stylesheet", "css_feature"}`;
`severity` ∈ `{"warning", "error"}`.

Genuinely broken input raises a `pdfox.PdfoxError` subclass
(`ParseError`, `LayoutError`, `EmissionError`, `FontError`, `ImageError`,
`IoError`).

### Concurrency

`render()` and `render_html()` release the GIL while rendering (the work is
pure-Rust and CPU-bound, ~70 ms for a typical page), so they parallelise across
threads. In async frameworks, call them from a thread pool:

```python
pdf = await loop.run_in_executor(None, pdfox.render_html, html)
```

## Develop

```sh
# From bindings/python/
pip install maturin pytest
maturin develop            # builds the extension into the active venv
pytest                     # runs tests/
```

> On a just-released CPython where the pinned PyO3 has no version table yet,
> set `PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1` before building.

