From 70948555e00c8a4677e82b24e623a3a524c0d5f2 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 12 Sep 2022 21:33:57 +0200 Subject: [PATCH 001/115] nuke: adding pipeline abstraction for new publisher --- openpype/hosts/nuke/api/__init__.py | 8 ++++ openpype/hosts/nuke/api/pipeline.py | 63 ++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index 962f31c1779..42b669fec3d 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -18,6 +18,10 @@ ls, + list_instances, + remove_instance, + select_instance, + containerise, parse_container, update_container, @@ -51,6 +55,10 @@ "ls", + "list_instances", + "remove_instance", + "select_instance", + "containerise", "parse_container", "update_container", diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index bac42128cc4..50e7dd94950 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -39,6 +39,7 @@ check_inventory_versions, set_avalon_knob_data, read_avalon_data, + get_avalon_knob_data ) from .lib_template_builder import ( create_placeholder, update_placeholder @@ -431,7 +432,6 @@ def ls(): """ all_nodes = nuke.allNodes(recurseGroups=False) - # TODO: add readgeo, readcamera, readimage nodes = [n for n in all_nodes] for n in nodes: @@ -439,3 +439,64 @@ def ls(): container = parse_container(n) if container: yield container + + +def list_instances(): + """List all created instances to publish from current workfile. + + For SubsetManager + + Returns: + (list) of dictionaries matching instances format + """ + instances = [] + for node in nuke.allNodes(): + + if node.Class() in ["Viewer", "Dot"]: + continue + + try: + if node["disable"].value(): + continue + except Exception as E: + log.warning(E) + + # get data from avalon knob + avalon_knob_data = get_avalon_knob_data( + node, ["avalon:", "ak:"]) + + if not avalon_knob_data: + continue + + if avalon_knob_data["id"] != "pyblish.avalon.instance": + continue + + # add node name + avalon_knob_data["name"] = node.name() + + instances.append(avalon_knob_data) + + return instances + + +def remove_instance(instance): + """Remove instance from current workfile metadata. + + For SubsetManager + + Args: + instance (dict): instance representation from subsetmanager model + """ + node = nuke.toNode(instance["name"]) + nuke.delete(node) + + +def select_instance(instance): + """ + Select instance in Node View + + Args: + instance (dict): instance representation from subsetmanager model + """ + node = nuke.toNode(instance["name"]) + node["selected"].setValue(True) From 8e3eab2f6007f666317f22af2894662568cb7f5f Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 12 Sep 2022 21:34:13 +0200 Subject: [PATCH 002/115] nuke: adding workfile creator --- .../nuke/plugins/create/workfile_creator.py | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 openpype/hosts/nuke/plugins/create/workfile_creator.py diff --git a/openpype/hosts/nuke/plugins/create/workfile_creator.py b/openpype/hosts/nuke/plugins/create/workfile_creator.py new file mode 100644 index 00000000000..9ceaf376c1f --- /dev/null +++ b/openpype/hosts/nuke/plugins/create/workfile_creator.py @@ -0,0 +1,77 @@ +import openpype.hosts.nuke.api as api +from openpype.client import get_asset_by_name +from openpype.pipeline import ( + AutoCreator, + CreatedInstance, + legacy_io, +) + + +class WorkfileCreator(AutoCreator): + identifier = "workfile" + family = "workfile" + + default_variant = "Main" + + def get_instance_attr_defs(self): + return [] + + def collect_instances(self): + for instance_data in api.list_instances(): + creator_id = instance_data.get("creator_identifier") + if creator_id == self.identifier: + subset_name = instance_data["subset"] + instance = CreatedInstance( + self.family, subset_name, instance_data, self + ) + self._add_instance_to_context(instance) + + def update_instances(self, update_list): + # nothing to change on workfiles + pass + + def create(self, options=None): + existing_instance = None + for instance in self.create_context.instances: + if instance.family == self.family: + existing_instance = instance + break + + project_name = legacy_io.Session["AVALON_PROJECT"] + asset_name = legacy_io.Session["AVALON_ASSET"] + task_name = legacy_io.Session["AVALON_TASK"] + host_name = legacy_io.Session["AVALON_APP"] + + if existing_instance is None: + asset_doc = get_asset_by_name(project_name, asset_name) + subset_name = self.get_subset_name( + self.default_variant, task_name, asset_doc, + project_name, host_name + ) + data = { + "asset": asset_name, + "task": task_name, + "variant": self.default_variant + } + data.update(self.get_dynamic_data( + self.default_variant, task_name, asset_doc, + project_name, host_name + )) + + new_instance = CreatedInstance( + self.family, subset_name, data, self + ) + self._add_instance_to_context(new_instance) + + elif ( + existing_instance["asset"] != asset_name + or existing_instance["task"] != task_name + ): + asset_doc = get_asset_by_name(project_name, asset_name) + subset_name = self.get_subset_name( + self.default_variant, task_name, asset_doc, + project_name, host_name + ) + existing_instance["asset"] = asset_name + existing_instance["task"] = task_name + existing_instance["subset"] = subset_name From a7caced36e5f5f6184a95f9c0ce7fc30e1666107 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 13 Sep 2022 12:18:50 +0200 Subject: [PATCH 003/115] nuke: refactor host to be NukeHost --- openpype/hosts/nuke/api/__init__.py | 9 +- openpype/hosts/nuke/api/lib.py | 26 +++++ openpype/hosts/nuke/api/pipeline.py | 165 ++++++++++++++++++---------- openpype/hosts/nuke/startup/menu.py | 65 +---------- 4 files changed, 138 insertions(+), 127 deletions(-) diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index 42b669fec3d..38f51a309ef 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -6,15 +6,12 @@ current_file, work_root, ) - from .command import ( viewer_update_and_undo_stop ) - from .plugin import OpenPypeCreator from .pipeline import ( - install, - uninstall, + NukeHost, ls, @@ -33,7 +30,6 @@ duplicate_node, convert_knob_value_to_correct_type ) - from .utils import ( colorspace_exists_on_node, get_colorspace_list @@ -50,8 +46,7 @@ "viewer_update_and_undo_stop", "OpenPypeCreator", - "install", - "uninstall", + "NukeHost", "ls", diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index e55fdbfcb27..764e9042951 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -2605,6 +2605,32 @@ def recreate_instance(origin_node, avalon_data=None): return new_node +def add_scripts_menu(): + try: + from scriptsmenu import launchfornuke + except ImportError: + log.warning( + "Skipping studio.menu install, because " + "'scriptsmenu' module seems unavailable." + ) + return + + # load configuration of custom menu + project_settings = get_project_settings(os.getenv("AVALON_PROJECT")) + config = project_settings["nuke"]["scriptsmenu"]["definition"] + _menu = project_settings["nuke"]["scriptsmenu"]["name"] + + if not config: + log.warning("Skipping studio menu, no definition found.") + return + + # run the launcher for Maya menu + studio_menu = launchfornuke.main(title=_menu.title()) + + # apply configuration + studio_menu.build_from_configuration(studio_menu, config) + + def add_scripts_gizmo(): # load configuration of custom menu diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 50e7dd94950..23011498726 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -1,12 +1,18 @@ +import nuke + import os import importlib from collections import OrderedDict -import nuke - import pyblish.api import openpype +from openpype.host import ( + HostBase, + IWorkfileHost, + ILoadHost, + INewPublisher +) from openpype.api import ( Logger, get_current_project_settings @@ -39,11 +45,23 @@ check_inventory_versions, set_avalon_knob_data, read_avalon_data, - get_avalon_knob_data + get_avalon_knob_data, + on_script_load, + dirmap_file_name_filter, + add_scripts_menu, + add_scripts_gizmo ) from .lib_template_builder import ( create_placeholder, update_placeholder ) +from .workio import ( + open_file, + save_file, + file_extensions, + has_unsaved_changes, + work_root, + current_file +) log = Logger.get_logger(__name__) @@ -62,6 +80,92 @@ pyblish.api.register_gui(os.getenv("PYBLISH_GUI", None)) +class NukeHost( + HostBase, IWorkfileHost, ILoadHost, INewPublisher +): + name = "nuke" + + def open_workfile(self, filepath): + return open_file(filepath) + + def save_workfile(self, filepath=None): + return save_file(filepath) + + def work_root(self, session): + return work_root(session) + + def get_current_workfile(self): + return current_file() + + def workfile_has_unsaved_changes(self): + return has_unsaved_changes() + + def get_workfile_extensions(self): + return file_extensions() + + def get_containers(self): + return ls() + + def install(self): + ''' Installing all requarements for Nuke host + ''' + + pyblish.api.register_host("nuke") + + self.log.info("Registering Nuke plug-ins..") + pyblish.api.register_plugin_path(PUBLISH_PATH) + register_loader_plugin_path(LOAD_PATH) + register_creator_plugin_path(CREATE_PATH) + register_inventory_action_path(INVENTORY_PATH) + + # Register Avalon event for workfiles loading. + register_event_callback("workio.open_file", check_inventory_versions) + register_event_callback("taskChanged", change_context_label) + + pyblish.api.register_callback( + "instanceToggled", on_pyblish_instance_toggled) + + _install_menu() + + # add script menu + add_scripts_menu() + add_scripts_gizmo() + + add_nuke_callbacks() + + launch_workfiles_app() + + def get_context_data(self): + pass + + def update_context_data(self, data, changes): + pass + + +def add_nuke_callbacks(): + + workfile_settings = WorkfileSettings() + # Set context settings. + nuke.addOnCreate( + workfile_settings.set_context_settings, nodeClass="Root") + nuke.addOnCreate(workfile_settings.set_favorites, nodeClass="Root") + nuke.addOnCreate(process_workfile_builder, nodeClass="Root") + + # fix ffmpeg settings on script + nuke.addOnScriptLoad(on_script_load) + + # set checker for last versions on loaded containers + nuke.addOnScriptLoad(check_inventory_versions) + nuke.addOnScriptSave(check_inventory_versions) + + # # set apply all workfile settings on script load and save + nuke.addOnScriptLoad(WorkfileSettings().set_context_settings) + + nuke.addFilenameFilter(dirmap_file_name_filter) + + log.info('Automatic syncing of write file knob to script version') + + def reload_config(): """Attempt to reload pipeline at run-time. @@ -88,52 +192,6 @@ def reload_config(): reload(module) -def install(): - ''' Installing all requarements for Nuke host - ''' - - pyblish.api.register_host("nuke") - - log.info("Registering Nuke plug-ins..") - pyblish.api.register_plugin_path(PUBLISH_PATH) - register_loader_plugin_path(LOAD_PATH) - register_creator_plugin_path(CREATE_PATH) - register_inventory_action_path(INVENTORY_PATH) - - # Register Avalon event for workfiles loading. - register_event_callback("workio.open_file", check_inventory_versions) - register_event_callback("taskChanged", change_context_label) - - pyblish.api.register_callback( - "instanceToggled", on_pyblish_instance_toggled) - workfile_settings = WorkfileSettings() - - # Set context settings. - nuke.addOnCreate(workfile_settings.set_context_settings, nodeClass="Root") - nuke.addOnCreate(workfile_settings.set_favorites, nodeClass="Root") - nuke.addOnCreate(process_workfile_builder, nodeClass="Root") - - _install_menu() - launch_workfiles_app() - - -def uninstall(): - '''Uninstalling host's integration - ''' - log.info("Deregistering Nuke plug-ins..") - pyblish.deregister_host("nuke") - pyblish.api.deregister_plugin_path(PUBLISH_PATH) - deregister_loader_plugin_path(LOAD_PATH) - deregister_creator_plugin_path(CREATE_PATH) - deregister_inventory_action_path(INVENTORY_PATH) - - pyblish.api.deregister_callback( - "instanceToggled", on_pyblish_instance_toggled) - - reload_config() - _uninstall_menu() - - def _show_workfiles(): # Make sure parent is not set # - this makes Workfiles tool as separated window which @@ -244,15 +302,6 @@ def _install_menu(): add_shortcuts_from_presets() -def _uninstall_menu(): - menubar = nuke.menu("Nuke") - menu = menubar.findItem(MENU_LABEL) - - for item in menu.items(): - log.info("Removing menu item: {}".format(item.name())) - menu.removeItem(item.name()) - - def change_context_label(): menubar = nuke.menu("Nuke") menu = menubar.findItem(MENU_LABEL) diff --git a/openpype/hosts/nuke/startup/menu.py b/openpype/hosts/nuke/startup/menu.py index 1461d413854..613d5083878 100644 --- a/openpype/hosts/nuke/startup/menu.py +++ b/openpype/hosts/nuke/startup/menu.py @@ -1,64 +1,5 @@ -import nuke -import os - -from openpype.api import Logger from openpype.pipeline import install_host -from openpype.hosts.nuke import api -from openpype.hosts.nuke.api.lib import ( - on_script_load, - check_inventory_versions, - WorkfileSettings, - dirmap_file_name_filter, - add_scripts_gizmo -) -from openpype.settings import get_project_settings - -log = Logger.get_logger(__name__) - - -install_host(api) - -# fix ffmpeg settings on script -nuke.addOnScriptLoad(on_script_load) - -# set checker for last versions on loaded containers -nuke.addOnScriptLoad(check_inventory_versions) -nuke.addOnScriptSave(check_inventory_versions) - -# # set apply all workfile settings on script load and save -nuke.addOnScriptLoad(WorkfileSettings().set_context_settings) - -nuke.addFilenameFilter(dirmap_file_name_filter) - -log.info('Automatic syncing of write file knob to script version') - - -def add_scripts_menu(): - try: - from scriptsmenu import launchfornuke - except ImportError: - log.warning( - "Skipping studio.menu install, because " - "'scriptsmenu' module seems unavailable." - ) - return - - # load configuration of custom menu - project_settings = get_project_settings(os.getenv("AVALON_PROJECT")) - config = project_settings["nuke"]["scriptsmenu"]["definition"] - _menu = project_settings["nuke"]["scriptsmenu"]["name"] - - if not config: - log.warning("Skipping studio menu, no definition found.") - return - - # run the launcher for Maya menu - studio_menu = launchfornuke.main(title=_menu.title()) - - # apply configuration - studio_menu.build_from_configuration(studio_menu, config) - - -add_scripts_menu() +from openpype.hosts.nuke.api import NukeHost -add_scripts_gizmo() +host = NukeHost() +install_host(host) From 501da09b79fc8bcf54b9abda92714cb5d5eabdd3 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 13 Sep 2022 12:23:30 +0200 Subject: [PATCH 004/115] nuke: change log info and removing unused imports --- openpype/hosts/nuke/api/pipeline.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 23011498726..26372d0047e 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -22,9 +22,6 @@ register_loader_plugin_path, register_creator_plugin_path, register_inventory_action_path, - deregister_loader_plugin_path, - deregister_creator_plugin_path, - deregister_inventory_action_path, AVALON_CONTAINER_ID, ) from openpype.pipeline.workfile import BuildWorkfile @@ -138,12 +135,13 @@ def install(self): def get_context_data(self): pass - def update_context_data(self, data, changes): + def update_context_data(self, data): pass def add_nuke_callbacks(): - + """ Adding all available nuke callbacks + """ workfile_settings = WorkfileSettings() # Set context settings. nuke.addOnCreate( @@ -163,7 +161,7 @@ def add_nuke_callbacks(): nuke.addFilenameFilter(dirmap_file_name_filter) - log.info('Automatic syncing of write file knob to script version') + log.info("Added Nuke callbacks ...") def reload_config(): From 8e1342fd086591f713588fbdc6b4380399d0cfdf Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 13 Sep 2022 15:00:35 +0200 Subject: [PATCH 005/115] nuke: menu change to new publisher --- openpype/hosts/nuke/api/pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 26372d0047e..cfc8fd52b24 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -231,7 +231,7 @@ def _install_menu(): ) menu.addCommand( "Publish...", - lambda: host_tools.show_publish(parent=main_window) + lambda: host_tools.show_publisher(parent=main_window) ) menu.addCommand( "Manage...", From 7a42beb2db9187e9180b75f2cc5a45d8b7081fa9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 13 Sep 2022 15:01:05 +0200 Subject: [PATCH 006/115] nuke: add update/get context data --- openpype/hosts/nuke/api/pipeline.py | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index cfc8fd52b24..373fd7134b5 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -1,6 +1,7 @@ import nuke import os +import json import importlib from collections import OrderedDict @@ -34,6 +35,8 @@ from .command import viewer_update_and_undo_stop from .lib import ( Context, + imprint, + Knobby, get_main_window, add_publish_knob, WorkfileSettings, @@ -133,10 +136,22 @@ def install(self): launch_workfiles_app() def get_context_data(self): - pass - - def update_context_data(self, data): - pass + root_node = nuke.root() + context_value = root_node["publish_context"].getValue() + return json.loads(context_value) + + def update_context_data(self, data, changes): + root_node = nuke.root() + imprint( + root_node, + { + "publish_context": Knobby( + "String_Knob", + json.dumps(data), + flags=[nuke.INVISIBLE] + ) + } + ) def add_nuke_callbacks(): From 9c050d47cba9ca85fb75fdf35f678701a9c77fdf Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 13 Sep 2022 22:44:08 +0200 Subject: [PATCH 007/115] nuke: implementing write and read create data functions --- openpype/hosts/nuke/api/lib.py | 100 +++++++++++++--------------- openpype/hosts/nuke/api/pipeline.py | 21 ++---- 2 files changed, 52 insertions(+), 69 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 764e9042951..90c19707d90 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -1,14 +1,13 @@ import os from pprint import pformat import re +import json import six import platform import tempfile import contextlib from collections import OrderedDict -import clique - import nuke from Qt import QtCore, QtWidgets @@ -64,6 +63,7 @@ 26, # Text Knob (But for backward compatibility, still be read # if value is not an empty string.) ) +JSON_PREFIX = "JSON:::" class Context: @@ -95,8 +95,38 @@ def get_main_window(): return Context.main_window +def write_create_data(node, knobname, data): + knob_value = JSON_PREFIX + json.dumps(data) + if knobname in node.knobs(): + knob = node[knobname] + knob.setValue(knob_value) + return + + knob = nuke.String_Knob(knobname) + knob.setValue(knob_value) + knob.setFlag(nuke.INVISIBLE) + node.addKnob(knob) + + +def read_create_data(node, knobname): + if knobname not in node.knobs(): + log.debug("get knob: {}".format(node[knobname])) + return + + rawdata = node[knobname].getValue() + if ( + isinstance(rawdata, six.string_types) + and rawdata.startswith(JSON_PREFIX) + ): + try: + return json.loads(rawdata[len(JSON_PREFIX):]) + except json.JSONDecodeError: + return + + class Knobby(object): - """For creating knob which it's type isn't mapped in `create_knobs` + """[DEPRICATED] For creating knob which it's type isn't + mapped in `create_knobs` Args: type (string): Nuke knob type name @@ -121,9 +151,15 @@ def create(self, name, nice=None): knob.setFlag(flag) return knob + @staticmethod + def nice_naming(key): + """Convert camelCase name into UI Display Name""" + words = re.findall('[A-Z][^A-Z]*', key[0].upper() + key[1:]) + return " ".join(words) + def create_knobs(data, tab=None): - """Create knobs by data + """[DEPRICATED] Create knobs by data Depending on the type of each dict value and creates the correct Knob. @@ -217,7 +253,7 @@ def nice_naming(key): def imprint(node, data, tab=None): - """Store attributes with value on node + """[DEPRICATED] Store attributes with value on node Parse user data into Node knobs. Use `collections.OrderedDict` to ensure knob order. @@ -273,7 +309,7 @@ def imprint(node, data, tab=None): def add_publish_knob(node): - """Add Publish knob to node + """[DEPRICATED] Add Publish knob to node Arguments: node (nuke.Node): nuke node to be processed @@ -291,7 +327,7 @@ def add_publish_knob(node): def set_avalon_knob_data(node, data=None, prefix="avalon:"): - """ Sets data into nodes's avalon knob + """[DEPRICATED] Sets data into nodes's avalon knob Arguments: node (nuke.Node): Nuke node to imprint with data, @@ -353,7 +389,7 @@ def set_avalon_knob_data(node, data=None, prefix="avalon:"): def get_avalon_knob_data(node, prefix="avalon:"): - """ Gets a data from nodes's avalon knob + """[DEPRICATED] Gets a data from nodes's avalon knob Arguments: node (obj): Nuke node to search for data, @@ -393,7 +429,7 @@ def get_avalon_knob_data(node, prefix="avalon:"): def fix_data_for_node_create(data): - """Fixing data to be used for nuke knobs + """[DEPRICATED] Fixing data to be used for nuke knobs """ for k, v in data.items(): if isinstance(v, six.text_type): @@ -404,7 +440,7 @@ def fix_data_for_node_create(data): def add_write_node_legacy(name, **kwarg): - """Adding nuke write node + """[DEPRICATED] Adding nuke write node Arguments: name (str): nuke node name kwarg (attrs): data for nuke knobs @@ -567,7 +603,7 @@ def get_nuke_imageio_settings(): def get_created_node_imageio_setting_legacy(nodeclass, creator, subset): - ''' Get preset data for dataflow (fileType, compression, bitDepth) + '''[DEPRICATED] Get preset data for dataflow (fileType, compression, bitDepth) ''' assert any([creator, nodeclass]), nuke.message( @@ -2811,48 +2847,6 @@ def dirmap_file_name_filter(file_name): return file_name -# ------------------------------------ -# This function seems to be deprecated -# ------------------------------------ -def ls_img_sequence(path): - """Listing all available coherent image sequence from path - - Arguments: - path (str): A nuke's node object - - Returns: - data (dict): with nuke formated path and frameranges - """ - file = os.path.basename(path) - dirpath = os.path.dirname(path) - base, ext = os.path.splitext(file) - name, padding = os.path.splitext(base) - - # populate list of files - files = [ - f for f in os.listdir(dirpath) - if name in f - if ext in f - ] - - # create collection from list of files - collections, reminder = clique.assemble(files) - - if len(collections) > 0: - head = collections[0].format("{head}") - padding = collections[0].format("{padding}") % 1 - padding = "#" * len(padding) - tail = collections[0].format("{tail}") - file = head + padding + tail - - return { - "path": os.path.join(dirpath, file).replace("\\", "/"), - "frames": collections[0].format("[{ranges}]") - } - - return False - - def get_group_io_nodes(nodes): """Get the input and the output of a group of nodes.""" diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 373fd7134b5..392573e1f65 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -1,7 +1,6 @@ import nuke import os -import json import importlib from collections import OrderedDict @@ -35,8 +34,6 @@ from .command import viewer_update_and_undo_stop from .lib import ( Context, - imprint, - Knobby, get_main_window, add_publish_knob, WorkfileSettings, @@ -49,7 +46,9 @@ on_script_load, dirmap_file_name_filter, add_scripts_menu, - add_scripts_gizmo + add_scripts_gizmo, + read_create_data, + write_create_data ) from .lib_template_builder import ( create_placeholder, update_placeholder @@ -137,21 +136,11 @@ def install(self): def get_context_data(self): root_node = nuke.root() - context_value = root_node["publish_context"].getValue() - return json.loads(context_value) + return read_create_data(root_node, "publish_context") def update_context_data(self, data, changes): root_node = nuke.root() - imprint( - root_node, - { - "publish_context": Knobby( - "String_Knob", - json.dumps(data), - flags=[nuke.INVISIBLE] - ) - } - ) + write_create_data(root_node, "publish_context", data) def add_nuke_callbacks(): From 69c964d806c993ab4d5b5e72591bdb137bfbb098 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 15 Sep 2022 10:23:24 +0200 Subject: [PATCH 008/115] nuke: new creator wip --- openpype/hosts/nuke/api/lib.py | 55 +++++++++---- openpype/hosts/nuke/api/pipeline.py | 20 +++-- openpype/hosts/nuke/api/plugin.py | 121 +++++++++++++++++++++++++++- 3 files changed, 171 insertions(+), 25 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 90c19707d90..9959ed79ea6 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -64,6 +64,8 @@ # if value is not an empty string.) ) JSON_PREFIX = "JSON:::" +ROOT_DATA_KNOB = "publish_context" +INSTANCE_DATA_KNOB = "publish_instance" class Context: @@ -95,22 +97,32 @@ def get_main_window(): return Context.main_window -def write_create_data(node, knobname, data): - knob_value = JSON_PREFIX + json.dumps(data) +def write_node_data(node, knobname, data): + # if exists then update data if knobname in node.knobs(): - knob = node[knobname] - knob.setValue(knob_value) + log.debug("Updating knobname `{}` on node `{}`".format( + knobname, node.name() + )) + update_node_data(node, knobname, data) return + log.debug("Creating knobname `{}` on node `{}`".format( + knobname, node.name() + )) + # else create new + knob_value = JSON_PREFIX + json.dumps(data) knob = nuke.String_Knob(knobname) knob.setValue(knob_value) knob.setFlag(nuke.INVISIBLE) node.addKnob(knob) -def read_create_data(node, knobname): +def read_node_data(node, knobname): + if knobname not in node.knobs(): - log.debug("get knob: {}".format(node[knobname])) + log.warnig("Knobname `{}` does not exist on node `{}`".format( + knobname, node.name() + )) return rawdata = node[knobname].getValue() @@ -124,6 +136,14 @@ def read_create_data(node, knobname): return +def update_node_data(node, knobname, data): + knob = node[knobname] + node_data = read_node_data(node, knobname) + node_data.update(data) + knob_value = JSON_PREFIX + json.dumps(node_data) + knob.setValue(knob_value) + + class Knobby(object): """[DEPRICATED] For creating knob which it's type isn't mapped in `create_knobs` @@ -2168,11 +2188,14 @@ def reset_frame_range_handles(self): node['frame_range_lock'].setValue(True) # adding handle_start/end to root avalon knob - if not set_avalon_knob_data(self._root_node, { - "handleStart": int(handle_start), - "handleEnd": int(handle_end) - }): - log.warning("Cannot set Avalon knob to Root node!") + write_node_data( + self._root_node, + INSTANCE_DATA_KNOB, + { + "handleStart": int(handle_start), + "handleEnd": int(handle_end) + } + ) def reset_resolution(self): """Set resolution to project resolution.""" @@ -2295,7 +2318,6 @@ def get_write_node_template_attr(node): subset=avalon_knob_data["subset"] ) - # collecting correct data correct_data = OrderedDict() @@ -2347,10 +2369,11 @@ def get_dependent_nodes(nodes): def find_free_space_to_paste_nodes( - nodes, - group=nuke.root(), - direction="right", - offset=300): + nodes, + group=nuke.root(), + direction="right", + offset=300 +): """ For getting coordinates in DAG (node graph) for placing new nodes diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 392573e1f65..a18d3b54e78 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -34,6 +34,7 @@ from .command import viewer_update_and_undo_stop from .lib import ( Context, + ROOT_DATA_KNOB, get_main_window, add_publish_knob, WorkfileSettings, @@ -47,8 +48,8 @@ dirmap_file_name_filter, add_scripts_menu, add_scripts_gizmo, - read_create_data, - write_create_data + read_node_data, + write_node_data ) from .lib_template_builder import ( create_placeholder, update_placeholder @@ -136,11 +137,11 @@ def install(self): def get_context_data(self): root_node = nuke.root() - return read_create_data(root_node, "publish_context") + return read_node_data(root_node, ROOT_DATA_KNOB) def update_context_data(self, data, changes): root_node = nuke.root() - write_create_data(root_node, "publish_context", data) + write_node_data(root_node, ROOT_DATA_KNOB, data) def add_nuke_callbacks(): @@ -492,7 +493,7 @@ def ls(): yield container -def list_instances(): +def list_instances(creator_id=None): """List all created instances to publish from current workfile. For SubsetManager @@ -514,7 +515,7 @@ def list_instances(): # get data from avalon knob avalon_knob_data = get_avalon_knob_data( - node, ["avalon:", "ak:"]) + node) if not avalon_knob_data: continue @@ -522,8 +523,13 @@ def list_instances(): if avalon_knob_data["id"] != "pyblish.avalon.instance": continue + if creator_id and avalon_knob_data["identifier"] != creator_id: + continue + # add node name - avalon_knob_data["name"] = node.name() + avalon_knob_data.update({ + "instance_node": node + }) instances.append(avalon_knob_data) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 37ce03dc55c..302d6c5cd72 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -1,15 +1,23 @@ +import nuke + import os +import sys +import six import random import string from collections import OrderedDict from abc import abstractmethod - -import nuke +from abc import ( + ABCMeta +) from openpype.api import get_current_project_settings from openpype.pipeline import ( LegacyCreator, LoaderPlugin, + CreatorError, + Creator as NewCreator, + CreatedInstance ) from .lib import ( Knobby, @@ -21,6 +29,115 @@ set_node_knobs_from_settings, get_view_process_node ) +from .pipeline import ( + list_instances +) + + +class OpenPypeCreatorError(CreatorError): + pass + + +@six.add_metaclass(ABCMeta) +class NukeCreator(NewCreator): + selected_nodes = [] + + def _create_instance_node( + self, + node_name, + knobs=None, + parent=None, + node_type="NoOp" + ): + """Create node representing instance. + + Arguments: + node_name (str): Name of the new node. + knobs (OrderedDict): knobs name and values + parent (str): Name of the parent node. + node_type (str, optional): Type of the node. + + Returns: + nuke.Node: Newly created instance node. + + """ + node_knobs = knobs or {} + + # set parent node + parent_node = nuke.root() + if parent: + parent_node = nuke.toNode(parent) + + with parent_node: + created_node = nuke.createNode(node_type) + created_node["name"].setValue(node_name) + + for key, values in node_knobs.items(): + if key in created_node.knobs(): + created_node["key"].setValue(values) + + return created_node + + # def create(self, subset_name, instance_data, pre_create_data): + # try: + # if pre_create_data.get("use_selection"): + # self.selected_nodes = nuke.selectedNodes() + + # # Get the node type and remove it from the data, not needed + # _node_type = instance_data.pop("node_type", None) + # if _node_type is None: + # _node_type = "NoOp" + + # instance_node = self._create_instance_node( + # subset_name, node_type=_node_type, pre_create_data) + + # instance_data["instance_node"] = instance_node.path() + + # instance = CreatedInstance( + # self.family, + # subset_name, + # instance_data, + # self) + # self._add_instance_to_context(instance) + # imprint(instance_node, instance.data_to_store()) + # return instance + + # except hou.Error as er: + # six.reraise( + # OpenPypeCreatorError, + # OpenPypeCreatorError("Creator error: {}".format(er)), + # sys.exc_info()[2]) + + # def collect_instances(self): + # for instance_data in list_instances(creator_id=self.identifier): + # created_instance = CreatedInstance.from_existing( + # instance_data, self + # ) + # self._add_instance_to_context(created_instance) + + # def update_instances(self, update_list): + # for created_inst, _changes in update_list: + # instance_node = created_inst.pop("instance_node", None) + # current_data = created_inst.data + + # imprint( + # instance_node, + # { + # key: value[1] for key, value in _changes.items() + # if current_data.get(key) != value[1] + # }, + # update=True + # ) + + # def remove_instances(self, instances): + # for instance in instances: + # remove_instance(instance) + # self._remove_instance_from_context(instance) + + # def get_pre_create_attr_defs(self): + # return [ + # BoolDef("use_selection", label="Use selection") + # ] class OpenPypeCreator(LegacyCreator): From 13f9789dd2308921449536d9a1aa77e2afeb5184 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 13:00:39 +0200 Subject: [PATCH 009/115] nuke: renaming and fixing node data setter and getter --- openpype/hosts/nuke/api/lib.py | 22 ++++++++++++++-------- openpype/hosts/nuke/api/pipeline.py | 9 +++++---- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 9959ed79ea6..d61d8c161ee 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -97,7 +97,8 @@ def get_main_window(): return Context.main_window -def write_node_data(node, knobname, data): +def set_node_data(node, knobname, data): + # TODO: doc string # if exists then update data if knobname in node.knobs(): log.debug("Updating knobname `{}` on node `{}`".format( @@ -107,8 +108,8 @@ def write_node_data(node, knobname, data): return log.debug("Creating knobname `{}` on node `{}`".format( - knobname, node.name() - )) + knobname, node.name() + )) # else create new knob_value = JSON_PREFIX + json.dumps(data) knob = nuke.String_Knob(knobname) @@ -117,8 +118,8 @@ def write_node_data(node, knobname, data): node.addKnob(knob) -def read_node_data(node, knobname): - +def get_node_data(node, knobname): + # TODO: doc string if knobname not in node.knobs(): log.warnig("Knobname `{}` does not exist on node `{}`".format( knobname, node.name() @@ -137,8 +138,9 @@ def read_node_data(node, knobname): def update_node_data(node, knobname, data): + # TODO: doc string knob = node[knobname] - node_data = read_node_data(node, knobname) + node_data = get_node_data(node, knobname) or {} node_data.update(data) knob_value = JSON_PREFIX + json.dumps(node_data) knob.setValue(knob_value) @@ -2179,7 +2181,8 @@ def reset_frame_range_handles(self): range = '{0}-{1}'.format( int(data["frameStart"]), - int(data["frameEnd"])) + int(data["frameEnd"]) + ) for node in nuke.allNodes(filter="Viewer"): node['frame_range'].setValue(range) @@ -2188,7 +2191,10 @@ def reset_frame_range_handles(self): node['frame_range_lock'].setValue(True) # adding handle_start/end to root avalon knob - write_node_data( + log.debug("self._root_node: {}".format(self._root_node)) + log.debug("self._root_node: {}".format(self._root_node)) + + set_node_data( self._root_node, INSTANCE_DATA_KNOB, { diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index ddc93d72566..3a8c235ee4c 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -44,8 +44,9 @@ dirmap_file_name_filter, add_scripts_menu, add_scripts_gizmo, - read_node_data, - write_node_data + get_node_data, + set_node_data, + update_node_data ) from .workfile_template_builder import ( NukePlaceholderLoadPlugin, @@ -137,11 +138,11 @@ def install(self): def get_context_data(self): root_node = nuke.root() - return read_node_data(root_node, ROOT_DATA_KNOB) + return get_node_data(root_node, ROOT_DATA_KNOB) def update_context_data(self, data, changes): root_node = nuke.root() - write_node_data(root_node, ROOT_DATA_KNOB, data) + set_node_data(root_node, ROOT_DATA_KNOB, data) def add_nuke_callbacks(): From 615b7780918f8659c6e559817bacaa7b549e661b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 13:07:02 +0200 Subject: [PATCH 010/115] Nuke: adding docstrings --- openpype/hosts/nuke/api/lib.py | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index d61d8c161ee..d9d3752d104 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -98,7 +98,16 @@ def get_main_window(): def set_node_data(node, knobname, data): - # TODO: doc string + """Write data to node invisible knob + + Will create new in case it doesnt exists + or update the one already created. + + Args: + node (nuke.Node): node object + knobname (str): knob name + data (dict): data to be stored in knob + """ # if exists then update data if knobname in node.knobs(): log.debug("Updating knobname `{}` on node `{}`".format( @@ -119,7 +128,15 @@ def set_node_data(node, knobname, data): def get_node_data(node, knobname): - # TODO: doc string + """Read data from node. + + Args: + node (nuke.Node): node object + knobname (str): knob name + + Returns: + dict: data stored in knob + """ if knobname not in node.knobs(): log.warnig("Knobname `{}` does not exist on node `{}`".format( knobname, node.name() @@ -138,7 +155,13 @@ def get_node_data(node, knobname): def update_node_data(node, knobname, data): - # TODO: doc string + """Update already present data. + + Args: + node (nuke.Node): node object + knobname (str): knob name + data (dict): data to update knob value + """ knob = node[knobname] node_data = get_node_data(node, knobname) or {} node_data.update(data) From 6a657f9d1a8a9df5ed485261633275a5939599ba Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 21:32:39 +0200 Subject: [PATCH 011/115] nuke: updating api --- openpype/hosts/nuke/api/__init__.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index 0cbae94bc5d..002e4e3dc68 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -9,7 +9,11 @@ from .command import ( viewer_update_and_undo_stop ) -from .plugin import OpenPypeCreator +from .plugin import ( + NukeCreator, + NukeCreatorError, + OpenPypeCreator +) from .pipeline import ( NukeHost, @@ -26,11 +30,16 @@ get_workfile_build_placeholder_plugins, ) from .lib import ( + INSTANCE_DATA_KNOB, + ROOT_DATA_KNOB, maintained_selection, reset_selection, get_view_process_node, duplicate_node, - convert_knob_value_to_correct_type + convert_knob_value_to_correct_type, + get_node_data, + set_node_data, + update_node_data ) from .utils import ( colorspace_exists_on_node, @@ -47,6 +56,8 @@ "viewer_update_and_undo_stop", + "NukeCreator", + "NukeCreatorError", "OpenPypeCreator", "NukeHost", @@ -62,11 +73,16 @@ "get_workfile_build_placeholder_plugins", + "INSTANCE_DATA_KNOB", + "ROOT_DATA_KNOB", "maintained_selection", "reset_selection", "get_view_process_node", "duplicate_node", "convert_knob_value_to_correct_type", + "get_node_data", + "set_node_data", + "update_node_data", "colorspace_exists_on_node", "get_colorspace_list" From 4a890a452d162110b93bca99a38129f12443d1e6 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 21:36:54 +0200 Subject: [PATCH 012/115] nuke: removing create from menu --- openpype/hosts/nuke/api/pipeline.py | 10 +++------- openpype/settings/defaults/project_settings/nuke.json | 1 - .../schemas/projects_schema/schema_project_nuke.json | 5 ----- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 3a8c235ee4c..5abe182c5ea 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -231,8 +231,8 @@ def _install_menu(): menu.addSeparator() menu.addCommand( - "Create...", - lambda: host_tools.show_creator(parent=main_window) + "Publish...", + lambda: host_tools.show_publisher(parent=main_window) ) menu.addCommand( "Load...", @@ -241,14 +241,11 @@ def _install_menu(): use_context=True ) ) - menu.addCommand( - "Publish...", - lambda: host_tools.show_publisher(parent=main_window) - ) menu.addCommand( "Manage...", lambda: host_tools.show_scene_inventory(parent=main_window) ) + menu.addSeparator() menu.addCommand( "Library...", lambda: host_tools.show_library_loader( @@ -344,7 +341,6 @@ def add_shortcuts_from_presets(): if nuke_presets.get("menu"): menu_label_mapping = { "manage": "Manage...", - "create": "Create...", "load": "Load...", "build_workfile": "Build Workfile", "publish": "Publish..." diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index c3eda2cbb42..7b3d07d4415 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -1,7 +1,6 @@ { "general": { "menu": { - "create": "ctrl+shift+alt+c", "publish": "ctrl+alt+p", "load": "ctrl+alt+l", "manage": "ctrl+alt+m", diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json index 7cf82b9e69a..c21df7d44d5 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json @@ -17,11 +17,6 @@ "key": "menu", "label": "OpenPype Menu shortcuts", "children": [ - { - "type": "text", - "key": "create", - "label": "Create..." - }, { "type": "text", "key": "publish", From 1ce3fa421a61722815653f34f585f9589b20c9e8 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 21:37:59 +0200 Subject: [PATCH 013/115] nuke: adding abstract NukeCreator class --- openpype/hosts/nuke/api/plugin.py | 153 ++++++++++++++++-------------- 1 file changed, 83 insertions(+), 70 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 302d6c5cd72..5ac144b2c72 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -12,6 +12,7 @@ ) from openpype.api import get_current_project_settings +from openpype.lib import BoolDef from openpype.pipeline import ( LegacyCreator, LoaderPlugin, @@ -20,6 +21,7 @@ CreatedInstance ) from .lib import ( + INSTANCE_DATA_KNOB, Knobby, check_subsetname_exists, maintained_selection, @@ -27,14 +29,16 @@ add_publish_knob, get_nuke_imageio_settings, set_node_knobs_from_settings, - get_view_process_node + get_view_process_node, + set_node_data ) from .pipeline import ( - list_instances + list_instances, + remove_instance ) -class OpenPypeCreatorError(CreatorError): +class NukeCreatorError(CreatorError): pass @@ -47,7 +51,7 @@ def _create_instance_node( node_name, knobs=None, parent=None, - node_type="NoOp" + node_type=None ): """Create node representing instance. @@ -61,6 +65,8 @@ def _create_instance_node( nuke.Node: Newly created instance node. """ + node_type = node_type or "NoOp" + node_knobs = knobs or {} # set parent node @@ -68,76 +74,83 @@ def _create_instance_node( if parent: parent_node = nuke.toNode(parent) - with parent_node: - created_node = nuke.createNode(node_type) - created_node["name"].setValue(node_name) + try: + with parent_node: + created_node = nuke.createNode(node_type) + created_node["name"].setValue(node_name) - for key, values in node_knobs.items(): - if key in created_node.knobs(): - created_node["key"].setValue(values) + for key, values in node_knobs.items(): + if key in created_node.knobs(): + created_node["key"].setValue(values) + except Exception as _err: + raise NukeCreatorError("Creating have failed: {}".format(_err)) return created_node - # def create(self, subset_name, instance_data, pre_create_data): - # try: - # if pre_create_data.get("use_selection"): - # self.selected_nodes = nuke.selectedNodes() - - # # Get the node type and remove it from the data, not needed - # _node_type = instance_data.pop("node_type", None) - # if _node_type is None: - # _node_type = "NoOp" - - # instance_node = self._create_instance_node( - # subset_name, node_type=_node_type, pre_create_data) - - # instance_data["instance_node"] = instance_node.path() - - # instance = CreatedInstance( - # self.family, - # subset_name, - # instance_data, - # self) - # self._add_instance_to_context(instance) - # imprint(instance_node, instance.data_to_store()) - # return instance - - # except hou.Error as er: - # six.reraise( - # OpenPypeCreatorError, - # OpenPypeCreatorError("Creator error: {}".format(er)), - # sys.exc_info()[2]) - - # def collect_instances(self): - # for instance_data in list_instances(creator_id=self.identifier): - # created_instance = CreatedInstance.from_existing( - # instance_data, self - # ) - # self._add_instance_to_context(created_instance) - - # def update_instances(self, update_list): - # for created_inst, _changes in update_list: - # instance_node = created_inst.pop("instance_node", None) - # current_data = created_inst.data - - # imprint( - # instance_node, - # { - # key: value[1] for key, value in _changes.items() - # if current_data.get(key) != value[1] - # }, - # update=True - # ) - - # def remove_instances(self, instances): - # for instance in instances: - # remove_instance(instance) - # self._remove_instance_from_context(instance) - - # def get_pre_create_attr_defs(self): - # return [ - # BoolDef("use_selection", label="Use selection") - # ] + def create(self, subset_name, instance_data, pre_create_data): + try: + if pre_create_data.get("use_selection"): + self.selected_nodes = nuke.selectedNodes() + else: + self.selected_nodes = None + + instance_node = self._create_instance_node( + subset_name, + node_type=instance_data.pop("node_type", None) + ) + + instance = CreatedInstance( + self.family, + subset_name, + instance_data, + self) + + instance.transient_data["node"] = instance_node + + self._add_instance_to_context(instance) + + set_node_data( + instance_node, INSTANCE_DATA_KNOB, instance.data_to_store()) + + return instance + + except Exception as er: + six.reraise( + NukeCreatorError, + NukeCreatorError("Creator error: {}".format(er)), + sys.exc_info()[2]) + + def collect_instances(self): + for (node, data) in list_instances(creator_id=self.identifier): + created_instance = CreatedInstance.from_existing( + data, self + ) + created_instance.transient_data["node"] = node + self._add_instance_to_context(created_instance) + + def update_instances(self, update_list): + for created_inst, _changes in update_list: + instance_node = created_inst.transient_data["node"] + current_data = created_inst.data + + set_node_data( + instance_node, + INSTANCE_DATA_KNOB, + { + key: value[1] for key, value in _changes.items() + if current_data.get(key) != value[1] + } + ) + + def remove_instances(self, instances): + for instance in instances: + remove_instance(instance) + self._remove_instance_from_context(instance) + + def get_pre_create_attr_defs(self): + return [ + BoolDef("use_selection", label="Use selection") + ] class OpenPypeCreator(LegacyCreator): From 02ac5c19e93970e5c86411eaa5b6c28db72cd6ff Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 21:39:01 +0200 Subject: [PATCH 014/115] nuke: improving workfile creator --- .../nuke/plugins/create/workfile_creator.py | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/workfile_creator.py b/openpype/hosts/nuke/plugins/create/workfile_creator.py index 9ceaf376c1f..f2227737b48 100644 --- a/openpype/hosts/nuke/plugins/create/workfile_creator.py +++ b/openpype/hosts/nuke/plugins/create/workfile_creator.py @@ -5,6 +5,7 @@ CreatedInstance, legacy_io, ) +import nuke class WorkfileCreator(AutoCreator): @@ -17,14 +18,37 @@ def get_instance_attr_defs(self): return [] def collect_instances(self): - for instance_data in api.list_instances(): - creator_id = instance_data.get("creator_identifier") - if creator_id == self.identifier: - subset_name = instance_data["subset"] - instance = CreatedInstance( - self.family, subset_name, instance_data, self - ) - self._add_instance_to_context(instance) + root_node = nuke.root() + instance_data = api.get_node_data( + root_node, api.INSTANCE_DATA_KNOB + ) + self.log.debug("__ instance_data: {}".format(instance_data)) + + project_name = legacy_io.Session["AVALON_PROJECT"] + asset_name = legacy_io.Session["AVALON_ASSET"] + task_name = legacy_io.Session["AVALON_TASK"] + host_name = legacy_io.Session["AVALON_APP"] + + asset_doc = get_asset_by_name(project_name, asset_name) + subset_name = self.get_subset_name( + self.default_variant, task_name, asset_doc, + project_name, host_name + ) + self.log.debug("__ subset_name: {}".format(subset_name)) + instance_data.update({ + "asset": asset_name, + "task": task_name, + "variant": self.default_variant + }) + instance_data.update(self.get_dynamic_data( + self.default_variant, task_name, asset_doc, + project_name, host_name + )) + + instance = CreatedInstance( + self.family, subset_name, instance_data, self + ) + self._add_instance_to_context(instance) def update_instances(self, update_list): # nothing to change on workfiles @@ -42,6 +66,8 @@ def create(self, options=None): task_name = legacy_io.Session["AVALON_TASK"] host_name = legacy_io.Session["AVALON_APP"] + self.log.debug("__ existing_instance: {}".format(existing_instance)) + if existing_instance is None: asset_doc = get_asset_by_name(project_name, asset_name) subset_name = self.get_subset_name( From 7b30692171bd377e6718f59e0d65dae2e8bb98f1 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 21:44:21 +0200 Subject: [PATCH 015/115] nuke: improving list/remove/select instance functions --- openpype/hosts/nuke/api/pipeline.py | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 5abe182c5ea..ecf38812cc6 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -31,6 +31,7 @@ from .lib import ( Context, ROOT_DATA_KNOB, + INSTANCE_DATA_KNOB, get_main_window, add_publish_knob, WorkfileSettings, @@ -504,8 +505,8 @@ def list_instances(creator_id=None): Returns: (list) of dictionaries matching instances format """ - instances = [] - for node in nuke.allNodes(): + listed_instances = [] + for node in nuke.allNodes(recurseGroups=True): if node.Class() in ["Viewer", "Dot"]: continue @@ -513,30 +514,29 @@ def list_instances(creator_id=None): try: if node["disable"].value(): continue - except Exception as E: - log.warning(E) + except Exception as _exc: + log.debug("Node {} have no disable knob - {}".format( + node.fullName(), _exc)) # get data from avalon knob - avalon_knob_data = get_avalon_knob_data( - node) + instance_data = get_node_data( + node, INSTANCE_DATA_KNOB) - if not avalon_knob_data: + if not instance_data: continue - if avalon_knob_data["id"] != "pyblish.avalon.instance": + if instance_data["id"] != "pyblish.avalon.instance": continue - if creator_id and avalon_knob_data["identifier"] != creator_id: + log.debug("_ creator_id: {}".format(creator_id)) + if creator_id and instance_data["creator_identifier"] != creator_id: continue - # add node name - avalon_knob_data.update({ - "instance_node": node - }) + listed_instances.append((node, instance_data)) instances.append(avalon_knob_data) - return instances + return listed_instances def remove_instance(instance): @@ -547,8 +547,8 @@ def remove_instance(instance): Args: instance (dict): instance representation from subsetmanager model """ - node = nuke.toNode(instance["name"]) - nuke.delete(node) + instance_node = instance.transient_data["node"] + nuke.delete(instance_node) def select_instance(instance): @@ -558,5 +558,5 @@ def select_instance(instance): Args: instance (dict): instance representation from subsetmanager model """ - node = nuke.toNode(instance["name"]) - node["selected"].setValue(True) + instance_node = instance.transient_data["node"] + instance_node["selected"].setValue(True) From e84eb355b6c978cb978487a74fc11c4f83bc1caf Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 21:46:25 +0200 Subject: [PATCH 016/115] nuke: remove residual code --- openpype/hosts/nuke/api/pipeline.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index ecf38812cc6..cbe8b547c6d 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -534,8 +534,6 @@ def list_instances(creator_id=None): listed_instances.append((node, instance_data)) - instances.append(avalon_knob_data) - return listed_instances From 9e609984e1b2b9225f49e7b2e3b60ac0be13dcfb Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 21:46:53 +0200 Subject: [PATCH 017/115] nuke: no need to log --- openpype/hosts/nuke/api/lib.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index d9d3752d104..211bab2d80e 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -138,9 +138,6 @@ def get_node_data(node, knobname): dict: data stored in knob """ if knobname not in node.knobs(): - log.warnig("Knobname `{}` does not exist on node `{}`".format( - knobname, node.name() - )) return rawdata = node[knobname].getValue() @@ -2213,10 +2210,6 @@ def reset_frame_range_handles(self): node['frame_range'].setValue(range) node['frame_range_lock'].setValue(True) - # adding handle_start/end to root avalon knob - log.debug("self._root_node: {}".format(self._root_node)) - log.debug("self._root_node: {}".format(self._root_node)) - set_node_data( self._root_node, INSTANCE_DATA_KNOB, From 541b9d41f2460e4da3a24f4188ec3309546a992a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 22:25:02 +0200 Subject: [PATCH 018/115] nuke: workfile creator cleaning --- .../nuke/plugins/create/workfile_creator.py | 50 ++----------------- 1 file changed, 4 insertions(+), 46 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/workfile_creator.py b/openpype/hosts/nuke/plugins/create/workfile_creator.py index f2227737b48..ae54d6bcb29 100644 --- a/openpype/hosts/nuke/plugins/create/workfile_creator.py +++ b/openpype/hosts/nuke/plugins/create/workfile_creator.py @@ -48,6 +48,7 @@ def collect_instances(self): instance = CreatedInstance( self.family, subset_name, instance_data, self ) + instance.transient_data["node"] = root_node self._add_instance_to_context(instance) def update_instances(self, update_list): @@ -55,49 +56,6 @@ def update_instances(self, update_list): pass def create(self, options=None): - existing_instance = None - for instance in self.create_context.instances: - if instance.family == self.family: - existing_instance = instance - break - - project_name = legacy_io.Session["AVALON_PROJECT"] - asset_name = legacy_io.Session["AVALON_ASSET"] - task_name = legacy_io.Session["AVALON_TASK"] - host_name = legacy_io.Session["AVALON_APP"] - - self.log.debug("__ existing_instance: {}".format(existing_instance)) - - if existing_instance is None: - asset_doc = get_asset_by_name(project_name, asset_name) - subset_name = self.get_subset_name( - self.default_variant, task_name, asset_doc, - project_name, host_name - ) - data = { - "asset": asset_name, - "task": task_name, - "variant": self.default_variant - } - data.update(self.get_dynamic_data( - self.default_variant, task_name, asset_doc, - project_name, host_name - )) - - new_instance = CreatedInstance( - self.family, subset_name, data, self - ) - self._add_instance_to_context(new_instance) - - elif ( - existing_instance["asset"] != asset_name - or existing_instance["task"] != task_name - ): - asset_doc = get_asset_by_name(project_name, asset_name) - subset_name = self.get_subset_name( - self.default_variant, task_name, asset_doc, - project_name, host_name - ) - existing_instance["asset"] = asset_name - existing_instance["task"] = task_name - existing_instance["subset"] = subset_name + # no need to create if it is created + # in `collect_instances` + pass From 5cde873d504e71970868301d33ffe4ffae4daaa5 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Sep 2022 22:25:10 +0200 Subject: [PATCH 019/115] fixing updating --- openpype/hosts/nuke/api/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 5ac144b2c72..af29fa2dd17 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -138,7 +138,7 @@ def update_instances(self, update_list): INSTANCE_DATA_KNOB, { key: value[1] for key, value in _changes.items() - if current_data.get(key) != value[1] + if current_data.get(key) != value[0] } ) From 495ea784148687c3e9a6437b9a949d0dfd17f71b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 3 Oct 2022 12:31:54 +0200 Subject: [PATCH 020/115] nuke: refactory Backdrop Creator to new publisher --- openpype/hosts/nuke/api/__init__.py | 2 + openpype/hosts/nuke/api/plugin.py | 77 ++++++++++++--- .../nuke/plugins/create/create_backdrop.py | 95 +++++++++---------- 3 files changed, 112 insertions(+), 62 deletions(-) diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index 002e4e3dc68..8b18d4bc3b5 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -34,6 +34,7 @@ ROOT_DATA_KNOB, maintained_selection, reset_selection, + select_nodes, get_view_process_node, duplicate_node, convert_knob_value_to_correct_type, @@ -77,6 +78,7 @@ "ROOT_DATA_KNOB", "maintained_selection", "reset_selection", + "select_nodes", "get_view_process_node", "duplicate_node", "convert_knob_value_to_correct_type", diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index af29fa2dd17..7cb8bc8b845 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -7,8 +7,10 @@ import string from collections import OrderedDict from abc import abstractmethod -from abc import ( - ABCMeta + +from openpype.client import ( + get_asset_by_name, + get_subsets, ) from openpype.api import get_current_project_settings @@ -18,7 +20,8 @@ LoaderPlugin, CreatorError, Creator as NewCreator, - CreatedInstance + CreatedInstance, + legacy_io ) from .lib import ( INSTANCE_DATA_KNOB, @@ -42,11 +45,39 @@ class NukeCreatorError(CreatorError): pass -@six.add_metaclass(ABCMeta) class NukeCreator(NewCreator): selected_nodes = [] - def _create_instance_node( + def add_info_knob(self, node): + if "OP_info" in node.knobs().keys(): + return + + # add info text + info_knob = nuke.Text_Knob("OP_info", "") + info_knob.setValue(""" +

Do not erase manually !

+

This node is maintained by OpenPype Publisher.

+

We recomand to remove it from the Publisher gui.

+ """) + node.addKnob(info_knob) + + def check_existing_subset(self, subset_name, instance_data): + """Check if existing subset name versions already exists.""" + # Get all subsets of the current asset + project_name = legacy_io.active_project() + asset_doc = get_asset_by_name( + project_name, instance_data["asset"], fields=["_id"] + ) + subset_docs = get_subsets( + project_name, asset_ids=[asset_doc["_id"]], fields=["name"] + ) + existing_subset_names_low = { + subset_doc["name"].lower() + for subset_doc in subset_docs + } + return subset_name.lower() in existing_subset_names_low + + def create_instance_node( self, node_name, knobs=None, @@ -57,9 +88,9 @@ def _create_instance_node( Arguments: node_name (str): Name of the new node. - knobs (OrderedDict): knobs name and values + knobs (OrderedDict): node knobs name and values parent (str): Name of the parent node. - node_type (str, optional): Type of the node. + node_type (str, optional): Nuke node Class. Returns: nuke.Node: Newly created instance node. @@ -79,6 +110,8 @@ def _create_instance_node( created_node = nuke.createNode(node_type) created_node["name"].setValue(node_name) + self.add_info_knob(created_node) + for key, values in node_knobs.items(): if key in created_node.knobs(): created_node["key"].setValue(values) @@ -87,23 +120,39 @@ def _create_instance_node( return created_node + def set_selected_nodes(self, pre_create_data): + if pre_create_data.get("use_selection"): + self.selected_nodes = nuke.selectedNodes() + if self.selected_nodes == []: + raise NukeCreatorError("Creator error: No active selection") + else: + self.selected_nodes = [] + + self.log.debug("Selection is: {}".format(self.selected_nodes)) + def create(self, subset_name, instance_data, pre_create_data): + + # make sure selected nodes are added + self.set_selected_nodes(pre_create_data) + + # make sure subset name is unique + if self.check_existing_subset(subset_name, instance_data): + raise NukeCreatorError( + ("subset {} is already published with different HDA" + "definition.").format(subset_name)) + try: - if pre_create_data.get("use_selection"): - self.selected_nodes = nuke.selectedNodes() - else: - self.selected_nodes = None - instance_node = self._create_instance_node( + instance_node = self.create_instance_node( subset_name, node_type=instance_data.pop("node_type", None) ) - instance = CreatedInstance( self.family, subset_name, instance_data, - self) + self + ) instance.transient_data["node"] = instance_node diff --git a/openpype/hosts/nuke/plugins/create/create_backdrop.py b/openpype/hosts/nuke/plugins/create/create_backdrop.py index 0c11b3f2740..e622fd12be9 100644 --- a/openpype/hosts/nuke/plugins/create/create_backdrop.py +++ b/openpype/hosts/nuke/plugins/create/create_backdrop.py @@ -1,56 +1,55 @@ -import nuke -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - select_nodes, - set_avalon_knob_data +from nukescripts import autoBackdrop + +from openpype.hosts.nuke.api import ( + NukeCreator, + NukeCreatorError, + maintained_selection, + select_nodes + ) -class CreateBackdrop(plugin.OpenPypeCreator): +class CreateBackdrop(NukeCreator): """Add Publishable Backdrop""" - name = "nukenodes" + identifier = "create_backdrop" label = "Create Backdrop" family = "nukenodes" icon = "file-archive-o" - defaults = ["Main"] - - def __init__(self, *args, **kwargs): - super(CreateBackdrop, self).__init__(*args, **kwargs) - self.nodes = nuke.selectedNodes() - self.node_color = "0xdfea5dff" - return - - def process(self): - from nukescripts import autoBackdrop - nodes = list() - if (self.options or {}).get("useSelection"): - nodes = self.nodes - - if len(nodes) >= 1: - select_nodes(nodes) - bckd_node = autoBackdrop() - bckd_node["name"].setValue("{}_BDN".format(self.name)) - bckd_node["tile_color"].setValue(int(self.node_color, 16)) - bckd_node["note_font_size"].setValue(24) - bckd_node["label"].setValue("[{}]".format(self.name)) - # add avalon knobs - instance = set_avalon_knob_data(bckd_node, self.data) - - return instance - else: - msg = str("Please select nodes you " - "wish to add to a container") - self.log.error(msg) - nuke.message(msg) - return - else: - bckd_node = autoBackdrop() - bckd_node["name"].setValue("{}_BDN".format(self.name)) - bckd_node["tile_color"].setValue(int(self.node_color, 16)) - bckd_node["note_font_size"].setValue(24) - bckd_node["label"].setValue("[{}]".format(self.name)) - # add avalon knobs - instance = set_avalon_knob_data(bckd_node, self.data) - - return instance + maintain_selection = True + + # plugin attributes + node_color = "0xdfea5dff" + + def create_instance_node( + self, + node_name, + knobs=None, + parent=None, + node_type=None + ): + with maintained_selection(): + if len(self.selected_nodes) >= 1: + select_nodes(self.selected_nodes) + + created_node = autoBackdrop() + created_node["name"].setValue(node_name) + created_node["tile_color"].setValue(int(self.node_color, 16)) + created_node["note_font_size"].setValue(24) + created_node["label"].setValue("[{}]".format(node_name)) + + return created_node + + def create(self, subset_name, instance_data, pre_create_data): + if self.check_existing_subset(subset_name, instance_data): + raise NukeCreatorError( + ("subset {} is already published with different HDA" + "definition.").format(subset_name)) + + instance = super(CreateBackdrop, self).create( + subset_name, + instance_data, + pre_create_data + ) + + return instance From 72dd122809fc29dddadabebf9692d60ab6043cab Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 3 Oct 2022 12:58:38 +0200 Subject: [PATCH 021/115] nuke: refactory publishing backdrop to new publisher --- .../nuke/plugins/publish/collect_backdrop.py | 18 +++++++++---- .../nuke/plugins/publish/extract_backdrop.py | 26 +++++++++---------- .../nuke/plugins/publish/validate_backdrop.py | 7 ++--- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py index 4efbb88b8c1..688b1054ab7 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py @@ -1,3 +1,4 @@ +from pprint import pformat import pyblish.api from openpype.hosts.nuke.api import lib as pnlib import nuke @@ -14,8 +15,14 @@ class CollectBackdrops(pyblish.api.InstancePlugin): families = ["nukenodes"] def process(self, instance): + self.log.debug(pformat(instance.data)) - bckn = instance[0] + # new publisher way + if instance.data.get("transientData"): + bckn = instance.data["transientData"]["node"] + else: + # or backward compatible + bckn = instance[0] # define size of the backdrop left = bckn.xpos() @@ -23,6 +30,7 @@ def process(self, instance): right = left + bckn['bdwidth'].value() bottom = top + bckn['bdheight'].value() + instance.data["transientData"]["childNodes"] = [] # iterate all nodes for node in nuke.allNodes(): @@ -37,13 +45,13 @@ def process(self, instance): and (node.ypos() + node.screenHeight() < bottom): # add contained nodes to instance's node list - instance.append(node) + instance.data["transientData"]["childNodes"].append(node) # get all connections from outside of backdrop - nodes = instance[1:] + nodes = instance.data["transientData"]["childNodes"] connections_in, connections_out = pnlib.get_dependent_nodes(nodes) - instance.data["nodeConnectionsIn"] = connections_in - instance.data["nodeConnectionsOut"] = connections_out + instance.data["transientData"]["nodeConnectionsIn"] = connections_in + instance.data["transientData"]["nodeConnectionsOut"] = connections_out # make label nicer instance.data["label"] = "{0} ({1} nodes)".format( diff --git a/openpype/hosts/nuke/plugins/publish/extract_backdrop.py b/openpype/hosts/nuke/plugins/publish/extract_backdrop.py index d1e5c4cc5ab..e62c715b9c0 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/extract_backdrop.py @@ -26,8 +26,14 @@ class ExtractBackdropNode(publish.Extractor): families = ["nukenodes"] def process(self, instance): - tmp_nodes = list() - nodes = instance[1:] + tmp_nodes = [] + child_nodes = instance.data["transientData"]["childNodes"] + # all connections outside of backdrop + connections_in = instance.data["transientData"]["nodeConnectionsIn"] + connections_out = instance.data["transientData"]["nodeConnectionsOut"] + self.log.debug("_ connections_in: `{}`".format(connections_in)) + self.log.debug("_ connections_out: `{}`".format(connections_out)) + # Define extract output file path stagingdir = self.staging_dir(instance) filename = "{0}.nk".format(instance.name) @@ -35,20 +41,14 @@ def process(self, instance): # maintain selection with maintained_selection(): - # all connections outside of backdrop - connections_in = instance.data["nodeConnectionsIn"] - connections_out = instance.data["nodeConnectionsOut"] - self.log.debug("_ connections_in: `{}`".format(connections_in)) - self.log.debug("_ connections_out: `{}`".format(connections_out)) - - # create input nodes and name them as passing node (*_INP) + # create input child_nodes and name them as passing node (*_INP) for n, inputs in connections_in.items(): for i, input in inputs: inpn = nuke.createNode("Input") inpn["name"].setValue("{}_{}_INP".format(n.name(), i)) n.setInput(i, inpn) inpn.setXYpos(input.xpos(), input.ypos()) - nodes.append(inpn) + child_nodes.append(inpn) tmp_nodes.append(inpn) reset_selection() @@ -63,13 +63,13 @@ def process(self, instance): if d.name() in n.name()), 0), opn) opn.setInput(0, n) opn.autoplace() - nodes.append(opn) + child_nodes.append(opn) tmp_nodes.append(opn) reset_selection() - # select nodes to copy + # select child_nodes to copy reset_selection() - select_nodes(nodes) + select_nodes(child_nodes) # create tmp nk file # save file to the path nuke.nodeCopy(path) diff --git a/openpype/hosts/nuke/plugins/publish/validate_backdrop.py b/openpype/hosts/nuke/plugins/publish/validate_backdrop.py index 17dc79dc568..7ce3ce0e3f1 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/validate_backdrop.py @@ -60,7 +60,8 @@ class ValidateBackdrop(pyblish.api.InstancePlugin): actions = [SelectCenterInNodeGraph] def process(self, instance): - connections_out = instance.data["nodeConnectionsOut"] + child_nodes = instance.data["transientData"]["childNodes"] + connections_out = instance.data["transientData"]["nodeConnectionsOut"] msg_multiple_outputs = ( "Only one outcoming connection from " @@ -78,10 +79,10 @@ def process(self, instance): self.log.debug( "Amount of nodes on instance: {}".format( - len(instance)) + len(child_nodes)) ) - if len(instance) == 1: + if child_nodes == []: raise PublishXmlValidationError( self, msg_no_nodes, From 4df13d790503620e456a8b40713282b14271f95f Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 3 Oct 2022 12:58:58 +0200 Subject: [PATCH 022/115] nuke: adding info knob to backdrop node creator --- openpype/hosts/nuke/plugins/create/create_backdrop.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/hosts/nuke/plugins/create/create_backdrop.py b/openpype/hosts/nuke/plugins/create/create_backdrop.py index e622fd12be9..40eaab08cf8 100644 --- a/openpype/hosts/nuke/plugins/create/create_backdrop.py +++ b/openpype/hosts/nuke/plugins/create/create_backdrop.py @@ -38,6 +38,8 @@ def create_instance_node( created_node["note_font_size"].setValue(24) created_node["label"].setValue("[{}]".format(node_name)) + self.add_info_knob(created_node) + return created_node def create(self, subset_name, instance_data, pre_create_data): From e9c8144d6edbd6452a50089cf41bb478f147f917 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 3 Oct 2022 20:42:41 +0200 Subject: [PATCH 023/115] nuke: adding apply settings to NukeCreator --- openpype/hosts/nuke/api/plugin.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 7cb8bc8b845..4b85334c035 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -201,6 +201,10 @@ def get_pre_create_attr_defs(self): BoolDef("use_selection", label="Use selection") ] + def apply_settings(self, project_settings, system_settings): + """Method called on initialization of plugin to apply settings.""" + self.creators_settings = project_settings["nuke"]["create"] + class OpenPypeCreator(LegacyCreator): """Pype Nuke Creator class wrapper""" From cab1a09d5fa857fd7b5471600709e3acca513668 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 3 Oct 2022 20:57:05 +0200 Subject: [PATCH 024/115] nuke: adding also active key check in validator --- openpype/hosts/nuke/plugins/publish/validate_knobs.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/publish/validate_knobs.py b/openpype/hosts/nuke/plugins/publish/validate_knobs.py index d44f27791a5..1d853f72b59 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_knobs.py +++ b/openpype/hosts/nuke/plugins/publish/validate_knobs.py @@ -62,7 +62,16 @@ def get_invalid_knobs(cls, context): for instance in context: # Filter publisable instances. - if not instance.data["publish"]: + if ( + instance.data.get("publish") + and instance.data["publish"] is False + ): + continue + + if ( + instance.data.get("active") + and instance.data["active"] is False + ): continue # Filter families. From 86e740c43be228f946835890ab9caaebdb23c542 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 3 Oct 2022 20:57:30 +0200 Subject: [PATCH 025/115] nuke: removing print --- openpype/hosts/nuke/plugins/publish/extract_backdrop.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/extract_backdrop.py b/openpype/hosts/nuke/plugins/publish/extract_backdrop.py index e62c715b9c0..5166fa4b2c0 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/extract_backdrop.py @@ -104,6 +104,3 @@ def process(self, instance): self.log.info("Extracted instance '{}' to: {}".format( instance.name, path)) - - self.log.info("Data {}".format( - instance.data)) From bcac2bd143bcd07517cef7604e7190f0d6c986c4 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 17:13:26 +0200 Subject: [PATCH 026/115] nuke: settings for write attributes --- .../defaults/project_settings/nuke.json | 26 +++++---- .../projects_schema/schema_project_nuke.json | 58 +++++-------------- .../schemas/template_nuke_write_attrs.json | 19 ++++++ 3 files changed, 49 insertions(+), 54 deletions(-) create mode 100644 openpype/settings/entities/schemas/projects_schema/schemas/template_nuke_write_attrs.json diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index 7b3d07d4415..cdb410b378a 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -56,12 +56,15 @@ ], "create": { "CreateWriteRender": { - "fpath_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}", - "defaults": [ + "temp_rendering_path_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}", + "default_variants": [ "Main", "Mask" ], - "knobs": [], + "instance_attributes": [ + "reviewable", + "farm_rendering" + ], "prenodes": { "Reformat01": { "nodeclass": "Reformat", @@ -82,27 +85,28 @@ } }, "CreateWritePrerender": { - "fpath_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}", - "use_range_limit": true, - "defaults": [ + "temp_rendering_path_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}", + "default_variants": [ "Key01", "Bg01", "Fg01", "Branch01", "Part01" ], - "reviewable": false, - "knobs": [], + "instance_attributes": [ + "farm_rendering", + "use_range_limit" + ], "prenodes": {} }, "CreateWriteStill": { - "fpath_template": "{work}/renders/nuke/{subset}/{subset}.{ext}", - "defaults": [ + "temp_rendering_path_template": "{work}/renders/nuke/{subset}/{subset}.{ext}", + "default_variants": [ "ImageFrame", "MPFrame", "LayoutFrame" ], - "knobs": [], + "instance_attributes": [], "prenodes": { "FrameHold01": { "nodeclass": "FrameHold", diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json index c21df7d44d5..520985154e7 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json @@ -97,26 +97,20 @@ "children": [ { "type": "text", - "key": "fpath_template", - "label": "Path template" + "key": "temp_rendering_path_template", + "label": "Temporary rendering path template" }, { "type": "list", - "key": "defaults", - "label": "Subset name defaults", + "key": "default_variants", + "label": "Default variants", "object_type": { "type": "text" } }, { "type": "schema_template", - "name": "template_nuke_knob_inputs", - "template_data": [ - { - "label": "Node knobs", - "key": "knobs" - } - ] + "name": "template_nuke_write_attrs" }, { "key": "prenodes", @@ -160,36 +154,20 @@ "children": [ { "type": "text", - "key": "fpath_template", - "label": "Path template" - }, - { - "type": "boolean", - "key": "use_range_limit", - "label": "Use Frame range limit by default" + "key": "temp_rendering_path_template", + "label": "Temporary rendering path template" }, { "type": "list", - "key": "defaults", - "label": "Subset name defaults", + "key": "default_variants", + "label": "Default variants", "object_type": { "type": "text" } }, - { - "type": "boolean", - "key": "reviewable", - "label": "Add reviewable toggle" - }, { "type": "schema_template", - "name": "template_nuke_knob_inputs", - "template_data": [ - { - "label": "Node knobs", - "key": "knobs" - } - ] + "name": "template_nuke_write_attrs" }, { "key": "prenodes", @@ -233,26 +211,20 @@ "children": [ { "type": "text", - "key": "fpath_template", - "label": "Path template" + "key": "temp_rendering_path_template", + "label": "Temporary rendering path template" }, { "type": "list", - "key": "defaults", - "label": "Subset name defaults", + "key": "default_variants", + "label": "Default variants", "object_type": { "type": "text" } }, { "type": "schema_template", - "name": "template_nuke_knob_inputs", - "template_data": [ - { - "label": "Node knobs", - "key": "knobs" - } - ] + "name": "template_nuke_write_attrs" }, { "key": "prenodes", diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/template_nuke_write_attrs.json b/openpype/settings/entities/schemas/projects_schema/schemas/template_nuke_write_attrs.json new file mode 100644 index 00000000000..8be48e669de --- /dev/null +++ b/openpype/settings/entities/schemas/projects_schema/schemas/template_nuke_write_attrs.json @@ -0,0 +1,19 @@ +[ + { + "key": "instance_attributes", + "label": "Instance attributes", + "type": "enum", + "multiselection": true, + "enum_items": [ + { + "reviewable": "Reviewable" + }, + { + "farm_rendering": "Farm rendering" + }, + { + "use_range_limit": "Use range limit" + } + ] + } +] From ca6d8bd7123616eb2fdb458761ba4556a95480ef Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 17:17:30 +0200 Subject: [PATCH 027/115] Nuke adding deprecation warning and adding it to deprecated functions --- openpype/hosts/nuke/api/lib.py | 99 ++++++++++++++++++++----------- openpype/hosts/nuke/api/plugin.py | 6 +- 2 files changed, 67 insertions(+), 38 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 211bab2d80e..68f0ca6e356 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -3,6 +3,8 @@ import re import json import six +import functools +import warnings import platform import tempfile import contextlib @@ -68,6 +70,51 @@ INSTANCE_DATA_KNOB = "publish_instance" +class DeprecatedWarning(DeprecationWarning): + pass + + +def deprecated(new_destination): + """Mark functions as deprecated. + + It will result in a warning being emitted when the function is used. + """ + + func = None + if callable(new_destination): + func = new_destination + new_destination = None + + def _decorator(decorated_func): + if new_destination is None: + warning_message = ( + " Please check content of deprecated function to figure out" + " possible replacement." + ) + else: + warning_message = " Please replace your usage with '{}'.".format( + new_destination + ) + + @functools.wraps(decorated_func) + def wrapper(*args, **kwargs): + warnings.simplefilter("always", DeprecatedWarning) + warnings.warn( + ( + "Call to deprecated function '{}'" + "\nFunction was moved or removed.{}" + ).format(decorated_func.__name__, warning_message), + category=DeprecatedWarning, + stacklevel=4 + ) + return decorated_func(*args, **kwargs) + return wrapper + + if func is None: + return _decorator + return _decorator(func) + + class Context: main_window = None context_label = None @@ -1164,8 +1211,6 @@ def create_write_node( data, input=None, prenodes=None, - review=True, - farm=True, linked_knobs=None, **kwargs ): @@ -1207,35 +1252,26 @@ def create_write_node( ''' prenodes = prenodes or {} - # group node knob overrides - knob_overrides = data.pop("knobs", []) - # filtering variables plugin_name = data["creator"] subset = data["subset"] # get knob settings for write node imageio_writes = get_imageio_node_setting( - node_class=data["nodeclass"], + node_class="Write", plugin_name=plugin_name, subset=subset ) for knob in imageio_writes["knobs"]: if knob["name"] == "file_type": - representation = knob["value"] - - try: - data.update({ - "imageio_writes": imageio_writes, - "representation": representation, - }) - anatomy_filled = format_anatomy(data) + ext = knob["value"] - except Exception as e: - msg = "problem with resolving anatomy template: {}".format(e) - log.error(msg) - nuke.message(msg) + data.update({ + "imageio_writes": imageio_writes, + "ext": ext + }) + anatomy_filled = format_anatomy(data) # build file path to workfiles fdir = str(anatomy_filled["work"]["folder"]).replace("\\", "/") @@ -1244,7 +1280,7 @@ def create_write_node( version=data["version"], subset=data["subset"], frame=data["frame"], - ext=representation + ext=ext ) # create directory @@ -1298,14 +1334,6 @@ def create_write_node( # connect to previous node now_node.setInput(0, prev_node) - # imprinting group node - set_avalon_knob_data(GN, data["avalon"]) - add_publish_knob(GN) - add_rendering_knobs(GN, farm) - - if review: - add_review_knob(GN) - # add divider GN.addKnob(nuke.Text_Knob('', 'Rendering')) @@ -1351,12 +1379,6 @@ def create_write_node( # adding write to read button add_button_clear_rendered(GN, os.path.dirname(fpath)) - # Deadline tab. - add_deadline_tab(GN) - - # open the our Tab as default - GN[_NODE_TAB_NAME].setFlag(0) - # set tile color tile_color = next( iter( @@ -1367,12 +1389,10 @@ def create_write_node( GN["tile_color"].setValue( color_gui_to_int(tile_color)) - # finally add knob overrides - set_node_knobs_from_settings(GN, knob_overrides, **kwargs) - return GN +@deprecated("openpype.hosts.nuke.api.lib.create_write_node") def create_write_node_legacy( name, data, input=None, prenodes=None, review=True, linked_knobs=None, farm=True @@ -1725,6 +1745,7 @@ def color_gui_to_int(color_gui): return int(hex_value, 16) +@deprecated def add_rendering_knobs(node, farm=True): ''' Adds additional rendering knobs to given node @@ -1745,6 +1766,7 @@ def add_rendering_knobs(node, farm=True): return node +@deprecated def add_review_knob(node): ''' Adds additional review knob to given node @@ -1761,7 +1783,9 @@ def add_review_knob(node): return node +@deprecated def add_deadline_tab(node): + # TODO: remove this as it is only linked to legacy create node.addKnob(nuke.Tab_Knob("Deadline")) knob = nuke.Int_Knob("deadlinePriority", "Priority") @@ -1787,7 +1811,10 @@ def add_deadline_tab(node): node.addKnob(knob) +@deprecated def get_deadline_knob_names(): + # TODO: remove this as it is only linked to legacy + # validate_write_deadline_tab return [ "Deadline", "deadlineChunkSize", diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 4b85334c035..cb062bc6474 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -33,7 +33,8 @@ get_nuke_imageio_settings, set_node_knobs_from_settings, get_view_process_node, - set_node_data + set_node_data, + deprecated ) from .pipeline import ( list_instances, @@ -138,7 +139,7 @@ def create(self, subset_name, instance_data, pre_create_data): # make sure subset name is unique if self.check_existing_subset(subset_name, instance_data): raise NukeCreatorError( - ("subset {} is already published with different HDA" + ("subset {} is already published" "definition.").format(subset_name)) try: @@ -736,6 +737,7 @@ def generate_mov(self, farm=False, **kwargs): return self.data +@deprecated("openpype.hosts.nuke.api.plugin.NukeWriteCreator") class AbstractWriteRender(OpenPypeCreator): """Abstract creator to gather similar implementation for Write creators""" name = "" From 57863b5151287f36d30159520f3f48181dc870f1 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 17:18:26 +0200 Subject: [PATCH 028/115] nuke: fix format anatomy func --- openpype/hosts/nuke/api/lib.py | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 68f0ca6e356..8bc905dfe8c 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -1082,27 +1082,14 @@ def format_anatomy(data): Return: path (str) ''' - # TODO: perhaps should be nonPublic - anatomy = Anatomy() log.debug("__ anatomy.templates: {}".format(anatomy.templates)) - try: - # TODO: bck compatibility with old anatomy template - padding = int( - anatomy.templates["render"].get( - "frame_padding", - anatomy.templates["render"].get("padding") - ) + padding = int( + anatomy.templates["render"].get( + "frame_padding" ) - except KeyError as e: - msg = ("`padding` key is not in `render` " - "or `frame_padding` on is not available in " - "Anatomy template. Please, add it there and restart " - "the pipeline (padding: \"4\"): `{}`").format(e) - - log.error(msg) - nuke.message(msg) + ) version = data.get("version", None) if not version: @@ -1110,16 +1097,16 @@ def format_anatomy(data): data["version"] = get_version_from_path(file) project_name = anatomy.project_name - asset_name = data["avalon"]["asset"] - task_name = os.environ["AVALON_TASK"] + asset_name = data["asset"] + task_name = data["task"] host_name = os.environ["AVALON_APP"] context_data = get_template_data_with_names( project_name, asset_name, task_name, host_name ) data.update(context_data) data.update({ - "subset": data["avalon"]["subset"], - "family": data["avalon"]["family"], + "subset": data["subset"], + "family": data["family"], "frame": "#" * padding, }) return anatomy.format(data) From 8d0758887ec84f7a0a14ab6d42dfe98c0f7e3e09 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 17:19:02 +0200 Subject: [PATCH 029/115] nuke: unparent publisher --- openpype/hosts/nuke/api/pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index cbe8b547c6d..e8fba8ae343 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -233,7 +233,7 @@ def _install_menu(): menu.addSeparator() menu.addCommand( "Publish...", - lambda: host_tools.show_publisher(parent=main_window) + host_tools.show_publisher ) menu.addCommand( "Load...", From 694d1026e8706a3a3f4d343ec27f8c300b4c39eb Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 17:19:23 +0200 Subject: [PATCH 030/115] nuke: add NukeWriteCreator --- openpype/hosts/nuke/api/plugin.py | 128 +++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index cb062bc6474..091ef81d0fc 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -1,3 +1,4 @@ +from pprint import pformat import nuke import os @@ -14,7 +15,10 @@ ) from openpype.api import get_current_project_settings -from openpype.lib import BoolDef +from openpype.lib import ( + BoolDef, + EnumDef +) from openpype.pipeline import ( LegacyCreator, LoaderPlugin, @@ -202,9 +206,127 @@ def get_pre_create_attr_defs(self): BoolDef("use_selection", label="Use selection") ] - def apply_settings(self, project_settings, system_settings): + def get_creator_settings(self, project_settings, settings_key=None): + if not settings_key: + settings_key = self.__class__.__name__ + return project_settings["nuke"]["create"][settings_key] + + +class NukeWriteCreator(NukeCreator): + """Add Publishable Write node""" + + identifier = "create_write" + label = "Create Write" + family = "write" + icon = "sign-out" + + def set_selected_nodes(self, pre_create_data): + if pre_create_data.get("use_selection"): + selected_nodes = nuke.selectedNodes() + if selected_nodes == []: + raise NukeCreatorError("Creator error: No active selection") + elif len(selected_nodes) > 1: + NukeCreatorError("Creator error: Select only one camera node") + self.selected_node = selected_nodes[0] + else: + self.selected_node = None + + def get_pre_create_attr_defs(self): + attr_defs = [ + BoolDef("use_selection", label="Use selection"), + self._get_render_target_enum() + ] + return attr_defs + + def get_instance_attr_defs(self): + attr_defs = [ + self._get_render_target_enum(), + self._get_reviewable_bool() + ] + return attr_defs + + def _get_render_target_enum(self): + rendering_targets = { + "local": "Local machine rendering", + "frames": "Use existing frames" + } + if ("farm_rendering" in self.instance_attributes): + rendering_targets["farm"] = "Farm rendering" + + return EnumDef( + "render_target", + items=rendering_targets, + label="Render target" + ) + + def _get_reviewable_bool(self): + return BoolDef( + "review", + default=("reviewable" in self.instance_attributes), + label="Review" + ) + + def create(self, subset_name, instance_data, pre_create_data): + # make sure selected nodes are added + self.set_selected_nodes(pre_create_data) + + # make sure subset name is unique + if self.check_existing_subset(subset_name, instance_data): + raise NukeCreatorError( + ("subset {} is already published" + "definition.").format(subset_name)) + + instance_node = self.create_instance_node( + subset_name, + instance_data + ) + + try: + instance = CreatedInstance( + self.family, + subset_name, + instance_data, + self + ) + + instance.transient_data["node"] = instance_node + + self._add_instance_to_context(instance) + + set_node_data( + instance_node, INSTANCE_DATA_KNOB, instance.data_to_store()) + + return instance + + except Exception as er: + six.reraise( + NukeCreatorError, + NukeCreatorError("Creator error: {}".format(er)), + sys.exc_info()[2]) + + return instance + + def apply_settings( + self, + project_settings, + system_settings, + # anatomy_settings + ): """Method called on initialization of plugin to apply settings.""" - self.creators_settings = project_settings["nuke"]["create"] + + # plugin settings + plugin_settings = self.get_creator_settings(project_settings) + + self.log.debug("___________________") + self.log.debug(pformat(plugin_settings)) + + # individual attributes + self.instance_attributes = plugin_settings[ + "instance_attributes"] + self.prenodes = plugin_settings["prenodes"] + self.default_variants = plugin_settings["default_variants"] + self.temp_rendering_path_template = plugin_settings[ + "temp_rendering_path_template"] class OpenPypeCreator(LegacyCreator): From 36672bb82704fbd2e2fdf698d1368d92dba7b3d6 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 17:19:42 +0200 Subject: [PATCH 031/115] Nuke: add camera creator --- .../nuke/plugins/create/create_camera.py | 110 +++++++++++------- 1 file changed, 65 insertions(+), 45 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_camera.py b/openpype/hosts/nuke/plugins/create/create_camera.py index 3b13c80dc4c..0b538d0088c 100644 --- a/openpype/hosts/nuke/plugins/create/create_camera.py +++ b/openpype/hosts/nuke/plugins/create/create_camera.py @@ -1,55 +1,75 @@ import nuke -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - set_avalon_knob_data +from openpype.hosts.nuke.api import ( + NukeCreator, + NukeCreatorError, + maintained_selection ) -class CreateCamera(plugin.OpenPypeCreator): - """Add Publishable Backdrop""" +class CreateCamera(NukeCreator): + """Add Publishable Camera""" - name = "camera" + identifier = "create_camera" label = "Create 3d Camera" family = "camera" icon = "camera" - defaults = ["Main"] - - def __init__(self, *args, **kwargs): - super(CreateCamera, self).__init__(*args, **kwargs) - self.nodes = nuke.selectedNodes() - self.node_color = "0xff9100ff" - return - - def process(self): - nodes = list() - if (self.options or {}).get("useSelection"): - nodes = self.nodes - - if len(nodes) >= 1: - # loop selected nodes - for n in nodes: - data = self.data.copy() - if len(nodes) > 1: - # rename subset name only if more - # then one node are selected - subset = self.family + n["name"].value().capitalize() - data["subset"] = subset - - # change node color - n["tile_color"].setValue(int(self.node_color, 16)) - # add avalon knobs - set_avalon_knob_data(n, data) - return True + + # plugin attributes + node_color = "0xff9100ff" + + def create_instance_node( + self, + node_name, + knobs=None, + parent=None, + node_type=None + ): + with maintained_selection(): + if self.selected_nodes: + created_node = self.selected_nodes[0] else: - msg = str("Please select nodes you " - "wish to add to a container") - self.log.error(msg) - nuke.message(msg) - return + created_node = nuke.createNode("Camera2") + + created_node["tile_color"].setValue( + int(self.node_color, 16)) + + created_node["name"].setValue(node_name) + + self.add_info_knob(created_node) + + return created_node + + def create(self, subset_name, instance_data, pre_create_data): + if self.check_existing_subset(subset_name, instance_data): + raise NukeCreatorError( + ("subset {} is already published with different HDA" + "definition.").format(subset_name)) + + instance = super(CreateCamera, self).create( + subset_name, + instance_data, + pre_create_data + ) + + return instance + + def set_selected_nodes(self, pre_create_data): + if pre_create_data.get("use_selection"): + self.selected_nodes = nuke.selectedNodes() + if self.selected_nodes == []: + raise NukeCreatorError("Creator error: No active selection") + elif len(self.selected_nodes) > 1: + NukeCreatorError("Creator error: Select only one camera node") else: - # if selected is off then create one node - camera_node = nuke.createNode("Camera2") - camera_node["tile_color"].setValue(int(self.node_color, 16)) - # add avalon knobs - instance = set_avalon_knob_data(camera_node, self.data) - return instance + self.selected_nodes = [] + + self.log.debug("Selection is: {}".format(self.selected_nodes)) + + def apply_settings(self, project_settings, system_settings): + """Method called on initialization of plugin to apply settings.""" + + # only selected keys ideally + # settings = self.get_creator_settings(project_settings) + + # self.key = settings["key"] + pass \ No newline at end of file From 5bafa21ea84da086f078999e4ee67a9f4d181a20 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 17:20:19 +0200 Subject: [PATCH 032/115] nuke: refactor create write render to new publisher --- .../plugins/create/create_write_render.py | 139 +++++++++--------- 1 file changed, 71 insertions(+), 68 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_write_render.py b/openpype/hosts/nuke/plugins/create/create_write_render.py index 23846c03325..3d7f5b8e370 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_render.py +++ b/openpype/hosts/nuke/plugins/create/create_write_render.py @@ -1,86 +1,89 @@ +from pprint import pformat import nuke +from openpype.lib import ( + BoolDef, + NumberDef, + UISeparatorDef, + UILabelDef +) from openpype.hosts.nuke.api import plugin from openpype.hosts.nuke.api.lib import ( - create_write_node, create_write_node_legacy) + create_write_node) -class CreateWriteRender(plugin.AbstractWriteRender): - # change this to template preset - name = "WriteRender" +class CreateWriteRender(plugin.NukeWriteCreator): + identifier = "create_write_render" label = "Create Write Render" - hosts = ["nuke"] - n_class = "Write" family = "render" icon = "sign-out" - # settings - fpath_template = "{work}/render/nuke/{subset}/{subset}.{frame}.{ext}" - defaults = ["Main", "Mask"] - prenodes = { - "Reformat01": { - "nodeclass": "Reformat", - "dependent": None, - "knobs": [ - { - "type": "text", - "name": "resize", - "value": "none" - }, - { - "type": "bool", - "name": "black_outside", - "value": True - } - ] - } - } + def get_pre_create_attr_defs(self): + attr_defs = [ + BoolDef("use_selection", label="Use selection"), + self._get_render_target_enum() + ] + return attr_defs - def __init__(self, *args, **kwargs): - super(CreateWriteRender, self).__init__(*args, **kwargs) + def get_instance_attr_defs(self): + attr_defs = [ + self._get_render_target_enum(), + self._get_reviewable_bool() + ] + if "farm_rendering" in self.instance_attributes: + attr_defs.extend([ + UISeparatorDef(), + UILabelDef("Farm rendering attributes"), + BoolDef("suspended_publish", label="Suspended publishing"), + NumberDef( + "farm_priority", + label="Priority", + minimum=1, + maximum=99, + default=50 + ), + NumberDef( + "farm_chunk", + label="Chunk size", + minimum=1, + maximum=99, + default=10 + ), + NumberDef( + "farm_concurency", + label="Concurent tasks", + minimum=1, + maximum=10, + default=1 + ) + ]) + return attr_defs - def _create_write_node(self, selected_node, inputs, outputs, write_data): + def create_instance_node(self, subset_name, instance_data): # add fpath_template - write_data["fpath_template"] = self.fpath_template + write_data = { + "creator": self.__class__.__name__, + "subset": subset_name, + "fpath_template": self.temp_rendering_path_template + } + + write_data.update(instance_data) - # add reformat node to cut off all outside of format bounding box # get width and height - try: - width, height = (selected_node.width(), selected_node.height()) - except AttributeError: + if self.selected_node: + width, height = ( + self.selected_node.width(), self.selected_node.height()) + else: actual_format = nuke.root().knob('format').value() width, height = (actual_format.width(), actual_format.height()) - if not self.is_legacy(): - return create_write_node( - self.data["subset"], - write_data, - input=selected_node, - prenodes=self.prenodes, - **{ - "width": width, - "height": height - } - ) - else: - _prenodes = [ - { - "name": "Reformat01", - "class": "Reformat", - "knobs": [ - ("resize", 0), - ("black_outside", 1), - ], - "dependent": None - } - ] - - return create_write_node_legacy( - self.data["subset"], - write_data, - input=selected_node, - prenodes=_prenodes - ) - - def _modify_write_node(self, write_node): - return write_node + return create_write_node( + subset_name, + write_data, + input=self.selected_node, + prenodes=self.prenodes, + **{ + "width": width, + "height": height + } + ) From 3a02562b7aa8d401216af3fefab189ab78cad510 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 21:08:13 +0200 Subject: [PATCH 033/115] Nuke: adding missing api functions --- openpype/hosts/nuke/api/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index 8b18d4bc3b5..47a62aa3e01 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -11,6 +11,7 @@ ) from .plugin import ( NukeCreator, + NukeWriteCreator, NukeCreatorError, OpenPypeCreator ) @@ -40,7 +41,8 @@ convert_knob_value_to_correct_type, get_node_data, set_node_data, - update_node_data + update_node_data, + create_write_node ) from .utils import ( colorspace_exists_on_node, @@ -58,6 +60,7 @@ "viewer_update_and_undo_stop", "NukeCreator", + "NukeWriteCreator", "NukeCreatorError", "OpenPypeCreator", "NukeHost", @@ -85,6 +88,7 @@ "get_node_data", "set_node_data", "update_node_data", + "create_write_node", "colorspace_exists_on_node", "get_colorspace_list" From 7635528199e89bf8a87b76d8ca24f6d55d6ee2a8 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 21:08:38 +0200 Subject: [PATCH 034/115] nuke: cosmetic changes --- openpype/hosts/nuke/api/lib.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 8bc905dfe8c..a9e12c0f4d2 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -1366,6 +1366,8 @@ def create_write_node( # adding write to read button add_button_clear_rendered(GN, os.path.dirname(fpath)) + GN.addKnob(nuke.Text_Knob('', '')) + # set tile color tile_color = next( iter( From 96b6f87a922a5ab1ca32233a276ea7ea174d9f5e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 21:09:06 +0200 Subject: [PATCH 035/115] nuke: make the info text less aggressive --- openpype/hosts/nuke/api/plugin.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 091ef81d0fc..32cdaf9c861 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -60,9 +60,10 @@ def add_info_knob(self, node): # add info text info_knob = nuke.Text_Knob("OP_info", "") info_knob.setValue(""" -

Do not erase manually !

+

This node is maintained by OpenPype Publisher.

-

We recomand to remove it from the Publisher gui.

+

To remove it use Publisher gui.

+
""") node.addKnob(info_knob) @@ -302,9 +303,8 @@ def create(self, subset_name, instance_data, pre_create_data): six.reraise( NukeCreatorError, NukeCreatorError("Creator error: {}".format(er)), - sys.exc_info()[2]) - - return instance + sys.exc_info()[2] + ) def apply_settings( self, From d7037a7b354e49fde1135e6ad100fae14f768bcb Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 21:09:33 +0200 Subject: [PATCH 036/115] nuke: add create function into write render creator --- .../plugins/create/create_write_render.py | 59 +++++++++++++++++-- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_write_render.py b/openpype/hosts/nuke/plugins/create/create_write_render.py index 3d7f5b8e370..85aaedb208e 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_render.py +++ b/openpype/hosts/nuke/plugins/create/create_write_render.py @@ -1,18 +1,20 @@ -from pprint import pformat import nuke +import sys +import six +from openpype.pipeline import ( + CreatedInstance +) from openpype.lib import ( BoolDef, NumberDef, UISeparatorDef, UILabelDef ) -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - create_write_node) +from openpype.hosts.nuke import api as napi -class CreateWriteRender(plugin.NukeWriteCreator): +class CreateWriteRender(napi.NukeWriteCreator): identifier = "create_write_render" label = "Create Write Render" family = "render" @@ -77,7 +79,7 @@ def create_instance_node(self, subset_name, instance_data): actual_format = nuke.root().knob('format').value() width, height = (actual_format.width(), actual_format.height()) - return create_write_node( + created_node = napi.create_write_node( subset_name, write_data, input=self.selected_node, @@ -87,3 +89,48 @@ def create_instance_node(self, subset_name, instance_data): "height": height } ) + self.add_info_knob(created_node) + + return created_node + + def create(self, subset_name, instance_data, pre_create_data): + # make sure selected nodes are added + self.set_selected_nodes(pre_create_data) + + # make sure subset name is unique + if self.check_existing_subset(subset_name, instance_data): + raise napi.NukeCreatorError( + ("subset {} is already published" + "definition.").format(subset_name)) + + instance_node = self.create_instance_node( + subset_name, + instance_data + ) + + try: + instance = CreatedInstance( + self.family, + subset_name, + instance_data, + self + ) + + instance.transient_data["node"] = instance_node + + self._add_instance_to_context(instance) + + napi.set_node_data( + instance_node, + napi.INSTANCE_DATA_KNOB, + instance.data_to_store() + ) + + return instance + + except Exception as er: + six.reraise( + napi.NukeCreatorError, + napi.NukeCreatorError("Creator error: {}".format(er)), + sys.exc_info()[2] + ) From 0e0df359d69c7aea92834a93d014fe9e072b3f9e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 5 Oct 2022 21:32:30 +0200 Subject: [PATCH 037/115] nuke: adding relinking function --- openpype/hosts/nuke/api/plugin.py | 20 +++++++++++++++++++ .../plugins/create/create_write_render.py | 2 ++ 2 files changed, 22 insertions(+) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 32cdaf9c861..340ccc7abb6 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -221,6 +221,26 @@ class NukeWriteCreator(NukeCreator): family = "write" icon = "sign-out" + def integrate_links(self, node, outputs=True): + # skip if no selection + if not self.selected_node: + return + + # collect dependencies + input_nodes = [self.selected_node] + dependent_nodes = self.selected_node.dependent() if outputs else [] + + # relinking to collected connections + for i, input in enumerate(input_nodes): + node.setInput(i, input) + + # make it nicer in graph + node.autoplace() + + # relink also dependent nodes + for dep_nodes in dependent_nodes: + dep_nodes.setInput(0, node) + def set_selected_nodes(self, pre_create_data): if pre_create_data.get("use_selection"): selected_nodes = nuke.selectedNodes() diff --git a/openpype/hosts/nuke/plugins/create/create_write_render.py b/openpype/hosts/nuke/plugins/create/create_write_render.py index 85aaedb208e..560b9e0c364 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_render.py +++ b/openpype/hosts/nuke/plugins/create/create_write_render.py @@ -91,6 +91,8 @@ def create_instance_node(self, subset_name, instance_data): ) self.add_info_knob(created_node) + self.integrate_links(created_node, outputs=False) + return created_node def create(self, subset_name, instance_data, pre_create_data): From 4aedaa975e8513b9b6aee9e70e23105c15b97bd9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 6 Oct 2022 16:42:39 +0200 Subject: [PATCH 038/115] Nuke refactory write still creator --- openpype/hosts/nuke/api/lib.py | 1 - .../nuke/plugins/create/create_write_still.py | 195 +++++++++++------- 2 files changed, 116 insertions(+), 80 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index a9e12c0f4d2..b09a164ac11 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -1680,7 +1680,6 @@ def set_node_knobs_from_settings(node, knob_settings, **kwargs): _knob_value = template.format( **kwargs ) - log.debug("__ knob_value0: {}".format(_knob_value)) except KeyError as msg: log.warning("__ msg: {}".format(msg)) raise KeyError(msg) diff --git a/openpype/hosts/nuke/plugins/create/create_write_still.py b/openpype/hosts/nuke/plugins/create/create_write_still.py index bb08e8c2c6d..7627bc3d9f8 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_still.py +++ b/openpype/hosts/nuke/plugins/create/create_write_still.py @@ -1,96 +1,133 @@ import nuke +import sys +import six -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - create_write_node, - create_write_node_legacy, - get_created_node_imageio_setting_legacy +from openpype.pipeline import ( + CreatedInstance ) - -# HACK: just to disable still image on projects which -# are not having anatomy imageio preset for CreateWriteStill -# TODO: remove this code as soon as it will be obsolete -imageio_writes = get_created_node_imageio_setting_legacy( - "Write", - "CreateWriteStill", - "stillMain" +from openpype.lib import ( + BoolDef, + NumberDef, + UISeparatorDef, + EnumDef ) -print(imageio_writes["knobs"]) +from openpype.hosts.nuke import api as napi -class CreateWriteStill(plugin.AbstractWriteRender): - # change this to template preset - name = "WriteStillFrame" - label = "Create Write Still Image" - hosts = ["nuke"] - n_class = "Write" +class CreateWriteStill(napi.NukeWriteCreator): + identifier = "create_write_still" + label = "Create Write Still Frame" family = "still" - icon = "image" - - # settings - fpath_template = "{work}/render/nuke/{subset}/{subset}.{ext}" - defaults = [ - "ImageFrame", - "MPFrame", - "LayoutFrame" - ] - prenodes = { - "FrameHold01": { - "nodeclass": "FrameHold", - "dependent": None, - "knobs": [ - { - "type": "formatable", - "name": "first_frame", - "template": "{frame}", - "to_type": "number" - } - ] + icon = "sign-out" + + def get_pre_create_attr_defs(self): + attr_defs = [ + BoolDef("use_selection", label="Use selection"), + self._get_render_target_enum(), + UISeparatorDef(), + self._get_frame_source_number() + ] + return attr_defs + + def _get_render_target_enum(self): + rendering_targets = { + "local": "Local machine rendering", + "frames": "Use existing frames" } - } - def __init__(self, *args, **kwargs): - super(CreateWriteStill, self).__init__(*args, **kwargs) + return EnumDef( + "render_target", + items=rendering_targets, + label="Render target" + ) - def _create_write_node(self, selected_node, inputs, outputs, write_data): + def _get_frame_source_number(self): + return NumberDef( + "active_frame", + label="Active frame", + default=nuke.frame() + ) + + def get_instance_attr_defs(self): + attr_defs = [ + self._get_render_target_enum(), + self._get_reviewable_bool() + ] + return attr_defs + + def create_instance_node(self, subset_name, instance_data): # add fpath_template - write_data["fpath_template"] = self.fpath_template - - if not self.is_legacy(): - return create_write_node( - self.name, - write_data, - input=selected_node, - review=False, - prenodes=self.prenodes, - farm=False, - linked_knobs=["channels", "___", "first", "last", "use_limit"], - **{ - "frame": nuke.frame() - } + write_data = { + "creator": self.__class__.__name__, + "subset": subset_name, + "fpath_template": self.temp_rendering_path_template + } + + write_data.update(instance_data) + + created_node = napi.create_write_node( + subset_name, + write_data, + input=self.selected_node, + prenodes=self.prenodes, + linked_knobs=["channels", "___", "first", "last", "use_limit"], + **{ + "frame": nuke.frame() + } + ) + self.add_info_knob(created_node) + + self._add_frame_range_limit(created_node) + + self.integrate_links(created_node, outputs=False) + + return created_node + + def create(self, subset_name, instance_data, pre_create_data): + subset_name = subset_name.format(**pre_create_data) + + # make sure selected nodes are added + self.set_selected_nodes(pre_create_data) + + # make sure subset name is unique + if self.check_existing_subset(subset_name, instance_data): + raise napi.NukeCreatorError( + ("subset {} is already published" + "definition.").format(subset_name)) + + instance_node = self.create_instance_node( + subset_name, + instance_data + ) + + try: + instance = CreatedInstance( + self.family, + subset_name, + instance_data, + self ) - else: - _prenodes = [ - { - "name": "FrameHold01", - "class": "FrameHold", - "knobs": [ - ("first_frame", nuke.frame()) - ], - "dependent": None - } - ] - return create_write_node_legacy( - self.name, - write_data, - input=selected_node, - review=False, - prenodes=_prenodes, - farm=False, - linked_knobs=["channels", "___", "first", "last", "use_limit"] + + instance.transient_data["node"] = instance_node + + self._add_instance_to_context(instance) + + napi.set_node_data( + instance_node, + napi.INSTANCE_DATA_KNOB, + instance.data_to_store() + ) + + return instance + + except Exception as er: + six.reraise( + napi.NukeCreatorError, + napi.NukeCreatorError("Creator error: {}".format(er)), + sys.exc_info()[2] ) - def _modify_write_node(self, write_node): + def _add_frame_range_limit(self, write_node): write_node.begin() for n in nuke.allNodes(): # get write node From d8df51e49f589ccfa951fa92f511aa178c2a859b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 6 Oct 2022 21:21:17 +0200 Subject: [PATCH 039/115] nuke: adding expression value knob to settings template --- openpype/hosts/nuke/api/lib.py | 7 +++++++ .../schemas/template_nuke_knob_inputs.json | 16 ++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index b09a164ac11..4478633198f 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -1672,6 +1672,13 @@ def set_node_knobs_from_settings(node, knob_settings, **kwargs): if knob_name not in node.knobs(): continue + if knob_type == "expression": + knob_expression = knob["expression"] + node[knob_name].setExpression( + knob_expression + ) + continue + # first deal with formatable knob settings if knob_type == "formatable": template = knob["template"] diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/template_nuke_knob_inputs.json b/openpype/settings/entities/schemas/projects_schema/schemas/template_nuke_knob_inputs.json index 52a14e06363..c9dee8681ab 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/template_nuke_knob_inputs.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/template_nuke_knob_inputs.json @@ -28,6 +28,22 @@ } ] }, + { + "key": "expression", + "label": "Expression", + "children": [ + { + "type": "text", + "key": "name", + "label": "Name" + }, + { + "type": "text", + "key": "expression", + "label": "Expression" + } + ] + }, { "key": "formatable", "label": "Formate from template", From 4b42d55ce1acac083aa95ee7babe2467fe83b32e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 6 Oct 2022 21:22:05 +0200 Subject: [PATCH 040/115] nuke: improving still write creator settings --- openpype/settings/defaults/project_settings/nuke.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index cdb410b378a..783b42348c1 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -106,17 +106,18 @@ "MPFrame", "LayoutFrame" ], - "instance_attributes": [], + "instance_attributes": [ + "use_range_limit" + ], "prenodes": { "FrameHold01": { "nodeclass": "FrameHold", "dependent": "", "knobs": [ { - "type": "formatable", + "type": "expression", "name": "first_frame", - "template": "{frame}", - "to_type": "number" + "expression": "parent.first" } ] } From 63c46e10112392daaccea1f3fd0cde65305729b9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 6 Oct 2022 21:22:43 +0200 Subject: [PATCH 041/115] nuke: adding optional use frame range to plugin --- openpype/hosts/nuke/plugins/create/create_write_still.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_write_still.py b/openpype/hosts/nuke/plugins/create/create_write_still.py index 7627bc3d9f8..a254df4b62e 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_still.py +++ b/openpype/hosts/nuke/plugins/create/create_write_still.py @@ -56,13 +56,16 @@ def get_instance_attr_defs(self): return attr_defs def create_instance_node(self, subset_name, instance_data): + linked_knobs_ = [] + if "use_range_limit" in self.instance_attributes: + linked_knobs_ = ["channels", "___", "first", "last", "use_limit"] + # add fpath_template write_data = { "creator": self.__class__.__name__, "subset": subset_name, "fpath_template": self.temp_rendering_path_template } - write_data.update(instance_data) created_node = napi.create_write_node( @@ -70,7 +73,7 @@ def create_instance_node(self, subset_name, instance_data): write_data, input=self.selected_node, prenodes=self.prenodes, - linked_knobs=["channels", "___", "first", "last", "use_limit"], + linked_knobs=linked_knobs_, **{ "frame": nuke.frame() } @@ -137,6 +140,6 @@ def _add_frame_range_limit(self, write_node): w_node["use_limit"].setValue(True) w_node["first"].setValue(nuke.frame()) - w_node["last"].setValue(nuke.frame()) + w_node["last"].setExpression("first") return write_node From 5946ea708c63bc317419e3f3ea8212f558091caf Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 6 Oct 2022 21:24:01 +0200 Subject: [PATCH 042/115] nuke clear printing --- openpype/hosts/nuke/api/plugin.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 340ccc7abb6..585841ece8a 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -337,9 +337,6 @@ def apply_settings( # plugin settings plugin_settings = self.get_creator_settings(project_settings) - self.log.debug("___________________") - self.log.debug(pformat(plugin_settings)) - # individual attributes self.instance_attributes = plugin_settings[ "instance_attributes"] From 82e18450ce55abf20d3967d53896c95cbd333b84 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 6 Oct 2022 21:50:49 +0200 Subject: [PATCH 043/115] nuke: refectory prerender write creator --- .../plugins/create/create_write_prerender.py | 178 ++++++++++++++---- .../nuke/plugins/create/create_write_still.py | 3 + 2 files changed, 140 insertions(+), 41 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_write_prerender.py b/openpype/hosts/nuke/plugins/create/create_write_prerender.py index fec97167fb2..976b3261d97 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_prerender.py +++ b/openpype/hosts/nuke/plugins/create/create_write_prerender.py @@ -1,56 +1,153 @@ import nuke +import sys +import six -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - create_write_node, create_write_node_legacy) +from openpype.pipeline import ( + CreatedInstance +) +from openpype.lib import ( + BoolDef, + NumberDef, + UISeparatorDef, + UILabelDef +) +from openpype.hosts.nuke import api as napi -class CreateWritePrerender(plugin.AbstractWriteRender): - # change this to template preset - name = "WritePrerender" +class CreateWritePrerender(napi.NukeWriteCreator): + identifier = "create_write_prerender" label = "Create Write Prerender" - hosts = ["nuke"] - n_class = "Write" family = "prerender" icon = "sign-out" - # settings - fpath_template = "{work}/render/nuke/{subset}/{subset}.{frame}.{ext}" - defaults = ["Key01", "Bg01", "Fg01", "Branch01", "Part01"] - reviewable = False - use_range_limit = True + def get_pre_create_attr_defs(self): + attr_defs = [ + BoolDef("use_selection", label="Use selection"), + self._get_render_target_enum() + ] + return attr_defs - def __init__(self, *args, **kwargs): - super(CreateWritePrerender, self).__init__(*args, **kwargs) + def get_instance_attr_defs(self): + attr_defs = [ + self._get_render_target_enum(), + self._get_reviewable_bool() + ] + if "farm_rendering" in self.instance_attributes: + attr_defs.extend([ + UISeparatorDef(), + UILabelDef("Farm rendering attributes"), + BoolDef("suspended_publish", label="Suspended publishing"), + NumberDef( + "farm_priority", + label="Priority", + minimum=1, + maximum=99, + default=50 + ), + NumberDef( + "farm_chunk", + label="Chunk size", + minimum=1, + maximum=99, + default=10 + ), + NumberDef( + "farm_concurency", + label="Concurent tasks", + minimum=1, + maximum=10, + default=1 + ) + ]) + return attr_defs + + def create_instance_node(self, subset_name, instance_data): + linked_knobs_ = [] + if "use_range_limit" in self.instance_attributes: + linked_knobs_ = ["channels", "___", "first", "last", "use_limit"] - def _create_write_node(self, selected_node, inputs, outputs, write_data): # add fpath_template - write_data["fpath_template"] = self.fpath_template - write_data["use_range_limit"] = self.use_range_limit - write_data["frame_range"] = ( - nuke.root()["first_frame"].value(), - nuke.root()["last_frame"].value() + write_data = { + "creator": self.__class__.__name__, + "subset": subset_name, + "fpath_template": self.temp_rendering_path_template + } + + write_data.update(instance_data) + + # get width and height + if self.selected_node: + width, height = ( + self.selected_node.width(), self.selected_node.height()) + else: + actual_format = nuke.root().knob('format').value() + width, height = (actual_format.width(), actual_format.height()) + + created_node = napi.create_write_node( + subset_name, + write_data, + input=self.selected_node, + prenodes=self.prenodes, + linked_knobs=linked_knobs_, + **{ + "width": width, + "height": height + } + ) + self.add_info_knob(created_node) + + self._add_frame_range_limit(created_node) + + self.integrate_links(created_node, outputs=False) + + return created_node + + def create(self, subset_name, instance_data, pre_create_data): + # make sure selected nodes are added + self.set_selected_nodes(pre_create_data) + + # make sure subset name is unique + if self.check_existing_subset(subset_name, instance_data): + raise napi.NukeCreatorError( + ("subset {} is already published" + "definition.").format(subset_name)) + + instance_node = self.create_instance_node( + subset_name, + instance_data ) - if not self.is_legacy(): - return create_write_node( - self.data["subset"], - write_data, - input=selected_node, - review=self.reviewable, - linked_knobs=["channels", "___", "first", "last", "use_limit"] + try: + instance = CreatedInstance( + self.family, + subset_name, + instance_data, + self ) - else: - return create_write_node_legacy( - self.data["subset"], - write_data, - input=selected_node, - review=self.reviewable, - linked_knobs=["channels", "___", "first", "last", "use_limit"] + + instance.transient_data["node"] = instance_node + + self._add_instance_to_context(instance) + + napi.set_node_data( + instance_node, + napi.INSTANCE_DATA_KNOB, + instance.data_to_store() ) - def _modify_write_node(self, write_node): - # open group node + return instance + + except Exception as er: + six.reraise( + napi.NukeCreatorError, + napi.NukeCreatorError("Creator error: {}".format(er)), + sys.exc_info()[2] + ) + + def _add_frame_range_limit(self, write_node): + if "use_range_limit" not in self.instance_attributes: + return + write_node.begin() for n in nuke.allNodes(): # get write node @@ -58,9 +155,8 @@ def _modify_write_node(self, write_node): w_node = n write_node.end() - if self.use_range_limit: - w_node["use_limit"].setValue(True) - w_node["first"].setValue(nuke.root()["first_frame"].value()) - w_node["last"].setValue(nuke.root()["last_frame"].value()) + w_node["use_limit"].setValue(True) + w_node["first"].setValue(nuke.root()["first_frame"].value()) + w_node["last"].setValue(nuke.root()["last_frame"].value()) return write_node diff --git a/openpype/hosts/nuke/plugins/create/create_write_still.py b/openpype/hosts/nuke/plugins/create/create_write_still.py index a254df4b62e..e77c51e9bea 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_still.py +++ b/openpype/hosts/nuke/plugins/create/create_write_still.py @@ -131,6 +131,9 @@ def create(self, subset_name, instance_data, pre_create_data): ) def _add_frame_range_limit(self, write_node): + if "use_range_limit" not in self.instance_attributes: + return + write_node.begin() for n in nuke.allNodes(): # get write node From 42e993c0bb3c3a2e7c2d1746264e8c837c533ce4 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 7 Oct 2022 14:08:00 +0200 Subject: [PATCH 044/115] nuke: adding function for passing attributes from pre create to instance --- openpype/hosts/nuke/api/plugin.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 585841ece8a..a509630fb72 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -53,6 +53,19 @@ class NukeCreatorError(CreatorError): class NukeCreator(NewCreator): selected_nodes = [] + def pass_pre_attributes_to_instance( + self, + instance_data, + pre_create_data, + keys=None + ): + if not keys: + keys = pre_create_data.keys() + + creator_attrs = instance_data["creator_attributes"] = {} + for pass_key in keys: + creator_attrs[pass_key] = pre_create_data[pass_key] + def add_info_knob(self, node): if "OP_info" in node.knobs().keys(): return From a68f74a37b6b06f94ce754ca36abf0201744abda Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 7 Oct 2022 14:08:24 +0200 Subject: [PATCH 045/115] nuke: updating write creators --- .../plugins/create/create_write_prerender.py | 17 +++++++++-- .../plugins/create/create_write_render.py | 14 ++++++++- .../nuke/plugins/create/create_write_still.py | 29 +++++++++++++++---- 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_write_prerender.py b/openpype/hosts/nuke/plugins/create/create_write_prerender.py index 976b3261d97..1ce30379ade 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_prerender.py +++ b/openpype/hosts/nuke/plugins/create/create_write_prerender.py @@ -22,7 +22,11 @@ class CreateWritePrerender(napi.NukeWriteCreator): def get_pre_create_attr_defs(self): attr_defs = [ - BoolDef("use_selection", label="Use selection"), + BoolDef( + "use_selection", + default=True, + label="Use selection" + ), self._get_render_target_enum() ] return attr_defs @@ -98,11 +102,20 @@ def create_instance_node(self, subset_name, instance_data): self._add_frame_range_limit(created_node) - self.integrate_links(created_node, outputs=False) + self.integrate_links(created_node, outputs=True) return created_node def create(self, subset_name, instance_data, pre_create_data): + # pass values from precreate to instance + self.pass_pre_attributes_to_instance( + instance_data, + pre_create_data, + [ + "render_target" + ] + ) + # make sure selected nodes are added self.set_selected_nodes(pre_create_data) diff --git a/openpype/hosts/nuke/plugins/create/create_write_render.py b/openpype/hosts/nuke/plugins/create/create_write_render.py index 560b9e0c364..89696f55e01 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_render.py +++ b/openpype/hosts/nuke/plugins/create/create_write_render.py @@ -22,7 +22,11 @@ class CreateWriteRender(napi.NukeWriteCreator): def get_pre_create_attr_defs(self): attr_defs = [ - BoolDef("use_selection", label="Use selection"), + BoolDef( + "use_selection", + default=True, + label="Use selection" + ), self._get_render_target_enum() ] return attr_defs @@ -96,6 +100,14 @@ def create_instance_node(self, subset_name, instance_data): return created_node def create(self, subset_name, instance_data, pre_create_data): + # pass values from precreate to instance + self.pass_pre_attributes_to_instance( + instance_data, + pre_create_data, + [ + "render_target" + ] + ) # make sure selected nodes are added self.set_selected_nodes(pre_create_data) diff --git a/openpype/hosts/nuke/plugins/create/create_write_still.py b/openpype/hosts/nuke/plugins/create/create_write_still.py index e77c51e9bea..b3a096a5ba5 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_still.py +++ b/openpype/hosts/nuke/plugins/create/create_write_still.py @@ -22,7 +22,11 @@ class CreateWriteStill(napi.NukeWriteCreator): def get_pre_create_attr_defs(self): attr_defs = [ - BoolDef("use_selection", label="Use selection"), + BoolDef( + "use_selection", + default=True, + label="Use selection" + ), self._get_render_target_enum(), UISeparatorDef(), self._get_frame_source_number() @@ -80,15 +84,25 @@ def create_instance_node(self, subset_name, instance_data): ) self.add_info_knob(created_node) - self._add_frame_range_limit(created_node) + self._add_frame_range_limit(created_node, instance_data) - self.integrate_links(created_node, outputs=False) + self.integrate_links(created_node, outputs=True) return created_node def create(self, subset_name, instance_data, pre_create_data): subset_name = subset_name.format(**pre_create_data) + # pass values from precreate to instance + self.pass_pre_attributes_to_instance( + instance_data, + pre_create_data, + [ + "active_frame", + "render_target" + ] + ) + # make sure selected nodes are added self.set_selected_nodes(pre_create_data) @@ -100,7 +114,7 @@ def create(self, subset_name, instance_data, pre_create_data): instance_node = self.create_instance_node( subset_name, - instance_data + instance_data, ) try: @@ -130,10 +144,13 @@ def create(self, subset_name, instance_data, pre_create_data): sys.exc_info()[2] ) - def _add_frame_range_limit(self, write_node): + def _add_frame_range_limit(self, write_node, instance_data): if "use_range_limit" not in self.instance_attributes: return + active_frame = ( + instance_data["creator_attributes"].get("active_frame")) + write_node.begin() for n in nuke.allNodes(): # get write node @@ -142,7 +159,7 @@ def _add_frame_range_limit(self, write_node): write_node.end() w_node["use_limit"].setValue(True) - w_node["first"].setValue(nuke.frame()) + w_node["first"].setValue(active_frame or nuke.frame()) w_node["last"].setExpression("first") return write_node From 519642b6c5d7dba2456b4dbb0112c0262a2b5f06 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 7 Oct 2022 15:21:21 +0200 Subject: [PATCH 046/115] nuke: two way compatibility for getting node from instance --- openpype/hosts/nuke/api/__init__.py | 4 +++- openpype/hosts/nuke/api/plugin.py | 10 +++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index 47a62aa3e01..156b3f0de09 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -13,7 +13,8 @@ NukeCreator, NukeWriteCreator, NukeCreatorError, - OpenPypeCreator + OpenPypeCreator, + get_instance_node ) from .pipeline import ( NukeHost, @@ -64,6 +65,7 @@ "NukeCreatorError", "OpenPypeCreator", "NukeHost", + "get_instance_node", "ls", diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index a509630fb72..193c2e8c2d5 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -1,4 +1,3 @@ -from pprint import pformat import nuke import os @@ -407,6 +406,15 @@ def process(self): return instance +def get_instance_node(instance): + # new publisher way + if instance.data.get("transientData"): + return instance.data["transientData"]["node"] + else: + # or backward compatible + return instance[0] + + def get_review_presets_config(): settings = get_current_project_settings() review_profiles = ( From 61068436c418513cf0399123a2ea93d9e7c9b195 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 7 Oct 2022 15:22:04 +0200 Subject: [PATCH 047/115] nuke: two way compatibility for publish plugins getting instance node and child nodes --- .../nuke/plugins/publish/collect_backdrop.py | 9 ++------ .../nuke/plugins/publish/collect_gizmo.py | 5 ++--- .../nuke/plugins/publish/collect_model.py | 7 +++--- .../nuke/plugins/publish/collect_reads.py | 9 ++++---- .../plugins/publish/collect_slate_node.py | 3 ++- .../nuke/plugins/publish/extract_gizmo.py | 6 +++-- .../nuke/plugins/publish/extract_model.py | 6 +++-- .../plugins/publish/extract_render_local.py | 6 ++++- .../nuke/plugins/publish/extract_thumbnail.py | 12 ++++------ .../nuke/plugins/publish/precollect_writes.py | 7 +++++- .../plugins/publish/validate_asset_name.py | 9 ++++---- .../nuke/plugins/publish/validate_backdrop.py | 10 ++++----- .../nuke/plugins/publish/validate_gizmo.py | 8 +++---- .../publish/validate_output_resolution.py | 20 ++++++++++++----- .../plugins/publish/validate_read_legacy.py | 22 +++++++++---------- .../publish/validate_rendered_frames.py | 7 ++++-- .../plugins/publish/validate_write_legacy.py | 6 ++--- .../plugins/publish/validate_write_nodes.py | 19 ++++++++++++---- 18 files changed, 99 insertions(+), 72 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py index 688b1054ab7..dcabedf231c 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py @@ -1,6 +1,7 @@ from pprint import pformat import pyblish.api from openpype.hosts.nuke.api import lib as pnlib +from openpype.hosts.nuke import api as napi import nuke @@ -17,12 +18,7 @@ class CollectBackdrops(pyblish.api.InstancePlugin): def process(self, instance): self.log.debug(pformat(instance.data)) - # new publisher way - if instance.data.get("transientData"): - bckn = instance.data["transientData"]["node"] - else: - # or backward compatible - bckn = instance[0] + bckn = napi.get_instance_node(instance) # define size of the backdrop left = bckn.xpos() @@ -91,5 +87,4 @@ def process(self, instance): "frameStart": first_frame, "frameEnd": last_frame }) - self.log.info("Backdrop content collected: `{}`".format(instance[:])) self.log.info("Backdrop instance collected: `{}`".format(instance)) diff --git a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py index 3db26096ae1..755c196f8e9 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py @@ -1,4 +1,5 @@ import pyblish.api +from openpype.hosts.nuke import api as napi import nuke @@ -13,8 +14,7 @@ class CollectGizmo(pyblish.api.InstancePlugin): families = ["gizmo"] def process(self, instance): - - grpn = instance[0] + grpn = napi.get_instance_node(instance) # add family to familiess instance.data["families"].insert(0, instance.data["family"]) @@ -46,5 +46,4 @@ def process(self, instance): "frameStart": first_frame, "frameEnd": last_frame }) - self.log.info("Gizmo content collected: `{}`".format(instance[:])) self.log.info("Gizmo instance collected: `{}`".format(instance)) diff --git a/openpype/hosts/nuke/plugins/publish/collect_model.py b/openpype/hosts/nuke/plugins/publish/collect_model.py index 5fca240553a..253121ffd43 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_model.py +++ b/openpype/hosts/nuke/plugins/publish/collect_model.py @@ -1,6 +1,6 @@ import pyblish.api import nuke - +from openpype.hosts.nuke import api as napi @pyblish.api.log class CollectModel(pyblish.api.InstancePlugin): @@ -14,12 +14,12 @@ class CollectModel(pyblish.api.InstancePlugin): def process(self, instance): - grpn = instance[0] + geo_node = napi.get_instance_node(instance) # add family to familiess instance.data["families"].insert(0, instance.data["family"]) # make label nicer - instance.data["label"] = grpn.name() + instance.data["label"] = geo_node.name() # Get frame range handle_start = instance.context.data["handleStart"] @@ -45,5 +45,4 @@ def process(self, instance): "frameStart": first_frame, "frameEnd": last_frame }) - self.log.info("Model content collected: `{}`".format(instance[:])) self.log.info("Model instance collected: `{}`".format(instance)) diff --git a/openpype/hosts/nuke/plugins/publish/collect_reads.py b/openpype/hosts/nuke/plugins/publish/collect_reads.py index b79d9646d59..7390ec68843 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_reads.py +++ b/openpype/hosts/nuke/plugins/publish/collect_reads.py @@ -5,6 +5,7 @@ from openpype.client import get_asset_by_name from openpype.pipeline import legacy_io +from openpype.hosts.nuke import api as napi @pyblish.api.log @@ -17,6 +18,8 @@ class CollectNukeReads(pyblish.api.InstancePlugin): families = ["source"] def process(self, instance): + node = napi.get_instance_node(instance) + project_name = legacy_io.active_project() asset_name = legacy_io.Session["AVALON_ASSET"] asset_doc = get_asset_by_name(project_name, asset_name) @@ -25,7 +28,6 @@ def process(self, instance): self.log.debug("checking instance: {}".format(instance)) - node = instance[0] if node.Class() != "Read": return @@ -99,10 +101,7 @@ def process(self, instance): } instance.data["representations"].append(representation) - transfer = False - if "publish" in node.knobs(): - transfer = node["publish"] - + transfer = node["publish"] if "publish" in node.knobs() else False instance.data['transfer'] = transfer # Add version data to instance diff --git a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py index bfe32d8fd1b..0a98bcf973c 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py +++ b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py @@ -1,4 +1,5 @@ import pyblish.api +from openpype.hosts.nuke import api as napi import nuke @@ -11,7 +12,7 @@ class CollectSlate(pyblish.api.InstancePlugin): families = ["render", "render.local", "render.farm"] def process(self, instance): - node = instance[0] + node = napi.get_instance_node(instance) slate = next((n for n in nuke.allNodes() if "slate" in n.name().lower() diff --git a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py index 3047ad67242..a3df497893e 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py @@ -4,6 +4,7 @@ import pyblish.api from openpype.pipeline import publish +from openpype.hosts.nuke import api as napi from openpype.hosts.nuke.api import utils as pnutils from openpype.hosts.nuke.api.lib import ( maintained_selection, @@ -24,8 +25,9 @@ class ExtractGizmo(publish.Extractor): families = ["gizmo"] def process(self, instance): - tmp_nodes = list() - orig_grpn = instance[0] + tmp_nodes = [] + orig_grpn = napi.get_instance_node(instance) + # Define extract output file path stagingdir = self.staging_dir(instance) filename = "{0}.nk".format(instance.name) diff --git a/openpype/hosts/nuke/plugins/publish/extract_model.py b/openpype/hosts/nuke/plugins/publish/extract_model.py index d82cb3110b7..5ca617f1479 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_model.py +++ b/openpype/hosts/nuke/plugins/publish/extract_model.py @@ -3,6 +3,7 @@ import nuke import pyblish.api +from openpype.hosts.nuke import api as napi from openpype.pipeline import publish from openpype.hosts.nuke.api.lib import ( maintained_selection, @@ -36,8 +37,9 @@ def process(self, instance): self.log.info("instance.data: `{}`".format( pformat(instance.data))) - rm_nodes = list() - model_node = instance[0] + rm_nodes = [] + model_node = napi.get_instance_node(instance) + self.log.info("Crating additional nodes") subset = instance.data["subset"] staging_dir = self.staging_dir(instance) diff --git a/openpype/hosts/nuke/plugins/publish/extract_render_local.py b/openpype/hosts/nuke/plugins/publish/extract_render_local.py index 843d5887866..811b2d4ffbb 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_render_local.py +++ b/openpype/hosts/nuke/plugins/publish/extract_render_local.py @@ -23,9 +23,13 @@ class NukeRenderLocal(publish.Extractor): def process(self, instance): families = instance.data["families"] + child_nodes = ( + instance.data.get("transientData", {}).get("childNodes") + or instance + ) node = None - for x in instance: + for x in child_nodes: if x.Class() == "Write": node = x diff --git a/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py b/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py index 19eae9638b9..dfb1b382840 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py @@ -4,11 +4,7 @@ import pyblish.api from openpype.pipeline import publish -from openpype.hosts.nuke.api import ( - maintained_selection, - get_view_process_node -) - +from openpype.hosts.nuke import api as napi if sys.version_info[0] >= 3: unicode = str @@ -38,7 +34,7 @@ def process(self, instance): if "render.farm" in instance.data["families"]: return - with maintained_selection(): + with napi.maintained_selection(): self.log.debug("instance: {}".format(instance)) self.log.debug("instance.data[families]: {}".format( instance.data["families"])) @@ -69,7 +65,7 @@ def render_thumbnail(self, instance, output_name=None, **kwargs): bake_viewer_input_process_node = kwargs[ "bake_viewer_input_process"] - node = instance[0] # group node + node = napi.get_instance_node(instance) # group node self.log.info("Creating staging dir...") if "representations" not in instance.data: @@ -144,7 +140,7 @@ def render_thumbnail(self, instance, output_name=None, **kwargs): if bake_viewer_process: if bake_viewer_input_process_node: # get input process and connect it to baking - ipn = get_view_process_node() + ipn = napi.get_view_process_node() if ipn is not None: ipn.setInput(0, previous_node) previous_node = ipn diff --git a/openpype/hosts/nuke/plugins/publish/precollect_writes.py b/openpype/hosts/nuke/plugins/publish/precollect_writes.py index 17c4bc30cfa..10eeb91644b 100644 --- a/openpype/hosts/nuke/plugins/publish/precollect_writes.py +++ b/openpype/hosts/nuke/plugins/publish/precollect_writes.py @@ -27,8 +27,13 @@ def process(self, instance): _families_test = [instance.data["family"]] + instance.data["families"] self.log.debug("_families_test: {}".format(_families_test)) + child_nodes = ( + instance.data.get("transientData", {}).get("childNodes") + or instance + ) + node = None - for x in instance: + for x in child_nodes: if x.Class() == "Write": node = x diff --git a/openpype/hosts/nuke/plugins/publish/validate_asset_name.py b/openpype/hosts/nuke/plugins/publish/validate_asset_name.py index 52731140ffe..0d64da074ea 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_asset_name.py +++ b/openpype/hosts/nuke/plugins/publish/validate_asset_name.py @@ -6,7 +6,7 @@ import pyblish.api import openpype.hosts.nuke.api.lib as nlib -import openpype.hosts.nuke.api as nuke_api +from openpype.hosts.nuke import api as napi from openpype.pipeline.publish import ( ValidateContentsOrder, PublishXmlValidationError, @@ -85,8 +85,8 @@ def process(self, context, plugin): context_asset = context.data["assetEntity"]["name"] for instance in instances: - origin_node = instance[0] - nuke_api.lib.recreate_instance( + origin_node = napi.get_instance_node(instance) + napi.lib.recreate_instance( origin_node, avalon_data={"asset": context_asset} ) @@ -112,6 +112,7 @@ class ValidateCorrectAssetName(pyblish.api.InstancePlugin): def process(self, instance): asset = instance.data.get("asset") context_asset = instance.context.data["assetEntity"]["name"] + node = napi.get_instance_node(instance) msg = ( "Instance `{}` has wrong shot/asset name:\n" @@ -123,7 +124,7 @@ def process(self, instance): if asset != context_asset: raise PublishXmlValidationError( self, msg, formatting_data={ - "node_name": instance[0]["name"].value(), + "node_name": node.name(), "wrong_name": asset, "correct_name": context_asset } diff --git a/openpype/hosts/nuke/plugins/publish/validate_backdrop.py b/openpype/hosts/nuke/plugins/publish/validate_backdrop.py index 7ce3ce0e3f1..8ee8e631b86 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/validate_backdrop.py @@ -1,6 +1,6 @@ import nuke import pyblish -from openpype.hosts.nuke.api.lib import maintained_selection +from openpype.hosts.nuke import api as napi from openpype.pipeline import PublishXmlValidationError @@ -25,14 +25,14 @@ def process(self, context, plugin): # Apply pyblish.logic to get the instances for the plug-in instances = pyblish.api.instances_by_plugin(failed, plugin) - all_xC = list() - all_yC = list() + all_xC = [] + all_yC = [] # maintain selection - with maintained_selection(): + with napi.maintained_selection(): # collect all failed nodes xpos and ypos for instance in instances: - bdn = instance[0] + bdn = napi.get_instance_node(instance) xC = bdn.xpos() + bdn.screenWidth() / 2 yC = bdn.ypos() + bdn.screenHeight() / 2 diff --git a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py index 2321bd1fd44..05a40854838 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py @@ -1,6 +1,6 @@ import pyblish from openpype.pipeline import PublishXmlValidationError -from openpype.hosts.nuke.api import maintained_selection +from openpype.hosts.nuke import api as napi import nuke @@ -26,10 +26,10 @@ def process(self, context, plugin): instances = pyblish.api.instances_by_plugin(failed, plugin) # maintain selection - with maintained_selection(): + with napi.maintained_selection(): # collect all failed nodes xpos and ypos for instance in instances: - grpn = instance[0] + grpn = napi.get_instance_node(instance) nuke.showDag(grpn) @@ -45,7 +45,7 @@ class ValidateGizmo(pyblish.api.InstancePlugin): actions = [OpenFailedGroupNode] def process(self, instance): - grpn = instance[0] + grpn = napi.get_instance_node(instance) with grpn: connections_out = nuke.allNodes('Output') diff --git a/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py b/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py index 1e59880f900..b7095e9ed77 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py +++ b/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py @@ -1,6 +1,6 @@ import pyblish.api -from openpype.hosts.nuke.api import maintained_selection +from openpype.hosts.nuke import api as napi from openpype.pipeline import PublishXmlValidationError from openpype.pipeline.publish import RepairAction import nuke @@ -30,8 +30,13 @@ def process(self, instance): @classmethod def get_reformat(cls, instance): + child_nodes = ( + instance.data.get("transientData", {}).get("childNodes") + or instance + ) + reformat = None - for inode in instance: + for inode in child_nodes: if inode.Class() != "Reformat": continue reformat = inode @@ -64,21 +69,26 @@ def _check_resolution(instance, reformat): @classmethod def repair(cls, instance): + child_nodes = ( + instance.data.get("transientData", {}).get("childNodes") + or instance + ) + invalid = cls.get_invalid(instance) - grp_node = instance[0] + grp_node = napi.get_instance_node(instance) if cls.missing_msg == invalid: # make sure we are inside of the group node with grp_node: # find input node and select it _input = None - for inode in instance: + for inode in child_nodes: if inode.Class() != "Input": continue _input = inode # add reformat node under it - with maintained_selection(): + with napi.maintained_selection(): _input['selected'].setValue(True) _rfn = nuke.createNode("Reformat", "name Reformat01") _rfn["resize"].setValue(0) diff --git a/openpype/hosts/nuke/plugins/publish/validate_read_legacy.py b/openpype/hosts/nuke/plugins/publish/validate_read_legacy.py index 2bf1ff81f87..ffd5cee710e 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_read_legacy.py +++ b/openpype/hosts/nuke/plugins/publish/validate_read_legacy.py @@ -5,7 +5,7 @@ import toml import pyblish.api from bson.objectid import ObjectId - +from openpype.hosts.nuke import api as napi from openpype.pipeline import ( discover_loader_plugins, load_container, @@ -31,22 +31,22 @@ def process(self, context, plugin): instances = pyblish.api.instances_by_plugin(failed, plugin) for instance in instances: - - data = toml.loads(instance[0]["avalon"].value()) - data["name"] = instance[0].name() - data["xpos"] = instance[0].xpos() - data["ypos"] = instance[0].ypos() + node = napi.get_instance_node(instance) + data = toml.loads(node["avalon"].value()) + data["name"] = node.name() + data["xpos"] = node.xpos() + data["ypos"] = node.ypos() data["extension"] = os.path.splitext( - instance[0]["file"].value() + node["file"].value() )[1][1:] data["connections"] = [] - for d in instance[0].dependent(): + for d in node.dependent(): for i in range(d.inputs()): - if d.input(i) == instance[0]: + if d.input(i) == node: data["connections"].append([i, d]) - nuke.delete(instance[0]) + nuke.delete(node) loader_name = "LoadSequence" if data["extension"] == "mov": @@ -72,7 +72,7 @@ def process(self, context, plugin): class ValidateReadLegacy(pyblish.api.InstancePlugin): - """Validate legacy read instance[0]s.""" + """Validate legacy read nodes.""" order = pyblish.api.ValidatorOrder optional = True diff --git a/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py b/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py index 237ff423e5f..c1e511f5346 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py +++ b/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py @@ -1,6 +1,7 @@ import os import pyblish.api import clique +from openpype.hosts.nuke import api as napi from openpype.pipeline import PublishXmlValidationError @@ -23,6 +24,7 @@ def get_instance(context, plugin): def repair_knob(self, instances, state): for instance in instances: + node = napi.get_instance_node(instance) files_remove = [os.path.join(instance.data["outputDir"], f) for r in instance.data.get("representations", []) for f in r.get("files", []) @@ -31,7 +33,7 @@ def repair_knob(self, instances, state): for f in files_remove: os.remove(f) self.log.debug("removing file: {}".format(f)) - instance[0]["render"].setValue(state) + node["render"].setValue(state) self.log.info("Rendering toggled to `{}`".format(state)) @@ -62,9 +64,10 @@ class ValidateRenderedFrames(pyblish.api.InstancePlugin): actions = [RepairCollectionActionToLocal, RepairCollectionActionToFarm] def process(self, instance): + node = napi.get_instance_node(instance) f_data = { - "node_name": instance[0]["name"].value() + "node_name": node.name() } for repre in instance.data["representations"]: diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_legacy.py b/openpype/hosts/nuke/plugins/publish/validate_write_legacy.py index 699526ef572..e9bcb08b00f 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_legacy.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_legacy.py @@ -7,7 +7,7 @@ from openpype.pipeline import discover_creator_plugins from openpype.pipeline.publish import RepairAction from openpype.hosts.nuke.api.lib import get_avalon_knob_data - +from openpype.hosts.nuke import api as napi class ValidateWriteLegacy(pyblish.api.InstancePlugin): """Validate legacy write nodes.""" @@ -20,7 +20,7 @@ class ValidateWriteLegacy(pyblish.api.InstancePlugin): actions = [RepairAction] def process(self, instance): - node = instance[0] + node = napi.get_instance_node(instance) msg = "Clean up legacy write node \"{}\"".format(instance) if node.Class() not in ["Group", "Write"]: @@ -48,7 +48,7 @@ def process(self, instance): @classmethod def repair(cls, instance): - node = instance[0] + node = napi.get_instance_node(instance) if "Write" in node.Class(): data = toml.loads(node["avalon"].value()) diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py index 26a563b13ba..490ab2e5ae0 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py @@ -5,6 +5,7 @@ set_node_knobs_from_settings, color_gui_to_int ) +from openpype.hosts.nuke import api as napi from openpype.pipeline import PublishXmlValidationError @@ -18,10 +19,15 @@ def process(self, context, plugin): instances = get_errored_instances_from_context(context) for instance in instances: - write_group_node = instance[0] + child_nodes = ( + instance.data.get("transientData", {}).get("childNodes") + or instance + ) + + write_group_node = napi.get_instance_node(instance) # get write node from inside of group write_node = None - for x in instance: + for x in child_nodes: if x.Class() == "Write": write_node = x @@ -47,11 +53,16 @@ class ValidateNukeWriteNode(pyblish.api.InstancePlugin): hosts = ["nuke"] def process(self, instance): - write_group_node = instance[0] + child_nodes = ( + instance.data.get("transientData", {}).get("childNodes") + or instance + ) + + write_group_node = napi.get_instance_node(instance) # get write node from inside of group write_node = None - for x in instance: + for x in child_nodes: if x.Class() == "Write": write_node = x From f8cba8d477853ff024899084d9798f6c110d87af Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 7 Oct 2022 15:39:35 +0200 Subject: [PATCH 048/115] nuke: renaming precollect to collect --- .../publish/{precollect_instances.py => collect_instances.py} | 4 ++-- .../publish/{precollect_workfile.py => collect_workfile.py} | 2 +- .../publish/{precollect_writes.py => collect_writes.py} | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename openpype/hosts/nuke/plugins/publish/{precollect_instances.py => collect_instances.py} (98%) rename openpype/hosts/nuke/plugins/publish/{precollect_workfile.py => collect_workfile.py} (98%) rename openpype/hosts/nuke/plugins/publish/{precollect_writes.py => collect_writes.py} (99%) diff --git a/openpype/hosts/nuke/plugins/publish/precollect_instances.py b/openpype/hosts/nuke/plugins/publish/collect_instances.py similarity index 98% rename from openpype/hosts/nuke/plugins/publish/precollect_instances.py rename to openpype/hosts/nuke/plugins/publish/collect_instances.py index b396056eb98..54ad0229dd2 100644 --- a/openpype/hosts/nuke/plugins/publish/precollect_instances.py +++ b/openpype/hosts/nuke/plugins/publish/collect_instances.py @@ -8,11 +8,11 @@ @pyblish.api.log -class PreCollectNukeInstances(pyblish.api.ContextPlugin): +class CollectNukeInstances(pyblish.api.ContextPlugin): """Collect all nodes with Avalon knob.""" order = pyblish.api.CollectorOrder - 0.49 - label = "Pre-collect Instances" + label = "Collect Instances" hosts = ["nuke", "nukeassist"] # presets diff --git a/openpype/hosts/nuke/plugins/publish/precollect_workfile.py b/openpype/hosts/nuke/plugins/publish/collect_workfile.py similarity index 98% rename from openpype/hosts/nuke/plugins/publish/precollect_workfile.py rename to openpype/hosts/nuke/plugins/publish/collect_workfile.py index 822f405a6f0..8b6ab5d0723 100644 --- a/openpype/hosts/nuke/plugins/publish/precollect_workfile.py +++ b/openpype/hosts/nuke/plugins/publish/collect_workfile.py @@ -15,7 +15,7 @@ class CollectWorkfile(pyblish.api.ContextPlugin): """Collect current script for publish.""" order = pyblish.api.CollectorOrder - 0.50 - label = "Pre-collect Workfile" + label = "Collect Workfile" hosts = ['nuke'] def process(self, context): # sourcery skip: avoid-builtin-shadow diff --git a/openpype/hosts/nuke/plugins/publish/precollect_writes.py b/openpype/hosts/nuke/plugins/publish/collect_writes.py similarity index 99% rename from openpype/hosts/nuke/plugins/publish/precollect_writes.py rename to openpype/hosts/nuke/plugins/publish/collect_writes.py index 10eeb91644b..8d7ae5d0df6 100644 --- a/openpype/hosts/nuke/plugins/publish/precollect_writes.py +++ b/openpype/hosts/nuke/plugins/publish/collect_writes.py @@ -19,7 +19,7 @@ class CollectNukeWrites(pyblish.api.InstancePlugin): """Collect all write nodes.""" order = pyblish.api.CollectorOrder - 0.48 - label = "Pre-collect Writes" + label = "Collect Writes" hosts = ["nuke", "nukeassist"] families = ["write"] From 173a531f5f9d3b16c0779176093eb5b3488bef25 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Sat, 8 Oct 2022 21:51:15 +0200 Subject: [PATCH 049/115] nuke: updating settings --- openpype/settings/defaults/project_anatomy/imageio.json | 2 +- openpype/settings/defaults/project_settings/nuke.json | 6 +++--- .../schemas/projects_schema/schema_project_nuke.json | 4 ++-- .../projects_schema/schemas/schema_nuke_publish.json | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/openpype/settings/defaults/project_anatomy/imageio.json b/openpype/settings/defaults/project_anatomy/imageio.json index f0be8f95f4d..caa2a8a2060 100644 --- a/openpype/settings/defaults/project_anatomy/imageio.json +++ b/openpype/settings/defaults/project_anatomy/imageio.json @@ -156,7 +156,7 @@ }, { "plugins": [ - "CreateWriteStill" + "CreateWriteImage" ], "nukeNodeClass": "Write", "knobs": [ diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index 783b42348c1..8e4dd163ab2 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -99,10 +99,10 @@ ], "prenodes": {} }, - "CreateWriteStill": { + "CreateWriteImage": { "temp_rendering_path_template": "{work}/renders/nuke/{subset}/{subset}.{ext}", "default_variants": [ - "ImageFrame", + "StillFrame", "MPFrame", "LayoutFrame" ], @@ -125,7 +125,7 @@ } }, "publish": { - "PreCollectNukeInstances": { + "CollectInstanceData": { "sync_workfile_version_on_families": [ "nukenodes", "camera", diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json index 520985154e7..00ba3d5f034 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json @@ -205,8 +205,8 @@ { "type": "dict", "collapsible": true, - "key": "CreateWriteStill", - "label": "CreateWriteStill", + "key": "CreateWriteImage", + "label": "CreateWriteImage", "is_group": true, "children": [ { diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json index e5827a92c47..aa0c785e7aa 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json @@ -11,8 +11,8 @@ { "type": "dict", "collapsible": true, - "key": "PreCollectNukeInstances", - "label": "PreCollectNukeInstances", + "key": "CollectInstanceData", + "label": "CollectInstanceData", "is_group": true, "children": [ { From 5ba40a60526fb1d221b6af6a323da3ebc8501eaa Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Sat, 8 Oct 2022 21:52:16 +0200 Subject: [PATCH 050/115] Nuke: rename still to image and change family --- .../{create_write_still.py => create_write_image.py} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename openpype/hosts/nuke/plugins/create/{create_write_still.py => create_write_image.py} (96%) diff --git a/openpype/hosts/nuke/plugins/create/create_write_still.py b/openpype/hosts/nuke/plugins/create/create_write_image.py similarity index 96% rename from openpype/hosts/nuke/plugins/create/create_write_still.py rename to openpype/hosts/nuke/plugins/create/create_write_image.py index b3a096a5ba5..1bb114903fc 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_still.py +++ b/openpype/hosts/nuke/plugins/create/create_write_image.py @@ -14,10 +14,10 @@ from openpype.hosts.nuke import api as napi -class CreateWriteStill(napi.NukeWriteCreator): - identifier = "create_write_still" - label = "Create Write Still Frame" - family = "still" +class CreateWriteImage(napi.NukeWriteCreator): + identifier = "create_write_image" + label = "Create Write Image" + family = "image" icon = "sign-out" def get_pre_create_attr_defs(self): From f8455915ac5dcb6f422c517b68438e5371ad4b4a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Sat, 8 Oct 2022 21:52:52 +0200 Subject: [PATCH 051/115] Nuke: refactor instance collector --- .../plugins/publish/collect_instance_data.py | 45 +++++ .../nuke/plugins/publish/collect_instances.py | 158 ------------------ 2 files changed, 45 insertions(+), 158 deletions(-) create mode 100644 openpype/hosts/nuke/plugins/publish/collect_instance_data.py delete mode 100644 openpype/hosts/nuke/plugins/publish/collect_instances.py diff --git a/openpype/hosts/nuke/plugins/publish/collect_instance_data.py b/openpype/hosts/nuke/plugins/publish/collect_instance_data.py new file mode 100644 index 00000000000..9614ebdea64 --- /dev/null +++ b/openpype/hosts/nuke/plugins/publish/collect_instance_data.py @@ -0,0 +1,45 @@ +import nuke +import pyblish.api + + +@pyblish.api.log +class CollectInstanceData(pyblish.api.InstancePlugin): + """Collect all nodes with Avalon knob.""" + + order = pyblish.api.CollectorOrder - 0.49 + label = "Collect Instance Data" + hosts = ["nuke", "nukeassist"] + + # presets + sync_workfile_version_on_families = [] + + def process(self, instance): + family = instance.data["family"] + + # Get format + root = nuke.root() + format_ = root['format'].value() + resolution_width = format_.width() + resolution_height = format_.height() + pixel_aspect = format_.pixelAspect() + + # sync workfile version + if family in self.sync_workfile_version_on_families: + self.log.debug( + "Syncing version with workfile for '{}'".format( + family + ) + ) + # get version to instance for integration + instance.data['version'] = instance.context.data['version'] + + instance.data.update({ + "step": 1, + "fps": root['fps'].value(), + "resolutionWidth": resolution_width, + "resolutionHeight": resolution_height, + "pixelAspect": pixel_aspect + + }) + self.log.debug("Collected instance: {}".format( + instance.data)) diff --git a/openpype/hosts/nuke/plugins/publish/collect_instances.py b/openpype/hosts/nuke/plugins/publish/collect_instances.py deleted file mode 100644 index 54ad0229dd2..00000000000 --- a/openpype/hosts/nuke/plugins/publish/collect_instances.py +++ /dev/null @@ -1,158 +0,0 @@ -import nuke -import pyblish.api - -from openpype.hosts.nuke.api.lib import ( - add_publish_knob, - get_avalon_knob_data -) - - -@pyblish.api.log -class CollectNukeInstances(pyblish.api.ContextPlugin): - """Collect all nodes with Avalon knob.""" - - order = pyblish.api.CollectorOrder - 0.49 - label = "Collect Instances" - hosts = ["nuke", "nukeassist"] - - # presets - sync_workfile_version_on_families = [] - - def process(self, context): - instances = [] - - root = nuke.root() - - self.log.debug("nuke.allNodes(): {}".format(nuke.allNodes())) - for node in nuke.allNodes(): - - if node.Class() in ["Viewer", "Dot"]: - continue - - try: - if node["disable"].value(): - continue - except Exception as E: - self.log.warning(E) - - # get data from avalon knob - avalon_knob_data = get_avalon_knob_data( - node, ["avalon:", "ak:"]) - - self.log.debug("avalon_knob_data: {}".format(avalon_knob_data)) - - if not avalon_knob_data: - continue - - if avalon_knob_data["id"] != "pyblish.avalon.instance": - continue - - # establish families - family = avalon_knob_data["family"] - families_ak = avalon_knob_data.get("families", []) - families = [] - - # except disabled nodes but exclude backdrops in test - if ("nukenodes" not in family) and (node["disable"].value()): - continue - - subset = avalon_knob_data.get( - "subset", None) or node["name"].value() - - # Create instance - instance = context.create_instance(subset) - instance.append(node) - - suspend_publish = False - if "suspend_publish" in node.knobs(): - suspend_publish = node["suspend_publish"].value() - instance.data["suspend_publish"] = suspend_publish - - # get review knob value - review = False - if "review" in node.knobs(): - review = node["review"].value() - - if review: - families.append("review") - - # Add all nodes in group instances. - if node.Class() == "Group": - # only alter families for render family - if families_ak and "write" in families_ak.lower(): - target = node["render"].value() - if target == "Use existing frames": - # Local rendering - self.log.info("flagged for no render") - families.append(families_ak.lower()) - elif target == "Local": - # Local rendering - self.log.info("flagged for local render") - families.append("{}.local".format(family)) - family = families_ak.lower() - elif target == "On farm": - # Farm rendering - self.log.info("flagged for farm render") - instance.data["transfer"] = False - instance.data["farm"] = True - families.append("{}.farm".format(family)) - family = families_ak.lower() - - node.begin() - for i in nuke.allNodes(): - instance.append(i) - node.end() - - if not families and families_ak and family not in [ - "render", "prerender"]: - families.append(families_ak.lower()) - - self.log.debug("__ family: `{}`".format(family)) - self.log.debug("__ families: `{}`".format(families)) - - # Get format - format_ = root['format'].value() - resolution_width = format_.width() - resolution_height = format_.height() - pixel_aspect = format_.pixelAspect() - - # get publish knob value - if "publish" not in node.knobs(): - add_publish_knob(node) - - # sync workfile version - _families_test = [family] + families - self.log.debug("__ _families_test: `{}`".format(_families_test)) - for family_test in _families_test: - if family_test in self.sync_workfile_version_on_families: - self.log.debug( - "Syncing version with workfile for '{}'".format( - family_test - ) - ) - # get version to instance for integration - instance.data['version'] = instance.context.data['version'] - - instance.data.update({ - "subset": subset, - "asset": avalon_knob_data["asset"], - "label": node.name(), - "name": node.name(), - "subset": subset, - "family": family, - "families": families, - "avalonKnob": avalon_knob_data, - "step": 1, - "publish": node.knob('publish').value(), - "fps": nuke.root()['fps'].value(), - "resolutionWidth": resolution_width, - "resolutionHeight": resolution_height, - "pixelAspect": pixel_aspect, - "review": review, - "representations": [] - - }) - self.log.info("collected instance: {}".format(instance.data)) - instances.append(instance) - - self.log.debug("context: {}".format(context)) From 0e3a8ffb82008b895813caf8ac60b19f8b5c5cd9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Sat, 8 Oct 2022 21:53:12 +0200 Subject: [PATCH 052/115] nuke: refactor collect writes --- .../nuke/plugins/publish/collect_writes.py | 228 ++++++++---------- 1 file changed, 104 insertions(+), 124 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_writes.py b/openpype/hosts/nuke/plugins/publish/collect_writes.py index 8d7ae5d0df6..32d837f4001 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_writes.py +++ b/openpype/hosts/nuke/plugins/publish/collect_writes.py @@ -1,17 +1,8 @@ import os -import re from pprint import pformat import nuke import pyblish.api - -from openpype.client import ( - get_last_version_by_subset_name, - get_representations, -) -from openpype.pipeline import ( - legacy_io, - get_representation_path, -) +from openpype.hosts.nuke import api as napi @pyblish.api.log @@ -21,35 +12,49 @@ class CollectNukeWrites(pyblish.api.InstancePlugin): order = pyblish.api.CollectorOrder - 0.48 label = "Collect Writes" hosts = ["nuke", "nukeassist"] - families = ["write"] + families = ["render", "prerender", "image"] def process(self, instance): - _families_test = [instance.data["family"]] + instance.data["families"] - self.log.debug("_families_test: {}".format(_families_test)) + self.log.debug(pformat(instance.data)) + instance.data.update(instance.data["creator_attributes"]) + + group_node = napi.get_instance_node(instance) + render_target = instance.data["render_target"] + family = instance.data["family"] + families = instance.data["families"] - child_nodes = ( - instance.data.get("transientData", {}).get("childNodes") - or instance + # add targeted family to families + instance.data["families"].append( + "{}.{}".format(family, render_target) ) + # add additional keys to farm targeted + if render_target == "farm": + # Farm rendering + self.log.info("flagged for farm render") + instance.data["transfer"] = False + instance.data["farm"] = True - node = None + child_nodes = napi.get_instance_group_node_childs(instance) + instance.data["transientData"]["childNodes"] = child_nodes + + write_node = None for x in child_nodes: if x.Class() == "Write": - node = x - - if node is None: + write_node = x + + if write_node is None: + self.log.warning( + "Created node '{}' is missing write node!".format( + group_node.name() + ) + ) return - instance.data["writeNode"] = node + instance.data["writeNode"] = write_node self.log.debug("checking instance: {}".format(instance)) # Determine defined file type - ext = node["file_type"].value() - - # Determine output type - output_type = "img" - if ext == "mov": - output_type = "mov" + ext = write_node["file_type"].value() # Get frame range handle_start = instance.context.data["handleStart"] @@ -58,105 +63,85 @@ def process(self, instance): last_frame = int(nuke.root()["last_frame"].getValue()) frame_length = int(last_frame - first_frame + 1) - if node["use_limit"].getValue(): - first_frame = int(node["first"].getValue()) - last_frame = int(node["last"].getValue()) - - # Prepare expected output paths by evaluating each frame of write node - # - paths are first collected to set to avoid duplicated paths, then - # sorted and converted to list - node_file = node["file"] - expected_paths = list(sorted({ - node_file.evaluate(frame) - for frame in range(first_frame, last_frame + 1) - })) - expected_filenames = [ - os.path.basename(filepath) - for filepath in expected_paths - ] - path = nuke.filename(node) - output_dir = os.path.dirname(path) + if write_node["use_limit"].getValue(): + first_frame = int(write_node["first"].getValue()) + last_frame = int(write_node["last"].getValue()) - self.log.debug('output dir: {}'.format(output_dir)) + write_file_path = nuke.filename(write_node) + output_dir = os.path.dirname(write_file_path) - # create label - name = node.name() - # Include start and end render frame in label - label = "{0} ({1}-{2})".format( - name, - int(first_frame), - int(last_frame) - ) + self.log.debug('output dir: {}'.format(output_dir)) - if [fm for fm in _families_test - if fm in ["render", "prerender", "still"]]: - if "representations" not in instance.data: - instance.data["representations"] = list() + if render_target == "frame": representation = { 'name': ext, 'ext': ext, "stagingDir": output_dir, - "tags": list() + "tags": [] } - try: - collected_frames = [ - filename - for filename in os.listdir(output_dir) - if filename in expected_filenames - ] - if collected_frames: - collected_frames_len = len(collected_frames) - frame_start_str = "%0{}d".format( - len(str(last_frame))) % first_frame - representation['frameStart'] = frame_start_str - - # in case slate is expected and not yet rendered - self.log.debug("_ frame_length: {}".format(frame_length)) - self.log.debug( - "_ collected_frames_len: {}".format( - collected_frames_len)) - # this will only run if slate frame is not already - # rendered from previews publishes - if "slate" in _families_test \ - and (frame_length == collected_frames_len) \ - and ("prerender" not in _families_test): - frame_slate_str = "%0{}d".format( - len(str(last_frame))) % (first_frame - 1) - slate_frame = collected_frames[0].replace( - frame_start_str, frame_slate_str) - collected_frames.insert(0, slate_frame) + # get file path knob + node_file_knob = write_node["file"] + # list file paths based on input frames + expected_paths = list(sorted({ + node_file_knob.evaluate(frame) + for frame in range(first_frame, last_frame + 1) + })) + + # convert only to base names + expected_filenames = [ + os.path.basename(filepath) + for filepath in expected_paths + ] + + # make sure files are existing at folder + collected_frames = [ + filename + for filename in os.listdir(output_dir) + if filename in expected_filenames + ] + + if collected_frames: + collected_frames_len = len(collected_frames) + frame_start_str = "%0{}d".format( + len(str(last_frame))) % first_frame + representation['frameStart'] = frame_start_str + + # in case slate is expected and not yet rendered + self.log.debug("_ frame_length: {}".format(frame_length)) + self.log.debug("_ collected_frames_len: {}".format( + collected_frames_len)) + + # this will only run if slate frame is not already + # rendered from previews publishes + if ( + "slate" in families + and frame_length == collected_frames_len + and family == "render" + ): + frame_slate_str = ( + "{{:0{}d}}".format(len(str(last_frame))) + ).format(first_frame - 1) + + slate_frame = collected_frames[0].replace( + frame_start_str, frame_slate_str) + collected_frames.insert(0, slate_frame) if collected_frames_len == 1: representation['files'] = collected_frames.pop() - if "still" in _families_test: - instance.data['family'] = 'image' - instance.data["families"].remove('still') else: representation['files'] = collected_frames - instance.data["representations"].append(representation) - except Exception: - instance.data["representations"].append(representation) - self.log.debug("couldn't collect frames: {}".format(label)) - - # Add version data to instance - colorspace = node["colorspace"].value() - # remove default part of the string - if "default (" in colorspace: - colorspace = re.sub(r"default.\(|\)", "", colorspace) - self.log.debug("colorspace: `{}`".format(colorspace)) + instance.data["representations"].append(representation) + # get colorspace and add to version data + colorspace = napi.get_colorspace_from_node(write_node) version_data = { - "families": [ - _f.replace(".local", "").replace(".farm", "") - for _f in _families_test if "write" != _f - ], "colorspace": colorspace } - group_node = [x for x in instance if x.Class() == "Group"][0] + # get deadline related attributes dl_chunk_size = 1 if "deadlineChunkSize" in group_node.knobs(): dl_chunk_size = group_node["deadlineChunkSize"].value() @@ -171,42 +156,37 @@ def process(self, instance): instance.data.update({ "versionData": version_data, - "path": path, + "path": write_file_path, "outputDir": output_dir, "ext": ext, - "label": label, - "outputType": output_type, "colorspace": colorspace, "deadlineChunkSize": dl_chunk_size, "deadlinePriority": dl_priority, "deadlineConcurrentTasks": dl_concurrent_tasks }) - if self.is_prerender(_families_test): + if family == "render": instance.data.update({ - "handleStart": 0, - "handleEnd": 0, - "frameStart": first_frame, - "frameEnd": last_frame, + "handleStart": handle_start, + "handleEnd": handle_end, + "frameStart": first_frame + handle_start, + "frameEnd": last_frame - handle_end, "frameStartHandle": first_frame, "frameEndHandle": last_frame, }) else: instance.data.update({ - "handleStart": handle_start, - "handleEnd": handle_end, - "frameStart": first_frame + handle_start, - "frameEnd": last_frame - handle_end, + "handleStart": 0, + "handleEnd": 0, + "frameStart": first_frame, + "frameEnd": last_frame, "frameStartHandle": first_frame, "frameEndHandle": last_frame, }) - # make sure rendered sequence on farm will - # be used for exctract review - if not instance.data["review"]: - instance.data["useSequenceForReview"] = False + # make sure rendered sequence on farm will + # be used for exctract review + if not instance.data["review"]: + instance.data["useSequenceForReview"] = False self.log.debug("instance.data: {}".format(pformat(instance.data))) - - def is_prerender(self, families): - return next((f for f in families if "prerender" in f), None) From ef27fc4cf21ffd99c0ffdd949f8d045caa86de88 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Sat, 8 Oct 2022 21:53:34 +0200 Subject: [PATCH 053/115] Nuke: refactor collect slates --- openpype/hosts/nuke/plugins/publish/collect_slate_node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py index 0a98bcf973c..e3f24a233eb 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py +++ b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py @@ -9,7 +9,7 @@ class CollectSlate(pyblish.api.InstancePlugin): order = pyblish.api.CollectorOrder + 0.09 label = "Collect Slate Node" hosts = ["nuke"] - families = ["render", "render.local", "render.farm"] + families = ["render"] def process(self, instance): node = napi.get_instance_node(instance) From ce0d2b8fe16a03be90a917cc666f4dcc5158fb70 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Sat, 8 Oct 2022 21:54:14 +0200 Subject: [PATCH 054/115] nuke: adding supporting functions to plugin.py --- openpype/hosts/nuke/api/__init__.py | 6 ++++- openpype/hosts/nuke/api/plugin.py | 37 ++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index 156b3f0de09..8aaaff43b31 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -14,7 +14,9 @@ NukeWriteCreator, NukeCreatorError, OpenPypeCreator, - get_instance_node + get_instance_node, + get_instance_group_node_childs, + get_colorspace_from_node ) from .pipeline import ( NukeHost, @@ -66,6 +68,8 @@ "OpenPypeCreator", "NukeHost", "get_instance_node", + "get_instance_group_node_childs", + "get_colorspace_from_node", "ls", diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 193c2e8c2d5..45f16b29439 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -1,5 +1,5 @@ import nuke - +import re import os import sys import six @@ -415,6 +415,41 @@ def get_instance_node(instance): return instance[0] +def get_instance_group_node_childs(instance): + """Return list of instance group node children + + Args: + instance (pyblish.Instance): pyblish instance + + Returns: + list: [nuke.Node] + """ + node = get_instance_node(instance) + + if node.Class() != "Group": + return + + # collect child nodes + child_nodes = [] + # iterate all nodes + for node in nuke.allNodes(group=node): + # add contained nodes to instance's node list + child_nodes.append(node) + + return child_nodes + + +def get_colorspace_from_node(node): + # Add version data to instance + colorspace = node["colorspace"].value() + + # remove default part of the string + if "default (" in colorspace: + colorspace = re.sub(r"default.\(|\)", "", colorspace) + + return colorspace + + def get_review_presets_config(): settings = get_current_project_settings() review_profiles = ( From 0bce4fc67ad3a93b2014a94834f3c293c51bf9f9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Sat, 8 Oct 2022 21:55:38 +0200 Subject: [PATCH 055/115] nuke: adding deprecated decorator --- openpype/hosts/nuke/api/lib.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 4478633198f..df0b303878d 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -691,6 +691,7 @@ def get_nuke_imageio_settings(): return get_anatomy_settings(Context.project_name)["imageio"]["nuke"] +@deprecated("openpype.hosts.nuke.api.lib.get_nuke_imageio_settings") def get_created_node_imageio_setting_legacy(nodeclass, creator, subset): '''[DEPRICATED] Get preset data for dataflow (fileType, compression, bitDepth) ''' From a45666c4c45325bd13973397824d2ce5fc698a3a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 10 Oct 2022 17:37:32 +0200 Subject: [PATCH 056/115] Nuke: plugin better update instances --- openpype/hosts/nuke/api/plugin.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 45f16b29439..748c52eb1f2 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -198,15 +198,11 @@ def collect_instances(self): def update_instances(self, update_list): for created_inst, _changes in update_list: instance_node = created_inst.transient_data["node"] - current_data = created_inst.data set_node_data( instance_node, INSTANCE_DATA_KNOB, - { - key: value[1] for key, value in _changes.items() - if current_data.get(key) != value[0] - } + created_inst.data_to_store() ) def remove_instances(self, instances): From c975429799163f7f2fbbeb52c6654c1f604eb000 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 10 Oct 2022 17:38:04 +0200 Subject: [PATCH 057/115] Nuke: update write validator --- .../nuke/plugins/publish/validate_write_nodes.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py index 490ab2e5ae0..ab1671ad0ef 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py @@ -6,7 +6,10 @@ color_gui_to_int ) from openpype.hosts.nuke import api as napi -from openpype.pipeline import PublishXmlValidationError +from openpype.pipeline.publish import ( + PublishXmlValidationError, + OptionalPyblishPluginMixin, +) @pyblish.api.log @@ -38,7 +41,10 @@ def process(self, context, plugin): self.log.info("Node attributes were fixed") -class ValidateNukeWriteNode(pyblish.api.InstancePlugin): +class ValidateNukeWriteNode( + OptionalPyblishPluginMixin, + pyblish.api.InstancePlugin +): """ Validate Write node's knobs. Compare knobs on write node inside the render group @@ -48,11 +54,14 @@ class ValidateNukeWriteNode(pyblish.api.InstancePlugin): order = pyblish.api.ValidatorOrder optional = True families = ["render"] - label = "Write Node" + label = "Validate write node" actions = [RepairNukeWriteNodeAction] hosts = ["nuke"] def process(self, instance): + if not self.is_active(instance.data): + return + child_nodes = ( instance.data.get("transientData", {}).get("childNodes") or instance From 0271e3b60fe018bf78f9fad25fe2c81afab26a33 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 10 Oct 2022 20:58:10 +0200 Subject: [PATCH 058/115] Nuke: improving error message. --- openpype/hosts/nuke/plugins/create/create_backdrop.py | 4 ++-- openpype/hosts/nuke/plugins/create/create_camera.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_backdrop.py b/openpype/hosts/nuke/plugins/create/create_backdrop.py index 40eaab08cf8..d82456392af 100644 --- a/openpype/hosts/nuke/plugins/create/create_backdrop.py +++ b/openpype/hosts/nuke/plugins/create/create_backdrop.py @@ -45,8 +45,8 @@ def create_instance_node( def create(self, subset_name, instance_data, pre_create_data): if self.check_existing_subset(subset_name, instance_data): raise NukeCreatorError( - ("subset {} is already published with different HDA" - "definition.").format(subset_name)) + ("Subset name '{}' is already used. " + "Please specify different Variant.").format(subset_name)) instance = super(CreateBackdrop, self).create( subset_name, diff --git a/openpype/hosts/nuke/plugins/create/create_camera.py b/openpype/hosts/nuke/plugins/create/create_camera.py index 0b538d0088c..ea2fd4b9710 100644 --- a/openpype/hosts/nuke/plugins/create/create_camera.py +++ b/openpype/hosts/nuke/plugins/create/create_camera.py @@ -42,8 +42,8 @@ def create_instance_node( def create(self, subset_name, instance_data, pre_create_data): if self.check_existing_subset(subset_name, instance_data): raise NukeCreatorError( - ("subset {} is already published with different HDA" - "definition.").format(subset_name)) + ("Subset name '{}' is already used. " + "Please specify different Variant.").format(subset_name)) instance = super(CreateCamera, self).create( subset_name, From 0a29bcfcc5f1724080993dfad76c47c1965b9f01 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 10 Oct 2022 20:58:26 +0200 Subject: [PATCH 059/115] Nuke: refactory model creator --- .../hosts/nuke/plugins/create/create_model.py | 120 ++++++++---------- 1 file changed, 50 insertions(+), 70 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_model.py b/openpype/hosts/nuke/plugins/create/create_model.py index 15a4e3ab8a0..bfddcb64c30 100644 --- a/openpype/hosts/nuke/plugins/create/create_model.py +++ b/openpype/hosts/nuke/plugins/create/create_model.py @@ -1,87 +1,67 @@ import nuke -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - set_avalon_knob_data +from openpype.hosts.nuke.api import ( + NukeCreator, + NukeCreatorError, + maintained_selection ) -class CreateModel(plugin.OpenPypeCreator): - """Add Publishable Model Geometry""" +class CreateModel(NukeCreator): + """Add Publishable Camera""" - name = "model" + identifier = "create_model" label = "Create 3d Model" family = "model" icon = "cube" - defaults = ["Main"] + default_variants = ["Main"] - def __init__(self, *args, **kwargs): - super(CreateModel, self).__init__(*args, **kwargs) - self.nodes = nuke.selectedNodes() - self.node_color = "0xff3200ff" - return + # plugin attributes + node_color = "0xff3200ff" - def process(self): - nodes = list() - if (self.options or {}).get("useSelection"): - nodes = self.nodes - for n in nodes: - n['selected'].setValue(0) - end_nodes = list() + def create_instance_node( + self, + node_name, + knobs=None, + parent=None, + node_type=None + ): + with maintained_selection(): + if self.selected_nodes: + created_node = self.selected_nodes[0] + else: + created_node = nuke.createNode("Scene") - # get the latest nodes in tree for selecion - for n in nodes: - x = n - end = 0 - while end == 0: - try: - x = x.dependent()[0] - except: - end_node = x - end = 1 - end_nodes.append(end_node) + created_node["tile_color"].setValue( + int(self.node_color, 16)) - # set end_nodes - end_nodes = list(set(end_nodes)) + created_node["name"].setValue(node_name) - # check if nodes is 3d nodes - for n in end_nodes: - n['selected'].setValue(1) - sn = nuke.createNode("Scene") - if not sn.input(0): - end_nodes.remove(n) - nuke.delete(sn) + self.add_info_knob(created_node) - # loop over end nodes - for n in end_nodes: - n['selected'].setValue(1) + return created_node - self.nodes = nuke.selectedNodes() - nodes = self.nodes - if len(nodes) >= 1: - # loop selected nodes - for n in nodes: - data = self.data.copy() - if len(nodes) > 1: - # rename subset name only if more - # then one node are selected - subset = self.family + n["name"].value().capitalize() - data["subset"] = subset + def create(self, subset_name, instance_data, pre_create_data): + if self.check_existing_subset(subset_name, instance_data): + raise NukeCreatorError( + ("Subset name '{}' is already used. " + "Please specify different Variant.").format(subset_name)) - # change node color - n["tile_color"].setValue(int(self.node_color, 16)) - # add avalon knobs - set_avalon_knob_data(n, data) - return True - else: - msg = str("Please select nodes you " - "wish to add to a container") - self.log.error(msg) - nuke.message(msg) - return + instance = super(CreateModel, self).create( + subset_name, + instance_data, + pre_create_data + ) + + return instance + + def set_selected_nodes(self, pre_create_data): + if pre_create_data.get("use_selection"): + self.selected_nodes = nuke.selectedNodes() + if self.selected_nodes == []: + raise NukeCreatorError("Creator error: No active selection") + elif len(self.selected_nodes) > 1: + NukeCreatorError("Creator error: Select only one camera node") else: - # if selected is off then create one node - model_node = nuke.createNode("WriteGeo") - model_node["tile_color"].setValue(int(self.node_color, 16)) - # add avalon knobs - instance = set_avalon_knob_data(model_node, self.data) - return instance + self.selected_nodes = [] + + self.log.debug("Selection is: {}".format(self.selected_nodes)) From 3361c9a66d4921741ec836a5728a24c6ea6cb5f3 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 11 Oct 2022 17:30:53 +0200 Subject: [PATCH 060/115] nuke: convert_to_valid_instaces function convert old instances to new publisher --- openpype/hosts/nuke/api/plugin.py | 139 +++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 748c52eb1f2..8ef6c60296b 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -1,3 +1,4 @@ +from pprint import pformat import nuke import re import os @@ -37,6 +38,7 @@ set_node_knobs_from_settings, get_view_process_node, set_node_data, + get_node_data, deprecated ) from .pipeline import ( @@ -189,6 +191,10 @@ def create(self, subset_name, instance_data, pre_create_data): def collect_instances(self): for (node, data) in list_instances(creator_id=self.identifier): + self.log.debug("_" * 50) + self.log.debug("_ self.identifier: `{}`".format(self.identifier)) + self.log.debug("_ data: `{}`".format(pformat(data))) + created_instance = CreatedInstance.from_existing( data, self ) @@ -337,8 +343,7 @@ def create(self, subset_name, instance_data, pre_create_data): def apply_settings( self, project_settings, - system_settings, - # anatomy_settings + system_settings ): """Method called on initialization of plugin to apply settings.""" @@ -1080,3 +1085,133 @@ def _modify_write_node(self, write_node): node (nuke.Node): group node with data as Knobs """ pass + + +def convert_to_valid_instaces(): + """ Check and convert to latest publisher instances + + Also save as new minor version of workfile. + """ + def family_to_identifier(family): + mapping = { + "render": "create_write_render", + "prerender": "create_write_prerender", + "still": "create_write_image", + "model": "create_model", + "camera": "create_camera", + "nukenodes": "create_backdrop", + "gizmo": "create_gizmo", + "source": "create_source" + + } + return mapping[family] + + from openpype.hosts.nuke.api.lib import ( + get_avalon_knob_data + ) + from openpype.hosts.nuke.api import workio + + task_name = legacy_io.Session["AVALON_TASK"] + + # save into new workfile + current_file = workio.current_file() + new_workfile = current_file[:-3] + "_publisherConvert" + current_file[-3:] + + path = new_workfile.replace("\\", "/") + nuke.scriptSaveAs(new_workfile, overwrite=1) + nuke.Root()["name"].setValue(path) + nuke.Root()["project_directory"].setValue(os.path.dirname(path)) + nuke.Root().setModified(False) + + # loop all nodes and convert + for node in nuke.allNodes(recurseGroups=True): + transfer_data = { + "creator_attributes": {} + } + creator_attr = transfer_data["creator_attributes"] + + if node.Class() in ["Viewer", "Dot"]: + continue + + if get_node_data(node, INSTANCE_DATA_KNOB): + continue + + # get data from avalon knob + avalon_knob_data = get_avalon_knob_data( + node, ["avalon:", "ak:"]) + + if not avalon_knob_data: + continue + + if avalon_knob_data["id"] != "pyblish.avalon.instance": + continue + + transfer_data.update({ + k: v for k, v in avalon_knob_data.items() + if k not in ["families", "creator"] + }) + + transfer_data["task"] = task_name + + family = avalon_knob_data["family"] + # establish families + families_ak = avalon_knob_data.get("families", []) + + if "suspend_publish" in node.knobs(): + creator_attr["suspended_publish"] = ( + node["suspend_publish"].value()) + + # get review knob value + if "review" in node.knobs(): + creator_attr["review"] = ( + node["review"].value()) + + if "publish" in node.knobs(): + transfer_data["active"] = ( + node["publish"].value()) + + # add idetifier + transfer_data["creator_identifier"] = family_to_identifier(family) + + # Add all nodes in group instances. + if node.Class() == "Group": + # only alter families for render family + if families_ak and "write" in families_ak.lower(): + target = node["render"].value() + if target == "Use existing frames": + creator_attr["render_target"] = "frames" + elif target == "Local": + # Local rendering + creator_attr["render_target"] = "local" + elif target == "On farm": + # Farm rendering + creator_attr["render_target"] = "farm" + + if "deadlinePriority" in node.knobs(): + transfer_data["farm_priority"] = ( + node["deadlinePriority"].value()) + if "deadlineChunkSize" in node.knobs(): + creator_attr["farm_chunk"] = ( + node["deadlineChunkSize"].value()) + if "deadlineConcurrentTasks" in node.knobs(): + creator_attr["farm_concurency"] = ( + node["deadlineConcurrentTasks"].value()) + + remove_knobs = [ + "review", "publish", "render", "suspend_publish", "warn", "divd", + "OpenpypeDataGroup", "OpenpypeDataGroup_End", "deadlinePriority", + "deadlineChunkSize", "deadlineConcurrentTasks", "Deadline" + ] + + # remove all old knobs + for knob in node.allKnobs(): + if knob.name() in remove_knobs: + node.removeKnob(knob) + elif "avalon" in knob.name(): + node.removeKnob(knob) + + # add new instance knob with transfer data + set_node_data( + node, INSTANCE_DATA_KNOB, transfer_data) + + nuke.scriptSave() From e185ba57cd2b9adf8d1ffa182ccc57149c570b1d Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 13 Oct 2022 15:43:30 +0200 Subject: [PATCH 061/115] nuke: fixing missing instance data --- openpype/hosts/nuke/plugins/create/workfile_creator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/create/workfile_creator.py b/openpype/hosts/nuke/plugins/create/workfile_creator.py index ae54d6bcb29..ae05cee99f2 100644 --- a/openpype/hosts/nuke/plugins/create/workfile_creator.py +++ b/openpype/hosts/nuke/plugins/create/workfile_creator.py @@ -42,7 +42,7 @@ def collect_instances(self): }) instance_data.update(self.get_dynamic_data( self.default_variant, task_name, asset_doc, - project_name, host_name + project_name, host_name, instance_data )) instance = CreatedInstance( From 8180a02b1873170dd7bf02364496dd69082a5d95 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 13 Oct 2022 15:44:47 +0200 Subject: [PATCH 062/115] nuke: better creator names --- openpype/hosts/nuke/plugins/create/create_backdrop.py | 2 +- openpype/hosts/nuke/plugins/create/create_camera.py | 2 +- openpype/hosts/nuke/plugins/create/create_model.py | 2 +- openpype/hosts/nuke/plugins/create/create_read.py | 2 +- openpype/hosts/nuke/plugins/create/create_write_image.py | 2 +- openpype/hosts/nuke/plugins/create/create_write_prerender.py | 2 +- openpype/hosts/nuke/plugins/create/create_write_render.py | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_backdrop.py b/openpype/hosts/nuke/plugins/create/create_backdrop.py index d82456392af..ebc66e95a77 100644 --- a/openpype/hosts/nuke/plugins/create/create_backdrop.py +++ b/openpype/hosts/nuke/plugins/create/create_backdrop.py @@ -13,7 +13,7 @@ class CreateBackdrop(NukeCreator): """Add Publishable Backdrop""" identifier = "create_backdrop" - label = "Create Backdrop" + label = "Nukenodes (backdrop)" family = "nukenodes" icon = "file-archive-o" maintain_selection = True diff --git a/openpype/hosts/nuke/plugins/create/create_camera.py b/openpype/hosts/nuke/plugins/create/create_camera.py index ea2fd4b9710..2a48b8a72b3 100644 --- a/openpype/hosts/nuke/plugins/create/create_camera.py +++ b/openpype/hosts/nuke/plugins/create/create_camera.py @@ -10,7 +10,7 @@ class CreateCamera(NukeCreator): """Add Publishable Camera""" identifier = "create_camera" - label = "Create 3d Camera" + label = "Camera (3d)" family = "camera" icon = "camera" diff --git a/openpype/hosts/nuke/plugins/create/create_model.py b/openpype/hosts/nuke/plugins/create/create_model.py index bfddcb64c30..a1a96bf4124 100644 --- a/openpype/hosts/nuke/plugins/create/create_model.py +++ b/openpype/hosts/nuke/plugins/create/create_model.py @@ -10,7 +10,7 @@ class CreateModel(NukeCreator): """Add Publishable Camera""" identifier = "create_model" - label = "Create 3d Model" + label = "Model (3d)" family = "model" icon = "cube" default_variants = ["Main"] diff --git a/openpype/hosts/nuke/plugins/create/create_read.py b/openpype/hosts/nuke/plugins/create/create_read.py index 87a9dff0f86..d4f63e6b9f4 100644 --- a/openpype/hosts/nuke/plugins/create/create_read.py +++ b/openpype/hosts/nuke/plugins/create/create_read.py @@ -11,7 +11,7 @@ class CrateRead(plugin.OpenPypeCreator): # change this to template preset name = "ReadCopy" - label = "Create Read Copy" + label = "Source (read)" hosts = ["nuke"] family = "source" families = family diff --git a/openpype/hosts/nuke/plugins/create/create_write_image.py b/openpype/hosts/nuke/plugins/create/create_write_image.py index 1bb114903fc..e9ff33a32b1 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_image.py +++ b/openpype/hosts/nuke/plugins/create/create_write_image.py @@ -16,7 +16,7 @@ class CreateWriteImage(napi.NukeWriteCreator): identifier = "create_write_image" - label = "Create Write Image" + label = "Image (write)" family = "image" icon = "sign-out" diff --git a/openpype/hosts/nuke/plugins/create/create_write_prerender.py b/openpype/hosts/nuke/plugins/create/create_write_prerender.py index 1ce30379ade..b7d0f4ade9e 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_prerender.py +++ b/openpype/hosts/nuke/plugins/create/create_write_prerender.py @@ -16,7 +16,7 @@ class CreateWritePrerender(napi.NukeWriteCreator): identifier = "create_write_prerender" - label = "Create Write Prerender" + label = "Prerender (write)" family = "prerender" icon = "sign-out" diff --git a/openpype/hosts/nuke/plugins/create/create_write_render.py b/openpype/hosts/nuke/plugins/create/create_write_render.py index 89696f55e01..3d96e8c13ba 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_render.py +++ b/openpype/hosts/nuke/plugins/create/create_write_render.py @@ -16,7 +16,7 @@ class CreateWriteRender(napi.NukeWriteCreator): identifier = "create_write_render" - label = "Create Write Render" + label = "Render (write)" family = "render" icon = "sign-out" From 8521a2eac42a6f3c081e08e3351383b197de07c1 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 13 Oct 2022 15:45:38 +0200 Subject: [PATCH 063/115] nuke: missing try to catch ValueError --- openpype/hosts/nuke/api/pipeline.py | 8 ++++++-- openpype/hosts/nuke/api/plugin.py | 13 ++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index c93a4f090fa..258b09f7a87 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -37,7 +37,6 @@ check_inventory_versions, set_avalon_knob_data, read_avalon_data, - get_avalon_knob_data, on_script_load, dirmap_file_name_filter, add_scripts_menu, @@ -61,6 +60,7 @@ work_root, current_file ) +from openpype.hosts.nuke.api import plugin log = Logger.get_logger(__name__) @@ -297,7 +297,11 @@ def _install_menu(): "Experimental tools...", lambda: host_tools.show_experimental_tools_dialog(parent=main_window) ) - + menu.addSeparator() + menu.addCommand( + "Convert old publishing instances", + plugin.convert_to_valid_instaces + ) # add reload pipeline only in debug mode if bool(os.getenv("NUKE_DEBUG")): menu.addSeparator() diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index c9460295fb3..96d9b48ba65 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -1202,14 +1202,17 @@ def family_to_identifier(family): "OpenpypeDataGroup", "OpenpypeDataGroup_End", "deadlinePriority", "deadlineChunkSize", "deadlineConcurrentTasks", "Deadline" ] + print(node.name()) # remove all old knobs for knob in node.allKnobs(): - if knob.name() in remove_knobs: - node.removeKnob(knob) - elif "avalon" in knob.name(): - node.removeKnob(knob) - + try: + if knob.name() in remove_knobs: + node.removeKnob(knob) + elif "avalon" in knob.name(): + node.removeKnob(knob) + except ValueError: + pass # add new instance knob with transfer data set_node_data( node, INSTANCE_DATA_KNOB, transfer_data) From 8965b5712bbe2a3639493f970374f5662a229697 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 13 Oct 2022 16:24:52 +0200 Subject: [PATCH 064/115] nuke: removing unused code --- openpype/hosts/nuke/plugins/create/create_camera.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_camera.py b/openpype/hosts/nuke/plugins/create/create_camera.py index 2a48b8a72b3..c559aa27566 100644 --- a/openpype/hosts/nuke/plugins/create/create_camera.py +++ b/openpype/hosts/nuke/plugins/create/create_camera.py @@ -64,12 +64,3 @@ def set_selected_nodes(self, pre_create_data): self.selected_nodes = [] self.log.debug("Selection is: {}".format(self.selected_nodes)) - - def apply_settings(self, project_settings, system_settings): - """Method called on initialization of plugin to apply settings.""" - - # only selected keys ideally - # settings = self.get_creator_settings(project_settings) - - # self.key = settings["key"] - pass \ No newline at end of file From 1407de25a5651909446070aa999aa869adfef82b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 13 Oct 2022 16:25:11 +0200 Subject: [PATCH 065/115] nuke: refactor create read to create source --- .../hosts/nuke/plugins/create/create_read.py | 57 ------------ .../nuke/plugins/create/create_source.py | 93 +++++++++++++++++++ 2 files changed, 93 insertions(+), 57 deletions(-) delete mode 100644 openpype/hosts/nuke/plugins/create/create_read.py create mode 100644 openpype/hosts/nuke/plugins/create/create_source.py diff --git a/openpype/hosts/nuke/plugins/create/create_read.py b/openpype/hosts/nuke/plugins/create/create_read.py deleted file mode 100644 index d4f63e6b9f4..00000000000 --- a/openpype/hosts/nuke/plugins/create/create_read.py +++ /dev/null @@ -1,57 +0,0 @@ -from collections import OrderedDict - -import nuke - -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - set_avalon_knob_data -) - - -class CrateRead(plugin.OpenPypeCreator): - # change this to template preset - name = "ReadCopy" - label = "Source (read)" - hosts = ["nuke"] - family = "source" - families = family - icon = "film" - defaults = ["Effect", "Backplate", "Fire", "Smoke"] - - def __init__(self, *args, **kwargs): - super(CrateRead, self).__init__(*args, **kwargs) - self.nodes = nuke.selectedNodes() - data = OrderedDict() - data['family'] = self.family - data['families'] = self.families - - for k, v in self.data.items(): - if k not in data.keys(): - data.update({k: v}) - - self.data = data - - def process(self): - self.name = self.data["subset"] - nodes = self.nodes - - if not nodes or len(nodes) == 0: - msg = "Please select Read node" - self.log.error(msg) - nuke.message(msg) - else: - count_reads = 0 - for node in nodes: - if node.Class() != 'Read': - continue - avalon_data = self.data - avalon_data['subset'] = "{}".format(self.name) - set_avalon_knob_data(node, avalon_data) - node['tile_color'].setValue(16744935) - count_reads += 1 - - if count_reads < 1: - msg = "Please select Read node" - self.log.error(msg) - nuke.message(msg) - return diff --git a/openpype/hosts/nuke/plugins/create/create_source.py b/openpype/hosts/nuke/plugins/create/create_source.py new file mode 100644 index 00000000000..48f9f862197 --- /dev/null +++ b/openpype/hosts/nuke/plugins/create/create_source.py @@ -0,0 +1,93 @@ +import nuke +import six +import sys +from openpype.hosts.nuke.api import ( + INSTANCE_DATA_KNOB, + NukeCreator, + NukeCreatorError, + set_node_data +) +from openpype.pipeline import ( + CreatedInstance +) + + +class CreateSource(NukeCreator): + """Add Publishable Read with source""" + + identifier = "create_source" + label = "Source (read)" + family = "source" + icon = "film" + default_variants = ["Effect", "Backplate", "Fire", "Smoke"] + + # plugin attributes + node_color = "0xff9100ff" + + def create_instance_node( + self, + node_name, + read_node + ): + read_node["tile_color"].setValue( + int(self.node_color, 16)) + read_node["name"].setValue(node_name) + self.add_info_knob(read_node) + return read_node + + def create(self, subset_name, instance_data, pre_create_data): + + # make sure selected nodes are added + self.set_selected_nodes(pre_create_data) + + try: + for read_node in self.selected_nodes: + if read_node.Class() != 'Read': + continue + + node_name = read_node.name() + _subset_name = subset_name + node_name + + # make sure subset name is unique + if self.check_existing_subset(_subset_name, instance_data): + raise NukeCreatorError( + ("subset {} is already published" + "definition.").format(_subset_name)) + + instance_node = self.create_instance_node( + _subset_name, + read_node + ) + instance = CreatedInstance( + self.family, + _subset_name, + instance_data, + self + ) + + instance.transient_data["node"] = instance_node + + self._add_instance_to_context(instance) + + set_node_data( + instance_node, + INSTANCE_DATA_KNOB, + instance.data_to_store() + ) + + except Exception as er: + six.reraise( + NukeCreatorError, + NukeCreatorError("Creator error: {}".format(er)), + sys.exc_info()[2]) + + def set_selected_nodes(self, pre_create_data): + if pre_create_data.get("use_selection"): + self.selected_nodes = nuke.selectedNodes() + if self.selected_nodes == []: + raise NukeCreatorError("Creator error: No active selection") + else: + NukeCreatorError( + "Creator error: only supprted with active selection") + + self.log.debug("Selection is: {}".format(self.selected_nodes)) From acde5a81fca7909820a48841f6339d8f9fdda9bf Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 15:54:55 +0200 Subject: [PATCH 066/115] nuke: remove obsolete validators --- .../plugins/publish/validate_read_legacy.py | 87 -------------- .../publish/validate_write_deadline_tab.py | 53 --------- .../plugins/publish/validate_write_legacy.py | 108 ------------------ 3 files changed, 248 deletions(-) delete mode 100644 openpype/hosts/nuke/plugins/publish/validate_read_legacy.py delete mode 100644 openpype/hosts/nuke/plugins/publish/validate_write_deadline_tab.py delete mode 100644 openpype/hosts/nuke/plugins/publish/validate_write_legacy.py diff --git a/openpype/hosts/nuke/plugins/publish/validate_read_legacy.py b/openpype/hosts/nuke/plugins/publish/validate_read_legacy.py deleted file mode 100644 index ffd5cee710e..00000000000 --- a/openpype/hosts/nuke/plugins/publish/validate_read_legacy.py +++ /dev/null @@ -1,87 +0,0 @@ -import os - -import nuke - -import toml -import pyblish.api -from bson.objectid import ObjectId -from openpype.hosts.nuke import api as napi -from openpype.pipeline import ( - discover_loader_plugins, - load_container, -) - - -class RepairReadLegacyAction(pyblish.api.Action): - - label = "Repair" - icon = "wrench" - on = "failed" - - def process(self, context, plugin): - - # Get the errored instances - failed = [] - for result in context.data["results"]: - if (result["error"] is not None and result["instance"] is not None - and result["instance"] not in failed): - failed.append(result["instance"]) - - # Apply pyblish.logic to get the instances for the plug-in - instances = pyblish.api.instances_by_plugin(failed, plugin) - - for instance in instances: - node = napi.get_instance_node(instance) - data = toml.loads(node["avalon"].value()) - data["name"] = node.name() - data["xpos"] = node.xpos() - data["ypos"] = node.ypos() - data["extension"] = os.path.splitext( - node["file"].value() - )[1][1:] - - data["connections"] = [] - for d in node.dependent(): - for i in range(d.inputs()): - if d.input(i) == node: - data["connections"].append([i, d]) - - nuke.delete(node) - - loader_name = "LoadSequence" - if data["extension"] == "mov": - loader_name = "LoadMov" - - loader_plugin = None - for Loader in discover_loader_plugins(): - if Loader.__name__ != loader_name: - continue - - loader_plugin = Loader - - load_container( - Loader=loader_plugin, - representation=ObjectId(data["representation"]) - ) - - node = nuke.toNode(data["name"]) - for connection in data["connections"]: - connection[1].setInput(connection[0], node) - - node.setXYpos(data["xpos"], data["ypos"]) - - -class ValidateReadLegacy(pyblish.api.InstancePlugin): - """Validate legacy read nodes.""" - - order = pyblish.api.ValidatorOrder - optional = True - families = ["read.legacy"] - label = "Read Legacy" - hosts = ["nuke"] - actions = [RepairReadLegacyAction] - - def process(self, instance): - - msg = "Clean up legacy read node \"{}\"".format(instance) - assert False, msg diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_deadline_tab.py b/openpype/hosts/nuke/plugins/publish/validate_write_deadline_tab.py deleted file mode 100644 index 907577a97dd..00000000000 --- a/openpype/hosts/nuke/plugins/publish/validate_write_deadline_tab.py +++ /dev/null @@ -1,53 +0,0 @@ -import pyblish.api -import openpype.hosts.nuke.lib - - -class RepairNukeWriteDeadlineTab(pyblish.api.Action): - - label = "Repair" - icon = "wrench" - on = "failed" - - def process(self, context, plugin): - - # Get the errored instances - failed = [] - for result in context.data["results"]: - if (result["error"] is not None and result["instance"] is not None - and result["instance"] not in failed): - failed.append(result["instance"]) - - # Apply pyblish.logic to get the instances for the plug-in - instances = pyblish.api.instances_by_plugin(failed, plugin) - - for instance in instances: - group_node = [x for x in instance if x.Class() == "Group"][0] - - # Remove existing knobs. - knob_names = openpype.hosts.nuke.lib.get_deadline_knob_names() - for name, knob in group_node.knobs().items(): - if name in knob_names: - group_node.removeKnob(knob) - - openpype.hosts.nuke.lib.add_deadline_tab(group_node) - - -class ValidateNukeWriteDeadlineTab(pyblish.api.InstancePlugin): - """Ensure Deadline tab is present and current.""" - - order = pyblish.api.ValidatorOrder - label = "Deadline Tab" - hosts = ["nuke"] - optional = True - families = ["render"] - actions = [RepairNukeWriteDeadlineTab] - - def process(self, instance): - group_node = [x for x in instance if x.Class() == "Group"][0] - - knob_names = openpype.hosts.nuke.lib.get_deadline_knob_names() - missing_knobs = [] - for name in knob_names: - if name not in group_node.knobs().keys(): - missing_knobs.append(name) - assert not missing_knobs, "Missing knobs: {}".format(missing_knobs) diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_legacy.py b/openpype/hosts/nuke/plugins/publish/validate_write_legacy.py deleted file mode 100644 index e9bcb08b00f..00000000000 --- a/openpype/hosts/nuke/plugins/publish/validate_write_legacy.py +++ /dev/null @@ -1,108 +0,0 @@ -import toml - -import nuke - -import pyblish.api - -from openpype.pipeline import discover_creator_plugins -from openpype.pipeline.publish import RepairAction -from openpype.hosts.nuke.api.lib import get_avalon_knob_data -from openpype.hosts.nuke import api as napi - -class ValidateWriteLegacy(pyblish.api.InstancePlugin): - """Validate legacy write nodes.""" - - order = pyblish.api.ValidatorOrder - optional = True - families = ["write"] - label = "Validate Write Legacy" - hosts = ["nuke"] - actions = [RepairAction] - - def process(self, instance): - node = napi.get_instance_node(instance) - msg = "Clean up legacy write node \"{}\"".format(instance) - - if node.Class() not in ["Group", "Write"]: - return - - # test avalon knobs - family_knobs = ["ak:family", "avalon:family"] - family_test = [k for k in node.knobs().keys() if k in family_knobs] - self.log.debug("_ family_test: {}".format(family_test)) - - # test if render in family test knob - # and only one item should be available - assert len(family_test) == 1, msg + " > More avalon attributes" - assert "render" in node[family_test[0]].value() \ - or "still" in node[family_test[0]].value(), msg + \ - " > Not correct family" - # test if `file` knob in node, this way old - # non-group-node write could be detected - assert "file" not in node.knobs(), msg + \ - " > file knob should not be present" - - # check if write node is having old render targeting - assert "render_farm" not in node.knobs(), msg + \ - " > old way of setting render target" - - @classmethod - def repair(cls, instance): - node = napi.get_instance_node(instance) - - if "Write" in node.Class(): - data = toml.loads(node["avalon"].value()) - else: - data = get_avalon_knob_data(node) - - # collect reusable data - data["XYpos"] = (node.xpos(), node.ypos()) - data["input"] = node.input(0) - data["publish"] = node["publish"].value() - data["render"] = node["render"].value() - data["render_farm"] = node["render_farm"].value() - data["review"] = node["review"].value() - data["use_limit"] = node["use_limit"].value() - data["first"] = node["first"].value() - data["last"] = node["last"].value() - - family = data["family"] - cls.log.debug("_ orig node family: {}".format(family)) - - # define what family of write node should be recreated - if family == "render": - Create_name = "CreateWriteRender" - elif family == "prerender": - Create_name = "CreateWritePrerender" - elif family == "still": - Create_name = "CreateWriteStill" - - # get appropriate plugin class - creator_plugin = None - for Creator in discover_creator_plugins(): - if Creator.__name__ != Create_name: - continue - - creator_plugin = Creator - - # delete the legaci write node - nuke.delete(node) - - # create write node with creator - new_node_name = data["subset"] - creator_plugin(new_node_name, data["asset"]).process() - - node = nuke.toNode(new_node_name) - node.setXYpos(*data["XYpos"]) - node.setInput(0, data["input"]) - node["publish"].setValue(data["publish"]) - node["review"].setValue(data["review"]) - node["use_limit"].setValue(data["use_limit"]) - node["first"].setValue(data["first"]) - node["last"].setValue(data["last"]) - - # recreate render targets - if data["render"]: - node["render"].setValue("Local") - if data["render_farm"]: - node["render"].setValue("On farm") From 50dbbcdb184bdc2d96697294578ec8e73de57a91 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 16:00:00 +0200 Subject: [PATCH 067/115] nuke: no need for abstraction of getting instance node --- openpype/hosts/nuke/api/__init__.py | 2 -- openpype/hosts/nuke/api/plugin.py | 11 +---------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index 8aaaff43b31..3b00ca9f6f1 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -14,7 +14,6 @@ NukeWriteCreator, NukeCreatorError, OpenPypeCreator, - get_instance_node, get_instance_group_node_childs, get_colorspace_from_node ) @@ -67,7 +66,6 @@ "NukeCreatorError", "OpenPypeCreator", "NukeHost", - "get_instance_node", "get_instance_group_node_childs", "get_colorspace_from_node", diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 96d9b48ba65..7e3c131104f 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -407,15 +407,6 @@ def process(self): return instance -def get_instance_node(instance): - # new publisher way - if instance.data.get("transientData"): - return instance.data["transientData"]["node"] - else: - # or backward compatible - return instance[0] - - def get_instance_group_node_childs(instance): """Return list of instance group node children @@ -425,7 +416,7 @@ def get_instance_group_node_childs(instance): Returns: list: [nuke.Node] """ - node = get_instance_node(instance) + node = instance.data["transientData"]["node"] if node.Class() != "Group": return From fcf84d1ba3c8373730f6dc68bb5b25cc9ebcb3cd Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 16:00:58 +0200 Subject: [PATCH 068/115] nuke: get instance node directly form instance --- openpype/hosts/nuke/plugins/publish/collect_backdrop.py | 2 +- openpype/hosts/nuke/plugins/publish/collect_gizmo.py | 2 +- openpype/hosts/nuke/plugins/publish/collect_model.py | 2 +- openpype/hosts/nuke/plugins/publish/collect_reads.py | 2 +- openpype/hosts/nuke/plugins/publish/collect_slate_node.py | 2 +- openpype/hosts/nuke/plugins/publish/collect_writes.py | 2 +- openpype/hosts/nuke/plugins/publish/extract_gizmo.py | 2 +- openpype/hosts/nuke/plugins/publish/extract_model.py | 2 +- openpype/hosts/nuke/plugins/publish/extract_thumbnail.py | 2 +- openpype/hosts/nuke/plugins/publish/validate_asset_name.py | 4 ++-- openpype/hosts/nuke/plugins/publish/validate_backdrop.py | 2 +- openpype/hosts/nuke/plugins/publish/validate_gizmo.py | 4 ++-- .../hosts/nuke/plugins/publish/validate_output_resolution.py | 2 +- .../hosts/nuke/plugins/publish/validate_rendered_frames.py | 4 ++-- openpype/hosts/nuke/plugins/publish/validate_write_nodes.py | 4 ++-- 15 files changed, 19 insertions(+), 19 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py index dcabedf231c..2d375cfb624 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py @@ -18,7 +18,7 @@ class CollectBackdrops(pyblish.api.InstancePlugin): def process(self, instance): self.log.debug(pformat(instance.data)) - bckn = napi.get_instance_node(instance) + bckn = instance.data["transientData"]["node"] # define size of the backdrop left = bckn.xpos() diff --git a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py index 755c196f8e9..5979cd123de 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py @@ -14,7 +14,7 @@ class CollectGizmo(pyblish.api.InstancePlugin): families = ["gizmo"] def process(self, instance): - grpn = napi.get_instance_node(instance) + grpn = instance.data["transientData"]["node"] # add family to familiess instance.data["families"].insert(0, instance.data["family"]) diff --git a/openpype/hosts/nuke/plugins/publish/collect_model.py b/openpype/hosts/nuke/plugins/publish/collect_model.py index 253121ffd43..ad3e99dfad2 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_model.py +++ b/openpype/hosts/nuke/plugins/publish/collect_model.py @@ -14,7 +14,7 @@ class CollectModel(pyblish.api.InstancePlugin): def process(self, instance): - geo_node = napi.get_instance_node(instance) + geo_node = instance.data["transientData"]["node"] # add family to familiess instance.data["families"].insert(0, instance.data["family"]) diff --git a/openpype/hosts/nuke/plugins/publish/collect_reads.py b/openpype/hosts/nuke/plugins/publish/collect_reads.py index 7390ec68843..3d14b2f231d 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_reads.py +++ b/openpype/hosts/nuke/plugins/publish/collect_reads.py @@ -18,7 +18,7 @@ class CollectNukeReads(pyblish.api.InstancePlugin): families = ["source"] def process(self, instance): - node = napi.get_instance_node(instance) + node = instance.data["transientData"]["node"] project_name = legacy_io.active_project() asset_name = legacy_io.Session["AVALON_ASSET"] diff --git a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py index e3f24a233eb..14692926640 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py +++ b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py @@ -12,7 +12,7 @@ class CollectSlate(pyblish.api.InstancePlugin): families = ["render"] def process(self, instance): - node = napi.get_instance_node(instance) + node = instance.data["transientData"]["node"] slate = next((n for n in nuke.allNodes() if "slate" in n.name().lower() diff --git a/openpype/hosts/nuke/plugins/publish/collect_writes.py b/openpype/hosts/nuke/plugins/publish/collect_writes.py index 32d837f4001..8122776ccce 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_writes.py +++ b/openpype/hosts/nuke/plugins/publish/collect_writes.py @@ -18,7 +18,7 @@ def process(self, instance): self.log.debug(pformat(instance.data)) instance.data.update(instance.data["creator_attributes"]) - group_node = napi.get_instance_node(instance) + group_node = instance.data["transientData"]["node"] render_target = instance.data["render_target"] family = instance.data["family"] families = instance.data["families"] diff --git a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py index a3df497893e..7ea9435571a 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py @@ -26,7 +26,7 @@ class ExtractGizmo(publish.Extractor): def process(self, instance): tmp_nodes = [] - orig_grpn = napi.get_instance_node(instance) + orig_grpn = instance.data["transientData"]["node"] # Define extract output file path stagingdir = self.staging_dir(instance) diff --git a/openpype/hosts/nuke/plugins/publish/extract_model.py b/openpype/hosts/nuke/plugins/publish/extract_model.py index 5ca617f1479..f44d699e1b3 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_model.py +++ b/openpype/hosts/nuke/plugins/publish/extract_model.py @@ -38,7 +38,7 @@ def process(self, instance): pformat(instance.data))) rm_nodes = [] - model_node = napi.get_instance_node(instance) + model_node = instance.data["transientData"]["node"] self.log.info("Crating additional nodes") subset = instance.data["subset"] diff --git a/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py b/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py index dfb1b382840..a1a0e241c07 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py @@ -65,7 +65,7 @@ def render_thumbnail(self, instance, output_name=None, **kwargs): bake_viewer_input_process_node = kwargs[ "bake_viewer_input_process"] - node = napi.get_instance_node(instance) # group node + node = instance.data["transientData"]["node"] # group node self.log.info("Creating staging dir...") if "representations" not in instance.data: diff --git a/openpype/hosts/nuke/plugins/publish/validate_asset_name.py b/openpype/hosts/nuke/plugins/publish/validate_asset_name.py index 0d64da074ea..230717cf181 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_asset_name.py +++ b/openpype/hosts/nuke/plugins/publish/validate_asset_name.py @@ -85,7 +85,7 @@ def process(self, context, plugin): context_asset = context.data["assetEntity"]["name"] for instance in instances: - origin_node = napi.get_instance_node(instance) + origin_node = instance.data["transientData"]["node"] napi.lib.recreate_instance( origin_node, avalon_data={"asset": context_asset} ) @@ -112,7 +112,7 @@ class ValidateCorrectAssetName(pyblish.api.InstancePlugin): def process(self, instance): asset = instance.data.get("asset") context_asset = instance.context.data["assetEntity"]["name"] - node = napi.get_instance_node(instance) + node = instance.data["transientData"]["node"] msg = ( "Instance `{}` has wrong shot/asset name:\n" diff --git a/openpype/hosts/nuke/plugins/publish/validate_backdrop.py b/openpype/hosts/nuke/plugins/publish/validate_backdrop.py index 8ee8e631b86..e4df3430f98 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/validate_backdrop.py @@ -32,7 +32,7 @@ def process(self, context, plugin): with napi.maintained_selection(): # collect all failed nodes xpos and ypos for instance in instances: - bdn = napi.get_instance_node(instance) + bdn = instance.data["transientData"]["node"] xC = bdn.xpos() + bdn.screenWidth() / 2 yC = bdn.ypos() + bdn.screenHeight() / 2 diff --git a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py index 05a40854838..1fc3726a047 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py @@ -29,7 +29,7 @@ def process(self, context, plugin): with napi.maintained_selection(): # collect all failed nodes xpos and ypos for instance in instances: - grpn = napi.get_instance_node(instance) + grpn = instance.data["transientData"]["node"] nuke.showDag(grpn) @@ -45,7 +45,7 @@ class ValidateGizmo(pyblish.api.InstancePlugin): actions = [OpenFailedGroupNode] def process(self, instance): - grpn = napi.get_instance_node(instance) + grpn = instance.data["transientData"]["node"] with grpn: connections_out = nuke.allNodes('Output') diff --git a/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py b/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py index b7095e9ed77..c581e682a78 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py +++ b/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py @@ -75,7 +75,7 @@ def repair(cls, instance): ) invalid = cls.get_invalid(instance) - grp_node = napi.get_instance_node(instance) + grp_node = instance.data["transientData"]["node"] if cls.missing_msg == invalid: # make sure we are inside of the group node diff --git a/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py b/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py index c1e511f5346..89136124b8e 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py +++ b/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py @@ -24,7 +24,7 @@ def get_instance(context, plugin): def repair_knob(self, instances, state): for instance in instances: - node = napi.get_instance_node(instance) + node = instance.data["transientData"]["node"] files_remove = [os.path.join(instance.data["outputDir"], f) for r in instance.data.get("representations", []) for f in r.get("files", []) @@ -64,7 +64,7 @@ class ValidateRenderedFrames(pyblish.api.InstancePlugin): actions = [RepairCollectionActionToLocal, RepairCollectionActionToFarm] def process(self, instance): - node = napi.get_instance_node(instance) + node = instance.data["transientData"]["node"] f_data = { "node_name": node.name() diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py index cfd0fb38712..fc5e054fa81 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py @@ -27,7 +27,7 @@ def process(self, context, plugin): or instance ) - write_group_node = napi.get_instance_node(instance) + write_group_node = instance.data["transientData"]["node"] # get write node from inside of group write_node = None for x in child_nodes: @@ -67,7 +67,7 @@ def process(self, instance): or instance ) - write_group_node = napi.get_instance_node(instance) + write_group_node = instance.data["transientData"]["node"] # get write node from inside of group write_node = None From c6ca7243b84a141add78af617514044c02198d07 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 16:32:56 +0200 Subject: [PATCH 069/115] nuke: fixing supporting function for resolving imageio nodes --- openpype/hosts/nuke/api/lib.py | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 157a2eb321c..54fce77c79d 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -2362,26 +2362,34 @@ def get_write_node_template_attr(node): ''' Gets all defined data from presets ''' + # TODO: remove this backward compatibility for old settings + # TASK: add identifiers to settings and rename settings key + plugin_names_mapping = { + "create_write_image": "CreateWriteImage", + "create_write_prerender": "CreateWritePrerender", + "create_write_render": "CreateWriteRender" + } # get avalon data from node - avalon_knob_data = read_avalon_data(node) + node_data = get_node_data(node, INSTANCE_DATA_KNOB) + identifier = node_data["creator_identifier"] # get template data nuke_imageio_writes = get_imageio_node_setting( - node_class=avalon_knob_data["families"], - plugin_name=avalon_knob_data["creator"], - subset=avalon_knob_data["subset"] + node_class="Write", + plugin_name=plugin_names_mapping[identifier], + subset=node_data["subset"] ) - # collecting correct data - correct_data = OrderedDict() + # collecting solved data + return_data = OrderedDict() - # adding imageio knob presets - for k, v in nuke_imageio_writes.items(): - if k in ["_id", "_previous"]: - continue - correct_data[k] = v + for knob in nuke_imageio_writes["knobs"]: + knob_type = knob["type"] + knob_value = knob["value"] + new_knob_value = convert_knob_value_to_correct_type( + knob_type, knob_value) + return_data[knob["name"]] = new_knob_value - # fix badly encoded data - return fix_data_for_node_create(correct_data) + return return_data def get_dependent_nodes(nodes): From 83d60936bc597a8f6a7f174e15b72f6b4812e728 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 16:33:25 +0200 Subject: [PATCH 070/115] Nuke: fixing validator --- .../nuke/plugins/publish/validate_write_nodes.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py index fc5e054fa81..ec2fba7ea78 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py @@ -5,7 +5,7 @@ set_node_knobs_from_settings, color_gui_to_int ) -from openpype.hosts.nuke import api as napi + from openpype.pipeline.publish import ( PublishXmlValidationError, OptionalPyblishPluginMixin, @@ -80,19 +80,12 @@ def process(self, instance): correct_data = get_write_node_template_attr(write_group_node) - if correct_data: - check_knobs = correct_data["knobs"] - else: - return - check = [] self.log.debug("__ write_node: {}".format( write_node )) - for knob_data in check_knobs: - key = knob_data["name"] - value = knob_data["value"] + for key, value in correct_data.items(): node_value = write_node[key].value() # fix type differences From 6324b0339c04cec093653e847340cccc93a46800 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 20:27:16 +0200 Subject: [PATCH 071/115] Nuke: using transient data for nodes --- openpype/hosts/nuke/plugins/publish/collect_backdrop.py | 2 +- openpype/hosts/nuke/plugins/publish/extract_camera.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py index 2d375cfb624..b8317137da5 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py @@ -51,7 +51,7 @@ def process(self, instance): # make label nicer instance.data["label"] = "{0} ({1} nodes)".format( - bckn.name(), len(instance) - 1) + bckn.name(), len(instance.data["transientData"]["childNodes"])) instance.data["families"].append(instance.data["family"]) diff --git a/openpype/hosts/nuke/plugins/publish/extract_camera.py b/openpype/hosts/nuke/plugins/publish/extract_camera.py index b751bfab039..4286f71e834 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_camera.py +++ b/openpype/hosts/nuke/plugins/publish/extract_camera.py @@ -28,6 +28,7 @@ class ExtractCamera(publish.Extractor): ] def process(self, instance): + camera_node = instance.data["transientData"]["node"] handle_start = instance.context.data["handleStart"] handle_end = instance.context.data["handleEnd"] first_frame = int(nuke.root()["first_frame"].getValue()) @@ -38,7 +39,7 @@ def process(self, instance): self.log.info("instance.data: `{}`".format( pformat(instance.data))) - rm_nodes = list() + rm_nodes = [] self.log.info("Crating additional nodes") subset = instance.data["subset"] staging_dir = self.staging_dir(instance) @@ -58,7 +59,7 @@ def process(self, instance): with maintained_selection(): # bake camera with axeses onto word coordinate XYZ rm_n = bakeCameraWithAxeses( - nuke.toNode(instance.data["name"]), output_range) + camera_node, output_range) rm_nodes.append(rm_n) # create scene node From 76ca1e83c09759703f43471c56530428e6b9bd6a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 20:27:32 +0200 Subject: [PATCH 072/115] nuke: removing unused import --- openpype/hosts/nuke/plugins/publish/collect_backdrop.py | 1 - openpype/hosts/nuke/plugins/publish/collect_gizmo.py | 1 - openpype/hosts/nuke/plugins/publish/collect_model.py | 2 +- openpype/hosts/nuke/plugins/publish/collect_reads.py | 1 - openpype/hosts/nuke/plugins/publish/collect_slate_node.py | 1 - openpype/hosts/nuke/plugins/publish/extract_gizmo.py | 1 - openpype/hosts/nuke/plugins/publish/extract_model.py | 1 - openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py | 1 - 8 files changed, 1 insertion(+), 8 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py index b8317137da5..1545bb602d7 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py @@ -1,7 +1,6 @@ from pprint import pformat import pyblish.api from openpype.hosts.nuke.api import lib as pnlib -from openpype.hosts.nuke import api as napi import nuke diff --git a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py index 5979cd123de..2cd996971a3 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py @@ -1,5 +1,4 @@ import pyblish.api -from openpype.hosts.nuke import api as napi import nuke diff --git a/openpype/hosts/nuke/plugins/publish/collect_model.py b/openpype/hosts/nuke/plugins/publish/collect_model.py index ad3e99dfad2..d24382b757a 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_model.py +++ b/openpype/hosts/nuke/plugins/publish/collect_model.py @@ -1,6 +1,6 @@ import pyblish.api import nuke -from openpype.hosts.nuke import api as napi + @pyblish.api.log class CollectModel(pyblish.api.InstancePlugin): diff --git a/openpype/hosts/nuke/plugins/publish/collect_reads.py b/openpype/hosts/nuke/plugins/publish/collect_reads.py index 3d14b2f231d..9fad8dddf8c 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_reads.py +++ b/openpype/hosts/nuke/plugins/publish/collect_reads.py @@ -5,7 +5,6 @@ from openpype.client import get_asset_by_name from openpype.pipeline import legacy_io -from openpype.hosts.nuke import api as napi @pyblish.api.log diff --git a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py index 14692926640..72b0614d2bb 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py +++ b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py @@ -1,5 +1,4 @@ import pyblish.api -from openpype.hosts.nuke import api as napi import nuke diff --git a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py index 7ea9435571a..4ca80e9995b 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py @@ -4,7 +4,6 @@ import pyblish.api from openpype.pipeline import publish -from openpype.hosts.nuke import api as napi from openpype.hosts.nuke.api import utils as pnutils from openpype.hosts.nuke.api.lib import ( maintained_selection, diff --git a/openpype/hosts/nuke/plugins/publish/extract_model.py b/openpype/hosts/nuke/plugins/publish/extract_model.py index f44d699e1b3..814d4041375 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_model.py +++ b/openpype/hosts/nuke/plugins/publish/extract_model.py @@ -3,7 +3,6 @@ import nuke import pyblish.api -from openpype.hosts.nuke import api as napi from openpype.pipeline import publish from openpype.hosts.nuke.api.lib import ( maintained_selection, diff --git a/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py b/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py index 89136124b8e..e0eb254ba10 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py +++ b/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py @@ -1,7 +1,6 @@ import os import pyblish.api import clique -from openpype.hosts.nuke import api as napi from openpype.pipeline import PublishXmlValidationError From 2a0f4da03f7a2ec4b1a980e8f1522911ef25815b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 20:36:44 +0200 Subject: [PATCH 073/115] nuke: removing decoration which is not needed --- openpype/hosts/nuke/plugins/publish/collect_backdrop.py | 1 - openpype/hosts/nuke/plugins/publish/collect_gizmo.py | 1 - openpype/hosts/nuke/plugins/publish/collect_instance_data.py | 1 - openpype/hosts/nuke/plugins/publish/collect_model.py | 1 - openpype/hosts/nuke/plugins/publish/collect_reads.py | 2 -- openpype/hosts/nuke/plugins/publish/collect_writes.py | 1 - openpype/hosts/nuke/plugins/publish/validate_backdrop.py | 1 - openpype/hosts/nuke/plugins/publish/validate_gizmo.py | 1 - openpype/hosts/nuke/plugins/publish/validate_proxy_mode.py | 1 - openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py | 1 - .../hosts/nuke/plugins/publish/validate_script_attributes.py | 1 - openpype/hosts/nuke/plugins/publish/validate_write_nodes.py | 1 - 12 files changed, 13 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py index 1545bb602d7..8eaefa68541 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py @@ -4,7 +4,6 @@ import nuke -@pyblish.api.log class CollectBackdrops(pyblish.api.InstancePlugin): """Collect Backdrop node instance and its content """ diff --git a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py index 2cd996971a3..c194f70f7e6 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py @@ -2,7 +2,6 @@ import nuke -@pyblish.api.log class CollectGizmo(pyblish.api.InstancePlugin): """Collect Gizmo (group) node instance and its content """ diff --git a/openpype/hosts/nuke/plugins/publish/collect_instance_data.py b/openpype/hosts/nuke/plugins/publish/collect_instance_data.py index 9614ebdea64..3908aef4bcc 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_instance_data.py +++ b/openpype/hosts/nuke/plugins/publish/collect_instance_data.py @@ -2,7 +2,6 @@ import pyblish.api -@pyblish.api.log class CollectInstanceData(pyblish.api.InstancePlugin): """Collect all nodes with Avalon knob.""" diff --git a/openpype/hosts/nuke/plugins/publish/collect_model.py b/openpype/hosts/nuke/plugins/publish/collect_model.py index d24382b757a..9da056052be 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_model.py +++ b/openpype/hosts/nuke/plugins/publish/collect_model.py @@ -2,7 +2,6 @@ import nuke -@pyblish.api.log class CollectModel(pyblish.api.InstancePlugin): """Collect Model node instance and its content """ diff --git a/openpype/hosts/nuke/plugins/publish/collect_reads.py b/openpype/hosts/nuke/plugins/publish/collect_reads.py index 9fad8dddf8c..a1144fbcc31 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_reads.py +++ b/openpype/hosts/nuke/plugins/publish/collect_reads.py @@ -2,12 +2,10 @@ import re import nuke import pyblish.api - from openpype.client import get_asset_by_name from openpype.pipeline import legacy_io -@pyblish.api.log class CollectNukeReads(pyblish.api.InstancePlugin): """Collect all read nodes.""" diff --git a/openpype/hosts/nuke/plugins/publish/collect_writes.py b/openpype/hosts/nuke/plugins/publish/collect_writes.py index 8122776ccce..e18fbbdf6f2 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_writes.py +++ b/openpype/hosts/nuke/plugins/publish/collect_writes.py @@ -5,7 +5,6 @@ from openpype.hosts.nuke import api as napi -@pyblish.api.log class CollectNukeWrites(pyblish.api.InstancePlugin): """Collect all write nodes.""" diff --git a/openpype/hosts/nuke/plugins/publish/validate_backdrop.py b/openpype/hosts/nuke/plugins/publish/validate_backdrop.py index e4df3430f98..208d4a24985 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/validate_backdrop.py @@ -46,7 +46,6 @@ def process(self, context, plugin): nuke.zoom(2, [min(all_xC), min(all_yC)]) -@pyblish.api.log class ValidateBackdrop(pyblish.api.InstancePlugin): """ Validate amount of nodes on backdrop node in case user forgoten to add nodes above the publishing backdrop node. diff --git a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py index 1fc3726a047..57d7d5fc3bb 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py @@ -33,7 +33,6 @@ def process(self, context, plugin): nuke.showDag(grpn) -@pyblish.api.log class ValidateGizmo(pyblish.api.InstancePlugin): """Validate amount of output nodes in gizmo (group) node""" diff --git a/openpype/hosts/nuke/plugins/publish/validate_proxy_mode.py b/openpype/hosts/nuke/plugins/publish/validate_proxy_mode.py index dac240ad197..c26a03f31a9 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_proxy_mode.py +++ b/openpype/hosts/nuke/plugins/publish/validate_proxy_mode.py @@ -17,7 +17,6 @@ def process(self, context, plugin): rootNode["proxy"].setValue(False) -@pyblish.api.log class ValidateProxyMode(pyblish.api.ContextPlugin): """Validate active proxy mode""" diff --git a/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py b/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py index e0eb254ba10..1c22c5b9d00 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py +++ b/openpype/hosts/nuke/plugins/publish/validate_rendered_frames.py @@ -4,7 +4,6 @@ from openpype.pipeline import PublishXmlValidationError -@pyblish.api.log class RepairActionBase(pyblish.api.Action): on = "failed" icon = "wrench" diff --git a/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py b/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py index f0632f80807..3ebc34f1952 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py @@ -10,7 +10,6 @@ import nuke -@pyblish.api.log class ValidateScriptAttributes(pyblish.api.InstancePlugin): """ Validates file output. """ diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py index ec2fba7ea78..c0b81f64eaf 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py @@ -12,7 +12,6 @@ ) -@pyblish.api.log class RepairNukeWriteNodeAction(pyblish.api.Action): label = "Repair" on = "failed" From 2fff046532f6a023b8be16ca3de405e4ea03d309 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 20:39:12 +0200 Subject: [PATCH 074/115] nuke: better logic --- .../hosts/nuke/plugins/publish/validate_gizmo.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py index 57d7d5fc3bb..8e844247eeb 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py @@ -48,22 +48,22 @@ def process(self, instance): with grpn: connections_out = nuke.allNodes('Output') - msg_multiple_outputs = ( - "Only one outcoming connection from " - "\"{}\" is allowed").format(instance.data["name"]) - if len(connections_out) > 1: + msg_multiple_outputs = ( + "Only one outcoming connection from " + "\"{}\" is allowed").format(instance.data["name"]) + raise PublishXmlValidationError( self, msg_multiple_outputs, "multiple_outputs", {"node_name": grpn["name"].value()} ) connections_in = nuke.allNodes('Input') - msg_missing_inputs = ( - "At least one Input node has to be inside Group: " - "\"{}\"").format(instance.data["name"]) - if len(connections_in) == 0: + msg_missing_inputs = ( + "At least one Input node has to be inside Group: " + "\"{}\"").format(instance.data["name"]) + raise PublishXmlValidationError( self, msg_missing_inputs, "no_inputs", {"node_name": grpn["name"].value()} From b6107fe5611345a379440932d1020a199e69ed8a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 21:05:27 +0200 Subject: [PATCH 075/115] nuke: refactor workfile collector --- .../nuke/plugins/publish/collect_workfile.py | 41 +++++-------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_workfile.py b/openpype/hosts/nuke/plugins/publish/collect_workfile.py index 8b6ab5d0723..7f4849be679 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_workfile.py +++ b/openpype/hosts/nuke/plugins/publish/collect_workfile.py @@ -3,22 +3,19 @@ import nuke import pyblish.api -import openpype.api as pype -from openpype.hosts.nuke.api.lib import ( - add_publish_knob, - get_avalon_knob_data -) +import openpype.api as api from openpype.pipeline import KnownPublishError -class CollectWorkfile(pyblish.api.ContextPlugin): +class CollectWorkfile(pyblish.api.InstancePlugin): """Collect current script for publish.""" - order = pyblish.api.CollectorOrder - 0.50 + order = pyblish.api.CollectorOrder - 0.499 label = "Collect Workfile" hosts = ['nuke'] + families = ["workfile"] - def process(self, context): # sourcery skip: avoid-builtin-shadow + def process(self, instance): # sourcery skip: avoid-builtin-shadow root = nuke.root() current_file = os.path.normpath(nuke.root().name()) @@ -29,23 +26,16 @@ def process(self, context): # sourcery skip: avoid-builtin-shadow "Use workfile tool to manage the name correctly." ) - knob_data = get_avalon_knob_data(root) - - add_publish_knob(root) - - family = "workfile" - task = os.getenv("AVALON_TASK", None) # creating instances per write node staging_dir = os.path.dirname(current_file) base_name = os.path.basename(current_file) - subset = family + task.capitalize() # Get frame range first_frame = int(root["first_frame"].getValue()) last_frame = int(root["last_frame"].getValue()) - handle_start = int(knob_data.get("handleStart", 0)) - handle_end = int(knob_data.get("handleEnd", 0)) + handle_start = instance.data["handleStart"] + handle_end = instance.data["handleEnd"] # Get format format = root['format'].value() @@ -53,33 +43,27 @@ def process(self, context): # sourcery skip: avoid-builtin-shadow resolution_height = format.height() pixel_aspect = format.pixelAspect() - # Create instance - instance = context.create_instance(subset) - instance.add(root) - script_data = { - "asset": os.getenv("AVALON_ASSET", None), "frameStart": first_frame + handle_start, "frameEnd": last_frame - handle_end, "resolutionWidth": resolution_width, "resolutionHeight": resolution_height, "pixelAspect": pixel_aspect, - # backward compatibility + # backward compatibility handles "handles": handle_start, - "handleStart": handle_start, "handleEnd": handle_end, "step": 1, "fps": root['fps'].value(), "currentFile": current_file, - "version": int(pype.get_version_from_path(current_file)), + "version": int(api.get_version_from_path(current_file)), "host": pyblish.api.current_host(), "hostVersion": nuke.NUKE_VERSION_STRING } - context.data.update(script_data) + instance.context.data.update(script_data) # creating representation representation = { @@ -91,12 +75,7 @@ def process(self, context): # sourcery skip: avoid-builtin-shadow # creating instance data instance.data.update({ - "subset": subset, - "label": base_name, "name": base_name, - "publish": root.knob('publish').value(), - "family": family, - "families": [family], "representations": [representation] }) From cdd11eae8f2acdc4c8172eb03ef106a2a42b0f40 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 21:34:44 +0200 Subject: [PATCH 076/115] Deadline: nuke submitter gets node with new way --- .../modules/deadline/plugins/publish/submit_nuke_deadline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_nuke_deadline.py b/openpype/modules/deadline/plugins/publish/submit_nuke_deadline.py index b09d2935abf..083c2bcd78b 100644 --- a/openpype/modules/deadline/plugins/publish/submit_nuke_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_nuke_deadline.py @@ -40,7 +40,7 @@ def process(self, instance): instance.data["toBeRenderedOn"] = "deadline" families = instance.data["families"] - node = instance[0] + node = instance.data["transientData"]["node"] context = instance.context # get default deadline webservice url from deadline module From f8b4183b49b7b5d83af574f1ad78702a9ed7d5a2 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Oct 2022 21:35:01 +0200 Subject: [PATCH 077/115] nuke: fixing review and frames conditions --- .../nuke/plugins/publish/collect_writes.py | 47 +++++++++---------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_writes.py b/openpype/hosts/nuke/plugins/publish/collect_writes.py index e18fbbdf6f2..3054e5a30c5 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_writes.py +++ b/openpype/hosts/nuke/plugins/publish/collect_writes.py @@ -15,7 +15,8 @@ class CollectNukeWrites(pyblish.api.InstancePlugin): def process(self, instance): self.log.debug(pformat(instance.data)) - instance.data.update(instance.data["creator_attributes"]) + creator_attributes = instance.data["creator_attributes"] + instance.data.update(creator_attributes) group_node = instance.data["transientData"]["node"] render_target = instance.data["render_target"] @@ -26,12 +27,8 @@ def process(self, instance): instance.data["families"].append( "{}.{}".format(family, render_target) ) - # add additional keys to farm targeted - if render_target == "farm": - # Farm rendering - self.log.info("flagged for farm render") - instance.data["transfer"] = False - instance.data["farm"] = True + if instance.data.get("review"): + instance.data["families"].append("review") child_nodes = napi.get_instance_group_node_childs(instance) instance.data["transientData"]["childNodes"] = child_nodes @@ -71,8 +68,7 @@ def process(self, instance): self.log.debug('output dir: {}'.format(output_dir)) - if render_target == "frame": - + if render_target == "frames": representation = { 'name': ext, 'ext': ext, @@ -133,6 +129,21 @@ def process(self, instance): representation['files'] = collected_frames instance.data["representations"].append(representation) + self.log.info("Publishing rendered frames ...") + + elif render_target == "farm": + farm_priority = creator_attributes.get("farm_priority") + farm_chunk = creator_attributes.get("farm_chunk") + farm_concurency = creator_attributes.get("farm_concurency") + instance.data.update({ + "deadlineChunkSize": farm_chunk or 1, + "deadlinePriority": farm_priority or 50, + "deadlineConcurrentTasks": farm_concurency or 0 + }) + # Farm rendering + instance.data["transfer"] = False + instance.data["farm"] = True + self.log.info("Farm rendering ON ...") # get colorspace and add to version data colorspace = napi.get_colorspace_from_node(write_node) @@ -140,28 +151,12 @@ def process(self, instance): "colorspace": colorspace } - # get deadline related attributes - dl_chunk_size = 1 - if "deadlineChunkSize" in group_node.knobs(): - dl_chunk_size = group_node["deadlineChunkSize"].value() - - dl_priority = 50 - if "deadlinePriority" in group_node.knobs(): - dl_priority = group_node["deadlinePriority"].value() - - dl_concurrent_tasks = 0 - if "deadlineConcurrentTasks" in group_node.knobs(): - dl_concurrent_tasks = group_node["deadlineConcurrentTasks"].value() - instance.data.update({ "versionData": version_data, "path": write_file_path, "outputDir": output_dir, "ext": ext, - "colorspace": colorspace, - "deadlineChunkSize": dl_chunk_size, - "deadlinePriority": dl_priority, - "deadlineConcurrentTasks": dl_concurrent_tasks + "colorspace": colorspace }) if family == "render": From 462e141ab00ec65454af1d932130b6c70e7c31aa Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 19 Oct 2022 17:41:36 +0200 Subject: [PATCH 078/115] removing old code --- openpype/hosts/nuke/plugins/publish/validate_knobs.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/validate_knobs.py b/openpype/hosts/nuke/plugins/publish/validate_knobs.py index 1d853f72b59..ee8a824d8f3 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_knobs.py +++ b/openpype/hosts/nuke/plugins/publish/validate_knobs.py @@ -62,16 +62,7 @@ def get_invalid_knobs(cls, context): for instance in context: # Filter publisable instances. - if ( - instance.data.get("publish") - and instance.data["publish"] is False - ): - continue - - if ( - instance.data.get("active") - and instance.data["active"] is False - ): + if not instance.data.get("active"): continue # Filter families. From a7aff0e50cf46471497968646425d0fac28830ff Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 19 Oct 2022 17:46:01 +0200 Subject: [PATCH 079/115] nuke: removing old logic code --- openpype/hosts/nuke/plugins/publish/validate_knobs.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/validate_knobs.py b/openpype/hosts/nuke/plugins/publish/validate_knobs.py index ee8a824d8f3..db21cdc7c50 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_knobs.py +++ b/openpype/hosts/nuke/plugins/publish/validate_knobs.py @@ -61,17 +61,11 @@ def get_invalid_knobs(cls, context): invalid_knobs = [] for instance in context: - # Filter publisable instances. - if not instance.data.get("active"): - continue # Filter families. families = [instance.data["family"]] families += instance.data.get("families", []) - if not families: - continue - # Get all knobs to validate. knobs = {} for family in families: From 71c2458d6a1c582aeee991842390bc12ffa21ebc Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 20 Oct 2022 10:36:38 +0200 Subject: [PATCH 080/115] nuke: fix tab --- openpype/hosts/nuke/api/lib.py | 38 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 54fce77c79d..fd9c0de9c0d 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -2726,29 +2726,29 @@ def recreate_instance(origin_node, avalon_data=None): def add_scripts_menu(): - try: - from scriptsmenu import launchfornuke - except ImportError: - log.warning( - "Skipping studio.menu install, because " - "'scriptsmenu' module seems unavailable." - ) - return + try: + from scriptsmenu import launchfornuke + except ImportError: + log.warning( + "Skipping studio.menu install, because " + "'scriptsmenu' module seems unavailable." + ) + return - # load configuration of custom menu - project_settings = get_project_settings(os.getenv("AVALON_PROJECT")) - config = project_settings["nuke"]["scriptsmenu"]["definition"] - _menu = project_settings["nuke"]["scriptsmenu"]["name"] + # load configuration of custom menu + project_settings = get_project_settings(os.getenv("AVALON_PROJECT")) + config = project_settings["nuke"]["scriptsmenu"]["definition"] + _menu = project_settings["nuke"]["scriptsmenu"]["name"] - if not config: - log.warning("Skipping studio menu, no definition found.") - return + if not config: + log.warning("Skipping studio menu, no definition found.") + return - # run the launcher for Maya menu - studio_menu = launchfornuke.main(title=_menu.title()) + # run the launcher for Maya menu + studio_menu = launchfornuke.main(title=_menu.title()) - # apply configuration - studio_menu.build_from_configuration(studio_menu, config) + # apply configuration + studio_menu.build_from_configuration(studio_menu, config) def add_scripts_gizmo(): From bb3105cefb1bc10e6e0841c59303e3f703e47460 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 20 Oct 2022 16:25:47 +0200 Subject: [PATCH 081/115] Nuke: make fallback in case node is erased manually --- openpype/hosts/nuke/api/plugin.py | 44 ++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 7e3c131104f..88da6c5eb2c 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -205,6 +205,13 @@ def update_instances(self, update_list): for created_inst, _changes in update_list: instance_node = created_inst.transient_data["node"] + # in case node is not existing anymore (user erased it manually) + try: + instance_node.fullName() + except ValueError: + self.remove_instances([created_inst]) + continue + set_node_data( instance_node, INSTANCE_DATA_KNOB, @@ -1114,6 +1121,8 @@ def family_to_identifier(family): nuke.Root()["project_directory"].setValue(os.path.dirname(path)) nuke.Root().setModified(False) + _remove_old_knobs(nuke.Root()) + # loop all nodes and convert for node in nuke.allNodes(recurseGroups=True): transfer_data = { @@ -1188,24 +1197,29 @@ def family_to_identifier(family): creator_attr["farm_concurency"] = ( node["deadlineConcurrentTasks"].value()) - remove_knobs = [ - "review", "publish", "render", "suspend_publish", "warn", "divd", - "OpenpypeDataGroup", "OpenpypeDataGroup_End", "deadlinePriority", - "deadlineChunkSize", "deadlineConcurrentTasks", "Deadline" - ] - print(node.name()) + _remove_old_knobs(node) - # remove all old knobs - for knob in node.allKnobs(): - try: - if knob.name() in remove_knobs: - node.removeKnob(knob) - elif "avalon" in knob.name(): - node.removeKnob(knob) - except ValueError: - pass # add new instance knob with transfer data set_node_data( node, INSTANCE_DATA_KNOB, transfer_data) nuke.scriptSave() + + +def _remove_old_knobs(node): + remove_knobs = [ + "review", "publish", "render", "suspend_publish", "warn", "divd", + "OpenpypeDataGroup", "OpenpypeDataGroup_End", "deadlinePriority", + "deadlineChunkSize", "deadlineConcurrentTasks", "Deadline" + ] + print(node.name()) + + # remove all old knobs + for knob in node.allKnobs(): + try: + if knob.name() in remove_knobs: + node.removeKnob(knob) + elif "avalon" in knob.name(): + node.removeKnob(knob) + except ValueError: + pass From d8bda695ce183950c320fcf4f04ae2fc983a8298 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 20 Oct 2022 16:30:27 +0200 Subject: [PATCH 082/115] Nuke: Creator depricated --- openpype/hosts/nuke/api/pipeline.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 258b09f7a87..700db9a8edb 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -228,6 +228,11 @@ def _install_menu(): ) menu.addSeparator() + menu.addCommand( + "Create... [depricated]", + lambda: nuke.message( + "New position is in \"Publish...\" and \"Create\" tab") + ) menu.addCommand( "Publish...", host_tools.show_publisher From 88a1e11faee664d7740a28f417e3d590fa49104e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 20 Oct 2022 16:52:32 +0200 Subject: [PATCH 083/115] nuke: shortcut could be set in project overrides --- openpype/hosts/nuke/api/pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 700db9a8edb..73761660293 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -365,7 +365,7 @@ def add_shortcuts_from_presets(): item_label = menu_label_mapping[command_name] menuitem = menu.findItem(item_label) menuitem.setShortcut(shortcut_str) - except AttributeError as e: + except (AttributeError, KeyError) as e: log.error(e) From dc9a355965afb1b0149df8b1cd6c05241150187b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 20 Oct 2022 17:49:15 +0200 Subject: [PATCH 084/115] Nuke: adding fallbacks if settings have overrides --- openpype/hosts/nuke/api/plugin.py | 13 ++++++++----- .../hosts/nuke/plugins/create/create_write_image.py | 11 +++++++++++ .../nuke/plugins/create/create_write_prerender.py | 13 +++++++++++++ .../nuke/plugins/create/create_write_render.py | 10 ++++++++++ 4 files changed, 42 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 88da6c5eb2c..b8fc54e4432 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -358,12 +358,15 @@ def apply_settings( plugin_settings = self.get_creator_settings(project_settings) # individual attributes - self.instance_attributes = plugin_settings[ - "instance_attributes"] + self.instance_attributes = plugin_settings.get( + "instance_attributes") or self.instance_attributes self.prenodes = plugin_settings["prenodes"] - self.default_variants = plugin_settings["default_variants"] - self.temp_rendering_path_template = plugin_settings[ - "temp_rendering_path_template"] + self.default_variants = plugin_settings.get( + "default_variants") or self.default_variants + self.temp_rendering_path_template = ( + plugin_settings.get("temp_rendering_path_template") + or self.temp_rendering_path_template + ) class OpenPypeCreator(LegacyCreator): diff --git a/openpype/hosts/nuke/plugins/create/create_write_image.py b/openpype/hosts/nuke/plugins/create/create_write_image.py index e9ff33a32b1..cf70063abc5 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_image.py +++ b/openpype/hosts/nuke/plugins/create/create_write_image.py @@ -20,6 +20,17 @@ class CreateWriteImage(napi.NukeWriteCreator): family = "image" icon = "sign-out" + instance_attributes = [ + "use_range_limit" + ] + default_variants = [ + "StillFrame", + "MPFrame", + "LayoutFrame" + ] + temp_rendering_path_template = ( + "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}") + def get_pre_create_attr_defs(self): attr_defs = [ BoolDef( diff --git a/openpype/hosts/nuke/plugins/create/create_write_prerender.py b/openpype/hosts/nuke/plugins/create/create_write_prerender.py index b7d0f4ade9e..daa2319c4b1 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_prerender.py +++ b/openpype/hosts/nuke/plugins/create/create_write_prerender.py @@ -20,6 +20,19 @@ class CreateWritePrerender(napi.NukeWriteCreator): family = "prerender" icon = "sign-out" + instance_attributes = [ + "use_range_limit" + ] + default_variants = [ + "Key01", + "Bg01", + "Fg01", + "Branch01", + "Part01" + ] + temp_rendering_path_template = ( + "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}") + def get_pre_create_attr_defs(self): attr_defs = [ BoolDef( diff --git a/openpype/hosts/nuke/plugins/create/create_write_render.py b/openpype/hosts/nuke/plugins/create/create_write_render.py index 3d96e8c13ba..85133458d10 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_render.py +++ b/openpype/hosts/nuke/plugins/create/create_write_render.py @@ -20,6 +20,16 @@ class CreateWriteRender(napi.NukeWriteCreator): family = "render" icon = "sign-out" + instance_attributes = [ + "reviewable" + ] + default_variants = [ + "Main", + "Mask" + ] + temp_rendering_path_template = ( + "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}") + def get_pre_create_attr_defs(self): attr_defs = [ BoolDef( From 6ed91d4634aea05d7ed6d33631482335d9691772 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 26 Oct 2022 11:38:49 +0200 Subject: [PATCH 085/115] missing dot --- openpype/hosts/nuke/api/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 974afffc72e..7237b8f3982 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -692,7 +692,7 @@ def get_nuke_imageio_settings(): Context.project_name)["nuke"]["imageio"] # backward compatibility for project started before 3.10 - # those are still having `__legacy__` knob types + # those are still having `__legacy__` knob types. if not project_imageio["enabled"]: return get_anatomy_settings(Context.project_name)["imageio"]["nuke"] From c63c9d5fb7a8fe96424882e52abb8fee6fd5371d Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 26 Oct 2022 12:22:32 +0200 Subject: [PATCH 086/115] integrate creator legacy convertor plugin --- openpype/hosts/nuke/api/pipeline.py | 4 -- openpype/hosts/nuke/api/plugin.py | 15 ++++-- .../nuke/plugins/create/convert_legacy.py | 49 +++++++++++++++++++ 3 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 openpype/hosts/nuke/plugins/create/convert_legacy.py diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index f682247143a..2622a457725 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -302,10 +302,6 @@ def _install_menu(): lambda: host_tools.show_experimental_tools_dialog(parent=main_window) ) menu.addSeparator() - menu.addCommand( - "Convert old publishing instances", - plugin.convert_to_valid_instaces - ) # add reload pipeline only in debug mode if bool(os.getenv("NUKE_DEBUG")): menu.addSeparator() diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index a2560317e6e..1ef5b47bd79 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -32,6 +32,7 @@ Knobby, check_subsetname_exists, maintained_selection, + get_avalon_knob_data, set_avalon_knob_data, add_publish_knob, get_nuke_imageio_settings, @@ -1135,16 +1136,22 @@ def family_to_identifier(family): } return mapping[family] - from openpype.hosts.nuke.api.lib import ( - get_avalon_knob_data - ) from openpype.hosts.nuke.api import workio task_name = legacy_io.Session["AVALON_TASK"] # save into new workfile current_file = workio.current_file() - new_workfile = current_file[:-3] + "_publisherConvert" + current_file[-3:] + + # add file suffex if not + if "_publisherConvert" not in current_file: + new_workfile = ( + current_file[:-3] + + "_publisherConvert" + + current_file[-3:] + ) + else: + new_workfile = current_file path = new_workfile.replace("\\", "/") nuke.scriptSaveAs(new_workfile, overwrite=1) diff --git a/openpype/hosts/nuke/plugins/create/convert_legacy.py b/openpype/hosts/nuke/plugins/create/convert_legacy.py new file mode 100644 index 00000000000..08bf66309e6 --- /dev/null +++ b/openpype/hosts/nuke/plugins/create/convert_legacy.py @@ -0,0 +1,49 @@ +from openpype.pipeline.create.creator_plugins import SubsetConvertorPlugin +from openpype.hosts.nuke.api.lib import ( + INSTANCE_DATA_KNOB, + get_node_data, + get_avalon_knob_data +) +from openpype.hosts.nuke.api.plugin import convert_to_valid_instaces + +import nuke + + +class LegacyConverted(SubsetConvertorPlugin): + identifier = "legacy.converter" + + def find_instances(self): + + legacy_found = False + # search for first available legacy item + for node in nuke.allNodes(recurseGroups=True): + + if node.Class() in ["Viewer", "Dot"]: + continue + + if get_node_data(node, INSTANCE_DATA_KNOB): + continue + + # get data from avalon knob + avalon_knob_data = get_avalon_knob_data( + node, ["avalon:", "ak:"]) + + if not avalon_knob_data: + continue + + if avalon_knob_data["id"] != "pyblish.avalon.instance": + continue + + # catch and break + legacy_found = True + break + + if legacy_found: + # if not item do not add legacy instance convertor + self.add_convertor_item("Convert legacy instances") + + def convert(self): + # loop all instances and convert them + convert_to_valid_instaces() + # remove legacy item if all is fine + self.remove_convertor_item() From b6c6fad10e029552c48ae61c4e90c487b2b27d76 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 26 Oct 2022 12:31:53 +0200 Subject: [PATCH 087/115] remove unused imports --- openpype/hosts/nuke/api/pipeline.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 2622a457725..eaab98f292b 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -42,8 +42,7 @@ add_scripts_menu, add_scripts_gizmo, get_node_data, - set_node_data, - update_node_data + set_node_data ) from .workfile_template_builder import ( NukePlaceholderLoadPlugin, @@ -60,7 +59,6 @@ work_root, current_file ) -from openpype.hosts.nuke.api import plugin log = Logger.get_logger(__name__) From 8a2c10e3d1ed558054e204672b219d28c327e0da Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 27 Oct 2022 11:20:21 +0200 Subject: [PATCH 088/115] Nuke: rewrite collect workfile so we are able to disable its publishing --- .../plugins/publish/collect_context_data.py | 69 +++++++++++++++++++ .../nuke/plugins/publish/collect_workfile.py | 51 +------------- 2 files changed, 72 insertions(+), 48 deletions(-) create mode 100644 openpype/hosts/nuke/plugins/publish/collect_context_data.py diff --git a/openpype/hosts/nuke/plugins/publish/collect_context_data.py b/openpype/hosts/nuke/plugins/publish/collect_context_data.py new file mode 100644 index 00000000000..5a1cdcf49ec --- /dev/null +++ b/openpype/hosts/nuke/plugins/publish/collect_context_data.py @@ -0,0 +1,69 @@ +import os +import nuke +import pyblish.api +import openpype.api as api +import openpype.hosts.nuke.api as napi +from openpype.pipeline import KnownPublishError + + +class CollectContextData(pyblish.api.ContextPlugin): + """Collect current context publish.""" + + order = pyblish.api.CollectorOrder - 0.499 + label = "Collect context data" + hosts = ['nuke'] + + def process(self, context): # sourcery skip: avoid-builtin-shadow + root_node = nuke.root() + + current_file = os.path.normpath(root_node.name()) + + if current_file.lower() == "root": + raise KnownPublishError( + "Workfile is not correct file name. \n" + "Use workfile tool to manage the name correctly." + ) + + # Get frame range + first_frame = int(root_node["first_frame"].getValue()) + last_frame = int(root_node["last_frame"].getValue()) + + # get instance data from root + root_instance_context = napi.get_node_data( + root_node, napi.INSTANCE_DATA_KNOB + ) + + handle_start = root_instance_context["handleStart"] + handle_end = root_instance_context["handleEnd"] + + # Get format + format = root_node['format'].value() + resolution_width = format.width() + resolution_height = format.height() + pixel_aspect = format.pixelAspect() + + script_data = { + "frameStart": first_frame + handle_start, + "frameEnd": last_frame - handle_end, + "resolutionWidth": resolution_width, + "resolutionHeight": resolution_height, + "pixelAspect": pixel_aspect, + + # backward compatibility handles + "handles": handle_start, + "handleStart": handle_start, + "handleEnd": handle_end, + "step": 1, + "fps": root_node['fps'].value(), + + "currentFile": current_file, + "version": int(api.get_version_from_path(current_file)), + + "host": pyblish.api.current_host(), + "hostVersion": nuke.NUKE_VERSION_STRING + } + + context.data["scriptData"] = script_data + context.data.update(script_data) + + self.log.info('Context from Nuke script collected') diff --git a/openpype/hosts/nuke/plugins/publish/collect_workfile.py b/openpype/hosts/nuke/plugins/publish/collect_workfile.py index 7f4849be679..54c77b1e4ec 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_workfile.py +++ b/openpype/hosts/nuke/plugins/publish/collect_workfile.py @@ -1,70 +1,25 @@ import os - import nuke - import pyblish.api -import openpype.api as api -from openpype.pipeline import KnownPublishError class CollectWorkfile(pyblish.api.InstancePlugin): """Collect current script for publish.""" - order = pyblish.api.CollectorOrder - 0.499 + order = pyblish.api.CollectorOrder - 0.498 label = "Collect Workfile" hosts = ['nuke'] families = ["workfile"] def process(self, instance): # sourcery skip: avoid-builtin-shadow - root = nuke.root() + script_data = instance.context.data["scriptData"] current_file = os.path.normpath(nuke.root().name()) - if current_file.lower() == "root": - raise KnownPublishError( - "Workfile is not correct file name. \n" - "Use workfile tool to manage the name correctly." - ) - # creating instances per write node staging_dir = os.path.dirname(current_file) base_name = os.path.basename(current_file) - # Get frame range - first_frame = int(root["first_frame"].getValue()) - last_frame = int(root["last_frame"].getValue()) - - handle_start = instance.data["handleStart"] - handle_end = instance.data["handleEnd"] - - # Get format - format = root['format'].value() - resolution_width = format.width() - resolution_height = format.height() - pixel_aspect = format.pixelAspect() - - script_data = { - "frameStart": first_frame + handle_start, - "frameEnd": last_frame - handle_end, - "resolutionWidth": resolution_width, - "resolutionHeight": resolution_height, - "pixelAspect": pixel_aspect, - - # backward compatibility handles - "handles": handle_start, - "handleStart": handle_start, - "handleEnd": handle_end, - "step": 1, - "fps": root['fps'].value(), - - "currentFile": current_file, - "version": int(api.get_version_from_path(current_file)), - - "host": pyblish.api.current_host(), - "hostVersion": nuke.NUKE_VERSION_STRING - } - instance.context.data.update(script_data) - # creating representation representation = { 'name': 'nk', @@ -82,4 +37,4 @@ def process(self, instance): # sourcery skip: avoid-builtin-shadow # adding basic script data instance.data.update(script_data) - self.log.info('Publishing script version') + self.log.info("Collect script version") From fc87bf19e8e79ec30cfd3fa058f5a2bb3020a848 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 27 Oct 2022 12:00:52 +0200 Subject: [PATCH 089/115] nuke: fixing extractor for transient data --- .../hosts/nuke/plugins/publish/extract_ouput_node.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py b/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py index eb9bc0b4290..6067e6cf6b2 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py +++ b/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py @@ -16,9 +16,12 @@ class CreateOutputNode(pyblish.api.ContextPlugin): def process(self, context): # capture selection state with maintained_selection(): - active_node = [node for inst in context - for node in inst - if "ak:family" in node.knobs()] + + active_node = [ + inst.data.get("transientData", {}).get("node") + for inst in context + if inst.data.get("transientData", {}).get("node") + ] if active_node: self.log.info(active_node) From 125fafa79006792db0ba61c7c13a04e320ac4853 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 27 Oct 2022 15:10:47 +0200 Subject: [PATCH 090/115] Nuke: depricated function in lib --- openpype/hosts/nuke/api/lib.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 7237b8f3982..869843e7117 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -477,7 +477,7 @@ def set_avalon_knob_data(node, data=None, prefix="avalon:"): return node -def get_avalon_knob_data(node, prefix="avalon:"): +def get_avalon_knob_data(node, prefix="avalon:", create=True): """[DEPRICATED] Gets a data from nodes's avalon knob Arguments: @@ -506,8 +506,11 @@ def get_avalon_knob_data(node, prefix="avalon:"): except NameError as e: # if it doesn't then create it log.debug("Creating avalon knob: `{}`".format(e)) - node = set_avalon_knob_data(node) - return get_avalon_knob_data(node) + if create: + node = set_avalon_knob_data(node) + return get_avalon_knob_data(node) + else: + return {} # get data from filtered knobs data.update({k.replace(p, ''): node[k].value() @@ -2660,6 +2663,7 @@ def process_workfile_builder(): open_file(last_workfile_path) +@deprecated def recreate_instance(origin_node, avalon_data=None): """Recreate input instance to different data From 95bf35b6fab3b0f7f9aedd7147739aec1020dc86 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 27 Oct 2022 15:11:25 +0200 Subject: [PATCH 091/115] nuke: improving list instances --- openpype/hosts/nuke/api/pipeline.py | 8 ++--- openpype/hosts/nuke/api/plugin.py | 30 +++++++++---------- .../nuke/plugins/create/convert_legacy.py | 2 +- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index eaab98f292b..0f494199035 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -490,7 +490,6 @@ def ls(): nodes = [n for n in all_nodes] for n in nodes: - log.debug("name: `{}`".format(n.name())) container = parse_container(n) if container: yield container @@ -513,9 +512,9 @@ def list_instances(creator_id=None): try: if node["disable"].value(): continue - except Exception as _exc: - log.debug("Node {} have no disable knob - {}".format( - node.fullName(), _exc)) + except NameError: + # pass if disable knob doesn't exist + pass # get data from avalon knob instance_data = get_node_data( @@ -527,7 +526,6 @@ def list_instances(creator_id=None): if instance_data["id"] != "pyblish.avalon.instance": continue - log.debug("_ creator_id: {}".format(creator_id)) if creator_id and instance_data["creator_identifier"] != creator_id: continue diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 1ef5b47bd79..1f102a2de57 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -1,4 +1,3 @@ -from pprint import pformat import nuke import re import os @@ -6,7 +5,7 @@ import six import random import string -from collections import OrderedDict +from collections import OrderedDict, defaultdict from abc import abstractmethod from openpype.client import ( @@ -49,6 +48,18 @@ ) +def _collect_and_cache_nodes(creator): + key = "openpype.nuke.nodes" + if key not in creator.collection_shared_data: + instances_by_identifier = defaultdict(list) + for item in list_instances(): + _, instance_data = item + identifier = instance_data["creator_identifier"] + instances_by_identifier[identifier].append(item) + creator.collection_shared_data[key] = instances_by_identifier + return creator.collection_shared_data[key] + + class NukeCreatorError(CreatorError): pass @@ -150,7 +161,6 @@ def set_selected_nodes(self, pre_create_data): else: self.selected_nodes = [] - self.log.debug("Selection is: {}".format(self.selected_nodes)) def create(self, subset_name, instance_data, pre_create_data): @@ -192,11 +202,8 @@ def create(self, subset_name, instance_data, pre_create_data): sys.exc_info()[2]) def collect_instances(self): - for (node, data) in list_instances(creator_id=self.identifier): - self.log.debug("_" * 50) - self.log.debug("_ self.identifier: `{}`".format(self.identifier)) - self.log.debug("_ data: `{}`".format(pformat(data))) - + cached_instances = _collect_and_cache_nodes(self) + for (node, data) in cached_instances[self.identifier]: created_instance = CreatedInstance.from_existing( data, self ) @@ -555,7 +562,6 @@ def __init__(self, def get_file_info(self): if self.collection: - self.log.debug("Collection: `{}`".format(self.collection)) # get path self.fname = os.path.basename(self.collection.format( "{head}{padding}{tail}")) @@ -690,7 +696,6 @@ def generate_lut(self, **kwargs): # connect self._temp_nodes.append(cms_node) self.previous_node = cms_node - self.log.debug("CMSTestPattern... `{}`".format(self._temp_nodes)) if bake_viewer_process: # Node View Process @@ -723,8 +728,6 @@ def generate_lut(self, **kwargs): # connect gen_lut_node.setInput(0, self.previous_node) self._temp_nodes.append(gen_lut_node) - self.log.debug("GenerateLUT... `{}`".format(self._temp_nodes)) - # ---------- end nodes creation # Export lut file @@ -738,8 +741,6 @@ def generate_lut(self, **kwargs): # ---------- generate representation data self.get_representation_data() - self.log.debug("Representation... `{}`".format(self.data)) - # ---------- Clean up self.clean_nodes() @@ -990,7 +991,6 @@ def __init__(self, *args, **kwargs): self.data = data self.nodes = nuke.selectedNodes() - self.log.debug("_ self.data: '{}'".format(self.data)) def process(self): diff --git a/openpype/hosts/nuke/plugins/create/convert_legacy.py b/openpype/hosts/nuke/plugins/create/convert_legacy.py index 08bf66309e6..d7341c625f4 100644 --- a/openpype/hosts/nuke/plugins/create/convert_legacy.py +++ b/openpype/hosts/nuke/plugins/create/convert_legacy.py @@ -26,7 +26,7 @@ def find_instances(self): # get data from avalon knob avalon_knob_data = get_avalon_knob_data( - node, ["avalon:", "ak:"]) + node, ["avalon:", "ak:"], create=False) if not avalon_knob_data: continue From a16d7c95b76eadde20f40bfb2c436aa539af1f8f Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 27 Oct 2022 15:12:03 +0200 Subject: [PATCH 092/115] removing logging --- openpype/hosts/nuke/plugins/create/create_camera.py | 2 -- openpype/hosts/nuke/plugins/create/create_model.py | 2 -- openpype/hosts/nuke/plugins/create/create_source.py | 2 -- openpype/hosts/nuke/plugins/create/workfile_creator.py | 2 -- 4 files changed, 8 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_camera.py b/openpype/hosts/nuke/plugins/create/create_camera.py index c559aa27566..ac1a0c7db74 100644 --- a/openpype/hosts/nuke/plugins/create/create_camera.py +++ b/openpype/hosts/nuke/plugins/create/create_camera.py @@ -62,5 +62,3 @@ def set_selected_nodes(self, pre_create_data): NukeCreatorError("Creator error: Select only one camera node") else: self.selected_nodes = [] - - self.log.debug("Selection is: {}".format(self.selected_nodes)) diff --git a/openpype/hosts/nuke/plugins/create/create_model.py b/openpype/hosts/nuke/plugins/create/create_model.py index a1a96bf4124..22b28cb7cee 100644 --- a/openpype/hosts/nuke/plugins/create/create_model.py +++ b/openpype/hosts/nuke/plugins/create/create_model.py @@ -63,5 +63,3 @@ def set_selected_nodes(self, pre_create_data): NukeCreatorError("Creator error: Select only one camera node") else: self.selected_nodes = [] - - self.log.debug("Selection is: {}".format(self.selected_nodes)) diff --git a/openpype/hosts/nuke/plugins/create/create_source.py b/openpype/hosts/nuke/plugins/create/create_source.py index 48f9f862197..35fe42c16b9 100644 --- a/openpype/hosts/nuke/plugins/create/create_source.py +++ b/openpype/hosts/nuke/plugins/create/create_source.py @@ -89,5 +89,3 @@ def set_selected_nodes(self, pre_create_data): else: NukeCreatorError( "Creator error: only supprted with active selection") - - self.log.debug("Selection is: {}".format(self.selected_nodes)) diff --git a/openpype/hosts/nuke/plugins/create/workfile_creator.py b/openpype/hosts/nuke/plugins/create/workfile_creator.py index ae05cee99f2..31068c18281 100644 --- a/openpype/hosts/nuke/plugins/create/workfile_creator.py +++ b/openpype/hosts/nuke/plugins/create/workfile_creator.py @@ -22,7 +22,6 @@ def collect_instances(self): instance_data = api.get_node_data( root_node, api.INSTANCE_DATA_KNOB ) - self.log.debug("__ instance_data: {}".format(instance_data)) project_name = legacy_io.Session["AVALON_PROJECT"] asset_name = legacy_io.Session["AVALON_ASSET"] @@ -34,7 +33,6 @@ def collect_instances(self): self.default_variant, task_name, asset_doc, project_name, host_name ) - self.log.debug("__ subset_name: {}".format(subset_name)) instance_data.update({ "asset": asset_name, "task": task_name, From b400a604f032de1c8ae32db00b4536a4b083dbac Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 27 Oct 2022 15:12:13 +0200 Subject: [PATCH 093/115] typo --- .../hosts/nuke/plugins/publish/help/validate_asset_name.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/publish/help/validate_asset_name.xml b/openpype/hosts/nuke/plugins/publish/help/validate_asset_name.xml index 1097909a5fa..0422917e9c4 100644 --- a/openpype/hosts/nuke/plugins/publish/help/validate_asset_name.xml +++ b/openpype/hosts/nuke/plugins/publish/help/validate_asset_name.xml @@ -1,7 +1,7 @@ - Shot/Asset mame + Shot/Asset name ## Invalid Shot/Asset name in subset From ebb07f928435146e08ad9014920afd740a0bb13e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 27 Oct 2022 15:12:31 +0200 Subject: [PATCH 094/115] nuke: fixing validators --- .../plugins/publish/validate_asset_name.py | 19 +++---- .../publish/validate_script_attributes.py | 54 ++++--------------- 2 files changed, 20 insertions(+), 53 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/validate_asset_name.py b/openpype/hosts/nuke/plugins/publish/validate_asset_name.py index 230717cf181..f6822bee45f 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_asset_name.py +++ b/openpype/hosts/nuke/plugins/publish/validate_asset_name.py @@ -2,11 +2,10 @@ """Validate if instance asset is the same as context asset.""" from __future__ import absolute_import -import nuke import pyblish.api import openpype.hosts.nuke.api.lib as nlib -from openpype.hosts.nuke import api as napi + from openpype.pipeline.publish import ( ValidateContentsOrder, PublishXmlValidationError, @@ -51,9 +50,10 @@ def process(self, context, plugin): self.deselect() def select(self, instances): - nlib.select_nodes( - [nuke.toNode(str(x)) for x in instances] - ) + for inst in instances: + if inst.data.get("transientData", {}).get("node"): + select_node = inst.data["transientData"]["node"] + select_node["selected"].setValue(True) def deselect(self): nlib.reset_selection() @@ -82,13 +82,14 @@ def process(self, context, plugin): # Apply pyblish.logic to get the instances for the plug-in instances = pyblish.api.instances_by_plugin(failed, plugin) + self.log.debug(instances) context_asset = context.data["assetEntity"]["name"] for instance in instances: - origin_node = instance.data["transientData"]["node"] - napi.lib.recreate_instance( - origin_node, avalon_data={"asset": context_asset} - ) + node = instance.data["transientData"]["node"] + node_data = nlib.get_node_data(node, nlib.INSTANCE_DATA_KNOB) + node_data["asset"] = context_asset + nlib.set_node_data(node, nlib.INSTANCE_DATA_KNOB, node_data) class ValidateCorrectAssetName(pyblish.api.InstancePlugin): diff --git a/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py b/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py index 3ebc34f1952..f932ef2c407 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py @@ -1,13 +1,10 @@ -from pprint import pformat +from copy import deepcopy import pyblish.api - from openpype.pipeline import PublishXmlValidationError from openpype.pipeline.publish import RepairAction from openpype.hosts.nuke.api.lib import ( - get_avalon_knob_data, WorkfileSettings ) -import nuke class ValidateScriptAttributes(pyblish.api.InstancePlugin): @@ -21,14 +18,9 @@ class ValidateScriptAttributes(pyblish.api.InstancePlugin): actions = [RepairAction] def process(self, instance): - root = nuke.root() - knob_data = get_avalon_knob_data(root) + script_data = deepcopy(instance.context.data["scriptData"]) + asset = instance.data["assetEntity"] - # get asset data frame values - frame_start = asset["data"]["frameStart"] - frame_end = asset["data"]["frameEnd"] - handle_start = asset["data"]["handleStart"] - handle_end = asset["data"]["handleEnd"] # These attributes will be checked attributes = [ @@ -47,37 +39,11 @@ def process(self, instance): for attr in attributes if attr in asset["data"] } - # fix float to max 4 digints (only for evaluating) - fps_data = float("{0:.4f}".format( - asset_attributes["fps"])) # fix frame values to include handles - asset_attributes.update({ - "frameStart": frame_start - handle_start, - "frameEnd": frame_end + handle_end, - "fps": fps_data - }) - - self.log.debug(pformat( - asset_attributes - )) - - # Get format - _format = root["format"].value() - - # Get values from nukescript - script_attributes = { - "handleStart": int(knob_data["handleStart"]), - "handleEnd": int(knob_data["handleEnd"]), - "fps": float("{0:.4f}".format(root['fps'].value())), - "frameStart": int(root["first_frame"].getValue()), - "frameEnd": int(root["last_frame"].getValue()), - "resolutionWidth": _format.width(), - "resolutionHeight": _format.height(), - "pixelAspect": _format.pixelAspect() - } - self.log.debug(pformat( - script_attributes - )) + asset_attributes["fps"] = float("{0:.4f}".format( + asset_attributes["fps"])) + script_data["fps"] = float("{0:.4f}".format( + script_data["fps"])) # Compare asset's values Nukescript X Database not_matching = [] @@ -86,14 +52,14 @@ def process(self, instance): "Asset vs Script attribute \"{}\": {}, {}".format( attr, asset_attributes[attr], - script_attributes[attr] + script_data[attr] ) ) - if asset_attributes[attr] != script_attributes[attr]: + if asset_attributes[attr] != script_data[attr]: not_matching.append({ "name": attr, "expected": asset_attributes[attr], - "actual": script_attributes[attr] + "actual": script_data[attr] }) # Raise error if not matching From bba88cad534b17dab5e111839741c9697198d679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Mon, 7 Nov 2022 13:48:25 +0100 Subject: [PATCH 095/115] Update openpype/hosts/nuke/api/pipeline.py Co-authored-by: Milan Kolar --- openpype/hosts/nuke/api/pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 0f494199035..40933994357 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -226,7 +226,7 @@ def _install_menu(): menu.addSeparator() menu.addCommand( - "Create... [depricated]", + "Create... [deprecated]", lambda: nuke.message( "New position is in \"Publish...\" and \"Create\" tab") ) From 9b230f615c2a36628fb7460b2a06ad9bf40a835f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Mon, 7 Nov 2022 13:48:47 +0100 Subject: [PATCH 096/115] Update openpype/hosts/nuke/api/pipeline.py Co-authored-by: Milan Kolar --- openpype/hosts/nuke/api/pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 40933994357..80b13be8f4d 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -228,7 +228,7 @@ def _install_menu(): menu.addCommand( "Create... [deprecated]", lambda: nuke.message( - "New position is in \"Publish...\" and \"Create\" tab") + "Creator has been moved, you'll find it in the Publish tool -> Create tab") ) menu.addCommand( "Publish...", From ca050aa9ae5c1b272970dbf6462a05c4f8a36f21 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 7 Nov 2022 14:47:31 +0100 Subject: [PATCH 097/115] shortening line --- openpype/hosts/nuke/api/pipeline.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 80b13be8f4d..58cd4453883 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -228,7 +228,9 @@ def _install_menu(): menu.addCommand( "Create... [deprecated]", lambda: nuke.message( - "Creator has been moved, you'll find it in the Publish tool -> Create tab") + "Creator has been moved, you'll find it " + "in the Publish tool -> Create tab" + ) ) menu.addCommand( "Publish...", From 33b407be3689244ac1e7d210df50b6987b29b708 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 7 Nov 2022 14:48:37 +0100 Subject: [PATCH 098/115] nuke: removing custom order --- openpype/hosts/nuke/plugins/publish/collect_workfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_workfile.py b/openpype/hosts/nuke/plugins/publish/collect_workfile.py index 54c77b1e4ec..852042e6e95 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_workfile.py +++ b/openpype/hosts/nuke/plugins/publish/collect_workfile.py @@ -6,7 +6,7 @@ class CollectWorkfile(pyblish.api.InstancePlugin): """Collect current script for publish.""" - order = pyblish.api.CollectorOrder - 0.498 + order = pyblish.api.CollectorOrder label = "Collect Workfile" hosts = ['nuke'] families = ["workfile"] From 9cfcea8e1ce74a112b3fd8b04d419d43a26885c2 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 10 Nov 2022 18:01:23 +0100 Subject: [PATCH 099/115] nuke: removing version data families > slate --- openpype/hosts/nuke/plugins/publish/collect_slate_node.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py index 72b0614d2bb..57010876977 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py +++ b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py @@ -35,7 +35,6 @@ def process(self, instance): instance.data["slateNode"] = slate_node instance.data["slate"] = True instance.data["families"].append("slate") - instance.data["versionData"]["families"].append("slate") self.log.info( "Slate node is in node graph: `{}`".format(slate.name())) self.log.debug( From 2f50c0261fe7798fad2a04c9e60faac7b847a4e5 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 10 Nov 2022 21:42:13 +0100 Subject: [PATCH 100/115] nuke: removing instance only clear instance data knob --- openpype/hosts/nuke/api/pipeline.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 58cd4453883..e739d7335ef 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -545,7 +545,8 @@ def remove_instance(instance): instance (dict): instance representation from subsetmanager model """ instance_node = instance.transient_data["node"] - nuke.delete(instance_node) + instance_knob = instance_node.knobs()[INSTANCE_DATA_KNOB] + instance_node.removeKnob(instance_knob) def select_instance(instance): From 0249eee113a282249f678925e80d3bf94238a8ce Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 10 Nov 2022 22:44:46 +0100 Subject: [PATCH 101/115] nuke: workfile instance updating changes --- .../hosts/nuke/plugins/create/workfile_creator.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/workfile_creator.py b/openpype/hosts/nuke/plugins/create/workfile_creator.py index 31068c18281..72ef61e63f2 100644 --- a/openpype/hosts/nuke/plugins/create/workfile_creator.py +++ b/openpype/hosts/nuke/plugins/create/workfile_creator.py @@ -5,6 +5,10 @@ CreatedInstance, legacy_io, ) +from openpype.hosts.nuke.api import ( + INSTANCE_DATA_KNOB, + set_node_data +) import nuke @@ -50,8 +54,14 @@ def collect_instances(self): self._add_instance_to_context(instance) def update_instances(self, update_list): - # nothing to change on workfiles - pass + for created_inst, _changes in update_list: + instance_node = created_inst.transient_data["node"] + + set_node_data( + instance_node, + INSTANCE_DATA_KNOB, + created_inst.data_to_store() + ) def create(self, options=None): # no need to create if it is created From b137b547a3b1e7a36cfb22489f2a16b26a31e86c Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 18 Nov 2022 13:54:14 +0100 Subject: [PATCH 102/115] nuke: validator with interactive publisher attribute --- .../publish/validate_output_resolution.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py b/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py index c581e682a78..70451ebc959 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py +++ b/openpype/hosts/nuke/plugins/publish/validate_output_resolution.py @@ -1,12 +1,19 @@ import pyblish.api from openpype.hosts.nuke import api as napi -from openpype.pipeline import PublishXmlValidationError from openpype.pipeline.publish import RepairAction +from openpype.pipeline import ( + PublishXmlValidationError, + OptionalPyblishPluginMixin +) + import nuke -class ValidateOutputResolution(pyblish.api.InstancePlugin): +class ValidateOutputResolution( + OptionalPyblishPluginMixin, + pyblish.api.InstancePlugin +): """Validates Output Resolution. It is making sure the resolution of write's input is the same as @@ -15,7 +22,7 @@ class ValidateOutputResolution(pyblish.api.InstancePlugin): order = pyblish.api.ValidatorOrder optional = True - families = ["render", "render.local", "render.farm"] + families = ["render"] label = "Write Resolution" hosts = ["nuke"] actions = [RepairAction] @@ -24,6 +31,9 @@ class ValidateOutputResolution(pyblish.api.InstancePlugin): resolution_msg = "Reformat is set to wrong format" def process(self, instance): + if not self.is_active(instance.data): + return + invalid = self.get_invalid(instance) if invalid: raise PublishXmlValidationError(self, invalid) From 2b0ed94fa4f565290d7550d08c2972d637862ac7 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 18 Nov 2022 16:14:17 +0100 Subject: [PATCH 103/115] nuke: adding interactive publish attribute --- .../plugins/publish/validate_script_attributes.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py b/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py index f932ef2c407..bd0bbf8044b 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_script_attributes.py @@ -1,13 +1,19 @@ from copy import deepcopy import pyblish.api -from openpype.pipeline import PublishXmlValidationError +from openpype.pipeline import ( + PublishXmlValidationError, + OptionalPyblishPluginMixin +) from openpype.pipeline.publish import RepairAction from openpype.hosts.nuke.api.lib import ( WorkfileSettings ) -class ValidateScriptAttributes(pyblish.api.InstancePlugin): +class ValidateScriptAttributes( + OptionalPyblishPluginMixin, + pyblish.api.InstancePlugin +): """ Validates file output. """ order = pyblish.api.ValidatorOrder + 0.1 @@ -18,6 +24,9 @@ class ValidateScriptAttributes(pyblish.api.InstancePlugin): actions = [RepairAction] def process(self, instance): + if not self.is_active(instance.data): + return + script_data = deepcopy(instance.context.data["scriptData"]) asset = instance.data["assetEntity"] From 93543a97367bdbe3c9dc1267bada1945764799c5 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 22 Nov 2022 21:37:15 +0100 Subject: [PATCH 104/115] Nuke: create opens to create tab --- openpype/hosts/nuke/api/pipeline.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 85283680bdf..6fd4c3651c8 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -226,15 +226,16 @@ def _install_menu(): menu.addSeparator() menu.addCommand( - "Create... [deprecated]", - lambda: nuke.message( - "Creator has been moved, you'll find it " - "in the Publish tool -> Create tab" + "Create...", + lambda: host_tools.show_publisher( + tab="create" ) ) menu.addCommand( "Publish...", - host_tools.show_publisher + lambda: host_tools.show_publisher( + tab="publish" + ) ) menu.addCommand( "Load...", From e89cdd0239927c930b6b708bc4128aef85250009 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 12 Dec 2022 10:12:59 +0100 Subject: [PATCH 105/115] Nuke: returning Create shorcut --- openpype/hosts/nuke/api/pipeline.py | 1 + openpype/settings/defaults/project_settings/nuke.json | 1 + 2 files changed, 2 insertions(+) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 6fd4c3651c8..268d25b68ef 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -343,6 +343,7 @@ def add_shortcuts_from_presets(): if nuke_presets.get("menu"): menu_label_mapping = { + "create": "Create...", "manage": "Manage...", "load": "Load...", "build_workfile": "Build Workfile", diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index a3f97c11c4a..5aeca288ad9 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -1,6 +1,7 @@ { "general": { "menu": { + "create": "ctrl+alt+c", "publish": "ctrl+alt+p", "load": "ctrl+alt+l", "manage": "ctrl+alt+m", From 3f4be3aa69062820f6f03a2dcb2265c72c123e6d Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 12 Dec 2022 10:13:23 +0100 Subject: [PATCH 106/115] Nuke: adding input node type validation --- openpype/hosts/nuke/plugins/create/create_camera.py | 10 ++++++++-- openpype/hosts/nuke/plugins/create/create_model.py | 6 +++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_camera.py b/openpype/hosts/nuke/plugins/create/create_camera.py index ac1a0c7db74..dc4a30f513d 100644 --- a/openpype/hosts/nuke/plugins/create/create_camera.py +++ b/openpype/hosts/nuke/plugins/create/create_camera.py @@ -26,6 +26,10 @@ def create_instance_node( ): with maintained_selection(): if self.selected_nodes: + node = self.selected_nodes[0] + if node.Class() != "Camera3": + raise NukeCreatorError( + "Creator error: Select only camera node type") created_node = self.selected_nodes[0] else: created_node = nuke.createNode("Camera2") @@ -57,8 +61,10 @@ def set_selected_nodes(self, pre_create_data): if pre_create_data.get("use_selection"): self.selected_nodes = nuke.selectedNodes() if self.selected_nodes == []: - raise NukeCreatorError("Creator error: No active selection") + raise NukeCreatorError( + "Creator error: No active selection") elif len(self.selected_nodes) > 1: - NukeCreatorError("Creator error: Select only one camera node") + raise NukeCreatorError( + "Creator error: Select only one camera node") else: self.selected_nodes = [] diff --git a/openpype/hosts/nuke/plugins/create/create_model.py b/openpype/hosts/nuke/plugins/create/create_model.py index 22b28cb7cee..f0d0f0918f4 100644 --- a/openpype/hosts/nuke/plugins/create/create_model.py +++ b/openpype/hosts/nuke/plugins/create/create_model.py @@ -27,7 +27,11 @@ def create_instance_node( ): with maintained_selection(): if self.selected_nodes: - created_node = self.selected_nodes[0] + node = self.selected_nodes[0] + if node.Class() != "Scene": + raise NukeCreatorError( + "Creator error: Select only 'Scene' node type") + created_node = node else: created_node = nuke.createNode("Scene") From 2413c8ca78b58dfcf5ec0b7bfcdab47f92d1c421 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 12 Dec 2022 10:32:57 +0100 Subject: [PATCH 107/115] nuke: refactor Create Gizmo plugin --- .../hosts/nuke/plugins/create/create_gizmo.py | 126 ++++++++---------- 1 file changed, 54 insertions(+), 72 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_gizmo.py b/openpype/hosts/nuke/plugins/create/create_gizmo.py index d616f6f7ad7..1869874e226 100644 --- a/openpype/hosts/nuke/plugins/create/create_gizmo.py +++ b/openpype/hosts/nuke/plugins/create/create_gizmo.py @@ -1,87 +1,69 @@ import nuke - -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - maintained_selection, - select_nodes, - set_avalon_knob_data +from openpype.hosts.nuke.api import ( + NukeCreator, + NukeCreatorError, + maintained_selection ) -class CreateGizmo(plugin.OpenPypeCreator): - """Add Publishable "gizmo" group - - The name is symbolically gizmo as presumably - it is something familiar to nuke users as group of nodes - distributed downstream in workflow - """ +class CreateGizmo(NukeCreator): + """Add Publishable Group as gizmo""" - name = "gizmo" - label = "Gizmo" + identifier = "create_gizmo" + label = "Gizmo (group)" family = "gizmo" icon = "file-archive-o" - defaults = ["ViewerInput", "Lut", "Effect"] + default_variants = ["ViewerInput", "Lut", "Effect"] - def __init__(self, *args, **kwargs): - super(CreateGizmo, self).__init__(*args, **kwargs) - self.nodes = nuke.selectedNodes() - self.node_color = "0x7533c1ff" - return + # plugin attributes + node_color = "0x7533c1ff" - def process(self): - if (self.options or {}).get("useSelection"): - nodes = self.nodes - self.log.info(len(nodes)) - if len(nodes) == 1: - select_nodes(nodes) - node = nodes[-1] - # check if Group node - if node.Class() in "Group": - node["name"].setValue("{}_GZM".format(self.name)) - node["tile_color"].setValue(int(self.node_color, 16)) - return set_avalon_knob_data(node, self.data) - else: - msg = ("Please select a group node " - "you wish to publish as the gizmo") - self.log.error(msg) - nuke.message(msg) + def create_instance_node( + self, + node_name, + knobs=None, + parent=None, + node_type=None + ): + with maintained_selection(): + if self.selected_nodes: + node = self.selected_nodes[0] + if node.Class() != "Group": + raise NukeCreatorError( + "Creator error: Select only 'Group' node type") + created_node = node + else: + created_node = nuke.collapseToGroup() - if len(nodes) >= 2: - select_nodes(nodes) - nuke.makeGroup() - gizmo_node = nuke.selectedNode() - gizmo_node["name"].setValue("{}_GZM".format(self.name)) - gizmo_node["tile_color"].setValue(int(self.node_color, 16)) + created_node["tile_color"].setValue( + int(self.node_color, 16)) - # add sticky node with guide - with gizmo_node: - sticky = nuke.createNode("StickyNote") - sticky["label"].setValue( - "Add following:\n- set Input" - " nodes\n- set one Output1\n" - "- create User knobs on the group") + created_node["name"].setValue(node_name) - # add avalon knobs - return set_avalon_knob_data(gizmo_node, self.data) + self.add_info_knob(created_node) - else: - msg = "Please select nodes you wish to add to the gizmo" - self.log.error(msg) - nuke.message(msg) - return - else: - with maintained_selection(): - gizmo_node = nuke.createNode("Group") - gizmo_node["name"].setValue("{}_GZM".format(self.name)) - gizmo_node["tile_color"].setValue(int(self.node_color, 16)) + return created_node + + def create(self, subset_name, instance_data, pre_create_data): + if self.check_existing_subset(subset_name, instance_data): + raise NukeCreatorError( + ("Subset name '{}' is already used. " + "Please specify different Variant.").format(subset_name)) - # add sticky node with guide - with gizmo_node: - sticky = nuke.createNode("StickyNote") - sticky["label"].setValue( - "Add following:\n- add Input" - " nodes\n- add one Output1\n" - "- create User knobs on the group") + instance = super(CreateGizmo, self).create( + subset_name, + instance_data, + pre_create_data + ) - # add avalon knobs - return set_avalon_knob_data(gizmo_node, self.data) + return instance + + def set_selected_nodes(self, pre_create_data): + if pre_create_data.get("use_selection"): + self.selected_nodes = nuke.selectedNodes() + if self.selected_nodes == []: + raise NukeCreatorError("Creator error: No active selection") + elif len(self.selected_nodes) > 1: + NukeCreatorError("Creator error: Select only one 'Group' node") + else: + self.selected_nodes = [] From 415987ec9b92bf9e679d69d7e78210ea935d957d Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 12 Dec 2022 10:33:12 +0100 Subject: [PATCH 108/115] nuke: fix error message --- openpype/hosts/nuke/plugins/create/create_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/create/create_model.py b/openpype/hosts/nuke/plugins/create/create_model.py index f0d0f0918f4..53b3a582880 100644 --- a/openpype/hosts/nuke/plugins/create/create_model.py +++ b/openpype/hosts/nuke/plugins/create/create_model.py @@ -64,6 +64,6 @@ def set_selected_nodes(self, pre_create_data): if self.selected_nodes == []: raise NukeCreatorError("Creator error: No active selection") elif len(self.selected_nodes) > 1: - NukeCreatorError("Creator error: Select only one camera node") + NukeCreatorError("Creator error: Select only one 'Scene' node") else: self.selected_nodes = [] From 86f57b1c910ffc9a3f62d25f782ecd7d602d4da9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 12 Dec 2022 11:39:38 +0100 Subject: [PATCH 109/115] nuke: gizmo flow consistency --- openpype/hosts/nuke/plugins/publish/collect_gizmo.py | 8 ++++---- openpype/hosts/nuke/plugins/publish/extract_gizmo.py | 11 +---------- openpype/hosts/nuke/plugins/publish/validate_gizmo.py | 2 +- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py index c194f70f7e6..3a877fc194a 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py @@ -7,18 +7,18 @@ class CollectGizmo(pyblish.api.InstancePlugin): """ order = pyblish.api.CollectorOrder + 0.22 - label = "Collect Gizmo (Group)" + label = "Collect Gizmo (group)" hosts = ["nuke"] families = ["gizmo"] def process(self, instance): - grpn = instance.data["transientData"]["node"] + + gizmo_node = instance.data["transientData"]["node"] # add family to familiess instance.data["families"].insert(0, instance.data["family"]) # make label nicer - instance.data["label"] = "{0} ({1} nodes)".format( - grpn.name(), len(instance) - 1) + instance.data["label"] = gizmo_node.name() # Get frame range handle_start = instance.context.data["handleStart"] diff --git a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py index 4ca80e9995b..b0b1a9f7b78 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py @@ -19,7 +19,7 @@ class ExtractGizmo(publish.Extractor): """ order = pyblish.api.ExtractorOrder - label = "Extract Gizmo (Group)" + label = "Extract Gizmo (group)" hosts = ["nuke"] families = ["gizmo"] @@ -55,15 +55,6 @@ def process(self, instance): # convert gizmos to groups pnutils.bake_gizmos_recursively(copy_grpn) - # remove avalonknobs - knobs = copy_grpn.knobs() - avalon_knobs = [k for k in knobs.keys() - for ak in ["avalon:", "ak:"] - if ak in k] - avalon_knobs.append("publish") - for ak in avalon_knobs: - copy_grpn.removeKnob(knobs[ak]) - # add to temporary nodes tmp_nodes.append(copy_grpn) diff --git a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py index 8e844247eeb..878d938bea3 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py @@ -39,7 +39,7 @@ class ValidateGizmo(pyblish.api.InstancePlugin): order = pyblish.api.ValidatorOrder optional = True families = ["gizmo"] - label = "Validate Gizmo (Group)" + label = "Validate Gizmo (group)" hosts = ["nuke"] actions = [OpenFailedGroupNode] From 49b7e58adcf0fa206e67acccfb811a9a1e068320 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 12 Dec 2022 11:40:15 +0100 Subject: [PATCH 110/115] nuke: fixing output node exctractor for Root exception --- openpype/hosts/nuke/plugins/publish/extract_ouput_node.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py b/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py index 6067e6cf6b2..e66cfd9018e 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py +++ b/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py @@ -21,11 +21,12 @@ def process(self, context): inst.data.get("transientData", {}).get("node") for inst in context if inst.data.get("transientData", {}).get("node") + if inst.data.get( + "transientData", {}).get("node").Class() != "Root" ] if active_node: - self.log.info(active_node) - active_node = active_node[0] + active_node = active_node.pop() self.log.info(active_node) active_node['selected'].setValue(True) From 9522607a242a2d8fc55e1c4e316474b0b9a09502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Fri, 16 Dec 2022 11:07:26 +0100 Subject: [PATCH 111/115] Update openpype/hosts/nuke/api/pipeline.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/hosts/nuke/api/pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 268d25b68ef..7fd22a0062f 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -78,7 +78,7 @@ class NukeHost( - HostBase, IWorkfileHost, ILoadHost, INewPublisher + HostBase, IWorkfileHost, ILoadHost, IPublishHost ): name = "nuke" From b06ea8c03352affbc64a6d70b28037e67d6e3f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Mon, 19 Dec 2022 13:33:02 +0100 Subject: [PATCH 112/115] Update openpype/hosts/nuke/api/pipeline.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/hosts/nuke/api/pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 7fd22a0062f..eb468d97c19 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -11,7 +11,7 @@ HostBase, IWorkfileHost, ILoadHost, - INewPublisher + IPublishHost ) from openpype.settings import get_current_project_settings from openpype.lib import register_event_callback, Logger From e1f040c9eaba834ae5585577c7c1b3779f0b7e3a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Dec 2022 15:05:34 +0100 Subject: [PATCH 113/115] nuke: validator exception legacy --- .../publish/help/validate_write_nodes.xml | 26 ++++++++++++++----- .../plugins/publish/validate_write_nodes.py | 21 +++++++++++++-- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/help/validate_write_nodes.xml b/openpype/hosts/nuke/plugins/publish/help/validate_write_nodes.xml index cdf85102bcc..1717622a456 100644 --- a/openpype/hosts/nuke/plugins/publish/help/validate_write_nodes.xml +++ b/openpype/hosts/nuke/plugins/publish/help/validate_write_nodes.xml @@ -3,16 +3,30 @@ Knobs values -## Invalid node's knobs values + ## Invalid node's knobs values -Following write node knobs needs to be repaired: + Following write node knobs needs to be repaired: -{xml_msg} + {xml_msg} -### How to repair? + ### How to repair? -1. Use Repair button. -2. Hit Reload button on the publisher. + 1. Use Repair button. + 2. Hit Reload button on the publisher. + + + + Legacy knob types + + ## Knobs are in obsolete configuration + + Settings needs to be fixed. + + ### How to repair? + + Contact your supervisor or fix it in project settings at + 'project_settings/nuke/imageio/nodes/requiredNodes' at knobs. + Each '__legacy__' type has to be defined accordingly to its type. \ No newline at end of file diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py index c0b81f64eaf..9027e54fc5b 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py @@ -77,14 +77,31 @@ def process(self, instance): if write_node is None: return - correct_data = get_write_node_template_attr(write_group_node) + check_knobs = get_write_node_template_attr(write_group_node) check = [] self.log.debug("__ write_node: {}".format( write_node )) + self.log.debug("__ check_knobs: {}".format( + check_knobs + )) - for key, value in correct_data.items(): + for knob_data in check_knobs: + if ( + "type" not in knob_data + or knob_data["type"] == "__legacy__" + ): + PublishXmlValidationError( + self, ( + "Please update data in settings 'project_settings" + "/nuke/imageio/nodes/requiredNodes'" + ), + key="legacy" + ) + + key = knob_data["name"] + value = knob_data["value"] node_value = write_node[key].value() # fix type differences From 47a31b44915a35cfdcd7a1efd8a4e2edf8256cb6 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 29 Dec 2022 15:46:44 +0100 Subject: [PATCH 114/115] nuke: write node validator check __legacy__ type --- openpype/hosts/nuke/api/lib.py | 21 +++++-------------- .../plugins/publish/validate_write_nodes.py | 18 +++++++++------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 2aa706d738a..c454086985d 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -2371,8 +2371,8 @@ def get_write_node_template_attr(node): ''' Gets all defined data from presets ''' - # TODO: remove this backward compatibility for old settings - # TASK: add identifiers to settings and rename settings key + + # TODO: add identifiers to settings and rename settings key plugin_names_mapping = { "create_write_image": "CreateWriteImage", "create_write_prerender": "CreateWritePrerender", @@ -2381,25 +2381,14 @@ def get_write_node_template_attr(node): # get avalon data from node node_data = get_node_data(node, INSTANCE_DATA_KNOB) identifier = node_data["creator_identifier"] - # get template data - nuke_imageio_writes = get_imageio_node_setting( + + # return template data + return get_imageio_node_setting( node_class="Write", plugin_name=plugin_names_mapping[identifier], subset=node_data["subset"] ) - # collecting solved data - return_data = OrderedDict() - - for knob in nuke_imageio_writes["knobs"]: - knob_type = knob["type"] - knob_value = knob["value"] - new_knob_value = convert_knob_value_to_correct_type( - knob_type, knob_value) - return_data[knob["name"]] = new_knob_value - - return return_data - def get_dependent_nodes(nodes): """Get all dependent nodes connected to the list of nodes. diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py index 9027e54fc5b..aeecea655f3 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py @@ -77,22 +77,26 @@ def process(self, instance): if write_node is None: return - check_knobs = get_write_node_template_attr(write_group_node) + correct_data = get_write_node_template_attr(write_group_node) check = [] self.log.debug("__ write_node: {}".format( write_node )) - self.log.debug("__ check_knobs: {}".format( - check_knobs + self.log.debug("__ correct_data: {}".format( + correct_data )) - for knob_data in check_knobs: + for knob_data in correct_data["knobs"]: + knob_type = knob_data["type"] + self.log.debug("__ knob_type: {}".format( + knob_type + )) + if ( - "type" not in knob_data - or knob_data["type"] == "__legacy__" + knob_type == "__legacy__" ): - PublishXmlValidationError( + raise PublishXmlValidationError( self, ( "Please update data in settings 'project_settings" "/nuke/imageio/nodes/requiredNodes'" From 3c1d340504f292cb96852bd56efea6f0bfe36e37 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 10 Jan 2023 17:29:03 +0100 Subject: [PATCH 115/115] Nuke: addressing comment --- openpype/hosts/nuke/api/plugin.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index c91c72afa05..abf9144c5b2 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -95,20 +95,14 @@ def add_info_knob(self, node): node.addKnob(info_knob) def check_existing_subset(self, subset_name, instance_data): - """Check if existing subset name versions already exists.""" - # Get all subsets of the current asset - project_name = legacy_io.active_project() - asset_doc = get_asset_by_name( - project_name, instance_data["asset"], fields=["_id"] - ) - subset_docs = get_subsets( - project_name, asset_ids=[asset_doc["_id"]], fields=["name"] - ) - existing_subset_names_low = { - subset_doc["name"].lower() - for subset_doc in subset_docs - } - return subset_name.lower() in existing_subset_names_low + """Check if existing subset name already exists.""" + exists = False + for node in nuke.allNodes(recurseGroups=True): + node_data = get_node_data(node, INSTANCE_DATA_KNOB) + if subset_name in node_data.get("subset"): + exists = True + + return exists def create_instance_node( self, @@ -161,7 +155,6 @@ def set_selected_nodes(self, pre_create_data): else: self.selected_nodes = [] - def create(self, subset_name, instance_data, pre_create_data): # make sure selected nodes are added @@ -174,7 +167,6 @@ def create(self, subset_name, instance_data, pre_create_data): "definition.").format(subset_name)) try: - instance_node = self.create_instance_node( subset_name, node_type=instance_data.pop("node_type", None)