-
Notifications
You must be signed in to change notification settings - Fork 0
Developer Guide
This page is for TD (Technical Directors) or Developers looking to maintain or extend the Ramses-Fusion plugin.
-
Ramses-Fusion.py: The entry point. Contains theRamsesFusionAppclass (UI and high-level logic). -
lib/fusion_host.py: The bridge. Implements theFusionHostclass, which inherits fromramses.RamHost. -
lib/fusion_config.py: The Lua parser. ContainsFusionConfigfor parsing and applying Saver node settings. -
lib/asset_browser.py: The Import Published dialog. Lists an upstream step's published deliverables one row at a time (image sequences collapsed to a single entry) and creates the Loaders. -
lib/ramses_patches.py: Runtime fixes for the vendored SDK, plus theDisableMakedirsguard. -
lib/ramses/: The vendored Ramses Python API. Do not modify these files — they are kept replaceable from upstream. Defects go upstream or intoramses_patches.py; seeUPSTREAM_SDK_FINDINGS.mdin the repository. -
lib/yaml,lib/ramses_ui_pyside: Vendored third-party dependencies. -
tests/: A comprehensive test suite usingunittestandunittest.mock.
Both main modules define __all__ for clear public API boundaries:
# fusion_host.py
__all__ = ["FusionHost"]
# fusion_config.py
__all__ = ["FusionConfig"]fusion_host.py exports constants for standardized render formats:
FORMAT_QUICKTIME = "QuickTimeMovies"
CODEC_PRORES_422 = "Apple ProRes 422_apcn" # Preview default
CODEC_PRORES_422_HQ = "Apple ProRes 422 HQ_apch" # Final defaultUse these constants instead of hardcoding strings when extending render functionality.
The project uses a mock Fusion environment to run tests without needing Fusion open.
Requirements: Python 3.9+ (tested with 3.10, 3.11, 3.14)
To run the full suite:
- Open a terminal in the project root.
- Run the batch file:
run_tests.bat(Windows). It setsPYTHONPATHtoRamses-FusionandRamses-Fusion/lib, then runs unittest discovery. - Or use Python directly, with that same
PYTHONPATH:python -m unittest discover tests -v
All tests must pass (244, one skipped, at the time of writing). If any fail, check for missing dependencies or Python version issues.
Important
Run the suite three ways before trusting it. A test that passes one way can fail another, and each of these has caught a real defect:
-
python -m unittest discover tests— the runnerrun_tests.batactually uses. -
python -m pytest tests— the only runner that appliestests/conftest.py, whose autouse fixtures catch directories created at a drive root and a leakedFusionHost._pinned_comp. -
Each test module on its own. Ordering hides things in both directions: a module once passed only because an alphabetically earlier one had already fixed up
sys.path.
The two runners order test classes differently — pytest keeps file order, unittest sorts alphabetically. A test that replaced a module attribute without restoring it therefore broke a later test under unittest only, and looked perfectly green under pytest for as long as nobody ran the batch file. When you stub a module attribute or anything on the RAMSES singleton, use patch.object with addCleanup, never a bare assignment.
If you are writing new tests, refer to tests/mocks.py. It contains a MockFusion class that simulates:
-
UIManagerandUIDispatcher. - Composition attributes and preferences.
- Tool (Node) creation and attribute management.
The plugin uses Fusion's bmd.UIDispatcher. Note that disp.RunLoop() is blocking.
To ensure robustness, almost all UI event handlers are wrapped with the @requires_connection decorator.
- Function: It checks if the Ramses Daemon is online before executing the wrapped function.
- Behavior: If the connection is lost, it automatically attempts a silent reconnect. If that fails, it shows a "Connection Lost" error and prevents the action from proceeding.
-
Benefits: This eliminated over 200 lines of repetitive check-and-return logic throughout
Ramses-Fusion.py.
Located at the top of lib/fusion_host.py, the monkey-patching block is used to fix upstream bugs in the ramses library. This is preferred over shipping a modified version of the library as it makes updates easier to track.
-
Targeted fixes: Robust identity matching (Windows), synchronous file copies, and state propagation during publish.
lib/ramses_patches.pyadds theDisableMakedirsguard that keeps read-only path lookups from creating folders. -
Implementation: Replaces static methods and private class attributes using standard Python attribute assignment, behind a
_fusion_patchedguard — the entry script reloads the host module on every launch, so the block runs again in the same interpreter. Any patch must be idempotent, or one wrapper layer stacks per launch. -
Remove a patch once upstream fixes it. Patches for the metadata manager and the daemon interface were dropped when the SDK moved to Ramses-Py
d19ce44. A patch that replaces a method wholesale keeps overriding upstream forever and masks any later improvement to it. When you drop one, keep the test — retarget it at the SDK so the behaviour stays asserted.
While the Ramses API supports background threading for file copies, Ramses-Fusion disables this. In a high-stakes publish environment, it is critical that the plugin waits for the file to be fully written and verified before updating the database status. Synchronous operations prevent "Ghost Publishes" where the status changes but the file is still being moved.
High-latency network calls (like fetching statuses for 100+ shots) are wrapped in concurrent.futures.ThreadPoolExecutor.
- The UI uses a "Header Refresh" logic that gates database queries based on the
currentFilePath.
CRITICAL: Always use self.ramses.host.normalizePath(path) when dealing with file paths. This ensures all paths use forward slashes (/), which prevents character escaping issues in Fusion's Lua-based string handling.
Fusion keeps one Python interpreter alive for the whole session. Reopening the panel re-runs Ramses-Fusion.py, but modules already imported from lib/ are not reloaded. After editing anything under lib/, restart Fusion — otherwise you are testing the old code and will draw the wrong conclusion from it.
Some questions cannot be answered by the mocked test suite at all, because they depend on how the host actually behaves — whether reading a value dirties the comp, whether an attribute survives a round trip. For those, write a small probe script, run it inside Fusion, and read the result. Measuring took minutes in cases where reasoning from the API docs had already produced several confident wrong answers.