Metadata-Version: 2.5
Name: pulze-renderflow
Version: 2.0.8
Summary: Official RenderFlow API client for Python
Project-URL: Homepage, https://pulze.io/products/renderflow
Author-email: Pulze <support@pulze.io>
License-Expression: MIT
License-File: LICENSE
Keywords: 3dsmax,arnold,blender,cinema4d,corona,fusion,houdini,maya,network-rendering,nuke,pulze,redshift,render-farm,renderflow,vray
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.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# pulze-renderflow

Official Python client for the [RenderFlow](https://pulze.io/products/renderflow) API.

## Installation

```bash
pip install pulze-renderflow
```

The package has **no dependencies** — the whole client is standard library. That is a feature,
not an accident: drop the folder on `sys.path` and it works inside a DCC's bundled Python (Maya,
Houdini, Nuke, VRED), where installing anything is a fight.

## Quick start

```python
import renderflow as rf

farm = rf.connect()                     # the local service on 127.0.0.1:44442
# farm = rf.connect("https://rf.studio.lan:44442", api_key="rf_...")

for job in farm.jobs.get_jobs(status="working").data:
    print(job.name, job.status)
```

`connect()` falls back to the environment for each argument it isn't given: `RENDERFLOW_URL`
for the address, `RENDERFLOW_API_KEY` for the key (the same variable `rfcli` reads). With
neither, it talks to the service on this machine — which needs no credential, and is how a DCC
plugin on a workstation submits.

## Finding the operation you want

Operations are grouped by tag and named after the API document's `operationId`, so a route
reads the same here, in the TypeScript SDK, in `rfcli` and in the MCP tools:

```python
farm.tags()                 # every group: jobs, nodes, pools, schedule, render_licenses, ...
dir(farm.jobs)              # every operation in one: get_jobs, create_job, stop_job, ...
help(farm.jobs.get_jobs)    # the operation's own documentation, generated from the document
```

| you want | you write |
| --- | --- |
| `GET /jobs` | `farm.jobs.get_jobs()` |
| `GET /jobs/{id}` | `farm.jobs.get_job(id)` |
| `POST /jobs` | `farm.jobs.create_job(body=...)` |
| `POST /jobs/{id}/stop` | `farm.jobs.stop_job(id)` |
| `GET /nodes` | `farm.nodes.get_nodes()` |

## Submitting a job

A recipe — `type` plus a file and the flat per-DCC fields — is the short way in; the service
expands it into the step tree:

Every recipe requires `type`, `file` and `host` — `host` is which application renders it, and only
its `id` is mandatory:

```python
job = farm.jobs.create_job(body={
    "type": "blender.render",
    "file": "//share/scenes/shot_010.blend",
    "host": {"id": "blender", "version": "4.5"},
    "frame": "1-100",
    "pool_id": "...",
})

print(job.id, job.status)
farm.jobs.stop_job(job.id)
```

Bodies are plain dicts; answers read with dot access (`job.name`, `page.data`) and hand back the
raw payload via `.to_dict()`.

## Models

Typed names for every request and response schema live in `renderflow.models`, and your editor
reads them from `models.pyi` — autocomplete and type checking with nothing to install:

```python
from renderflow.models import MayaRenderRecipe

recipe: MayaRenderRecipe = {"type": "maya.render", "file": "//share/scenes/hero.mb", "host": {"id": "maya", "version": "2026"}}
farm.jobs.create_job(body=recipe)
```

At runtime a model is a dict — the wire is JSON and the service validates.

## Errors

A refused call raises `renderflow.wire.ApiError`, carrying the status and the service's own
message — `str(error)` is the sentence an operator should read.

## How this package is built

There is no generated client. `renderflow/wire.py` binds operations off the OpenAPI document at
runtime, and the document ships inside the package as `renderflow/openapi.json` — a committed
copy of the service's `openapi.public.json`. An operation added to the API arrives here the
moment that copy is refreshed:

```bash
python scripts/generate.py     # copies ../../service/openapi.public.json + rewrites models.pyi
```

`models.pyi` is written by [datamodel-code-generator](https://github.com/koxudaxi/datamodel-code-generator),
a dev-only tool — never a dependency of the package.
