docs: document pre-GUI submission hooks for Maya - #462
Conversation
| aborts opening the submitter cleanly (no error dialog). To skip the prompt on non-interactive or | ||
| studio-locked workstations, enable auto-accept: | ||
| ``` | ||
| deadline config set settings.auto_accept true |
There was a problem hiding this comment.
The settings.auto_accept recommendation deserves a security caveat here. That setting is not hook-specific — its description in the client config is "Automatically accept the default choice for any interactive prompts." Enabling it to skip this one dialog also silently auto-accepts every other confirmation prompt the client raises (e.g. job-attachment / file-conflict confirmations), which is a broader change than the surrounding text implies.
More importantly, the hook confirmation dialog is the user's only informed-consent point before arbitrary code from DEADLINE_HOOKS_DIR executes on their workstation — the client's own _generate_hooks_confirmation_message comment calls it exactly that. DEADLINE_HOOKS_DIR is an ordinary environment variable, so anything that can set it in the artist's environment gains silent code execution once allow_environment_hooks and auto_accept are both true. Recommending auto_accept for "studio-locked workstations" without flagging that tradeoff reads as a safe convenience toggle when it removes the only guardrail.
Suggest noting that (a) auto_accept is global, not hook-scoped, and (b) it should only be set where DEADLINE_HOOKS_DIR and the hooks directory contents are themselves administratively controlled.
| # pregui_hook.py | ||
| import json, sys | ||
|
|
||
| # jobName, submitterName ("maya"), priority, parameters, farmId, queueId, ... |
There was a problem hiding this comment.
This comment advertises priority (and farmId / queueId) as useful inputs, but for the Maya submitter priority is always the hardcoded default 50, never the user's actual value.
src/deadline/maya_submitter/maya_render_submitter.py:328-334 builds the context with only four fields:
PreGuiHookContext(
bundle_dir=None,
job_name=render_settings.name,
submitter_name="maya",
parameters=dict(shared_parameter_values),
)PreGuiHookContext.priority defaults to 50, so it is never populated from render_settings.priority — which is a sticky field (data_classes.py:49) and can legitimately be something else after load_sticky_settings. A hook author who reads this line and branches on the incoming priority (e.g. "only raise it if the artist left it at default", or "clamp whatever they set") will get wrong behaviour, and it will look like a hook bug rather than a submitter one.
Either fix the call site to pass priority=render_settings.priority, or drop priority from this list / note that Maya always sends 50 at pre-GUI time. Worth double-checking the farmId/queueId claim too: those are left None in the context and so are resolved from defaults.farm_id / defaults.queue_id config rather than from anything the artist picked in the dialog (which has not opened yet).
6188a12 to
da86af9
Compare
|
|
||
| Before running any hooks, the submitter shows a **Job Submission Confirmation** dialog listing the | ||
| hook scripts that will execute. Click **Yes** to run them, or **No** to cancel — clicking **No** | ||
| aborts opening the submitter cleanly (no error dialog). To skip the prompt on non-interactive or |
There was a problem hiding this comment.
This section documents the cancel path but not the failure path, which is the one that will actually generate support tickets.
show_maya_render_submitter only catches DeadlineOperationCanceled (maya_render_submitter.py:337). Every other hook error is a DeadlineOperationError raised out of HookManager.execute_pre_gui_hooks, which propagates past the run_pre_gui_hooks call and reaches the caller's gui_error_handler — so the submitter never opens at all. The client raises that for:
- non-zero exit code (
Pre-GUI hook [N] failed with exit code ...) - timeout (
Pre-GUI hook [N] timed out after Ns) — defaulttimeoutis 60s - stdout that is not valid JSON (
produced invalid JSON) - output containing keys outside
{name, description, parameters} hook.commandnot resolvable (Hook command not found) — note relative commands are resolved against the hooks dir and thenPATH
This matters because it is a hard availability coupling: a studio that deploys a hook script referencing a Python interpreter path that does not exist on one artist's box makes the Deadline Cloud submitter completely unopenable for that artist, with a generic error dialog and no obvious link back to DEADLINE_HOOKS_DIR. It also interacts with the mayapy tip above — a stdout banner does not degrade gracefully, it blocks submission.
Suggest a sentence here (or in "Writing a pre-GUI hook") stating that any hook failure, timeout, or malformed stdout prevents the submitter from opening, and that hooks should therefore fail soft (catch their own errors and emit {}) and write diagnostics to stderr, not stdout.
|
|
||
| > **Version note (`deadline:` overrides):** routing of `deadline:`-prefixed job properties | ||
| > (`deadline:priority`, `deadline:maxFailedTasksCount`, `deadline:maxRetriesPerTask`) was fixed in | ||
| > `deadline` 0.60.4 ([deadline-cloud PR #1322][deadline-pr-1322]). The Maya submitter runs in-process |
There was a problem hiding this comment.
The stated reason for why Maya is unaffected is not the actual reason, and that matters because the real reason is fragile.
"The Maya submitter runs in-process" has nothing to do with it — apply_pre_gui_output is the same function on both paths. On 0.60.2/0.60.3 it routes by:
template_parameters = getattr(initial_settings, "parameters", None) or []
template_param_names = {p["name"] for p in template_parameters}
...
if param_name in template_param_names: # deadline:priority IS here for job bundles
... # -> misrouted onto settings.parameters
else:
initial_shared_parameter_values[param_name] = param_valueMaya works on 0.60.2 purely because RenderSubmitterUISettings happens to have no parameters attribute, so template_param_names is empty and deadline:priority falls through to the else. The job-bundle path breaks only because read_job_bundle_parameters leaves deadline:* in the parameters list, putting it in template_param_names. 0.60.4 fixed it by hoisting the startswith("deadline:") test above the template-name check.
So the correctness of deadline: overrides in Maya at the >= 0.60.2 floor rests on an incidental absence, not on a designed guarantee — exactly what this repo's own test asserts: "This guards against a regression where RenderSubmitterUISettings gains a parameters attribute that would misroute hook params" (test/unit/deadline_submitter_for_maya/test_pre_gui_hooks.py:11-13).
Two consequences worth reflecting in the text:
- Replace "runs in-process" with the real condition, or just say Maya is unaffected without asserting a mechanism — as written, a maintainer who later adds a
parametersfield toRenderSubmitterUISettingswill read this paragraph and conclude Maya is safe when it silently is not (on any client below 0.60.4). - Given
pyproject.tomlpinsdeadline >= 0.60.2,< 0.61, 0.60.2/0.60.3 are inside the supported range, so this is a live configuration rather than a historical one. If the intent is thatdeadline:routing is reliable, the cheaper fix is bumping the floor to>= 0.60.4and deleting this whole note.
| `parameters` (a map of parameter name → value). `deadline:`-prefixed keys map to shared job | ||
| properties such as `deadline:priority`, `deadline:maxFailedTasksCount`, and | ||
| `deadline:maxRetriesPerTask`, while names such as `CondaPackages` / `CondaChannels` / `RezPackages` | ||
| override the queue/package parameters the submitter seeds for the job. |
There was a problem hiding this comment.
Worth stating that a parameters name which is neither deadline:-prefixed nor an actual queue parameter is silently discarded — no error, no warning.
Because RenderSubmitterUISettings has no .parameters list, apply_pre_gui_output puts every non-deadline: name into initial_shared_parameter_values. From there it only survives if it matches a queue parameter definition returned by the farm/queue:
for parameter in queue_parameters:
if parameter["name"] in self.initial_shared_parameter_values:
parameter["value"] = self.initial_shared_parameter_values[parameter["name"]](shared_job_settings_tab.py, _handle_queue_parameters_update)
Anything else is never read again. So a hook returning {"parameters": {"Frames": "1-10"}} or {"CondaPackages": ...} misspelled as condaPackages produces zero feedback and zero effect — the dialog simply opens with the artist's original values. The Note below covers this from the UI-field angle ("hooks do not set the Job-specific settings tab"), but not the mechanism: the failure is silent even for a name the author believed was a valid queue parameter, and CondaChannels/RezPackages only work because the queue happens to define them.
Two things that would help a hook author here:
- Say explicitly that only
deadline:*job properties and names matching queue parameters defined on the target queue take effect; other names are ignored without error. - Note that
RezPackages/CondaPackagesare seeded by the submitter asmayaIO-<ver> deadline_cloud_for_maya/maya=<ver>.* maya-openjd=<ver>.*and that a hook returning them replaces the whole string rather than appending — so a hook that overridesCondaPackagesand omitsmaya-openjdproduces a job that cannot run.
Signed-off-by: Leon Li <2182521+leon-li-inspire@users.noreply.github.com>
da86af9 to
23d8543
Compare
| `deadline >= 0.60.2` (the client version this package depends on), which ships the pre-GUI hook API. | ||
| For Maya, hooks are sourced only from the directory named by the `DEADLINE_HOOKS_DIR` environment | ||
| variable — Maya has no on-disk job bundle at pre-GUI time, so bundle-sourced hooks do not apply. They | ||
| complement the `preSubmission` / `postSubmission` hooks that run at submit time (see [Submission |
There was a problem hiding this comment.
This paragraph says pre-GUI hooks are "shared across DCC submitters", but the upstream client documentation this section links to states the opposite — and one of the two is wrong in a way that will mislead studio pipeline authors.
aws-deadline/deadline-cloud/docs/submission-hooks.md says, under Pre-GUI Hooks:
Supported only by
deadline bundle gui-submit. Pre-GUI hooks run on the standalone GUI submitter. They do not run in in-application (DCC) submitters such as Maya, Nuke, or Blender — those build their submission dialog directly and do not invoke the pre-GUI phase.
and again in its support matrix:
- In-application (DCC) submitters — pre-submission and post-submission hooks. The pre-GUI phase is not run by DCC submitters.
So as of the current client docs, Maya is the first and only DCC submitter wiring up run_pre_gui_hooks — the mechanism lives in the shared client library, but no other DCC invokes it. "Shared across DCC submitters" reads as "already works in Nuke/Blender too", which is not true today.
Two concrete consequences worth fixing:
- Reword to something like "the pre-GUI hook mechanism lives in the shared client library; the Maya submitter is currently the only DCC submitter that invokes it" — so a studio does not deploy one
DEADLINE_HOOKS_DIRexpecting thepreGUIentries to fire from Nuke/Blender as well. Note the failure mode is silent: the other DCCs simply never call the pre-GUI phase, so there is no error to debug. - Since the hooks directory is shared,
hooks.yamlpreGUIentries will run fordeadline bundle gui-submitand Maya, but nothing else. If the hook branches onsubmitterName(Maya passes"maya"), that is worth mentioning here, because a single studio-wide hooks dir is exactly the deployment this section recommends.
It would also be good to get the upstream doc updated in the same breath, otherwise the two READMEs contradict each other for whoever reads both.
|
|
||
| Pre-GUI hooks are provided by the [AWS Deadline Cloud client library][deadline-cloud-client] and are | ||
| shared across DCC submitters; the Maya submitter invokes them each time you open it. They require | ||
| `deadline >= 0.60.2` (the client version this package depends on), which ships the pre-GUI hook API. |
There was a problem hiding this comment.
The deadline >= 0.60.2 version floor stated here disagrees with the code comment in the submitter, and the README appears to be the wrong one.
src/deadline/maya_submitter/maya_render_submitter.py:318-320 justifies the lazy import with:
this ships in deadline-cloud 0.60.1+, and a top-level import would break importing this module — and every unit test that collects it — against older deadline-cloud releases.
I checked upstream: src/deadline/client/ui/pre_gui_hooks.py exists at tag 0.60.1 (and 0.60.2) but 404s at 0.60.0, so the code comment’s 0.60.1+ is the accurate floor for the API itself. pyproject.toml:33 pins deadline >= 0.60.2,< 0.61, which is the floor for this package’s dependency — a stricter constraint that happens to be satisfied, not the API’s requirement.
The parenthetical "(the client version this package depends on), which ships the pre-GUI hook API" conflates the two, which is what makes it misleading: it reads as "0.60.2 is where the API landed". Suggest either dropping the causal claim — e.g. "requires deadline >= 0.60.2, per this package’s dependency pin; the pre-GUI hook API itself landed in 0.60.1" — or just saying the API requires 0.60.1+ and this package pins 0.60.2+.
This matters more than typical doc nits because the import is lazy specifically to tolerate older clients. Anyone reasoning about which client versions degrade gracefully (vs. raising ImportError from inside show_maya_render_submitter, after the progress dialog has already been closed at line 305) needs the real floor. Also worth reconciling the two so they do not drift further apart.
| A pre-GUI hook receives the current submission metadata as JSON on **stdin** and returns the fields | ||
| it wants to override as JSON on **stdout**. Recognized keys are `name`, `description`, and | ||
| `parameters` (a map of parameter name → value). `deadline:`-prefixed keys map to shared job | ||
| properties such as `deadline:priority`, `deadline:maxFailedTasksCount`, and |
There was a problem hiding this comment.
The phrase "deadline:-prefixed keys map to shared job properties such as" implies an open, forgiving set. It is actually a closed set, and an unrecognized deadline: key is a hard crash that prevents the submitter from opening.
In the client, SharedJobSettingsWidget.__init__ loops over the shared values and calls set_parameter_value for every deadline:-prefixed name, with no try/except:
for name, value in initial_shared_parameter_values.items():
if name.startswith("deadline:"):
self.set_parameter_value({"name": name, "value": value})and set_parameter_value ends its if/elif chain with:
else:
raise KeyError(parameter_name)Only five names are accepted: deadline:targetTaskRunStatus, deadline:maxFailedTasksCount, deadline:maxRetriesPerTask, deadline:priority, deadline:maxWorkerCount.
So the failure mode for a typo is not "ignored" — apply_pre_gui_output routes any deadline:-prefixed name into shared_parameter_values unconditionally (it only checks the prefix), and the KeyError then escapes SubmitJobToDeadlineDialog construction at maya_render_submitter.py:349. That is after the cancel except DeadlineOperationCanceled at line 337, so it lands in the caller’s gui_error_handler and the dialog never opens.
The trap is concrete for Maya specifically: the sticky-settings field is named initial_status (data_classes.py:50), so deadline:initialStatus is a very natural guess — and it is wrong; the accepted name is deadline:targetTaskRunStatus. Same for deadline:maxWorkerCount vs. the max_worker_count field. A hook author guessing from the dataclass gets a broken submitter, not a no-op.
Suggest listing the five accepted keys explicitly (they are cheap to enumerate) and stating that any other deadline:-prefixed name raises an error that prevents the dialog from opening. Two related points worth a line:
- Values are fed straight into Qt spin boxes via
setValue, so"deadline:priority": "75"(string instead of int) is also a failure rather than a coercion — the example at line 199 gets this right but nothing says the types are strict. deadline:priorityis where a hook can set priority successfully, which is a useful contrast to the pre-GUIprioritymetadata field being hardcoded to50on the input side.
| > **Note:** pre-GUI hooks set the shared job properties above; they do **not** set the Maya render | ||
| > options on the `Job-specific settings` tab (render layers, cameras, frame range, output path, | ||
| > project directory, renderer, etc.). Those are initialized from the Maya scene's render settings and | ||
| > the per-scene sticky settings, and are edited in the submitter UI. |
There was a problem hiding this comment.
This Note explains what hooks do not set, but omits a side effect that will surprise studios: hook-supplied values get persisted into the per-scene sticky settings file on submit, so they keep applying even after the hook is removed.
The chain:
apply_pre_gui_outputwritesname/descriptiondirectly onto the Maya settings dataclass (initial_settings.name = ...).nameanddescriptionare bothmetadata={"sticky": True}(data_classes.py:46-47), as arepriority,initial_status,max_failed_tasks_count,max_retries_per_task,max_worker_count.- On submit,
on_create_job_bundle_callbackcallssettings.save_sticky_settings(Scene.name())(maya_render_submitter.py:179), writing every sticky field to<scene>.deadline_render_settings.json. - Next open with
load_sticky_setting=Truecallsload_sticky_settingsbefore hooks run (_set_render_settingat line 225, hooks at line 328), so the hook-written name/description come back as the baseline.
Consequences worth documenting:
- A hook that stamps a name like
"MyStudio Shot 010"(exactly the example above) permanently overwrites the artist’s own sticky job name for that scene. Disable the hook and the stamped value persists in the JSON file — it does not revert. - The sticky file lives next to the scene (
Path(scene).with_suffix(".deadline_render_settings.json")), so it typically follows the scene into version control / shared project dirs and propagates to other artists. - The two mechanisms silently fight for the same fields. Since hooks apply after sticky load, the hook always wins on each open — which is probably intended for
name, but means an artist can never make a manual priority/name change stick while the hook is deployed.
Note this asymmetry: deadline:-prefixed parameters go into shared_parameter_values, not onto the dataclass, so they only reach the sticky file indirectly via update_settings writeback from the dialog widgets — whereas name/description are written onto the dataclass unconditionally, even if the artist never touches the dialog.
A short sentence here noting that hook-set name/description are saved into the scene’s sticky settings on submit and persist after the hook is removed would save a confusing support ticket.
| - C:/deadline-hooks/pregui_hook.py | ||
| timeout: 60 | ||
| ``` | ||
| **Tip:** point `command` at a clean system Python interpreter, not Maya's bundled `mayapy` — |
There was a problem hiding this comment.
Two problems with this hooks.yaml example, both of which produce a broken setup rather than an obvious error.
1. The args entry duplicates the hooks dir, defeating relative paths. The example hard-codes C:/deadline-hooks/pregui_hook.py as an absolute arg while DEADLINE_HOOKS_DIR is already C:\deadline-hooks. The client resolves relative args against the hooks directory:
def _resolve_args(self, args):
for arg in args:
if not _os.path.isabs(arg):
relative_path = _os.path.join(self._script_resolve_dir, arg)
if _os.path.exists(relative_path): ...So args: [pregui_hook.py] is the portable form, and is what the upstream doc uses (args: [prefill.py]). As written, the example silently couples hooks.yaml to one hard-coded install path — move the directory (or deploy to Linux artists, where this example is the only one given) and the hook fails with Hook command not found / a non-zero exit, which per the client blocks the dialog from opening.
2. command is Windows-only, but step 2 documented both platforms. Step 2 gives setx and export variants; step 3 then gives only a C:/Program Files/Python311/python.exe command. A macOS/Linux artist copying this gets an absolute path that fails _os.path.isfile, raising Hook command not found. Worth adding the python3 form — which is also what makes point 1 matter, since python3 resolves via shutil.which.
Also, on the Tip about mayapy: the underlying rule is more useful than the specific example. Per the client, anything on stdout that is not the JSON contract breaks the hook (stdout is captured whole and parsed; stderr is what gets streamed as progress). So the guidance is "never write anything but the JSON object to stdout — use stderr for logging" and mayapy’s banner is one instance. A hook author using a clean python3 but calling a library that prints to stdout hits the identical failure, and the current phrasing suggests the interpreter choice alone fixes it.
Fixes: N/A — documentation gap follow-up to #437
What was the problem/requirement? (What/Why)
The pre-GUI submission hook support for the Maya submitter shipped in #437 (
feat: Run pre-GUI hooks in the Maya render submitter), but themainlineREADME has no documentation telling studios how to use it. Sibling integrations already document this (VRED, KeyShot), so Maya users had no discoverable guidance on enabling env-sourced hooks, authoring apreGUIhook, or understanding the confirmation-prompt behavior.What was the solution? (How)
Add a
## Pre-GUI Submission Hookssection toREADME.md, adapted to how Maya's submitter actually loads and applies hooks (per #437):deadline config set settings.allow_environment_hooks trueand pointingDEADLINE_HOOKS_DIRat a hooks directory with ahooks.yamlpreGUI:entry (Maya sources hooks only fromDEADLINE_HOOKS_DIR, since there is no on-disk job bundle at pre-GUI time —bundle_dir=None).pregui_hook.pysample that reads the submission metadata JSON on stdin and prints overrides forname/description/parameters(incl.deadline:priority,deadline:maxFailedTasksCount,deadline:maxRetriesPerTask, andCondaPackages/CondaChannels/RezPackages). The stdin comment reflects Maya'ssubmitterName("maya").Shared job settingstab; and a note that the Maya render options on theJob-specific settingstab (render layers, cameras, frame range, output/project path, renderer) are not set by the hook (they come from the scene's render settings and per-scene sticky settings).Job Submission Confirmationdialog, with No aborting cleanly, andsettings.auto_acceptto skip the prompt.mayapy-specific tip (pointcommandat a clean system Python so a bundled-interpreter startup banner does not corrupt the hook's JSON), and thedeadline >= 0.60.2client floor this package pins for the pre-GUI hook API (thedeadline:job-property overrides apply at this same floor — Maya's in-process submitter routes them straight to the shared job settings).Links the base client's hook docs via a
[submission-hooks]reference tohttps://github.com/aws-deadline/deadline-cloud#submission-hooks.What is the impact of this change?
Documentation only. No code changes — Maya users can now discover and configure pre-GUI hooks from the README.
How was this change tested?
Docs-only change. Verified the rendered Markdown, that the new
[submission-hooks]reference and existing[deadline-cloud-client]reference resolve, and that the field/behavior descriptions match the merged #437 implementation (show_maya_render_submitter→run_pre_gui_hooks/apply_pre_gui_output) and thedeadline >= 0.60.2floor inpyproject.toml.Integ test result
N/A — no
src/changes.Installer test result
N/A — no
installer/orsrc/changes.Did you run the "Job Bundle Output Tests"? If not, why not? If so, paste the test results here.
Not run — this change is documentation only and does not touch job bundle generation.
Was this change documented?
Yes — this PR is the documentation. It updates
README.mdonly.Did you modify schema files?
Is this a breaking change?
No. Documentation-only change.
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.