From f5406cedac8bc79d85b2a24411454cb74e66cf21 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 15 Jan 2024 18:27:11 +0000 Subject: [PATCH 1/6] Exposed knobs settings. --- .../nuke/server/settings/create_plugins.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/server_addon/nuke/server/settings/create_plugins.py b/server_addon/nuke/server/settings/create_plugins.py index 80aec51ae05..89ba87ad610 100644 --- a/server_addon/nuke/server/settings/create_plugins.py +++ b/server_addon/nuke/server/settings/create_plugins.py @@ -54,7 +54,10 @@ class CreateWriteRenderModel(BaseSettingsModel): enum_resolver=instance_attributes_enum, title="Instance attributes" ) - + exposed_knobs: list[str] = Field( + title="Exposed Knobs", + default_factory=list + ) prenodes: list[PrenodeModel] = Field( default_factory=list, title="Preceding nodes", @@ -80,7 +83,10 @@ class CreateWritePrerenderModel(BaseSettingsModel): enum_resolver=instance_attributes_enum, title="Instance attributes" ) - + exposed_knobs: list[str] = Field( + title="Exposed Knobs", + default_factory=list + ) prenodes: list[PrenodeModel] = Field( default_factory=list, title="Preceding nodes", @@ -106,7 +112,10 @@ class CreateWriteImageModel(BaseSettingsModel): enum_resolver=instance_attributes_enum, title="Instance attributes" ) - + exposed_knobs: list[str] = Field( + title="Exposed Knobs", + default_factory=list + ) prenodes: list[PrenodeModel] = Field( default_factory=list, title="Preceding nodes", @@ -145,6 +154,7 @@ class CreatorPluginsSettings(BaseSettingsModel): "reviewable", "farm_rendering" ], + "exposed_knobs": [], "prenodes": [ { "name": "Reformat01", @@ -178,6 +188,7 @@ class CreatorPluginsSettings(BaseSettingsModel): "farm_rendering", "use_range_limit" ], + "exposed_knobs": [], "prenodes": [] }, "CreateWriteImage": { @@ -190,6 +201,7 @@ class CreatorPluginsSettings(BaseSettingsModel): "instance_attributes": [ "use_range_limit" ], + "exposed_knobs": [], "prenodes": [ { "name": "FrameHold01", From 9e44545c2529536c745ecd919db472beb5380374 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 15 Jan 2024 18:27:22 +0000 Subject: [PATCH 2/6] Validate exposed knobs. --- .../plugins/publish/validate_write_nodes.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py index 0539c1188f7..434537022dd 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py @@ -1,5 +1,7 @@ from collections import defaultdict +import nuke + import pyblish.api from openpype.pipeline.publish import get_errored_instances_from_context from openpype.hosts.nuke.api.lib import ( @@ -11,6 +13,7 @@ from openpype.pipeline.publish import ( PublishXmlValidationError, OptionalPyblishPluginMixin, + PublishValidationError ) @@ -39,6 +42,19 @@ def process(self, context, plugin): set_node_knobs_from_settings(write_node, correct_data["knobs"]) + nuke_settings = instance.context.data["project_settings"]["nuke"] + create_settings = nuke_settings["create"]["CreateWriteRender"] + exposed_knobs = create_settings["exposed_knobs"] + for knob in exposed_knobs: + if knob in write_group_node.knobs(): + continue + + link = nuke.Link_Knob("") + link.makeLink(write_node.name(), knob) + link.setName(knob) + link.setFlag(0x1000) + write_group_node.addKnob(link) + self.log.debug("Node attributes were fixed") @@ -134,6 +150,27 @@ def process(self, instance): if check: self._make_error(check) + nuke_settings = instance.context.data["project_settings"]["nuke"] + create_settings = nuke_settings["create"]["CreateWriteRender"] + exposed_knobs = create_settings["exposed_knobs"] + unexposed_knobs = [] + for knob in exposed_knobs: + if knob not in write_group_node.knobs(): + unexposed_knobs.append(knob) + + """ + link = nuke.Link_Knob("") + link.makeLink(write_node.name(), knob) + link.setName(knob) + link.setFlag(0x1000) + write_group_node.addKnob(link) + """ + + if unexposed_knobs: + raise PublishValidationError( + "Missing exposed knobs: {}".format(unexposed_knobs) + ) + def _make_error(self, check): # sourcery skip: merge-assign-and-aug-assign, move-assign-in-block dbg_msg = "Write node's knobs values are not correct!\n" From 26a7363efe6c6eef0fbd42955c31e071941dea04 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 15 Jan 2024 18:27:35 +0000 Subject: [PATCH 3/6] Expose knobs on creation --- .../hosts/nuke/plugins/create/create_write_render.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/openpype/hosts/nuke/plugins/create/create_write_render.py b/openpype/hosts/nuke/plugins/create/create_write_render.py index 91acf4eabcb..e622376917d 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_render.py +++ b/openpype/hosts/nuke/plugins/create/create_write_render.py @@ -113,6 +113,16 @@ def create(self, subset_name, instance_data, pre_create_data): instance.data_to_store() ) + settings = self.project_settings["nuke"]["create"] + exposed_knobs = settings["CreateWriteRender"]["exposed_knobs"] + write_node = nuke.allNodes(group=instance_node, filter="Write")[0] + for knob in exposed_knobs: + link = nuke.Link_Knob("") + link.makeLink(write_node.name(), knob) + link.setName(knob) + link.setFlag(0x1000) + instance_node.addKnob(link) + return instance except Exception as er: From d1fb633ce72cf838ec29ef3a52173edb7ab06e38 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 17 Jan 2024 09:13:54 +0000 Subject: [PATCH 4/6] Increment version --- server_addon/nuke/server/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server_addon/nuke/server/version.py b/server_addon/nuke/server/version.py index 9cb17e79762..c49a95c3572 100644 --- a/server_addon/nuke/server/version.py +++ b/server_addon/nuke/server/version.py @@ -1 +1 @@ -__version__ = "0.1.8" +__version__ = "0.2.8" From 00ddff5ff19f2c17f672b77570d3e5407d621921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Thu, 18 Jan 2024 16:25:08 +0100 Subject: [PATCH 5/6] Update server_addon/nuke/server/version.py --- server_addon/nuke/server/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server_addon/nuke/server/version.py b/server_addon/nuke/server/version.py index c49a95c3572..c11f861afbe 100644 --- a/server_addon/nuke/server/version.py +++ b/server_addon/nuke/server/version.py @@ -1 +1 @@ -__version__ = "0.2.8" +__version__ = "0.1.9" From c5c4ef175494568d946d7b8a8cc5ae981149f9d2 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 29 Jan 2024 17:36:28 +0000 Subject: [PATCH 6/6] Settings, refactor, validate - Explicit settings label. - Refactor for code sharing between render, prerender and image families. - Validate typos on settings knob names. --- openpype/hosts/nuke/api/__init__.py | 4 +- openpype/hosts/nuke/api/lib.py | 24 ++++++ openpype/hosts/nuke/api/plugin.py | 11 ++- .../nuke/plugins/create/create_write_image.py | 5 ++ .../plugins/create/create_write_prerender.py | 5 ++ .../plugins/create/create_write_render.py | 13 +--- .../plugins/publish/validate_exposed_knobs.py | 77 +++++++++++++++++++ .../plugins/publish/validate_write_nodes.py | 39 +--------- .../nuke/server/settings/create_plugins.py | 12 +-- 9 files changed, 135 insertions(+), 55 deletions(-) create mode 100644 openpype/hosts/nuke/plugins/publish/validate_exposed_knobs.py diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index c6ccd0baf15..2536230637b 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -43,7 +43,8 @@ get_node_data, set_node_data, update_node_data, - create_write_node + create_write_node, + link_knobs ) from .utils import ( colorspace_exists_on_node, @@ -95,6 +96,7 @@ "set_node_data", "update_node_data", "create_write_node", + "link_knobs", "colorspace_exists_on_node", "get_colorspace_list", diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 7ba53caead9..cdefd05c114 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -3499,3 +3499,27 @@ def create_camera_node_by_version(): return nuke.createNode("Camera4") else: return nuke.createNode("Camera2") + + +def link_knobs(knobs, node, group_node): + """Link knobs from inside `group_node`""" + + missing_knobs = [] + for knob in knobs: + if knob in group_node.knobs(): + continue + + if knob not in node.knobs().keys(): + missing_knobs.append(knob) + + link = nuke.Link_Knob("") + link.makeLink(node.name(), knob) + link.setName(knob) + link.setFlag(0x1000) + group_node.addKnob(link) + + if missing_knobs: + raise ValueError( + "Write node exposed knobs missing:\n\n{}\n\nPlease review" + " project settings.".format("\n".join(missing_knobs)) + ) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 15d7bfc4b96..c8301b81fda 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -44,7 +44,8 @@ get_view_process_node, get_viewer_config_from_string, deprecated, - get_filenames_without_hash + get_filenames_without_hash, + link_knobs ) from .pipeline import ( list_instances, @@ -1344,3 +1345,11 @@ def _remove_old_knobs(node): node.removeKnob(knob) except ValueError: pass + + +def exposed_write_knobs(settings, plugin_name, instance_node): + exposed_knobs = settings["nuke"]["create"][plugin_name]["exposed_knobs"] + if exposed_knobs: + instance_node.addKnob(nuke.Text_Knob('', 'Write Knobs')) + write_node = nuke.allNodes(group=instance_node, filter="Write")[0] + link_knobs(exposed_knobs, write_node, instance_node) diff --git a/openpype/hosts/nuke/plugins/create/create_write_image.py b/openpype/hosts/nuke/plugins/create/create_write_image.py index 8c18739587e..f21d871c9f4 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_image.py +++ b/openpype/hosts/nuke/plugins/create/create_write_image.py @@ -12,6 +12,7 @@ EnumDef ) from openpype.hosts.nuke import api as napi +from openpype.hosts.nuke.api.plugin import exposed_write_knobs class CreateWriteImage(napi.NukeWriteCreator): @@ -132,6 +133,10 @@ def create(self, subset_name, instance_data, pre_create_data): instance.data_to_store() ) + exposed_write_knobs( + self.project_settings, self.__class__.__name__, instance_node + ) + return instance except Exception as er: diff --git a/openpype/hosts/nuke/plugins/create/create_write_prerender.py b/openpype/hosts/nuke/plugins/create/create_write_prerender.py index 395c3b002fd..742bfb20adf 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_prerender.py +++ b/openpype/hosts/nuke/plugins/create/create_write_prerender.py @@ -9,6 +9,7 @@ BoolDef ) from openpype.hosts.nuke import api as napi +from openpype.hosts.nuke.api.plugin import exposed_write_knobs class CreateWritePrerender(napi.NukeWriteCreator): @@ -119,6 +120,10 @@ def create(self, subset_name, instance_data, pre_create_data): instance.data_to_store() ) + exposed_write_knobs( + self.project_settings, self.__class__.__name__, instance_node + ) + return instance except Exception as er: diff --git a/openpype/hosts/nuke/plugins/create/create_write_render.py b/openpype/hosts/nuke/plugins/create/create_write_render.py index e622376917d..fc16876f757 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_render.py +++ b/openpype/hosts/nuke/plugins/create/create_write_render.py @@ -9,6 +9,7 @@ BoolDef ) from openpype.hosts.nuke import api as napi +from openpype.hosts.nuke.api.plugin import exposed_write_knobs class CreateWriteRender(napi.NukeWriteCreator): @@ -113,15 +114,9 @@ def create(self, subset_name, instance_data, pre_create_data): instance.data_to_store() ) - settings = self.project_settings["nuke"]["create"] - exposed_knobs = settings["CreateWriteRender"]["exposed_knobs"] - write_node = nuke.allNodes(group=instance_node, filter="Write")[0] - for knob in exposed_knobs: - link = nuke.Link_Knob("") - link.makeLink(write_node.name(), knob) - link.setName(knob) - link.setFlag(0x1000) - instance_node.addKnob(link) + exposed_write_knobs( + self.project_settings, self.__class__.__name__, instance_node + ) return instance diff --git a/openpype/hosts/nuke/plugins/publish/validate_exposed_knobs.py b/openpype/hosts/nuke/plugins/publish/validate_exposed_knobs.py new file mode 100644 index 00000000000..fe5644f0c91 --- /dev/null +++ b/openpype/hosts/nuke/plugins/publish/validate_exposed_knobs.py @@ -0,0 +1,77 @@ +import pyblish.api + +from openpype.pipeline.publish import get_errored_instances_from_context +from openpype.hosts.nuke.api.lib import link_knobs +from openpype.pipeline.publish import ( + OptionalPyblishPluginMixin, + PublishValidationError +) + + +class RepairExposedKnobs(pyblish.api.Action): + label = "Repair" + on = "failed" + icon = "wrench" + + def process(self, context, plugin): + instances = get_errored_instances_from_context(context) + + for instance in instances: + child_nodes = ( + instance.data.get("transientData", {}).get("childNodes") + or instance + ) + + write_group_node = instance.data["transientData"]["node"] + # get write node from inside of group + write_node = None + for x in child_nodes: + if x.Class() == "Write": + write_node = x + + plugin_name = plugin.families_mapping[instance.data["family"]] + nuke_settings = instance.context.data["project_settings"]["nuke"] + create_settings = nuke_settings["create"][plugin_name] + exposed_knobs = create_settings["exposed_knobs"] + link_knobs(exposed_knobs, write_node, write_group_node) + + +class ValidateExposedKnobs( + OptionalPyblishPluginMixin, + pyblish.api.InstancePlugin +): + """ Validate write node exposed knobs. + + Compare exposed linked knobs to settings. + """ + + order = pyblish.api.ValidatorOrder + optional = True + families = ["render", "prerender", "image"] + label = "Validate Exposed Knobs" + actions = [RepairExposedKnobs] + hosts = ["nuke"] + families_mapping = { + "render": "CreateWriteRender", + "prerender": "CreateWritePrerender", + "image": "CreateWriteImage" + } + + def process(self, instance): + if not self.is_active(instance.data): + return + + plugin = self.families_mapping[instance.data["family"]] + group_node = instance.data["transientData"]["node"] + nuke_settings = instance.context.data["project_settings"]["nuke"] + create_settings = nuke_settings["create"][plugin] + exposed_knobs = create_settings["exposed_knobs"] + unexposed_knobs = [] + for knob in exposed_knobs: + if knob not in group_node.knobs(): + unexposed_knobs.append(knob) + + if unexposed_knobs: + raise PublishValidationError( + "Missing exposed knobs: {}".format(unexposed_knobs) + ) diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py index 434537022dd..f490b580d6f 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py @@ -1,7 +1,5 @@ from collections import defaultdict -import nuke - import pyblish.api from openpype.pipeline.publish import get_errored_instances_from_context from openpype.hosts.nuke.api.lib import ( @@ -12,8 +10,7 @@ from openpype.pipeline.publish import ( PublishXmlValidationError, - OptionalPyblishPluginMixin, - PublishValidationError + OptionalPyblishPluginMixin ) @@ -42,19 +39,6 @@ def process(self, context, plugin): set_node_knobs_from_settings(write_node, correct_data["knobs"]) - nuke_settings = instance.context.data["project_settings"]["nuke"] - create_settings = nuke_settings["create"]["CreateWriteRender"] - exposed_knobs = create_settings["exposed_knobs"] - for knob in exposed_knobs: - if knob in write_group_node.knobs(): - continue - - link = nuke.Link_Knob("") - link.makeLink(write_node.name(), knob) - link.setName(knob) - link.setFlag(0x1000) - write_group_node.addKnob(link) - self.log.debug("Node attributes were fixed") @@ -150,27 +134,6 @@ def process(self, instance): if check: self._make_error(check) - nuke_settings = instance.context.data["project_settings"]["nuke"] - create_settings = nuke_settings["create"]["CreateWriteRender"] - exposed_knobs = create_settings["exposed_knobs"] - unexposed_knobs = [] - for knob in exposed_knobs: - if knob not in write_group_node.knobs(): - unexposed_knobs.append(knob) - - """ - link = nuke.Link_Knob("") - link.makeLink(write_node.name(), knob) - link.setName(knob) - link.setFlag(0x1000) - write_group_node.addKnob(link) - """ - - if unexposed_knobs: - raise PublishValidationError( - "Missing exposed knobs: {}".format(unexposed_knobs) - ) - def _make_error(self, check): # sourcery skip: merge-assign-and-aug-assign, move-assign-in-block dbg_msg = "Write node's knobs values are not correct!\n" diff --git a/server_addon/nuke/server/settings/create_plugins.py b/server_addon/nuke/server/settings/create_plugins.py index 30719c06f62..6bdc5ee5ad8 100644 --- a/server_addon/nuke/server/settings/create_plugins.py +++ b/server_addon/nuke/server/settings/create_plugins.py @@ -55,8 +55,8 @@ class CreateWriteRenderModel(BaseSettingsModel): enum_resolver=instance_attributes_enum, title="Instance attributes" ) - exposed_knobs: list[str] = Field( - title="Exposed Knobs", + exposed_knobs: list[str] = SettingsField( + title="Write Node Exposed Knobs", default_factory=list ) prenodes: list[PrenodeModel] = SettingsField( @@ -84,8 +84,8 @@ class CreateWritePrerenderModel(BaseSettingsModel): enum_resolver=instance_attributes_enum, title="Instance attributes" ) - exposed_knobs: list[str] = Field( - title="Exposed Knobs", + exposed_knobs: list[str] = SettingsField( + title="Write Node Exposed Knobs", default_factory=list ) prenodes: list[PrenodeModel] = SettingsField( @@ -113,8 +113,8 @@ class CreateWriteImageModel(BaseSettingsModel): enum_resolver=instance_attributes_enum, title="Instance attributes" ) - exposed_knobs: list[str] = Field( - title="Exposed Knobs", + exposed_knobs: list[str] = SettingsField( + title="Write Node Exposed Knobs", default_factory=list ) prenodes: list[PrenodeModel] = SettingsField(