Metadata-Version: 2.4
Name: pulp-engine
Version: 0.85.0
Summary: Python client for the Pulp Engine document generation API
Project-URL: Homepage, https://github.com/TroyCoderBoy/pulp-engine
Project-URL: Documentation, https://github.com/TroyCoderBoy/pulp-engine/tree/main/packages/sdk-python
Project-URL: Issues, https://github.com/TroyCoderBoy/pulp-engine/issues
Project-URL: Source, https://github.com/TroyCoderBoy/pulp-engine
Project-URL: Changelog, https://github.com/TroyCoderBoy/pulp-engine/blob/main/CHANGELOG.md
Author: Pulp Engine
License-Expression: MIT
Keywords: document-generation,pdf,pulp-engine,templates
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: httpx>=0.27.0
Requires-Dist: pydantic>=2.0.0
Provides-Extra: dev
Requires-Dist: build>=1.2.0; extra == 'dev'
Requires-Dist: mypy>=1.10.0; extra == 'dev'
Requires-Dist: pytest-httpx>=0.30.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.6.0; extra == 'dev'
Requires-Dist: twine>=5.0.0; extra == 'dev'
Description-Content-Type: text/markdown

# Pulp Engine Python SDK

Typed Python client for the [PulpEngine](https://github.com/TroyCoderBoy/pulp-engine) document generation API.

Mirrors the [TypeScript SDK](../sdk-typescript) 1:1 with snake_case method names and Pythonic conventions (context manager, type hints, Pydantic response models).

## Installation

> **Not yet published to PyPI.** This SDK currently ships in-repo only; registry
> publication is pending trusted-publisher setup. Until then, install from the
> workspace path (`pip install -e packages/sdk-python`). The command below will
> work once the package is live on PyPI.

```bash
pip install pulp-engine
```

Requires Python 3.11+.

## Quickstart

```python
from pulp_engine import PulpEngineClient

with PulpEngineClient(
    base_url="https://pulp-engine.example.com",
    api_key="dk_admin_...",
) as client:
    # List templates
    templates = client.templates.list()
    for t in templates.items:
        print(t.key, t.current_version)

    # Render a PDF
    result = client.render.pdf("invoice", {"amount": 100, "customer": "Acme"})
    result.save("invoice.pdf")

    # Render to HTML (returns string)
    html = client.render.html("invoice", {"amount": 100, "customer": "Acme"})
    print(html)
```

## Preview routes in production

The Pulp Engine OpenAPI spec this SDK is generated from includes `/render/preview/html` and `/render/preview/pdf` routes. In production (`NODE_ENV=production`), those routes return `404` unless the API operator has explicitly enabled them with `PREVIEW_ROUTES_ENABLED=true`. They are intended for the live editor, not for production rendering pipelines.

Before calling a preview method against an unknown deployment, query `GET /capabilities` at runtime and check the advertised preview capability. Use the production render endpoints (`POST /render/pdf` — `POST /render` is a deprecated alias — and the per-format routes `POST /render/html|csv|xlsx|docx|pptx`, plus `POST /render/batch` for bulk jobs) for all production document generation — they are always registered and are not affected by this flag.

## Authentication

Pass either an API key (`X-Api-Key` header) or an editor session token (`X-Editor-Token` header):

```python
# API key
client = PulpEngineClient(base_url="...", api_key="dk_admin_...")

# Editor session token
client = PulpEngineClient(base_url="...", editor_token="...")

# Switch at runtime
client.set_api_key("new-key")
client.set_editor_token("new-token")
```

## Available resources

| Resource | Methods |
|---|---|
| `client.templates` | `list`, `get`, `create`, `update`, `delete`, `schema`, `sample`, `validate`, `versions`, `get_version`, `restore` |
| `client.render` | `pdf`, `html`, `csv`, `xlsx`, `docx`, `pptx`, `dry_run`, `validate` |
| `client.batch` | `pdf`, `docx`, `submit_async`, `submit_async_docx`, `poll_job`, `wait_for_job` |
| `client.pdf_transform` | `merge`, `watermark`, `insert` |
| `client.assets` | `list`, `upload`, `delete` |
| `client.audit_events` | `list`, `purge` |
| `client.admin` | `list_users`, `create_user`, `update_user`, `delete_user`, `reload_users` |
| `client.auth` | `status`, `editor_token` |
| `client.health` | `liveness`, `readiness` |
| `client.schedules` | `list`, `get`, `create`, `update`, `patch`, `delete`, `trigger`, `list_executions`, `get_execution` |

## Error handling

All methods raise `PulpEngineError` on non-2xx responses:

```python
from pulp_engine import PulpEngineClient, PulpEngineError

try:
    client.render.pdf("missing-template", {})
except PulpEngineError as e:
    print(e.status)    # 404
    print(e.error)     # "NotFound"
    print(e.code)      # None (or e.g. "template_expression_error" for render errors)
    print(e.issues)    # None (or list[ValidationIssue] for 400/422)
    print(str(e))      # Human-readable message
```

## Dry-run mode (CI/CD pre-flight checks)

`client.render.dry_run()` validates input data and exercises all template
expressions via a trial HTML render, then returns a structured result without
producing any binary output. Skips Chromium / DOCX / PPTX entirely — typical
latency is 5–50 ms vs 1–10 s for a full PDF render. Useful for CI/CD
pre-flight checks and integration tests.

Unlike the normal render methods, `dry_run()` does **not** raise on template
author errors (validation failures, undefined variables, etc.) — those are
surfaced in the result so callers can display them to users. The only way it
raises is if the request itself is malformed (network error, 4xx auth, etc.).

```python
result = client.render.dry_run("invoice", {"amount": 100})

if result.valid:
    print(f"Template OK ({result.field_mappings_applied} field mappings applied)")
else:
    # Validation errors (schema mismatches)
    for err in result.validation.errors:
        print(f"Validation: {err.path}: {err.message}")

    # Expression errors (Handlebars failures, undefined variables)
    for err in result.expressions.errors:
        location = err.location.node_path if err.location else "(no location)"
        print(f"Expression at {location}: {err.message}")
        if err.suggestion:
            print(f"  Did you mean: {', '.join(err.suggestion.suggestions)}?")
```

The `format` parameter selects which per-format route to hit (defaults to
`"pdf"`). The result shape is identical regardless of format — the selector
only matters when different formats have different rate limits or feature
gates server-side:

```python
client.render.dry_run("invoice", data, format="html")
client.render.dry_run("invoice", data, format="docx")
```

## Binary results

PDF, CSV, XLSX, DOCX, and PPTX renders return a `BinaryResult` (or `PptxResult`) with:

- `.data` — raw bytes
- `.content_type` — response Content-Type header
- `.content_disposition` — response Content-Disposition header
- `.save(path)` — convenience method to write bytes to a file (creates parent dirs)

```python
result = client.render.pdf("invoice", {"amount": 100})
result.save("output/invoice.pdf")  # creates output/ if needed
```

`PptxResult` adds:

- `.warning_count` — number of structured warnings parsed from the `X-Render-Warnings` header

## Pagination

List endpoints return a `PaginatedResult[T]` envelope:

```python
page = client.templates.list(limit=20, offset=0)
print(page.total)       # total count across all pages
print(len(page.items))  # items on this page

# Auto-paginate with the helper
from pulp_engine import paginate

for template in paginate(lambda offset, limit: client.templates.list(limit=limit, offset=offset)):
    print(template.key)
```

## Development

```bash
cd packages/sdk-python
pip install -e ".[dev]"
pytest
```

## Releasing

See [RELEASING.md](./RELEASING.md) for the publish runbook. Releases are
automated via the [`publish-sdk-python.yml`](../../.github/workflows/publish-sdk-python.yml)
GitHub Actions workflow using PyPI Trusted Publishing (no API tokens).
