Skip to content

feat: Adds Arnold .ass export feature into Houdini Deadline Cloud submitter#341

Open
skarpree wants to merge 8 commits intoaws-deadline:mainlinefrom
skarpree:feature/arnold-ass-export-integration
Open

feat: Adds Arnold .ass export feature into Houdini Deadline Cloud submitter#341
skarpree wants to merge 8 commits intoaws-deadline:mainlinefrom
skarpree:feature/arnold-ass-export-integration

Conversation

@skarpree
Copy link
Copy Markdown

"## Summary

Integrates Arnold .ass export support into the Houdini Deadline Cloud submitter as a pre-submit step. When Arnold ROPs are detected in the input network, the submitter automatically configures them for safe .ass file export before job submission.

Changes

New: `arnold_utils.py`

  • `is_arnold_rop()` — detect Arnold ROP nodes
  • `find_arnold_rops_in_network()` — walk input ancestors to find all Arnold ROPs
  • `configure_arnold_rop_for_export()` — apply safe export config (enable .ass export, clear ar_picture, set logging)
  • `get_arnold_ass_output_directories()` — detect .ass output paths
  • `export_arnold_ass_locally()` — local .ass export from Arnold ROPs

Modified: `submitter.py`

  • Added `_auto_configure_arnold_rops()` — called in both `submit_callback` and `save_bundle_callback`
  • Added `export_ass_callback()` — local .ass export button handler
  • Arnold license env var (`ADSKFLEX_LICENSE_FILE`) propagated to farm workers in job template

Modified: `_assets.py`

  • Replaced `"Driver/arnold": "ar_picture"` with `_arnold_outputs()` function
  • Now prioritizes `ar_ass_file` over `ar_picture` for output directory detection

Modified: `hip_settings.py`

  • Added `ArnoldExportSettings` dataclass
  • Added `arnold_auto_configure` and `arnold_settings` fields to `HoudiniSubmitterUISettings`

Modified: `houdini_submitter_widget.py`

  • Added Arnold Export Settings UI section with 3 checkboxes:
    • Auto-configure Arnold ROPs for export
    • Enable .ass file export
    • Disable image render (prevent hang)

Modified: HDA (`DialogScript` + `PythonModule`)

  • Added `arnold_auto_configure` toggle parameter
  • Added `Export .ass` button for local export

New: Unit Tests

  • `test_arnold_utils.py` — tests for all arnold_utils functions
  • `test_arnold_callbacks.py` — tests for submitter callback integration

Problem Solved

Arnold ROPs have several known pitfalls when used with hython/farm rendering:

  1. `ar_picture: ip` causes hython to hang (interactive render mode)
  2. `ar_ass_export_enable` may be disabled — no .ass files written
  3. Arnold menu parameters expect strings, not integers
  4. License env var not propagated to workers

This PR automatically detects and fixes all of these before submission.

Testing

  • Unit tests for arnold_utils and callbacks
  • Manually verified with Houdini 21.0.559 + HtoA 6.4.4.1
  • Confirmed .ass file generation (891KB) from arnold_rubberytoy.hip test scene"

@skarpree skarpree requested a review from a team as a code owner March 17, 2026 21:16
@github-actions github-actions bot added the waiting-on-maintainers Waiting on the maintainers to review. label Mar 17, 2026
- Add arnold_utils.py with ROP detection, configuration, and local export
- Auto-configure Arnold ROPs before submit (enable .ass export, clear ar_picture)
- Add Arnold settings UI section to SceneSettingsWidget (3 checkboxes)
- Update _assets.py to detect .ass output directories (not just ar_picture)
- Add Export .ass button to HDA for local export from Deadline Cloud node
- Propagate ADSKFLEX_LICENSE_FILE to farm workers in job template
- Add unit tests for arnold_utils and arnold callbacks

Signed-off-by: skarpree <skarpree@amazon.com>
@skarpree skarpree force-pushed the feature/arnold-ass-export-integration branch from 11fd153 to 1fb4b4b Compare March 17, 2026 21:19
Signed-off-by: skarpree <skarpree@amazon.com>
Signed-off-by: skarpree <skarpree@amazon.com>
Signed-off-by: skarpree <skarpree@amazon.com>
… rename test method

Signed-off-by: skarpree <skarpree@amazon.com>
…ecurity hotspot

Signed-off-by: skarpree <skarpree@amazon.com>
…ud S5443

Signed-off-by: skarpree <skarpree@amazon.com>
Signed-off-by: skarpree <skarpree@amazon.com>
@sonarqubecloud
Copy link
Copy Markdown

@justinsaws justinsaws removed the waiting-on-maintainers Waiting on the maintainers to review. label Mar 24, 2026
@justinsaws
Copy link
Copy Markdown
Contributor

High level comment, are alll of your commits functional in and of themself? They seem like they are iterative and this description is one feature so they can likely be re-based into a single commit.


def _arnold_outputs(node: hou.Node) -> set[str]:
"""Get Arnold output directories, prioritizing .ass export path over ar_picture."""
from .arnold_utils import get_arnold_ass_output_directories
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a common pattern with houdini plugins to do the import in the function here?

def is_arnold_rop(node: "hou.Node") -> bool:
"""Check if a node is an Arnold ROP (Driver/arnold)."""
try:
return node.type().name() == "arnold"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What kind of exceptions would we expect this operation to throw?

return arnold_rops


def _set_parm_safe(parm: "hou.Parm", value) -> None:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing type on value.

try:
_set_parm_safe(parm, param_value)
except Exception as e:
logger.warning("Failed to set '%s' on '%s': %s", param_name, rop.path(), e)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this ok as just a warning? I would think we are losing information here.

try:
parm.set(value)
except Exception:
logger.warning("Failed to restore '%s' on '%s'", name, rop.path())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we actually just want to fail and continue here? A warning doesn't seem like a strong enough logging level.

return int(parm.eval()) if parm else default


def _get_frame_range_from_node(node: hou.Node):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing return type.

)


def export_ass_callback(kwargs):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing type definitions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants