Skip to content

API reference

This page renders the public Python API directly from the source. For higher-level concepts, see Library, CLI, Daemon, and MCP.

dvr

dvr

dvr — the missing CLI and Python library for DaVinci Resolve.

This package exposes a small, stable public API. Internal modules are prefixed with _ and may change between releases. The two things you almost always want are:

from dvr import Resolve, errors

Open a connection with r = Resolve() and navigate from there.

ClipQuery module-attribute

ClipQuery = ItemQuery

ClipFusion module-attribute

ClipFusion = ItemFusion

Asset module-attribute

Asset = Clip

Bin module-attribute

Bin = Folder

Resolve

Resolve(*, auto_launch: bool = True, timeout: float = 30.0, discover_remote: bool | None = None)

Top-level connection to a running DaVinci Resolve instance.

Parameters:

Name Type Description Default
auto_launch bool

If True, launch Resolve when it isn't running.

True
timeout float

Total seconds to wait for a connection.

30.0

The constructor establishes the connection and validates that Resolve is responsive. Use the lazy properties below to navigate further.

Example

from dvr import Resolve r = Resolve() r.app.page = "deliver" r.app.version '20.3.1'

Open a connection to DaVinci Resolve.

Parameters:

Name Type Description Default
auto_launch bool

Launch the local Resolve if it isn't running.

True
timeout float

Total seconds to wait for a connection.

30.0
discover_remote bool | None

If True, allow falling back to pinghosts network discovery (any Resolve on the LAN). Defaults to False (or the value of $DVR_DISCOVER_REMOTE). Only set when you intentionally want to drive a remote Resolve.

None

app property

app: App

App-level operations (page, layout, version).

page property writable

page: PageController

Current Resolve page — shortcut for r.app.page.

Reads as a string-like value: str(r.page) returns "edit", "color", etc. Assignable: r.page = "deliver". Also exposes a context manager via r.page.use(...).

project_manager property

project_manager: Any

Raw Resolve ProjectManager handle.

For most operations prefer :attr:project (the wrapped :class:dvr.project.ProjectNamespace). Use this when you need to reach API methods we don't yet wrap.

pm property

pm: Any

Short alias for :attr:project_manager.

project property

project: ProjectNamespace

Project-level namespace (current, list, ensure, load, ...).

timeline property

timeline: TimelineNamespace

Timeline-level namespace (current, list, ensure, ...).

render property

render: RenderNamespace

Render queue namespace (submit, watch, status, presets, ...).

storage property

storage: MediaStorage

Filesystem-side media access (volumes, file listings, bulk import).

raw property

raw: Any

The underlying scriptapp('Resolve') handle.

Use this only when dvr does not (yet) expose what you need. Anything reached through raw is unwrapped and unmonitored.

inspect

inspect() -> dict[str, Any]

One-call snapshot of app + current project + current timeline.

close

close(*, cancel_pending_renders: bool = True) -> None

Tear down anything Resolve() may have left running.

Parameters:

Name Type Description Default
cancel_pending_renders bool

If True (default), stop any in-progress render and clear any jobs we queued via :class:dvr.render.RenderNamespace.submit that didn't reach a terminal state.

True

App

App(raw: Any)

App-level operations: pages, layouts, version, quit.

page property writable

page: PageController

The currently visible page (edit, color, deliver ...).

version property

version: str

Resolve's version string, e.g. 20.3.1.

product property

product: str

DaVinci Resolve or DaVinci Resolve Studio.

quit

quit() -> None

Quit DaVinci Resolve gracefully.

Project

Project(raw: Any, manager: Any)

A single Resolve project (loaded or otherwise reachable).

settings property

settings: Settings

Typed proxy for project settings.

Read with attribute access (proj.settings.timeline_resolution_width) and write the same way. Falls back to string-key get/set for any unknown attribute name. Common settings are exposed as typed properties; everything else uses proj.get_setting(key) / proj.set_setting(key, value) directly.

timeline property

timeline: TimelineNamespace

Timeline namespace — current, list, ensure, switch, use() context manager.

Also iterable: for tl in project.timeline: .... Index/name lookup: project.timeline["Edit_v2"], project.timeline[0].

timelines property

timelines: TimelineNamespace

Plural alias for :attr:timeline — reads more naturally in loops.

current_timeline property writable

current_timeline: Any

The currently active timeline, or None. Settable.

Equivalent to project.timeline.current (read) and project.timeline.set_current(...) (write). Accepts a :class:Timeline or its name as a string.

media property

media: MediaPool

Wrapped media pool for this project.

media_pool property

media_pool: Any

Raw MediaPool handle. Prefer :attr:media in new code.

gallery property

gallery: Gallery

The project's gallery (still and PowerGrade albums).

get_setting

get_setting(key: str | None = None) -> Any

Return a single setting (or all of them if key is None).

set_setting

set_setting(key: str, value: Any) -> None

Set a project setting; raise :class:SettingsError on failure.

setting_context

setting_context(key: str, value: Any) -> Iterator[Any]

Set a project setting for the duration of the with block.

Captures the previous value with :meth:get_setting, applies value via :meth:set_setting, and restores the previous value in finally — even if the block raises. Useful for scoped flips around a single render or operation::

with project.setting_context("colorAcesODT", "Rec.709 BT.1886"):
    r.render.submit_and_wait(...)

The yielded value is the original (pre-flip) setting, so callers that need it for logging or conditional logic don't have to read it again. Restoration failures are logged at WARNING level rather than masking exceptions raised inside the block.

set_aces_idt

set_aces_idt(value: str) -> None

Set the project-default ACES Input Device Transform.

Wraps set_setting("colorAcesIDT", value) with a clearer error path for the HDR PQ rejection case (see :meth:set_setting). Basic IDT names like "No Input Transform", "Rec.2020", "P3-D65", "P3-D60", "DCDM" are accepted by Resolve's API; HDR PQ variants must be set via the UI or :meth:set_preset.

set_aces_odt

set_aces_odt(value: str) -> None

Set the project-default ACES Output Device Transform.

Same caveats as :meth:set_aces_idt.

presets

presets() -> list[dict[str, Any]]

Return the project-level preset list (from GetPresetList).

Each entry is a dict like {"Name": "MyPreset", "Width": 3840, "Height": 2160}.

set_preset

set_preset(name: str) -> None

Apply a project preset (saved configuration of project settings).

Useful as a workaround for settings that SetSetting cannot apply directly (notably HDR PQ ACES IDT/ODT): create the preset once in the Resolve UI with the desired transforms, then reuse it from scripts via this method. Raises :class:ProjectError on failure.

save_as_preset

save_as_preset(name: str) -> None

Save the current project settings as a named project preset.

ProjectNamespace

ProjectNamespace(resolve_raw: Any, manager: Any)

Project-manager operations exposed via :attr:Resolve.project.

list

list() -> List[str]

Return project names in the current PM folder.

folders

folders() -> List[str]

Return PM subfolder names in the current folder.

ensure

ensure(name: str) -> Project

Load the project if it exists, otherwise create it.

use

use(name: str) -> Iterator[Project]

Switch to name for the duration of the with block.

Timeline

Timeline(raw: Any, project: Any)

A single timeline within a project.

tracks property

tracks: TrackCollection

Track collection — tl.tracks.video, tl.tracks.audio.add(), etc.

Also callable for backward compatibility: tl.tracks() / tl.tracks("video") return a plain list of :class:Track.

markers property

markers: MarkerCollection

Marker collection — dict-like, with .add() / .remove() shortcuts.

Also callable for backward compatibility: tl.markers() returns a plain dict {frame: {color, name, note, duration, customData}}.

track

track(track_type: str, index: int) -> Track

Get a single track by type and 1-based index (Resolve convention).

delete_track

delete_track(track_type: str, index: int) -> None

Delete a track by type and 1-based index.

items

items(track_type: str | None = None) -> ItemQuery

Return a query over timeline items on track_type (or all).

find_clip

find_clip(predicate: Callable[[TimelineItem], bool] | None = None, *, name: str | None = None, track_type: str | None = None) -> TimelineItem | None

Return the first timeline item across all (or filtered) tracks.

Either pass a predicate callable, or name= for an exact :attr:TimelineItem.name match. track_type (video / audio / subtitle) restricts the search.

find_clips

find_clips(predicate: Callable[[TimelineItem], bool] | None = None, *, name: str | None = None, track_type: str | None = None) -> list[TimelineItem]

Like :meth:find_clip but returns every match (possibly empty).

find_gaps

find_gaps(*, track_type: str = 'video', track_index: int = 1) -> list[tuple[int, int]]

Return [(start_frame, end_frame), ...] for every gap on a track.

A gap is the empty stretch between adjacent items, plus any space before the first item (relative to :attr:start_frame) and after the last item (relative to :attr:end_frame).

Useful for sanity checks like "did the V2 build leave shot windows empty where V1 has content?". Sorted by start.

duplicate

duplicate(name: str | None = None) -> Timeline

Duplicate this timeline; returns the new :class:Timeline.

If name is omitted, Resolve assigns a default (typically "<original> 1"). Resolve switches the current timeline to the new copy.

delete

delete(items: Iterable[TimelineItem], *, ripple: bool = False) -> None

Batch-delete timeline items. Convenience for :meth:delete_clips.

delete_clips

delete_clips(items: Iterable[TimelineItem], *, ripple: bool = False) -> None

Batch-delete timeline items.

Parameters:

Name Type Description Default
items Iterable[TimelineItem]

An iterable of :class:TimelineItem objects.

required
ripple bool

If True, close the gap left by deleted items.

False

Raises :class:TimelineError if Resolve refuses the delete.

create_compound_from_clips

create_compound_from_clips(items: Iterable[TimelineItem], *, name: str, start_timecode: str | None = None) -> TimelineItem

Group a contiguous run of timeline items into a compound clip.

add_marker

add_marker(frame: int, *, color: str = 'Blue', name: str = '', note: str = '', duration: int = 1, custom_data: str = '') -> None

Convenience for :meth:MarkerCollection.add.

create_subtitles_from_audio

create_subtitles_from_audio(*, language: str = 'auto', chars_per_line: int = 42, line_break_type: str = 'Auto', preset: str | None = None) -> None

Run Resolve's Whisper-based audio-to-subtitle generation.

detect_scene_cuts

detect_scene_cuts() -> bool

Run Resolve's automatic scene-cut detection on the timeline.

TimelineNamespace

TimelineNamespace(parent: Any)

Operations on the timelines of a project.

Track

Track(timeline: Timeline, track_type: str, index: int)

A single video/audio/subtitle track on a timeline.

subtype property

subtype: str | None

Audio channel format (mono/stereo/5.1/7.1/adaptive). None for V/S.

items property

items: list[TimelineItem]

Timeline items placed on this track, ordered by start frame.

find

find(*, name: str | None = None, predicate: Callable[[TimelineItem], bool] | None = None) -> TimelineItem | None

Return the first item on this track matching name or predicate.

Mutually exclusive: pass either name= (exact match on :attr:TimelineItem.name) or predicate= (callable returning bool). Returns None if nothing matches.

find_all

find_all(*, name: str | None = None, predicate: Callable[[TimelineItem], bool] | None = None) -> list[TimelineItem]

Like :meth:find but returns every match (possibly empty).

delete

delete() -> None

Delete this track from the timeline.

Clip

Clip(raw: Any)

A clip in the media pool (Resolve's MediaPoolItem).

For the placed instance of a clip on a timeline, see :class:dvr.timeline.TimelineItem instead.

duration property

duration: str

Duration as a timecode string.

resolution property

resolution: str

e.g. 3840x2160.

codec property

codec: str

Video codec as reported by Resolve (e.g. Apple ProRes 4444 XQ).

kind property

kind: str

Clip type — e.g. Video, Audio, Compound Clip, Generator.

set_property

set_property(key: str, value: Any, *, raise_on_failure: bool = True) -> bool

Set a media-pool clip property. Returns True on success.

With raise_on_failure=True (default), raises :class:MediaError on failure. With raise_on_failure=False, returns False so you can do batch counting like sum(1 for c in clips if c.set_property(..., raise_on_failure=False)).

replace

replace(source_path: str, *, preserve_subclip: bool = True) -> None

Replace the underlying source file.

preserve_subclip=True keeps trim/marks if the API exposes ReplaceClipPreserveSubClip (newer Resolve versions). Otherwise falls back to ReplaceClip which resets the clip extents.

transcribe

transcribe(language: str = 'auto') -> None

Run Resolve's Whisper-based audio transcription on this clip.

Takes

Takes(item: TimelineItem)

Take / variant management on a single timeline item.

MediaPool

MediaPool(raw: Any, resolve_raw: Any)

The project-scoped media pool.

root property

root: Folder

The root folder of the media pool.

current_folder property

current_folder: Folder

The folder currently selected in the UI.

add_folder

add_folder(name: str, *, parent: Folder | None = None) -> Folder

Create a new (sub-)folder under parent (defaults to the current folder).

ensure_folder

ensure_folder(name: str, *, parent: Folder | None = None) -> Folder

Get-or-create a (sub-)folder by name. Idempotent.

find_folder

find_folder(name: str) -> Folder | None

Return the first folder named name (depth-first), or None.

walk

walk() -> Iterator[Folder]

Yield every folder in the pool (depth-first from root).

find_clips

find_clips(*, name: str | None = None, predicate: Callable[[Clip], bool] | None = None) -> list[Clip]

Recursively search the entire pool for matching clips.

Pass either name= (exact match) or predicate= (callable returning bool). Replaces ad-hoc build_clip_lookup helpers.

find_clip

find_clip(*, name: str | None = None, predicate: Callable[[Clip], bool] | None = None) -> Clip | None

Like :meth:find_clips but returns the first match (or None).

delete_folders

delete_folders(folders: Folder | Iterable[Folder]) -> None

Delete one or more (sub-)folders from the pool.

delete_timelines

delete_timelines(timelines: Any) -> None

Delete one or more timelines from the pool.

Accepts a :class:~dvr.timeline.Timeline, its name as a string, a raw fusionscript Timeline handle, or an iterable of any of those. Wraps Resolve's DeleteTimelines.

refresh

refresh() -> None

In collaboration mode, refresh stale folders.

import_media

import_media(paths: Iterable[str], *, folder: Folder | None = None) -> list[Clip]

Import file paths into the pool. Idempotent at the path level.

import_imf

import_imf(imf_dir: str, *, folder: Folder | None = None) -> list[Clip]

Import an IMF (Interoperable Master Format) package into the pool.

Pass the path to the IMF folder (the OV folder containing ASSETMAP.xml, CPL_*.xml, PKL_*.xml, and the .mxf essence files) — not the CPL XML itself. Resolve's MediaPool.ImportMedia([cpl_path]) returns empty for IMFs; MediaStorage.AddItemListToMediaPool([imf_dir]) is the working path and is what this method uses.

Each MXF in the package is imported as a separate Media Pool clip (picture, 5.1 audio, 2.0 audio, etc.). The CPL/PKL/ASSETMAP/OPL XMLs are recognized and skipped automatically by Resolve.

import_to

import_to(folder: str | Folder, paths: Iterable[str], *, create_missing: bool = True) -> list[Clip]

Idempotent "import these paths into this folder, restore previous folder when done".

folder may be a :class:Folder or a folder name (string). If the folder doesn't exist and create_missing=True (default), it is created under the root.

The current folder selection is restored after the import — useful when scripts shouldn't perturb the user's UI state.

find_or_import

find_or_import(path: str | PathLike[str], *, folder: Folder | str | None = None) -> Clip

Return the existing :class:Clip for path, importing if absent.

Walks the entire pool looking for a clip whose file_path matches the requested path (after :func:os.path.normpath / :func:os.path.normcase). If no match is found, imports it via :meth:import_media (or :meth:import_to when folder is given) and returns the freshly imported clip.

This is the right primitive when a script repeatedly references the same source file — for example, batch-extracting many shots out of a single master render. Without it, every call to :meth:import_media adds a duplicate Media Pool entry for the same path, which slows down the project and clutters the bin tree.

Parameters:

Name Type Description Default
path str | PathLike[str]

Source path on disk. May be str or Path.

required
folder Folder | str | None

Optional bin to import into if the clip isn't already in the pool. Accepts a :class:Folder or a folder name (auto-created under the root). Has no effect when the clip is found via lookup — already-pooled clips stay where they are.

None

Returns:

Name Type Description
A Clip

class:Clip for the requested path.

Raises:

Type Description
MediaImportError

if the path is not in the pool and Resolve refuses to import it.

append_to_timeline

append_to_timeline(items: Iterable[Clip | dict[str, Any]]) -> list[Any]

Append clips to the current timeline.

Each item is either a :class:Clip or a clipInfo dict (e.g. {"mediaPoolItem": clip.raw, "startFrame": 24, "endFrame": 96}).

delete_clips

delete_clips(clips: Clip | Iterable[Clip]) -> None

Delete one or more clips from the media pool.

move

move(clips: Iterable[Clip], target: Folder) -> None

Move clips into a target folder.

relink(clips: Iterable[Clip], folder: str) -> None

Relink clips to a folder of replacement files on disk.

create_subclip

create_subclip(source_path: str, *, start: int, end: int, name: str | None = None, folder: Folder | str | None = None) -> Clip

Import source_path as a sub-clip with explicit frame range.

Unlike :meth:import_with_subclips (which takes raw dicts), this is a typed primitive: (source_path, start_frame, end_frame, name) → Clip. Useful for EDL-driven ingestion where one master file spawns many sub-clips.

Resolve renames the imported clip to name if given. The clip is placed in folder (a :class:Folder, name string, or None for the current folder).

import_with_subclips

import_with_subclips(items: Iterable[dict[str, Any]], *, folder: Folder | None = None) -> list[Clip]

Import paths with explicit per-clip frame ranges.

Each entry is a dict {"FilePath": str, "StartIndex": int, "EndIndex": int}; pass-through to Resolve's MediaStorage.AddItemListToMediaPool which honours the indices to create sub-clips. Useful for EDL-driven ingestion where a single master file feeds many clips.

MediaStorage

MediaStorage(raw: Any, pool: MediaPool)

Resolve's view of the local/connected filesystem.

add_to_pool

add_to_pool(items: Iterable[str | dict[str, Any]], *, folder: Folder | None = None) -> list[Clip]

Import file paths (or {"FilePath": ..., "StartIndex": ...} dicts) into the pool.

RenderJob

RenderJob(namespace: RenderNamespace, job_id: str)

A single job in Resolve's render queue.

percent property

percent: float

Completion percentage as a float in [0, 100].

progress property

progress: float

Completion fraction in [0.0, 1.0] — same data as :attr:percent/100.

is_finished property

is_finished: bool

True iff the job has reached a terminal state (Complete/Failed/Cancelled).

poll

poll() -> dict[str, Any]

Non-blocking status snapshot — same payload as :meth:inspect.

Use this from a loop or scheduler when you don't want to block on :meth:wait. Returns the structured dict: {id, status, percent, progress, eta_seconds, output_path, error, is_finished}.

wait

wait(*, poll_interval: float = 1.0, timeout: float | None = None, stall_seconds: float = _DEFAULT_STALL_SECONDS) -> RenderJob

Block until this job finishes; return self.

Raises :class:RenderError on failure or timeout/stall.

RenderNamespace

RenderNamespace(resolve: Any)

Render queue operations exposed at :attr:Resolve.render.

set_format_and_codec

set_format_and_codec(format_name: str, codec: str) -> None

Set render container format and codec, with read-back verification.

Resolve's SetCurrentRenderFormatAndCodec returns None on both success and failure, so we verify by reading back the current pair. If the requested values didn't take, raise a structured error with the actual current state.

save_preset

save_preset(name: str) -> None

Save the current render settings as a new render preset.

delete_preset

delete_preset(name: str) -> None

Delete a saved render preset.

export_preset

export_preset(name: str, file_path: str) -> None

Export a render preset to a .xml file for backup or sharing.

import_preset

import_preset(file_path: str) -> None

Import a render preset from a .xml file.

is_rendering

is_rendering() -> bool

True iff Resolve reports an in-flight render.

Thin wrapper over Project.IsRenderingInProgress — exposed so callers don't have to reach through to project.raw for what is otherwise a one-liner.

status

status(job_id: str) -> dict[str, Any]

Return a normalized status snapshot for job_id.

Equivalent to RenderJob(ns, job_id).poll() but exposed at the namespace level so toolkit code (r.render.status(jid)) doesn't have to construct its own :class:RenderJob just to read the queue. The payload is::

{"id", "status", "percent", "progress", "eta_seconds",
 "output_path", "error", "is_finished"}

error is None for successful / in-progress jobs.

clear

clear(*, timeout: float = _DEFAULT_CLEAR_TIMEOUT_SECONDS, poll_interval: float = 0.5) -> None

Delete every job in the render queue, with bounded patience.

Resolve's DeleteAllRenderJobs is silently dropped on some builds when the queue still contains a freshly-finished image-sequence (EXR / DPX) job. To make it safe for toolkits to call r.render.clear() between shots, this method:

  • Returns immediately if the queue is already empty.
  • Refuses to clear while a render is in progress (raises :class:RenderError with the live queue size — the caller should wait or call :meth:stop first).
  • Issues DeleteAllRenderJobs once, then falls back to per-job DeleteRenderJob calls until the queue empties.
  • Bounds the whole loop with timeout (seconds). If queue deletion stalls past that, raises :class:RenderError listing the remaining job IDs rather than blocking forever.

submit

submit(*, target_dir: str, custom_name: str | None = None, preset: str | None = None, format: str | None = None, codec: str | None = None, settings: dict[str, Any] | None = None, start: bool = True) -> RenderJob

Configure and queue a render of the current timeline.

Parameters:

Name Type Description Default
target_dir str

Output directory (must exist).

required
custom_name str | None

Filename without extension. Defaults to timeline name.

None
preset str | None

Render preset to load before applying overrides.

None
format str | None

Container format (mov, mxf ...).

None
codec str | None

Codec name (e.g. ProRes4444XQ).

None
settings dict[str, Any] | None

Extra SetRenderSettings keys (e.g. {"MarkIn": 24}).

None
start bool

If True, start rendering immediately.

True

Returns:

Name Type Description
A RenderJob

class:RenderJob. If start=False, the job is queued

RenderJob

but not yet running; call :meth:RenderJob.wait after starting.

submit_per_clip

submit_per_clip(items: Iterable[TimelineItem], *, target_dir: str, naming_template: str = '{clip_name}', preset: str | None = None, format: str | None = None, codec: str | None = None, settings: dict[str, Any] | None = None, start: bool = True) -> list[RenderJob]

Queue one render job per timeline item, with the timeline marks constrained to that item's frame range.

naming_template is a Python format string; supported keys:

  • {clip_name} — the timeline item's name
  • {index} — 1-based position in items
  • {start} / {end} — record-frame bounds
  • {track} — track index (1-based)

Each job uses the same target directory; the per-job filename is derived from the template. Returns the list of submitted :class:RenderJob objects in the same order as items.

With start=True (default), Resolve picks them up sequentially in the order added. Use :meth:watch on the returned IDs.

submit_and_wait

submit_and_wait(*, target_dir: str, custom_name: str | None = None, preset: str | None = None, format: str | None = None, codec: str | None = None, settings: dict[str, Any] | None = None, poll_interval: float = 1.0, timeout: float | None = None, stall_seconds: float = _DEFAULT_STALL_SECONDS) -> str

Submit a render of the current timeline, block until done, return its output path.

Combines :meth:submit (with start=True) and :meth:RenderJob.wait. Used as a one-liner from build scripts that produce a single artifact per Resolve session::

output = r.render.submit_and_wait(
    target_dir="/Volumes/Out",
    custom_name="delivery_master",
    format="mov",
    codec="ProRes4444XQ",
)

Parameters:

Name Type Description Default
target_dir str

See :meth:submit.

required
custom_name str | None

See :meth:submit.

None
preset str | None

See :meth:submit.

None
format str | None

See :meth:submit.

None
codec str | None

See :meth:submit.

None
settings dict[str, Any] | None

See :meth:submit.

None
poll_interval float

See :meth:RenderJob.wait.

1.0
timeout float | None

See :meth:RenderJob.wait.

None
stall_seconds float

See :meth:RenderJob.wait.

_DEFAULT_STALL_SECONDS

Returns:

Type Description
str

The absolute path to the rendered file as reported by

str

Resolve's OutputFilename job property.

Raises:

Type Description
RenderError / RenderJobError

on submit failure or render failure / cancel / stall / timeout.

render_single_clip

render_single_clip(item: TimelineItem, *, target_dir: str, custom_name: str | None = None, preset: str | None = None, format: str | None = None, codec: str | None = None, settings: dict[str, Any] | None = None, start: bool = True) -> RenderJob

Convenience for "render exactly this one timeline item".

Sets the timeline mark in/out around the item, queues a single job, and (by default) starts it. Equivalent to calling :meth:submit_per_clip with one item, but returns a single :class:RenderJob.

watch

watch(job_ids: list[str] | None = None, *, poll_interval: float = 1.0) -> Iterator[dict[str, Any]]

Yield structured status events until all jobs finish.

Each event is a dict::

{"type": "progress", "job_id": "...", "percent": 47, "eta_s": 180}
{"type": "complete", "job_id": "...", "output_path": "..."}
{"type": "failed",   "job_id": "...", "error": "..."}

Image-sequence renders (EXR / DPX) sometimes never flip JobStatus from Rendering to Complete. To avoid spinning forever, when a job reports CompletionPercentage >= 100 and Project.IsRenderingInProgress() is False, this generator emits a synthetic complete event for it and moves on. Failure / cancel paths are unchanged.

ColorOps

ColorOps(clip: TimelineItem)

Color operations on a single :class:Clip.

add_version

add_version(name: str, *, version_type: int = 0) -> None

Add a color version. version_type 0 = local, 1 = remote.

set_cdl

set_cdl(*, node_index: int = 1, slope: tuple[float, float, float, float] | None = None, offset: tuple[float, float, float, float] | None = None, power: tuple[float, float, float, float] | None = None, saturation: float | None = None) -> None

Apply a CDL grade to a single node.

Each of slope/offset/power is a 4-tuple (R, G, B, Master). Omitted values are left untouched.

export_lut

export_lut(file_path: str, *, size: int = 33) -> None

Export the current grade as a 1D/3D LUT.

size corresponds to Resolve's EXPORT_LUT_* enum: 17, 33, 65, or use "vlt" (Panasonic VLT). Defaults to 33-point cube.

magic_mask

magic_mask(mode: str = 'BI') -> None

Run Magic Mask tracking. mode is F, B, or BI.

NodeGraph

NodeGraph(raw: Any)

A clip's color node graph (one layer).

ColorGroup

ColorGroup(raw: Any)

A color group (shared pre/post-clip grades for many clips).

dvr.errors

dvr.errors

Diagnostic exception system.

Every error in dvr carries three structured fields:

  • cause: the most likely reason the operation failed
  • fix: how to recover (often a snippet of code)
  • state: a snapshot of relevant state at the time of failure

The Resolve scripting API is notorious for silent None returns. The goal of this module is that every wrapped call decodes the failure into a DvrError whose __str__ reads like a diagnostic, not a Python traceback. LLM agents can branch on the error type; humans can read the fix and move on.

DvrError

DvrError(message: str, *, cause: str | None = None, fix: str | None = None, state: dict[str, Any] | None = None)

Bases: Exception

Base exception for all dvr failures.

Parameters:

Name Type Description Default
message str

Short, present-tense description of what failed.

required
cause str | None

The likely underlying reason. Computed by the caller from read-back state where possible.

None
fix str | None

How to recover. A code snippet or short imperative.

None
state dict[str, Any] | None

Relevant state snapshot for diagnostics (project name, current page, queue length, etc.).

None

to_dict

to_dict() -> dict[str, Any]

Serialize for JSON output / structured logs / MCP responses.

ConnectionError

ConnectionError(message: str, *, cause: str | None = None, fix: str | None = None, state: dict[str, Any] | None = None)

Bases: DvrError

Could not connect to a running DaVinci Resolve instance.

NotInstalledError

NotInstalledError(message: str, *, cause: str | None = None, fix: str | None = None, state: dict[str, Any] | None = None)

Bases: DvrError

DaVinci Resolve does not appear to be installed on this system.

ScriptingDisabledError

ScriptingDisabledError(message: str, *, cause: str | None = None, fix: str | None = None, state: dict[str, Any] | None = None)

Bases: DvrError

External scripting is not enabled in Resolve's preferences.

ProjectError

ProjectError(message: str, *, cause: str | None = None, fix: str | None = None, state: dict[str, Any] | None = None)

Bases: DvrError

A project-level operation failed.

TimelineError

TimelineError(message: str, *, cause: str | None = None, fix: str | None = None, state: dict[str, Any] | None = None)

Bases: DvrError

A timeline-level operation failed.

TrackError

TrackError(message: str, *, cause: str | None = None, fix: str | None = None, state: dict[str, Any] | None = None)

Bases: DvrError

A track-level operation failed (add / delete / lock / etc.).

ClipError

ClipError(message: str, *, cause: str | None = None, fix: str | None = None, state: dict[str, Any] | None = None)

Bases: DvrError

A clip-level (TimelineItem or MediaPoolItem) operation failed.

MediaError

MediaError(message: str, *, cause: str | None = None, fix: str | None = None, state: dict[str, Any] | None = None)

Bases: DvrError

A media import / relink / proxy operation failed.

MediaImportError

MediaImportError(message: str, *, cause: str | None = None, fix: str | None = None, state: dict[str, Any] | None = None)

Bases: MediaError

A media import specifically — distinguishable from relink/proxy failures.

TimelineNotFoundError

TimelineNotFoundError(message: str, *, cause: str | None = None, fix: str | None = None, state: dict[str, Any] | None = None)

Bases: TimelineError

Looked up a timeline by name and it didn't exist in the current project.

RenderError

RenderError(message: str, *, cause: str | None = None, fix: str | None = None, state: dict[str, Any] | None = None)

Bases: DvrError

A render submission, monitoring, or completion failed.

RenderJobError

RenderJobError(message: str, *, cause: str | None = None, fix: str | None = None, state: dict[str, Any] | None = None)

Bases: RenderError

A single render job failed (vs. queue / config errors).

SettingsError

SettingsError(message: str, *, cause: str | None = None, fix: str | None = None, state: dict[str, Any] | None = None)

Bases: DvrError

Setting an invalid project or timeline setting key/value.

ColorError

ColorError(message: str, *, cause: str | None = None, fix: str | None = None, state: dict[str, Any] | None = None)

Bases: DvrError

A color-page operation (grade / CDL / LUT) failed.

FusionError

FusionError(message: str, *, cause: str | None = None, fix: str | None = None, state: dict[str, Any] | None = None)

Bases: DvrError

A Fusion-comp wrap / unwrap / import / export failed.

InterchangeError

InterchangeError(message: str, *, cause: str | None = None, fix: str | None = None, state: dict[str, Any] | None = None)

Bases: DvrError

An import/export of an interchange format (EDL/AAF/FCPXML/...) failed.

SpecError

SpecError(message: str, *, cause: str | None = None, fix: str | None = None, state: dict[str, Any] | None = None)

Bases: DvrError

A declarative spec failed to parse or reconcile.

dvr.interchange

dvr.interchange

Unified interchange import/export.

Resolve supports 20+ interchange formats (AAF, EDL, FCPXML, OTIO, DRT, ALE, Dolby Vision, HDR10, etc.) but each is gated behind magic enum constants on the timeline Export() and media-pool ImportTimelineFromFile() methods. This module gives them all a single, format-friendly entry point.

Public API::

interchange.export(timeline, "out.fcpxml", format="fcpxml-1.10")
interchange.export(timeline, "out.edl", format="edl-cdl")
interchange.import_(media_pool, "in.aaf")

export_formats

export_formats() -> list[str]

Return the list of canonical format names accepted by :func:export.

export

export(timeline: Timeline, file_path: str | Path, *, format: str = 'fcpxml-1.10') -> str

Export timeline to file_path in the given interchange format.

Parameters:

Name Type Description Default
timeline Timeline

A :class:dvr.Timeline to export.

required
file_path str | Path

Destination path. Directory must exist.

required
format str

One of the keys in :data:EXPORT_FORMATS. See :func:export_formats for the live list.

'fcpxml-1.10'

Returns:

Type Description
str

The absolute string path of the export.

import_

import_(pool: MediaPool, file_path: str | Path, *, options: dict[str, Any] | None = None) -> Timeline

Import an interchange file (AAF/EDL/FCPXML/etc.) as a new timeline.

Resolve auto-detects the format from the file extension and contents.

dvr.audio

dvr.audio

Audio operations: channel mapping, voice isolation, Fairlight presets.

The Fairlight scripting surface is small. Resolve does not expose EQ / compression / routing programmatically. What this module covers:

  • Reading audio channel mapping (which embedded/linked tracks feed which timeline audio channel) for clips and assets.
  • Voice isolation (Fairlight feature) on timelines.
  • Inserting audio at the playhead.
  • Applying named Fairlight presets to the current timeline.

get_clip_audio_mapping

get_clip_audio_mapping(clip: TimelineItem) -> dict[str, Any]

Return the JSON-decoded audio mapping for a timeline clip.

get_asset_audio_mapping

get_asset_audio_mapping(asset: Any) -> dict[str, Any]

Return the JSON-decoded audio mapping for a media-pool asset.

voice_isolation_state

voice_isolation_state(timeline: Timeline) -> dict[str, Any]

Return {"enabled": bool, "amount": int} for the timeline.

set_voice_isolation

set_voice_isolation(timeline: Timeline, *, enabled: bool, amount: int = 50) -> None

Toggle voice isolation; amount is 0-100.

apply_fairlight_preset

apply_fairlight_preset(project: Project, name: str) -> None

Apply a named Fairlight preset to the current timeline.

insert_audio_at_playhead

insert_audio_at_playhead(project: Project, *, file_path: str, offset_samples: int = 0, duration_samples: int | None = None) -> None

Insert audio at the current track's playhead on the Fairlight page.

dvr.gallery

dvr.gallery

Gallery (still albums and PowerGrade albums) wrappers.

Still

Still(raw: Any)

A single gallery still.

Album

Album(raw: Any)

A gallery album (still or PowerGrade).

export_stills

export_stills(stills: list[Still], folder: str, prefix: str = '', *, format: str = 'png') -> None

Export stills to folder. Format: dpx | cin | tif | jpg | png | ppm | bmp | xpm.

Gallery

Gallery(raw: Any)

The project-scoped gallery (stills + PowerGrades).

gallery_for

gallery_for(project: Project) -> Gallery

Get the :class:Gallery for a project.

dvr.spec

dvr.spec

Declarative state — YAML/JSON specs reconciled against live Resolve state.

Inspired by kubectl apply: describe the desired state of a project (timelines, color settings, render presets) in a single file, then run dvr apply to bring Resolve in line. The engine computes a structured plan first; you can preview it (--dry-run) before applying.

Spec schema (informal)

::

project: MyShow
color_preset: rec2020_pq_4000              # optional
settings:                                  # optional, raw key/value
  timelineFrameRate: "24"
timelines:
  - name: Edit_v2
    fps: 24
    markers:                               # optional
      - {frame: 0, color: Blue, name: HEAD}

Hook dataclass

Hook(when: str, command: str, name: str = '')

A shell command run before or after the main reconciliation.

Action dataclass

Action(op: str, target: str, detail: str = '', payload: dict[str, Any] = dict())

A single change the engine will (or did) apply.

load_spec

load_spec(path: str | Path) -> Spec

Load a YAML or JSON spec file.

parse_spec

parse_spec(data: dict[str, Any]) -> Spec

Parse a dict into a :class:Spec.

plan

plan(spec: Spec, resolve: Resolve) -> list[Action]

Compute the actions required to bring Resolve in line with spec.

apply

apply(spec: Spec, resolve: Resolve, *, dry_run: bool = False, run_hooks: bool = True, continue_on_error: bool = False) -> list[Action]

Reconcile the live Resolve state to match spec.