Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 26 additions & 9 deletions client/ayon_nuke/plugins/load/load_effects.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import json

import nuke

from ayon_core.lib import StringTemplate
from ayon_core.pipeline import Anatomy, get_current_project_name
from ayon_nuke.api import plugin


Expand All @@ -28,8 +29,7 @@ def on_update(self, group_node, namespace, context):
return group_node

def connect_read_node(self, group_node, namespace, product_name):
"""
Finds read node and selects it
"""Finds read node and selects it

Arguments:
group_node (nuke.Node): Group node to connect to.
Expand All @@ -40,7 +40,7 @@ def connect_read_node(self, group_node, namespace, product_name):
nuke node: node is selected
None: if nothing found
"""
search_name = "{0}_{1}".format(namespace, product_name)
search_name = f"{namespace}_{product_name}"

read_node = next(
(
Expand All @@ -65,9 +65,8 @@ def connect_read_node(self, group_node, namespace, product_name):
def _load_effects_to_group(
self, context: dict, group_node: nuke.Node) -> str:
"""Load the json file and create nodes inside the group node"""

file = self.filepath_from_context(context).replace("\\", "/")
with open(file, "r") as f:
with open(file) as f:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
with open(file) as f:
with open(file, "r") as f:

json_f = json.load(f)

# get correct order of nodes by positions on track and subtrack
Expand All @@ -85,7 +84,6 @@ def _load_effects_to_group(

def _create_nodes_order(self, nodes_order: dict):
workfile_first_frame = int(nuke.root()["first_frame"].getValue())

# create input node
pre_node = nuke.createNode("Input")
pre_node["name"].setValue("rgb")
Expand All @@ -103,6 +101,26 @@ def _create_nodes_order(self, nodes_order: dict):
self.log.warning(e)
continue

# check if `file` in knob name then format the path
# so it is multiplatform compatible
if k == "file":
file_path = v
project_name = get_current_project_name()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

2 things:

  • it is possible to load from other projects
  • the Anatomy creation can be very heavy operation

Rather prepare the anatomy ahead in _load_effects_to_group and use project entity from context.

project_entity = context["project"]
anatomy = Anatomy(
    project_entity["name"], project_entity=project_entity
)

anatomy = Anatomy(project_name=project_name)
Comment on lines +108 to +109
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this should use the project from which we're loading. Mostly would be current project, but you can also load from library project. The project entity is stored in context, so you could just do

project_entity = context["project"]
anatomy = Anatomy(project_entity["name"], project_entity=project_entity)

Also could happen only once for the whole load logic in case the anatomy would be created multiple times.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Side note: Why is this actually happening? The loaded "files" can have loaded other files? That might be a mess. Imagine having file that is e.g. ocio file defined with environment variables instead of anatomy roots, it would just collapse.

_template_data = {
Comment on lines +107 to +110
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

get_current_project_name() inside the knob loop can resolve roots for the currently active project rather than the project being loaded from context. Since _load_effects_to_group already has context, consider passing context["project"]["name"] (or a prebuilt Anatomy) down into _create_nodes_order to avoid mismatches.

Copilot uses AI. Check for mistakes.
"root": anatomy.roots,
}
Comment on lines +108 to +112
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

Anatomy(...) is created inside the per-node/per-knob loop. If this hits settings/API each time, it can become a noticeable load-time cost. Create anatomy (and the template data dict) once before iterating nodes/knobs and reuse it.

Copilot uses AI. Check for mistakes.
success, rootless_path = \
anatomy.find_root_template_from_path(file_path)
Comment on lines +113 to +114
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

Avoid using a backslash line continuation here; wrap the call in parentheses instead. This is easier to edit and less error-prone if trailing whitespace changes.

Suggested change
success, rootless_path = \
anatomy.find_root_template_from_path(file_path)
success, rootless_path = (
anatomy.find_root_template_from_path(file_path)
)

Copilot uses AI. Check for mistakes.

self.log.info(f"rootless_path: {rootless_path}")
if success:
abs_resources_path = StringTemplate.format_strict_template(
rootless_path, _template_data
)
v = abs_resources_path
self.log.info(f"File path: {abs_resources_path}")
Comment on lines +116 to +122
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

These info logs will run for every file knob and will emit resolved absolute paths, which can be very noisy in normal usage. Consider lowering to debug (and/or logging only on failure) so routine loads don’t flood logs.

Suggested change
self.log.info(f"rootless_path: {rootless_path}")
if success:
abs_resources_path = StringTemplate.format_strict_template(
rootless_path, _template_data
)
v = abs_resources_path
self.log.info(f"File path: {abs_resources_path}")
self.log.debug(f"rootless_path: {rootless_path}")
if success:
abs_resources_path = StringTemplate.format_strict_template(
rootless_path, _template_data
)
v = abs_resources_path
self.log.debug(f"File path: {abs_resources_path}")

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
self.log.info(f"File path: {abs_resources_path}")


# Set node attribute values
if isinstance(v, list) and len(v) > 4:
node[k].setAnimated()
Expand Down Expand Up @@ -151,7 +169,6 @@ def _get_item(
if track_index == val["trackIndex"]}



class LoadEffectsInputProcess(LoadEffects):
"""Loading colorspace soft effect exported from nukestudio"""

Expand All @@ -169,4 +186,4 @@ def on_load(self, group_node, namespace, context):
def on_update(self, group_node, namespace, context):
# No post-process on update
# Only overridden to avoid behavior of LoadEffects
return group_node
return group_node
Loading