pulp-engine 0.85.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pulp_engine-0.85.0/.gitignore +69 -0
- pulp_engine-0.85.0/PKG-INFO +217 -0
- pulp_engine-0.85.0/README.md +184 -0
- pulp_engine-0.85.0/pulp_engine/__init__.py +48 -0
- pulp_engine-0.85.0/pulp_engine/_http.py +230 -0
- pulp_engine-0.85.0/pulp_engine/client.py +96 -0
- pulp_engine-0.85.0/pulp_engine/errors.py +142 -0
- pulp_engine-0.85.0/pulp_engine/pagination.py +51 -0
- pulp_engine-0.85.0/pulp_engine/py.typed +0 -0
- pulp_engine-0.85.0/pulp_engine/resources/__init__.py +25 -0
- pulp_engine-0.85.0/pulp_engine/resources/admin.py +71 -0
- pulp_engine-0.85.0/pulp_engine/resources/assets.py +68 -0
- pulp_engine-0.85.0/pulp_engine/resources/audit_events.py +62 -0
- pulp_engine-0.85.0/pulp_engine/resources/auth.py +26 -0
- pulp_engine-0.85.0/pulp_engine/resources/batch.py +146 -0
- pulp_engine-0.85.0/pulp_engine/resources/health.py +23 -0
- pulp_engine-0.85.0/pulp_engine/resources/pdf_transform.py +89 -0
- pulp_engine-0.85.0/pulp_engine/resources/render.py +309 -0
- pulp_engine-0.85.0/pulp_engine/resources/schedules.py +95 -0
- pulp_engine-0.85.0/pulp_engine/resources/templates.py +161 -0
- pulp_engine-0.85.0/pulp_engine/types.py +394 -0
- pulp_engine-0.85.0/pyproject.toml +73 -0
- pulp_engine-0.85.0/tests/__init__.py +0 -0
- pulp_engine-0.85.0/tests/conftest.py +35 -0
- pulp_engine-0.85.0/tests/test_batch.py +166 -0
- pulp_engine-0.85.0/tests/test_client.py +103 -0
- pulp_engine-0.85.0/tests/test_dry_run.py +297 -0
- pulp_engine-0.85.0/tests/test_errors.py +125 -0
- pulp_engine-0.85.0/tests/test_pagination.py +95 -0
- pulp_engine-0.85.0/tests/test_pdf_transform.py +68 -0
- pulp_engine-0.85.0/tests/test_render.py +187 -0
- pulp_engine-0.85.0/tests/test_templates.py +322 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
node_modules/
|
|
2
|
+
dist/
|
|
3
|
+
.turbo/
|
|
4
|
+
installer/staging/
|
|
5
|
+
installer/dist/
|
|
6
|
+
# Local async-batch render artifacts written at runtime by the file-backed job store.
|
|
7
|
+
apps/api/job-result-blobs/
|
|
8
|
+
|
|
9
|
+
.tmp/
|
|
10
|
+
tools/gh/
|
|
11
|
+
*.log
|
|
12
|
+
.env
|
|
13
|
+
.env.local
|
|
14
|
+
.env.*.local
|
|
15
|
+
test-results/
|
|
16
|
+
playwright-report/
|
|
17
|
+
# Playwright MCP server artifacts — per-tool-call snapshots, console
|
|
18
|
+
# dumps, and screenshots written by Chromium when the MCP drives it.
|
|
19
|
+
# Ephemeral; recreated every smoke-test session.
|
|
20
|
+
.playwright-mcp/
|
|
21
|
+
coverage/
|
|
22
|
+
|
|
23
|
+
# File-mode template/asset store test artifacts
|
|
24
|
+
/templates/*/
|
|
25
|
+
/apps/api/assets/
|
|
26
|
+
|
|
27
|
+
# Root-level test asset artifacts
|
|
28
|
+
/assets/
|
|
29
|
+
|
|
30
|
+
# Editor SPA build artifacts (built at deploy time)
|
|
31
|
+
apps/api/editor-dist/
|
|
32
|
+
|
|
33
|
+
# TypeScript incremental build info
|
|
34
|
+
*.tsbuildinfo
|
|
35
|
+
|
|
36
|
+
# Python SDK local virtualenvs and bytecode caches
|
|
37
|
+
packages/sdk-python/.venv/
|
|
38
|
+
**/__pycache__/
|
|
39
|
+
*.pyc
|
|
40
|
+
|
|
41
|
+
# File-mode audit log (created by audit-store at runtime)
|
|
42
|
+
/templates/.audit-events.jsonl
|
|
43
|
+
|
|
44
|
+
# Local scratch / debugging artifacts
|
|
45
|
+
/test.html
|
|
46
|
+
/test.ts
|
|
47
|
+
/git_log.txt
|
|
48
|
+
|
|
49
|
+
# Benchmark harness run artifacts (T4). Pack is published into
|
|
50
|
+
# docs/benchmark-pack.md directly; the raw CSVs + ad-hoc .env.benchmark
|
|
51
|
+
# stay out of git.
|
|
52
|
+
bench-results*/
|
|
53
|
+
.env.benchmark
|
|
54
|
+
|
|
55
|
+
# Generated website docs mirror — the canonical EVALUATION-LICENCE.md lives at
|
|
56
|
+
# the repo root for GitHub / GHCR / package-manager licence detection. The
|
|
57
|
+
# Astro docs collection only loads from docs/*.md, so apps/website/scripts/
|
|
58
|
+
# sync-evaluation-licence.mjs regenerates this mirror on website predev/prebuild.
|
|
59
|
+
# Edit EVALUATION-LICENCE.md at the repo root — never this file.
|
|
60
|
+
docs/evaluation-licence.md
|
|
61
|
+
|
|
62
|
+
# Generated website docs staging dir — populated by apps/website/scripts/
|
|
63
|
+
# sync-docs.mjs on predev/prebuild from repo-root docs/*.md, with relative
|
|
64
|
+
# markdown-link targets rewritten into website-routed URLs. The Astro content
|
|
65
|
+
# collection loads from here rather than docs/ directly, because Astro 6's
|
|
66
|
+
# glob() content loader does not apply markdown.rehype/remarkPlugins to
|
|
67
|
+
# entries rendered via astro:content's render() helper. Edit docs/*.md at
|
|
68
|
+
# the repo root — never files under _generated_docs/.
|
|
69
|
+
apps/website/src/_generated_docs/
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pulp-engine
|
|
3
|
+
Version: 0.85.0
|
|
4
|
+
Summary: Python client for the Pulp Engine document generation API
|
|
5
|
+
Project-URL: Homepage, https://github.com/TroyCoderBoy/pulp-engine
|
|
6
|
+
Project-URL: Documentation, https://github.com/TroyCoderBoy/pulp-engine/tree/main/packages/sdk-python
|
|
7
|
+
Project-URL: Issues, https://github.com/TroyCoderBoy/pulp-engine/issues
|
|
8
|
+
Project-URL: Source, https://github.com/TroyCoderBoy/pulp-engine
|
|
9
|
+
Project-URL: Changelog, https://github.com/TroyCoderBoy/pulp-engine/blob/main/CHANGELOG.md
|
|
10
|
+
Author: Pulp Engine
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
Keywords: document-generation,pdf,pulp-engine,templates
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Requires-Dist: httpx>=0.27.0
|
|
24
|
+
Requires-Dist: pydantic>=2.0.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: build>=1.2.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: mypy>=1.10.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest-httpx>=0.30.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: ruff>=0.6.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: twine>=5.0.0; extra == 'dev'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# Pulp Engine Python SDK
|
|
35
|
+
|
|
36
|
+
Typed Python client for the [PulpEngine](https://github.com/TroyCoderBoy/pulp-engine) document generation API.
|
|
37
|
+
|
|
38
|
+
Mirrors the [TypeScript SDK](../sdk-typescript) 1:1 with snake_case method names and Pythonic conventions (context manager, type hints, Pydantic response models).
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
> **Not yet published to PyPI.** This SDK currently ships in-repo only; registry
|
|
43
|
+
> publication is pending trusted-publisher setup. Until then, install from the
|
|
44
|
+
> workspace path (`pip install -e packages/sdk-python`). The command below will
|
|
45
|
+
> work once the package is live on PyPI.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install pulp-engine
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Requires Python 3.11+.
|
|
52
|
+
|
|
53
|
+
## Quickstart
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from pulp_engine import PulpEngineClient
|
|
57
|
+
|
|
58
|
+
with PulpEngineClient(
|
|
59
|
+
base_url="https://pulp-engine.example.com",
|
|
60
|
+
api_key="dk_admin_...",
|
|
61
|
+
) as client:
|
|
62
|
+
# List templates
|
|
63
|
+
templates = client.templates.list()
|
|
64
|
+
for t in templates.items:
|
|
65
|
+
print(t.key, t.current_version)
|
|
66
|
+
|
|
67
|
+
# Render a PDF
|
|
68
|
+
result = client.render.pdf("invoice", {"amount": 100, "customer": "Acme"})
|
|
69
|
+
result.save("invoice.pdf")
|
|
70
|
+
|
|
71
|
+
# Render to HTML (returns string)
|
|
72
|
+
html = client.render.html("invoice", {"amount": 100, "customer": "Acme"})
|
|
73
|
+
print(html)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Preview routes in production
|
|
77
|
+
|
|
78
|
+
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.
|
|
79
|
+
|
|
80
|
+
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.
|
|
81
|
+
|
|
82
|
+
## Authentication
|
|
83
|
+
|
|
84
|
+
Pass either an API key (`X-Api-Key` header) or an editor session token (`X-Editor-Token` header):
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
# API key
|
|
88
|
+
client = PulpEngineClient(base_url="...", api_key="dk_admin_...")
|
|
89
|
+
|
|
90
|
+
# Editor session token
|
|
91
|
+
client = PulpEngineClient(base_url="...", editor_token="...")
|
|
92
|
+
|
|
93
|
+
# Switch at runtime
|
|
94
|
+
client.set_api_key("new-key")
|
|
95
|
+
client.set_editor_token("new-token")
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Available resources
|
|
99
|
+
|
|
100
|
+
| Resource | Methods |
|
|
101
|
+
|---|---|
|
|
102
|
+
| `client.templates` | `list`, `get`, `create`, `update`, `delete`, `schema`, `sample`, `validate`, `versions`, `get_version`, `restore` |
|
|
103
|
+
| `client.render` | `pdf`, `html`, `csv`, `xlsx`, `docx`, `pptx`, `dry_run`, `validate` |
|
|
104
|
+
| `client.batch` | `pdf`, `docx`, `submit_async`, `submit_async_docx`, `poll_job`, `wait_for_job` |
|
|
105
|
+
| `client.pdf_transform` | `merge`, `watermark`, `insert` |
|
|
106
|
+
| `client.assets` | `list`, `upload`, `delete` |
|
|
107
|
+
| `client.audit_events` | `list`, `purge` |
|
|
108
|
+
| `client.admin` | `list_users`, `create_user`, `update_user`, `delete_user`, `reload_users` |
|
|
109
|
+
| `client.auth` | `status`, `editor_token` |
|
|
110
|
+
| `client.health` | `liveness`, `readiness` |
|
|
111
|
+
| `client.schedules` | `list`, `get`, `create`, `update`, `patch`, `delete`, `trigger`, `list_executions`, `get_execution` |
|
|
112
|
+
|
|
113
|
+
## Error handling
|
|
114
|
+
|
|
115
|
+
All methods raise `PulpEngineError` on non-2xx responses:
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
from pulp_engine import PulpEngineClient, PulpEngineError
|
|
119
|
+
|
|
120
|
+
try:
|
|
121
|
+
client.render.pdf("missing-template", {})
|
|
122
|
+
except PulpEngineError as e:
|
|
123
|
+
print(e.status) # 404
|
|
124
|
+
print(e.error) # "NotFound"
|
|
125
|
+
print(e.code) # None (or e.g. "template_expression_error" for render errors)
|
|
126
|
+
print(e.issues) # None (or list[ValidationIssue] for 400/422)
|
|
127
|
+
print(str(e)) # Human-readable message
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Dry-run mode (CI/CD pre-flight checks)
|
|
131
|
+
|
|
132
|
+
`client.render.dry_run()` validates input data and exercises all template
|
|
133
|
+
expressions via a trial HTML render, then returns a structured result without
|
|
134
|
+
producing any binary output. Skips Chromium / DOCX / PPTX entirely — typical
|
|
135
|
+
latency is 5–50 ms vs 1–10 s for a full PDF render. Useful for CI/CD
|
|
136
|
+
pre-flight checks and integration tests.
|
|
137
|
+
|
|
138
|
+
Unlike the normal render methods, `dry_run()` does **not** raise on template
|
|
139
|
+
author errors (validation failures, undefined variables, etc.) — those are
|
|
140
|
+
surfaced in the result so callers can display them to users. The only way it
|
|
141
|
+
raises is if the request itself is malformed (network error, 4xx auth, etc.).
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
result = client.render.dry_run("invoice", {"amount": 100})
|
|
145
|
+
|
|
146
|
+
if result.valid:
|
|
147
|
+
print(f"Template OK ({result.field_mappings_applied} field mappings applied)")
|
|
148
|
+
else:
|
|
149
|
+
# Validation errors (schema mismatches)
|
|
150
|
+
for err in result.validation.errors:
|
|
151
|
+
print(f"Validation: {err.path}: {err.message}")
|
|
152
|
+
|
|
153
|
+
# Expression errors (Handlebars failures, undefined variables)
|
|
154
|
+
for err in result.expressions.errors:
|
|
155
|
+
location = err.location.node_path if err.location else "(no location)"
|
|
156
|
+
print(f"Expression at {location}: {err.message}")
|
|
157
|
+
if err.suggestion:
|
|
158
|
+
print(f" Did you mean: {', '.join(err.suggestion.suggestions)}?")
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The `format` parameter selects which per-format route to hit (defaults to
|
|
162
|
+
`"pdf"`). The result shape is identical regardless of format — the selector
|
|
163
|
+
only matters when different formats have different rate limits or feature
|
|
164
|
+
gates server-side:
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
client.render.dry_run("invoice", data, format="html")
|
|
168
|
+
client.render.dry_run("invoice", data, format="docx")
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Binary results
|
|
172
|
+
|
|
173
|
+
PDF, CSV, XLSX, DOCX, and PPTX renders return a `BinaryResult` (or `PptxResult`) with:
|
|
174
|
+
|
|
175
|
+
- `.data` — raw bytes
|
|
176
|
+
- `.content_type` — response Content-Type header
|
|
177
|
+
- `.content_disposition` — response Content-Disposition header
|
|
178
|
+
- `.save(path)` — convenience method to write bytes to a file (creates parent dirs)
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
result = client.render.pdf("invoice", {"amount": 100})
|
|
182
|
+
result.save("output/invoice.pdf") # creates output/ if needed
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
`PptxResult` adds:
|
|
186
|
+
|
|
187
|
+
- `.warning_count` — number of structured warnings parsed from the `X-Render-Warnings` header
|
|
188
|
+
|
|
189
|
+
## Pagination
|
|
190
|
+
|
|
191
|
+
List endpoints return a `PaginatedResult[T]` envelope:
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
page = client.templates.list(limit=20, offset=0)
|
|
195
|
+
print(page.total) # total count across all pages
|
|
196
|
+
print(len(page.items)) # items on this page
|
|
197
|
+
|
|
198
|
+
# Auto-paginate with the helper
|
|
199
|
+
from pulp_engine import paginate
|
|
200
|
+
|
|
201
|
+
for template in paginate(lambda offset, limit: client.templates.list(limit=limit, offset=offset)):
|
|
202
|
+
print(template.key)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Development
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
cd packages/sdk-python
|
|
209
|
+
pip install -e ".[dev]"
|
|
210
|
+
pytest
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Releasing
|
|
214
|
+
|
|
215
|
+
See [RELEASING.md](./RELEASING.md) for the publish runbook. Releases are
|
|
216
|
+
automated via the [`publish-sdk-python.yml`](../../.github/workflows/publish-sdk-python.yml)
|
|
217
|
+
GitHub Actions workflow using PyPI Trusted Publishing (no API tokens).
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# Pulp Engine Python SDK
|
|
2
|
+
|
|
3
|
+
Typed Python client for the [PulpEngine](https://github.com/TroyCoderBoy/pulp-engine) document generation API.
|
|
4
|
+
|
|
5
|
+
Mirrors the [TypeScript SDK](../sdk-typescript) 1:1 with snake_case method names and Pythonic conventions (context manager, type hints, Pydantic response models).
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
> **Not yet published to PyPI.** This SDK currently ships in-repo only; registry
|
|
10
|
+
> publication is pending trusted-publisher setup. Until then, install from the
|
|
11
|
+
> workspace path (`pip install -e packages/sdk-python`). The command below will
|
|
12
|
+
> work once the package is live on PyPI.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install pulp-engine
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Requires Python 3.11+.
|
|
19
|
+
|
|
20
|
+
## Quickstart
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from pulp_engine import PulpEngineClient
|
|
24
|
+
|
|
25
|
+
with PulpEngineClient(
|
|
26
|
+
base_url="https://pulp-engine.example.com",
|
|
27
|
+
api_key="dk_admin_...",
|
|
28
|
+
) as client:
|
|
29
|
+
# List templates
|
|
30
|
+
templates = client.templates.list()
|
|
31
|
+
for t in templates.items:
|
|
32
|
+
print(t.key, t.current_version)
|
|
33
|
+
|
|
34
|
+
# Render a PDF
|
|
35
|
+
result = client.render.pdf("invoice", {"amount": 100, "customer": "Acme"})
|
|
36
|
+
result.save("invoice.pdf")
|
|
37
|
+
|
|
38
|
+
# Render to HTML (returns string)
|
|
39
|
+
html = client.render.html("invoice", {"amount": 100, "customer": "Acme"})
|
|
40
|
+
print(html)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Preview routes in production
|
|
44
|
+
|
|
45
|
+
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.
|
|
46
|
+
|
|
47
|
+
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.
|
|
48
|
+
|
|
49
|
+
## Authentication
|
|
50
|
+
|
|
51
|
+
Pass either an API key (`X-Api-Key` header) or an editor session token (`X-Editor-Token` header):
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
# API key
|
|
55
|
+
client = PulpEngineClient(base_url="...", api_key="dk_admin_...")
|
|
56
|
+
|
|
57
|
+
# Editor session token
|
|
58
|
+
client = PulpEngineClient(base_url="...", editor_token="...")
|
|
59
|
+
|
|
60
|
+
# Switch at runtime
|
|
61
|
+
client.set_api_key("new-key")
|
|
62
|
+
client.set_editor_token("new-token")
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Available resources
|
|
66
|
+
|
|
67
|
+
| Resource | Methods |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `client.templates` | `list`, `get`, `create`, `update`, `delete`, `schema`, `sample`, `validate`, `versions`, `get_version`, `restore` |
|
|
70
|
+
| `client.render` | `pdf`, `html`, `csv`, `xlsx`, `docx`, `pptx`, `dry_run`, `validate` |
|
|
71
|
+
| `client.batch` | `pdf`, `docx`, `submit_async`, `submit_async_docx`, `poll_job`, `wait_for_job` |
|
|
72
|
+
| `client.pdf_transform` | `merge`, `watermark`, `insert` |
|
|
73
|
+
| `client.assets` | `list`, `upload`, `delete` |
|
|
74
|
+
| `client.audit_events` | `list`, `purge` |
|
|
75
|
+
| `client.admin` | `list_users`, `create_user`, `update_user`, `delete_user`, `reload_users` |
|
|
76
|
+
| `client.auth` | `status`, `editor_token` |
|
|
77
|
+
| `client.health` | `liveness`, `readiness` |
|
|
78
|
+
| `client.schedules` | `list`, `get`, `create`, `update`, `patch`, `delete`, `trigger`, `list_executions`, `get_execution` |
|
|
79
|
+
|
|
80
|
+
## Error handling
|
|
81
|
+
|
|
82
|
+
All methods raise `PulpEngineError` on non-2xx responses:
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from pulp_engine import PulpEngineClient, PulpEngineError
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
client.render.pdf("missing-template", {})
|
|
89
|
+
except PulpEngineError as e:
|
|
90
|
+
print(e.status) # 404
|
|
91
|
+
print(e.error) # "NotFound"
|
|
92
|
+
print(e.code) # None (or e.g. "template_expression_error" for render errors)
|
|
93
|
+
print(e.issues) # None (or list[ValidationIssue] for 400/422)
|
|
94
|
+
print(str(e)) # Human-readable message
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Dry-run mode (CI/CD pre-flight checks)
|
|
98
|
+
|
|
99
|
+
`client.render.dry_run()` validates input data and exercises all template
|
|
100
|
+
expressions via a trial HTML render, then returns a structured result without
|
|
101
|
+
producing any binary output. Skips Chromium / DOCX / PPTX entirely — typical
|
|
102
|
+
latency is 5–50 ms vs 1–10 s for a full PDF render. Useful for CI/CD
|
|
103
|
+
pre-flight checks and integration tests.
|
|
104
|
+
|
|
105
|
+
Unlike the normal render methods, `dry_run()` does **not** raise on template
|
|
106
|
+
author errors (validation failures, undefined variables, etc.) — those are
|
|
107
|
+
surfaced in the result so callers can display them to users. The only way it
|
|
108
|
+
raises is if the request itself is malformed (network error, 4xx auth, etc.).
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
result = client.render.dry_run("invoice", {"amount": 100})
|
|
112
|
+
|
|
113
|
+
if result.valid:
|
|
114
|
+
print(f"Template OK ({result.field_mappings_applied} field mappings applied)")
|
|
115
|
+
else:
|
|
116
|
+
# Validation errors (schema mismatches)
|
|
117
|
+
for err in result.validation.errors:
|
|
118
|
+
print(f"Validation: {err.path}: {err.message}")
|
|
119
|
+
|
|
120
|
+
# Expression errors (Handlebars failures, undefined variables)
|
|
121
|
+
for err in result.expressions.errors:
|
|
122
|
+
location = err.location.node_path if err.location else "(no location)"
|
|
123
|
+
print(f"Expression at {location}: {err.message}")
|
|
124
|
+
if err.suggestion:
|
|
125
|
+
print(f" Did you mean: {', '.join(err.suggestion.suggestions)}?")
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The `format` parameter selects which per-format route to hit (defaults to
|
|
129
|
+
`"pdf"`). The result shape is identical regardless of format — the selector
|
|
130
|
+
only matters when different formats have different rate limits or feature
|
|
131
|
+
gates server-side:
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
client.render.dry_run("invoice", data, format="html")
|
|
135
|
+
client.render.dry_run("invoice", data, format="docx")
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Binary results
|
|
139
|
+
|
|
140
|
+
PDF, CSV, XLSX, DOCX, and PPTX renders return a `BinaryResult` (or `PptxResult`) with:
|
|
141
|
+
|
|
142
|
+
- `.data` — raw bytes
|
|
143
|
+
- `.content_type` — response Content-Type header
|
|
144
|
+
- `.content_disposition` — response Content-Disposition header
|
|
145
|
+
- `.save(path)` — convenience method to write bytes to a file (creates parent dirs)
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
result = client.render.pdf("invoice", {"amount": 100})
|
|
149
|
+
result.save("output/invoice.pdf") # creates output/ if needed
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
`PptxResult` adds:
|
|
153
|
+
|
|
154
|
+
- `.warning_count` — number of structured warnings parsed from the `X-Render-Warnings` header
|
|
155
|
+
|
|
156
|
+
## Pagination
|
|
157
|
+
|
|
158
|
+
List endpoints return a `PaginatedResult[T]` envelope:
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
page = client.templates.list(limit=20, offset=0)
|
|
162
|
+
print(page.total) # total count across all pages
|
|
163
|
+
print(len(page.items)) # items on this page
|
|
164
|
+
|
|
165
|
+
# Auto-paginate with the helper
|
|
166
|
+
from pulp_engine import paginate
|
|
167
|
+
|
|
168
|
+
for template in paginate(lambda offset, limit: client.templates.list(limit=limit, offset=offset)):
|
|
169
|
+
print(template.key)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Development
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
cd packages/sdk-python
|
|
176
|
+
pip install -e ".[dev]"
|
|
177
|
+
pytest
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Releasing
|
|
181
|
+
|
|
182
|
+
See [RELEASING.md](./RELEASING.md) for the publish runbook. Releases are
|
|
183
|
+
automated via the [`publish-sdk-python.yml`](../../.github/workflows/publish-sdk-python.yml)
|
|
184
|
+
GitHub Actions workflow using PyPI Trusted Publishing (no API tokens).
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Pulp Engine Python SDK — typed client for the Pulp Engine document generation API.
|
|
2
|
+
|
|
3
|
+
Example::
|
|
4
|
+
|
|
5
|
+
from pulp_engine import PulpEngineClient
|
|
6
|
+
|
|
7
|
+
with PulpEngineClient(
|
|
8
|
+
base_url="https://pulp-engine.example.com", api_key="dk_admin_..."
|
|
9
|
+
) as client:
|
|
10
|
+
result = client.render.pdf("invoice", {"amount": 100})
|
|
11
|
+
result.save("invoice.pdf")
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from .client import PulpEngineClient
|
|
15
|
+
from .errors import PulpEngineError, PulpEngineTimeoutError, ValidationIssue
|
|
16
|
+
from .pagination import PaginatedResult, paginate
|
|
17
|
+
from .resources.render import BinaryResult, DryRunFormat, PptxResult
|
|
18
|
+
from .types import (
|
|
19
|
+
DryRunExpressionError,
|
|
20
|
+
DryRunExpressionLocation,
|
|
21
|
+
DryRunExpressionsSection,
|
|
22
|
+
DryRunExpressionSuggestion,
|
|
23
|
+
DryRunResult,
|
|
24
|
+
DryRunValidationError,
|
|
25
|
+
DryRunValidationSection,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
__version__ = "0.60.0"
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
"PulpEngineClient",
|
|
32
|
+
"PulpEngineError",
|
|
33
|
+
"PulpEngineTimeoutError",
|
|
34
|
+
"ValidationIssue",
|
|
35
|
+
"PaginatedResult",
|
|
36
|
+
"paginate",
|
|
37
|
+
"BinaryResult",
|
|
38
|
+
"PptxResult",
|
|
39
|
+
"DryRunFormat",
|
|
40
|
+
"DryRunResult",
|
|
41
|
+
"DryRunExpressionError",
|
|
42
|
+
"DryRunExpressionLocation",
|
|
43
|
+
"DryRunExpressionSuggestion",
|
|
44
|
+
"DryRunValidationError",
|
|
45
|
+
"DryRunValidationSection",
|
|
46
|
+
"DryRunExpressionsSection",
|
|
47
|
+
"__version__",
|
|
48
|
+
]
|