Skip to content
Search

Python Developer API

On supported Engine versions, Locus exposes its shared request foundation directly under unreal. Python uses these requests rather than the Blueprint async-action proxies.

The entry point is unreal.LocusDeveloperRequestLibrary. Factory and property names are snake case, such as create_document, on_succeeded, operation_status, and request_id. Enum values use uppercase snake case, such as LocusDeveloperRequestState.NOT_STARTED and LocusDeveloperResultCode.STALE_REVISION.

This order is part of the contract:

Construct → Retain references → Bind → Start → Completion

Construction does not submit work. Retain the request, delegate wrappers, and bound Python callables until terminal completion. Bind success and failure before start() because admission failure can complete inline. Remove the bindings and release those references after completion.

import unreal
input_value = unreal.LocusDeveloperDocumentCreateInput(
path="DeveloperExamples/PythonGettingStarted.md",
markdown="# Created from Unreal Python\n",
presentation_root=unreal.LocusDeveloperDocumentRoot.LOCUS_DOCUMENTS,
)
request = unreal.LocusDeveloperRequestLibrary.create_document(input_value)
def on_succeeded(result):
unreal.log(f"Created {result.identity.relative_path}")
release_bindings()
def on_failed(error):
unreal.log_error(f"Locus failed: {error.code.name}: {error.message}")
release_bindings()
success_delegate = request.on_succeeded
failure_delegate = request.on_failed
def release_bindings():
success_delegate.remove_callable(on_succeeded)
failure_delegate.remove_callable(on_failed)
success_delegate.add_callable(on_succeeded)
failure_delegate.add_callable(on_failed)
if not request.start():
unreal.log_error("The request had already been started")

The example creates a real Document. Choose a project-appropriate path and handle an existing identity through the typed failure callback.

A completed typed request retains:

  • state and succeeded;
  • request_id;
  • typed result;
  • typed error;
  • operation_status.

It also exposes has_started() and is_completed(). Tick-driven inspection is valid. A busy polling loop is not: it blocks the Game Thread that must complete the request.

cancel() requests cooperative cancellation. It can prevent queued work, but cannot interrupt repository work or turn a committed mutation into a cancelled result.

Use the reflected set_* flags to express intent:

changes = unreal.LocusDeveloperNoteChanges()
changes.set_title = False # Leave unchanged; title is ignored.
changes.title = "ignored"
changes.set_body = True # Set a non-empty value.
changes.body = "Updated body"
changes.set_tags = True # Explicitly clear tags.
changes.tags = []
request = unreal.LocusDeveloperRequestLibrary.update_note(
note_identity,
current_revision,
changes,
)

There is no Python-specific None convention. Pin metadata changes use the same explicit set_title, set_description, set_pin_type, and set_tags properties.

The supported model is an Unreal Editor process with PythonScriptPlugin enabled:

External automation
UnrealEditor-Cmd full Editor environment
PythonScriptPlugin
Locus reflected requests

The supported unattended launch shape is shown below with UE 5.6; use the matching Editor executable for UE 5.7 or 5.8:

Terminal window
& "C:\Program Files\Epic Games\UE_5.6\Engine\Binaries\Win64\UnrealEditor-Cmd.exe" `
"C:\Path\To\Project.uproject" `
"-ExecutePythonScript=C:\Path\To\Script.py" `
-ScriptErrorsAreFatal -unattended -NullRHI -nosplash

An asynchronous unattended script should:

  1. call unreal.EditorPythonScripting.set_keep_python_script_alive(True);
  2. register unreal.register_slate_post_tick_callback(...);
  3. construct, retain, bind, and start its Locus request;
  4. allow normal Editor ticks to drive Locus’s existing executor;
  5. observe terminal completion and remove delegate bindings;
  6. unregister the tick callback;
  7. call set_keep_python_script_alive(False) for clean exit.

Do not use sleep(), spin waiting, a synchronous future wait, or manual Game Thread pumping.

  • Python requires an Unreal Editor process and PythonScriptPlugin.
  • Locus itself does not depend on PythonScriptPlugin and still loads when it is disabled.
  • Standalone python.exe cannot import Locus.
  • Pins require a supported saved project-owned world.
  • The -run=PythonScript commandlet is not the complete supported environment; validation received a transient unsaved world rather than the saved world required for the complete API.
  • Use the full Editor application’s -ExecutePythonScript path for unattended automation.
  • Startup or index reconciliation can produce retryable Unavailable; resubmit on a later normal Editor tick rather than blocking.

See the Developer API overview for identities, revisions, errors, operation status, and the capability matrix.