Template_Manager package

Submodules

Template_Manager.main module

Entry point for the Nuke Template Manager.

This module wires together the configuration layer, the scanner, and the PySide frontend to provide the three top-level commands exposed to artists through the Nuke menu:

Every function in this module is designed to be invoked directly from a Nuke menu callback and assumes a live Nuke session.

Template_Manager.main.launch_about_dialog() None

Open the Template Manager About dialog from the Nuke menu.

Template_Manager.main.launch_rules_editor() None

Open the auto-tag rules editor as a modal dialog.

Instantiates ui.AutoTagRulesDialog parented to Nuke’s main window (located via ui.get_nuke_main_window()) so the dialog floats correctly above the application rather than the desktop. The dialog reads its initial rule set from disk via saves.load_auto_tag_rules() and writes any changes back via saves.save_auto_tag_rules() when the user clicks Save.

The function blocks until the dialog is dismissed. Rule changes take effect on the next scan; templates already loaded in an open Template Manager window are unaffected until the user re-runs the Re-Evaluate Auto-Tags context-menu action.

Template_Manager.main.launch_save_ui() None

Save the current Nuke selection as a template, with fast-track logic.

The function is the standalone counterpart of the in-UI Save action: it can be triggered directly from the Nuke menu without first opening the Template Manager browser. The full flow is:

  1. Verify that at least one node is selected in the DAG, aborting with a user-facing message otherwise.

  2. Capture the current script’s root settings (format, fps, colorManagement, OCIO_config) into a template_context dict. If the settings match the agnostic defaults (2048x1556, 24fps, “Nuke” colorManagement) the context is set to None and no root injection will occur later.

  3. Walk the first configured template root to build two structures: projects_dict mapping display project names to known subfolder paths, and fast_track_db mapping lowercase template base names to their highest-version on-disk location.

  4. Inspect the active Nuke script name. If its base name (after version-suffix stripping) appears in fast_track_db, present a streamlined “Template Match Found” dialog offering quick options to version-up, overwrite the matched version, save as the script’s own version, or open the full save menu.

  5. If the user chooses a fast-track option the template is written directly via nuke.nodeCopy. Because nuke.nodeCopy only copies nodes and not project-level settings, a Root { ... } block built from template_context is then prepended to the saved .nk file (skipped if the context is None), and the function returns.

  6. Otherwise the full ui.SaveTemplateDialog is shown so the user can pick a project, subfolder, name, and versioning behaviour.

  7. When the save dialog accepts, any selected Read nodes are optionally swapped to Placeholder NoOps via ui.PlaceholderDialog, the template is copied to disk, the same Root { ... } block is injected when a non-agnostic context was captured, and the Read swap is reverted with an undo so the artist’s script is left untouched.

All transient Nuke graph modifications performed during the swap step are bracketed by nuke.Undo() calls and reverted in the finally block, so a user exception or paste failure cannot leave the artist’s session in a corrupted state.

Note

This function uses only message-box dialogs from PySide; it does not require the main ui.TemplateManagerUI window to be open.

Template_Manager.main.launch_ui() None

Initialise the environment and open the Template Manager browser.

The function performs the full startup sequence required to show the main UI:

  1. Resolve the effective list of template root directories via settings.get_effective_template_paths().

  2. Build the set of node classes available in the current Nuke session via scanner.get_available_nodes().

  3. Probe for the optional Stamps plugin by Adrian Pueyo, storing the result so the UI can offer Stamps-aware shortcuts.

  4. Run scanner.scan_templates() against every configured root, accumulating the parsed template records.

  5. Instantiate ui.TemplateManagerUI with the scan results and show it as a non-modal dialog.

Note

A global module-level reference (tm_window) is retained to prevent Nuke’s Python garbage collector from destroying the window immediately after the function returns. Replacing this reference will close the previous window without animation.

Template_Manager.scanner module

Deep-text scanning and dependency validation module.

This module is responsible for safely parsing Nuke script files (.nk) without using the heavy Nuke API. By bypassing the application layer it can scan thousands of files in seconds, even outside a running Nuke session, and is therefore safe to call before any Nuke import or paste operation has been attempted.

The parser uses a single compiled regular expression to identify node class declarations in the raw text. It cross-references those classes against a baseline of vanilla Nuke nodes (CORE_NODES) to detect missing OFX plugins and proprietary studio gizmos, and extracts project settings (FPS, resolution, colour management) from the Root block when present.

Template_Manager.scanner.NODE_FINDER

Compiled regular expression matching node class declarations at the start of a line, capturing the leading indentation, the class name, and any trailing text on the opening brace line. Top-level (un-indented) matches are treated as real nodes; indented matches are usually nested entries inside groups and are ignored by the default scanner pass.

Type:

re.Pattern

Template_Manager.scanner.CORE_NODES

The complete set of node class names shipped with vanilla Nuke. Any class found in a .nk file that is not present in this set, in get_available_nodes()’s output, and does not strip down to a known base by trailing-digit removal is reported as a missing dependency.

Type:

set[str]

Template_Manager.scanner.IGNORED_WORDS

Tokens the scanner should never treat as node classes even though they match the syntactic pattern. The Root block in particular looks like a node declaration but contains project settings rather than a node.

Type:

set[str]

Template_Manager.scanner.TemplateStatus

A Literal of the four status strings a Template entry may carry: "OK", "MISSING_NODES", "READ_ERROR", "FILE_TOO_LARGE".

Template_Manager.scanner.extract_project_settings_from_root(text: str) Tuple[float | None, Tuple[int, int] | None, str | None, str]

Parse project settings from a Nuke script’s Root block.

The function delegates to extract_root_block() to isolate the body of the Root declaration, then applies focused regexes to pull out the frame rate, resolution, and colour-management configuration. Missing fields fall back to the module-level defaults (DEFAULT_PROJECT_FPS, DEFAULT_PROJECT_RESOLUTION, DEFAULT_PROJECT_COLORSPACE) rather than being reported as None, so a partial Root block is treated as a valid project-settings template.

The OCIO_config knob takes precedence over colorManagement when both are present, mirroring Nuke’s own evaluation order when a template is loaded.

Parameters:

text – Raw contents of a .nk file as a single string.

Returns:

A 4-tuple (fps, resolution, colorspace, mode) where:

  • fps is a float or None (only None when no Root block exists),

  • resolution is a (width, height) tuple or None,

  • colorspace is a string or None,

  • mode is the string "ROOT_SETTINGS" when settings came from a Root block, or "AGNOSTIC" otherwise.

Return type:

tuple

Template_Manager.scanner.extract_root_block(text: str) str | None

Return the inner contents of a Nuke script’s Root { ... } block.

The function walks the text after the opening Root { looking for the matching closing brace, tracking nesting depth so braces inside expression knobs or string values do not terminate the block early. Only the body between the outermost braces is returned; the enclosing Root { ... } delimiters themselves are omitted.

Parameters:

text – Raw contents of a .nk file as a single string.

Returns:

The body of the Root blocßk if one is present, or None for project-agnostic templates that contain no Root declaration.

Return type:

str | None

Template_Manager.scanner.get_auto_tags(node_list: List[str]) List[str]

Evaluate the auto-tag rule engine against a list of node classes.

Loads the current rule set from disk via saves.load_auto_tag_rules() and applies each rule in turn. A rule attaches its tag name to the result if its match condition is satisfied. Three rule types are supported:

  • "any" — the tag applies if any of the rule’s target substrings appears inside any node class name (case-insensitive).

  • "all" — the tag applies only if every one of the rule’s target substrings appears inside at least one node class name.

  • "count" — the tag applies when the number of nodes that contain any of the rule’s target substrings reaches or exceeds the rule’s threshold value (default 5). Each node is counted at most once even if it matches several targets.

All comparisons are performed in lowercase, so rule authors should use lowercase target substrings.

Parameters:

node_list – List of node class names harvested from a single template by the scanner pass. Need not be unique.

Returns:

The tags whose rules matched, in arbitrary order. An empty list is returned when no rule matches.

Return type:

list[str]

Template_Manager.scanner.get_available_nodes() Set[str]

Build the set of node class names the current Nuke session can create.

When running inside Nuke the function combines four sources of truth to produce as complete a picture as possible:

  1. CORE_NODES — the vanilla Nuke baseline shipped with the application.

  2. nuke.nodeTypes() — the live list of registered node classes, including any loaded via the application’s own startup logic.

  3. nuke.plugins(...) filtered to .gizmo, .so, .dylib and .dll extensions, with the extension stripped to recover the bare class name.

  4. Every menu item under nuke.menu("Nodes"), recursively walked and parsed with a regex for createNode/createNodeLocal calls. This catches gizmos that are exposed only through custom menus.

When running outside Nuke the function returns just CORE_NODES, which is sufficient for offline scanning and development workflows. The returned set is stripped of incidental whitespace.

Returns:

All node class names the scanner should treat as resolvable in the current environment.

Return type:

set[str]

Template_Manager.scanner.is_running_in_nuke() bool

Detect whether the current Python process is hosted by Nuke.

The check imports the nuke module and verifies that the nodeTypes attribute exists, which is only true inside a real Nuke session. The standalone nuke PyPI shim, if installed in a venv for development, lacks this attribute and is correctly rejected.

Returns:

True if the script is running inside a live Nuke application instance, False if the import fails or the imported module does not expose the Nuke API.

Return type:

bool

Template_Manager.scanner.list_nk_files(folder_path: str) List[str]

Recursively enumerate every .nk file beneath a directory.

The walk uses os.walk(), so symlinked directories are followed according to the platform default. Filename matching is case-insensitive on the .nk extension, allowing files like Template.NK to be found on case-sensitive filesystems.

Parameters:

folder_path – Absolute path of the directory to search. If the path does not exist or is not a directory the function returns an empty list rather than raising.

Returns:

Absolute paths of every .nk file discovered. The order matches the traversal order of os.walk() and is not explicitly sorted.

Return type:

list[str]

Template_Manager.scanner.paste_template(tpl: Dict[str, Any]) None

Paste a scanned template into the current Nuke DAG.

Verifies that the template’s source file still exists on disk, then invokes nuke.nodePaste to insert the nodes at the current cursor position in the node graph. If the file has been moved or deleted since the scan, the function prints a diagnostic and returns without raising. When called outside Nuke (for development) it prints what would have been pasted and returns.

Parameters:

tpl – A Template record whose path field points to the .nk file to paste. No other fields are consulted.

Template_Manager.scanner.scan_templates(folder_path: str, available_nodes: Set[str], ignored_words: Set[str] = {'Root'}) List[Dict[str, Any]]

Parse every .nk file under a directory and build template records.

This is the core scanner entry point. For each .nk file found beneath folder_path the function:

  1. Reads file size and modification time and skips files that exceed settings.MAX_FILE_SIZE_BYTES, marking them with the "FILE_TOO_LARGE" status.

  2. Consults the on-disk cache via saves.load_cache() and reuses the cached parse result when the file’s modification time matches; otherwise re-parses the file from scratch and updates the cache.

  3. Extracts project settings from the Root block when present, falling back to "AGNOSTIC" mode for templates without one.

  4. Detects Stamps plugin usage via signature string matching.

  5. Identifies missing nodes by comparing the parsed class names against available_nodes and CORE_NODES, with a trailing-digit-stripping heuristic to fold versioned node names (for example Tracker4 resolving to Tracker).

  6. Merges manual user tags from saves.load_metadata() with auto-tags from get_auto_tags() for templates that have never been hand-tagged. Manual tags always take precedence once they exist.

  7. Bypasses standard Nuke API evaluation entirely, so malformed or untrusted scripts cannot crash the host process during scanning.

Any exception raised during parsing is captured into the template’s errors field, the status is set to "READ_ERROR", and the scan continues with the next file.

Parameters:
  • folder_path – Absolute path of the directory tree to scan. Non-existent paths simply yield an empty result list.

  • available_nodes – Set of node class names known to the current Nuke environment, typically the return value of get_available_nodes(). Used to flag missing dependencies.

  • ignored_words – Tokens that match the node syntax but should not be treated as real nodes (typically just IGNORED_WORDS).

Returns:

One Template record per .nk file discovered, populated with parsed metadata and a final status. Caller may sort or filter the list freely; the scanner makes no ordering guarantee.

Return type:

list[Template]

Template_Manager.settings module

Configuration and metadata management for the Template Manager.

This module handles disk I/O for JSON configuration files. It establishes a hierarchy for locating the main config file (prioritizing a studio-wide environment variable before falling back to the local user directory) and manages the reading/writing of custom template metadata.

Module-level constants in this file define the on-disk locations of every database file the plugin uses, as well as fallback defaults used by the scanner when project metadata cannot be parsed from a .nk file.

Template_Manager.settings.STUDIO_ENV_VAR

Name of the environment variable consulted first for the location of the configuration file. Setting this to an existing path lets a studio override every artist’s local configuration with a centrally managed file.

Type:

str

Template_Manager.settings.CONFIG_ROOT

Absolute path to the directory where Template Manager stores its per-user configuration and database files. Defaults to ~/.nuke/Template_Manager.

Type:

str

Template_Manager.settings.LOCAL_CONFIG_PATH

Absolute path to the local configuration JSON file used when STUDIO_ENV_VAR is unset or points to a missing file.

Type:

str

Template_Manager.settings.DEFAULT_TEMPLATE_PATH

Hardcoded fallback directory used to resolve template paths when no path is configured. Defaults to ~/.nuke/templates.

Type:

str

Template_Manager.settings.CACHE_PATH

Absolute path to the scanner cache JSON file, used by saves to memoize parsed node data between launches.

Type:

str

Template_Manager.settings.METADATA_PATH

Absolute path to the manual user tag database JSON file, used by saves to persist per-template tag overrides.

Type:

str

Template_Manager.settings.AUTO_TAGS_PATH

Absolute path to the auto-tagging rules JSON file, loaded and saved by saves and edited via the ui.AutoTagRulesDialog UI.

Type:

str

Template_Manager.settings.MAX_FILE_SIZE_BYTES

Hard limit (in bytes) above which the scanner refuses to parse a .nk file. Files exceeding this threshold are flagged with the FILE_TOO_LARGE status and skipped.

Type:

int

Template_Manager.settings.DEFAULT_PROJECT_FPS

Fallback frames-per-second value used when a template’s Root block contains no fps entry.

Type:

float

Template_Manager.settings.DEFAULT_PROJECT_RESOLUTION

Fallback (width, height) used when a template’s Root block contains no format entry.

Type:

tuple[int, int]

Template_Manager.settings.DEFAULT_PROJECT_COLORSPACE

Fallback colour management value used when a template’s Root block contains neither OCIO_config nor colorManagement entries.

Type:

str

Template_Manager.settings.get_config_path() str

Determine the absolute path to the active configuration file.

The function consults two sources, in order of priority:

  1. The environment variable named by STUDIO_ENV_VAR. If that variable is set and points to a path that exists on disk, the function returns it unchanged. This allows a studio pipeline to deploy a centrally managed config file to every artist without touching their local home directory.

  2. The local path LOCAL_CONFIG_PATH under the user’s home directory. If the parent directory does not yet exist it is created (along with any missing intermediates) so subsequent writes succeed.

Returns:

Absolute path to the JSON configuration file the plugin should read from and write to for this session. The returned path may not yet exist on disk; callers must handle missing files themselves.

Return type:

str

Template_Manager.settings.get_effective_template_paths() List[str]

Retrieve every existing directory the scanner should index.

The function reads the configuration file via load_config_data() and resolves the effective list of template root directories using the following fallback chain:

  1. The template_paths key, expected to be a list of strings.

  2. The legacy template_path key, expected to be a single string; wrapped in a one-element list for backward compatibility with configurations produced by earlier plugin versions.

  3. If neither key is present or yields any valid directory, DEFAULT_TEMPLATE_PATH is created on disk (if it does not already exist) and returned as the sole fallback.

All candidate paths are filtered through os.path.isdir(), so stale entries pointing at deleted directories are silently dropped rather than producing errors during scanning.

Returns:

A list of absolute directory paths that currently exist on disk and should be scanned for .nk templates. Always contains at least one entry, since DEFAULT_TEMPLATE_PATH is created and returned when no configured path resolves.

Return type:

list[str]

Template_Manager.settings.get_tags() List[str]

Retrieve the globally configured list of available tag strings.

Reads the tags key from the main configuration file. The returned list is intended to serve as the master vocabulary shown in the UI’s tag autocomplete and batch-tagging dialogs. It is independent of the per-template manual tags stored in the metadata database.

Returns:

The list of predefined tag strings, in the order they appear in the configuration file. Returns an empty list if the configuration file is missing or contains no tags entry.

Return type:

list[str]

Template_Manager.settings.load_config_data() dict

Load and parse the main configuration JSON file.

Resolves the active config path via get_config_path() and reads it as UTF-8 encoded JSON. Any error during file access or JSON decoding is caught and logged to standard output; the function then returns an empty dictionary so the rest of the plugin can continue with default behaviour rather than crashing.

Returns:

The parsed top-level JSON object from the configuration file, or an empty dictionary if the file does not exist, cannot be read, or contains invalid JSON.

Return type:

dict

Template_Manager.settings.use_folder_categories() bool

Check whether the UI should group templates by parent folder.

When this setting is enabled, the main Template Manager dialog organises templates into a hierarchical tree mirroring their on-disk folder structure. When disabled, templates are presented in a flat list.

Returns:

True if folder-based categorisation is enabled (the default when the key is absent), False if the user has explicitly opted out via the configuration file.

Return type:

bool

Template_Manager.ui module

PySide graphical user interface for the Nuke Template Manager.

This module builds every Qt dialog the plugin exposes to artists. It is designed to work transparently against both PySide6 (newer Nuke releases) and PySide2 (older releases) by attempting the PySide6 import first and falling back if it is unavailable.

The module owns six widget classes:

  • TemplateManagerUI — the main browser window: a searchable, taggable, hierarchical view of every scanned template.

  • SaveTemplateDialog — the form used to choose a project, subfolder, name, and versioning behaviour for a new template save.

  • BatchTagDialog — the small dialog driving the right-click Batch Tag action on multiple selected templates.

  • PlaceholderDialog — the checklist that lets artists decide which Read nodes to swap with Placeholder NoOps during save or import.

  • AutoTagRulesDialog — the form-based editor for the auto-tagging rule set persisted by saves.

  • RuleWidget — a single editable row inside the rules dialog.

The free function get_nuke_main_window() provides the parent widget every dialog uses so the windows float above Nuke rather than the desktop.

class Template_Manager.ui.AutoTagRulesDialog(*args: Any, **kwargs: Any)

Bases: QDialog

A form-based editor for the auto-tagging rule set.

Displays the current rule set as a scrollable list of RuleWidget rows. The user can add new rules with the “+ Add New Rule” button, remove any existing rule with its row’s X button, and persist the complete edited set with the Save button (which in turn calls saves.save_auto_tag_rules()). The Cancel button discards every change made since the dialog opened.

Rule changes take effect on the next scan or on the next use of the Re-Evaluate Auto-Tags context menu action; already-loaded templates in an open browser window are unaffected.

Parameters:

parent (QWidget, optional) – Parent widget for the dialog, typically Nuke’s main window obtained via get_nuke_main_window(). Defaults to None.

add_empty_rule()

Append a new blank rule row to the dialog.

Wired to the “+ Add New Rule” button. The created row carries no initial tag name and an empty rule dictionary, ready for the user to fill in. The row is appended to the bottom of the scrollable list, never inserted in the middle.

add_rule_widget(tag_name, rule_data)

Create a single RuleWidget and wire its delete button.

Instantiates the row widget pre-populated with the supplied tag name and rule data, connects its X button to remove_rule(), adds it to the scrollable rules layout, and records it in rule_widgets so save_rules() can iterate over every active row later.

Parameters:
  • tag_name (str) – Tag name to pre-fill in the row’s tag input. Pass "" for empty rows.

  • rule_data (dict) – Rule dictionary to pre-fill in the row’s controls. Pass {} for empty rows.

load_rules()

Load the persisted rule set from disk and populate the dialog.

Calls saves.load_auto_tag_rules() to read the current on-disk JSON, then creates one RuleWidget row per rule entry by delegating to add_rule_widget(). Invoked once during initialisation; never called again afterwards.

remove_rule(rw)

Remove a row widget from the dialog and schedule its destruction.

Wired to each RuleWidget’s X button via the lambda in add_rule_widget(). Detaches the widget from the layout, calls deleteLater to schedule its disposal on the next event-loop iteration, and removes the reference from rule_widgets so it cannot be re-saved.

Parameters:

rw (RuleWidget) – The row to remove.

save_rules()

Collect every row’s data, persist it, and close the dialog.

Iterates over every RuleWidget in rule_widgets, calls RuleWidget.get_data() on each, and assembles the results into a single dictionary suitable for saves.save_auto_tag_rules(). Rows whose tag name is empty are silently dropped (their get_data return is (None, None)). After the JSON has been written the user is informed via nuke.message() and the dialog accepts.

class Template_Manager.ui.BatchTagDialog(*args: Any, **kwargs: Any)

Bases: QDialog

Modal dialog letting the user batch-tag multiple selected templates.

Presents a single comma-separated tag input and two action buttons:

  • Overwrite replaces the tag list on every selected template with the typed tags, discarding whatever was there before.

  • Append merges the typed tags into each template’s existing tag list, deduplicating the result.

The chosen mode is stored in mode (either "append" or "overwrite") and the parsed tag list in tags, ready for the caller to consume after the dialog is accepted.

Parameters:

parent (QWidget, optional) – Parent widget for the dialog. Defaults to None.

accept_append()

Set the mode to "append" and accept the dialog.

Wired to the Append button. Records the chosen mode and delegates the actual tag parsing to _process_tags() before the dialog closes.

accept_overwrite()

Set the mode to "overwrite" and accept the dialog.

Wired to the Overwrite button. Records the chosen mode and delegates the actual tag parsing to _process_tags() before the dialog closes.

class Template_Manager.ui.PlaceholderDialog(*args: Any, **kwargs: Any)

Bases: QDialog

Modal checklist for choosing which Read nodes to swap with Placeholders.

Used by both the save flow (where the input list is a sequence of live nuke.Node objects) and the import flow (where the input list is a sequence of (name, file_path) tuples harvested by parsing the template’s raw text). The dialog transparently handles either input form, presenting each entry as a single check-box item showing the node name alongside its associated file’s basename.

Every entry starts in the checked state; the user unchecks any Read nodes that should be preserved as-is. The selected entries are returned by get_nodes_to_convert() as a list of whichever object form was originally supplied (live nodes or name strings).

Parameters:
  • read_items (list) – The Read nodes or (name, file_path) tuples to display. The two forms can be mixed in a single dialog but typically are not.

  • parent (QWidget, optional) – Parent widget. Defaults to None.

get_nodes_to_convert()

Return the original objects for every checked entry.

Walks node_data and returns the second element of each pair (the original nuke.Node or the node-name string, depending on which form was supplied at construction) for every list item still in the checked state.

Returns:

The subset of the originally-supplied objects that the user left checked, in the same order they were added to the dialog. The empty list is a valid return value and simply means the user unchecked everything.

Return type:

list

class Template_Manager.ui.RuleWidget(*args: Any, **kwargs: Any)

Bases: QWidget

A single editable row inside the auto-tag rules dialog.

Each row exposes four editable fields plus a delete button:

  • Tag Name — the tag that this rule emits when it matches.

  • Type — a dropdown choosing between OR (the JSON any type), AND (all), and How Many (count).

  • Threshold — an integer spin box, visible only when the type is How Many, controlling the minimum match count.

  • Nodes — a comma-separated list of lowercase node class substrings to match against the templates being scanned.

  • X — a remove button that destroys this row.

The widget translates between the rule dictionary schema used by saves.DEFAULT_TAG_RULES and the UI controls transparently: __init__() deserialises a rule into the widgets, and get_data() serialises the widget state back into a rule.

Parameters:
  • tag_name (str) – Initial tag name to display in the input field. Defaults to an empty string for new rules.

  • rule_data (dict, optional) – Initial rule dictionary, with the keys type, nodes and (for count rules) threshold. Defaults to None, which is treated as an empty rule.

  • parent (QWidget, optional) – Parent widget. Defaults to None.

get_data()

Serialise the row’s UI state into a rule dictionary.

Reads the four user-editable fields, sanitises them (stripping whitespace and splitting the comma-separated node list), and builds a rule dictionary in the schema consumed by scanner.get_auto_tags() and persisted by saves.save_auto_tag_rules(). Rows whose tag-name field is empty are treated as deletable and return a pair of None values so the caller can drop them.

Returns:

A 2-tuple (tag_name, rule_dict).

  • tag_name (str | None) — the cleaned tag string, or None when the row should be dropped because its tag name is empty.

  • rule_dict (dict | None) — a rule dictionary with the keys type (one of "any", "all", "count"), nodes (list of substrings), and for the count type threshold (int). None when the row should be dropped.

Return type:

tuple

on_type_changed(index)

Show or hide the threshold spinner when the rule type changes.

The threshold value is only meaningful for the How Many (count) rule type, so the spin box stays hidden in every other mode to keep the row visually compact.

Parameters:

index (int) – The newly selected index in the type dropdown. 2 corresponds to How Many; any other value hides the spinner.

class Template_Manager.ui.SaveTemplateDialog(*args: Any, **kwargs: Any)

Bases: QDialog

A dialog for saving new templates from Nuke’s node graph.

The dialog gathers four pieces of information from the user:

  • The template’s base name (used as the filename stem).

  • A project, either chosen from the dropdown of existing projects or created on the fly via the “[ + Create New Project ]” option.

  • An optional subfolder path within the project, selectable from a mini-tree of known subfolders or typed directly.

  • Whether to auto-version the saved file with a _v## suffix.

Parameters:
  • projects_dict (dict) – Mapping of project display names to sets of known subfolder paths. Used to populate both the project dropdown and the per-project subfolder tree.

  • project_raw_map (dict) – Mapping of project display names to their raw on-disk folder names. The display name is the title-cased, space-separated form shown to the user; the raw name is the snake-cased folder name used on disk.

  • detected_project (str | None) – Project name to pre-select in the dropdown, typically derived from the active Nuke script’s filename by main.launch_save_ui(). Pass None to leave the dropdown on its first entry.

  • default_root (str) – Filesystem path used as the base directory under which the new template will be written.

  • parent (QWidget, optional) – Parent widget for the dialog. Defaults to None, producing a free-floating top-level window.

get_save_data()

Return the validated save parameters chosen by the user.

Reads every input field, trims whitespace, replaces spaces with underscores in path-bound strings, normalises slashes for cross-platform safety, and assembles the absolute target directory. The returned base_name is the template’s filename stem with no extension and no version suffix; the Save Template flow combines it with the path and the version suffix downstream via saves.get_save_path().

Returns:

A 3-tuple (base_name, final_folder_path, do_version).

  • base_name (str) — the sanitised template filename stem.

  • final_folder_path (str) — the absolute directory the template should be written into, including the project and subfolder components.

  • do_version (bool) — True if auto-versioning is enabled, False if the user disabled it.

Return type:

tuple

on_project_changed()

Handle a change in the Project dropdown selection.

Shows the new-project text input only when the user selects the synthetic [ + Create New Project ] entry, hiding it in every other case so the form stays compact. Triggers a rebuild of the subfolder tree to reflect the newly selected project’s known subfolders.

on_tree_item_clicked(item, column)

Copy a clicked tree path into the subfolder text input.

Reads the full subfolder path stored on the clicked tree node (as UserRole data) and writes it into the text input so the user can edit it further or accept it as-is.

Parameters:
  • item (QtWidgets.QTreeWidgetItem) – The tree node the user clicked.

  • column (int) – The column index of the click. Unused; the path is stored on column 0 regardless.

update_subfolder_tree()

Rebuild the subfolder mini-tree from the current project’s data.

Looks up the currently selected project in projects_dict and populates the tree widget with every known subfolder path beneath that project, splitting on forward slashes to build the hierarchical structure. When the special "My Templates (Root)" entry is selected the tree is disabled entirely because root-level templates have no subfolder. The tree is fully expanded after population so artists can see every known path at a glance.

class Template_Manager.ui.TemplateManagerUI(*args: Any, **kwargs: Any)

Bases: QDialog

The main browser window for the Template Manager plugin.

The window presents every scanned template as a row in a multi-column tree view, organised by project (via the dropdown) and by subfolder (as expandable tree nodes). Core features exposed through the UI include:

  • A live search bar supporting plain text matches against template names and @tag queries against tag metadata, with autocomplete suggestions drawn from the union of every tag in the library.

  • A Project Settings column summarising each template’s frame rate, resolution, and colour management, with a one-click prompt to update the current Nuke script’s project settings to match the template at import time.

  • Inline tag editing in the Tags column, plus right-click batch tagging and a Re-Evaluate Auto-Tags action that re-runs the rule engine against the current template contents.

  • Procedural per-tag colouring derived from the tag string, keeping similar tags visually consistent across sessions.

  • Smart auto-detection of the active Nuke script’s project, with matching template rows pre-expanded and scrolled into view on launch.

Parameters:
  • templates (list[dict]) – The master list of scanned template dictionaries produced by scanner.scan_templates().

  • has_stamps (bool) – True if the Stamps plugin was found in the current Python environment. Reserved for future Stamps-aware UI behaviour; carried through from the scanner pass.

auto_detect_project()

Attempt to guess the active project from the current Nuke script name.

Uses three heuristics in descending priority:

  1. Exact template base-name match against the script filename.

  2. Filename prefix match against template prefixes in each project.

  3. Fallback folder-name match against the script path components.

Sets auto_target_base_name and auto_expand_prefixes as instance attributes so refresh_tree can highlight and expand the relevant rows.

execute_import(filepath)

Import a template file, optionally swapping Read nodes to Placeholders.

The function does not modify the on-disk template. Instead it reads the .nk source into memory, optionally rewrites the in-memory text to replace selected Read { ... } blocks with red-tile-coloured NoOp placeholders preserving the original node names and DAG positions, writes the modified text to a hidden temporary file under ~/.nuke/Template_Manager/.temp_import.nk, and pastes that temporary file via nuke.nodePaste. The temporary file is always deleted before the function returns, even on paste failure.

The user is prompted via PlaceholderDialog to choose which Read nodes (if any) should be converted. Cancelling that dialog aborts the import.

Parameters:

filepath (str) – Absolute path to the source .nk template file. Must be readable; failures during the initial read are logged but do not abort the import (the paste will simply use the original file).

Returns:

True if the paste completed successfully, False if the user cancelled the placeholder dialog or the Nuke paste call raised an exception.

Return type:

bool

filter_current_project()

Trigger a tree rebuild when the search bar text changes.

Wired to the search bar’s textChanged signal. Delegating to refresh_tree() ensures the filter logic, sort logic, and folder-expansion-preservation logic stay in one place.

get_tag_color(tag_string)

Generate a procedural QColor derived from a tag string.

The hue is computed by summing position-weighted character ordinals and then multiplying by a prime step to spread values across the 360-degree hue wheel. Saturation and value are fixed to keep colours vivid but consistent with the UI palette.

Parameters:

tag_string (str) – The tag whose colour should be calculated.

Returns:

An HSV colour unique to the given tag string.

Return type:

QtGui.QColor

group_templates_by_project()

Populate projects_dict by parsing every template’s path context.

Also stores _hierarchy back onto each template dict and builds project_raw_map for display-name-to-raw-folder lookups.

group_versions(template_list)

Group templates by base name and sort each group by version descending.

Templates whose names end in _v## are clustered together under the un-versioned base name. Templates without a version suffix receive version number 0 and are keyed by their absolute file path to guarantee uniqueness — same-named templates in different subfolders will never collide. The display label is always read from tpl['name'], not from the dict key.

Parameters:

template_list (list[dict]) – A filtered list of template metadata dicts.

Returns:

Mapping of base_name → sorted list of (version, tpl) tuples,

highest version first.

Return type:

dict

import_from_button()

Trigger the import flow from the Import Selected button.

Validates that at least one tree item is selected, then delegates to import_template() with column 0 as if the user had double-clicked the row directly. When the selection is empty, the user is informed via nuke.message() and no action is taken.

import_template(item, column)

Import the template represented by a tree item into Nuke.

Triggered by a double-click on the tree widget or by the Import Selected button. The behaviour depends on which column the user double-clicked and on the template’s status:

  • Clicks on columns 0–3 trigger the import flow. Before the paste, the function compares the template’s project settings (frame rate, resolution, colour management) against the current Nuke script and, if they differ, opens a three-way dialog letting the user update the project, import the template’s nodes without touching the project settings, or cancel.

  • Clicks on column 4 (Tags) instead put the cell into edit mode so the user can change tags inline.

  • Templates with a MISSING_NODES status produce an additional confirmation prompt before the paste actually runs.

  • Templates with a READ_ERROR status are silently ignored.

On a successful paste the manager window closes; on a user cancellation or paste failure it stays open so the user can try a different template.

Parameters:
  • item (QtWidgets.QTreeWidgetItem) – The tree item the user clicked. Must carry a template dictionary on UserRole for column 0; folder rows are ignored.

  • column (int) – The column index of the click.

natural_sort_key(base_name, template_dict)

Generate a key for natural alphanumeric sorting (e.g., v2 comes before v20).

Parameters:
  • base_name (str) – The display name of the template entry.

  • template_dict (dict) – The template metadata dictionary containing _hierarchy.

Returns:

A mixed list of strings and ints suitable for use as a sort key.

Return type:

list

on_header_clicked(logical_index)

Intercept header clicks to perform a safe Python sort instead of a destructive Qt sort.

Parameters:

logical_index (int) – The column index that was clicked.

open_context_menu(position)

Show the right-click context menu and dispatch the chosen action.

Builds a context menu offering two actions on the currently selected template rows: Batch Tag (opens BatchTagDialog to apply or replace tags on every selected row at once) and Re-Evaluate Auto-Tags (re-parses each selected .nk file and replaces its tags with the output of the current auto-tag rule engine, prompting the user once for confirmation first).

Folder rows that carry no template data are filtered out before the menu is built; if no real template rows are selected the menu does not appear.

Parameters:

position (QtCore.QPoint) – The click position in tree viewport coordinates, used to anchor the popup menu.

parse_path_context(template_path)

Split a template path into Project Display name, Project Raw name, and Hierarchy.

Parameters:

template_path (str) – The absolute filesystem path of the template file.

Returns:

A 3-tuple of (proj_display, proj_raw, hierarchy) where hierarchy

is a list of sub-folder display names below the project root.

Return type:

tuple

refresh_tree()

Rebuild the tree widget based on the selected project and current search text.

Preserves the expanded state of folder nodes across rebuilds, applies auto-detection highlights set by auto_detect_project(), and performs a Python-side natural sort so Qt’s built-in sort cannot destroy the folder hierarchy.

save_inline_tags(item, column)

Update template metadata and sync memory state after inline tag editing.

Called automatically by the itemChanged signal. Only processes changes to column 3 (the Tags column). Persists the new tags to disk via saves.save_metadata() and refreshes the autocomplete model.

Parameters:
  • item (QTreeWidgetItem) – The item whose cell was edited.

  • column (int) – The column that changed.

save_new_template()

Run the in-UI Save Template flow against the current Nuke selection.

Captures the current script’s root settings (format, fps, colorManagement, OCIO_config) into a template_context dict, or sets it to None when the settings match the agnostic defaults (2048x1556, 24fps, “Nuke” colorManagement).

Builds projects_dict (display name -> set of known subfolder paths) and project_raw_map from the currently loaded templates, then opens SaveTemplateDialog. On acceptance, resolves the final save path via saves.get_save_path(), optionally prompts for overwrite confirmation, and writes the nodes with nuke.nodeCopy. Because nuke.nodeCopy only copies nodes and not project-level settings, a Root { ... } block built from template_context is then prepended to the saved .nk file when a non-agnostic context was captured.

It also intercepts Read nodes and prompts the user to convert them to Placeholders.

Any Read-to-Placeholder swap performed during the save is reverted by an undo in the finally block so the artist’s Nuke script is left exactly as it was before the save.

update_autocomplete()

Refresh the search-bar QCompleter model with current tags.

Recomputes the set of every tag attached to any template in alltemplates, prefixes each with @, sorts the result, and installs it as the completer’s data source so newly-added tags appear in autocomplete suggestions immediately after they are saved.

Template_Manager.ui.delete_on_close(widget)

Mark a Qt widget for deletion when closed.

Template_Manager.ui.exec_dialog(dialog)

Compatible dialog exec for PySide2 and PySide6.

Template_Manager.ui.exec_menu(menu, position)

Compatible menu exec for PySide2 and PySide6.

Template_Manager.ui.get_nuke_main_window()

Locate Nuke’s main dock window so dialogs can parent themselves to it.

Walks every top-level widget known to the running Qt application and returns the first one whose class name matches Nuke’s internal dock-main-window class. Parenting plugin dialogs to this widget ensures they float on top of the host application and respect Nuke’s window-stacking rules rather than the desktop’s.

Returns:

The detected main window instance, or None if no widget matches (for example when running outside Nuke). Callers should tolerate the None case by parenting their dialogs to None, which produces a free-floating top-level window.

Return type:

QtWidgets.QMainWindow | None

Template_Manager.ui.show_about_dialog(parent=None)

Display a native Qt About dialog with tool and contact details.

Module contents