Skip to content

Using the SDK

fxqclient is the object-oriented Python client over the public API. It is the recommended way to script against fxquinox.

Install

pip install -e ./sdk-python      # from a checkout

Connect

from fxqclient import Session

fxq = Session("http://localhost:8000", api_key="...")  # see Authentication

See Authentication and API keys for how to get an API key.

Read records

Every entity type is reachable through entity() (or as an attribute), which returns a manager with get, filter, filter_raw and all:

# all shots in a project
shots = fxq.entity("Shot").filter(project="Demo Show").all()

# one record by id
task = fxq.entity("Task").get(task_id)

# the raw query DSL for anything filter() can't express
todo = fxq.entity("Task").filter_raw(
    ["and", ["status", "is", "waitingToStart"], ["project_id", "is", pid]]
).all()

for shot in shots:
    print(shot.id, shot.status, shot.data)

Records are thin wrappers: shot.id, shot.entity_type, shot.status, and the fields under shot.data.

Create and update

# Link fields are plain dicts: {"type": ..., "id": ...}
shot = fxq.entity("Shot").create(
    code="sh0010",
    project={"type": "Project", "id": pid},
)
fxq.entity("Task").create(
    name="comp",
    step="Compositing",
    entity={"type": "Shot", "id": shot.id},
    status="waitingToStart",
)

Publish

The publish chain is one call - it creates (or reuses) the product, allocates the next version number, and attaches representations:

result = fxq.publish(
    task_id=task.id,
    product="lightingMain",
    product_type="render",
    representations=[{"name": "exr", "files": [...]}],
    inputs=[upstream_version_id],   # lineage
    comment="first pass",
)

See Integrations for using this from a DCC, and How it works for the model.

Lineage and dependencies

Trace what a version was built from, in either direction:

fxq.lineage(version_id)        # the raw input/output lineage record
fxq.dependencies(version_id)   # the enriched upstream dependency tree (VAL-51)

Resolve a path from the project anatomy

Turn a project's templated anatomy into a concrete path for an entity:

path = fxq.resolve_path(
    template_key="publish",
    entity_type="Task",
    entity_id=task.id,
    root_name="work",       # which root to resolve against
    extra={"product": "lightingMain", "ext": "exr"},
)

Browse loadable products and scene inventory

Drive a DCC loader and keep an open scene up to date:

# everything publishable into a context (latest only)
items = fxq.browse_loadable(project_id=pid, product_type="render", latest_only=True)

# given the versions loaded in a scene, which are outdated?
inv = fxq.scene_inventory([v1_id, v2_id])   # each item: current / latest / outdated

Render farm

Submit and track farm jobs (the farm itself updates progress via the callback):

job = fxq.submit_farm_job(task_id=task.id, version_id=ver_id, frames="1-100")
fxq.farm_jobs(status="running")            # list / filter tracked jobs
fxq.update_farm_job(job["id"], status="completed", progress=100)

Multi-site sync (SiteSync)

Queue and process transfers of a representation between sites:

fxq.request_sync(representation_id=rep_id, target_site_id=site_id)
fxq.sync_jobs(status="queued")             # list transfer jobs
fxq.process_sync_queue()                   # process the queue once → completed count

See Pipeline APIs for the concepts behind anatomy, the loader, the farm and SiteSync.

The full surface is in the SDK reference.