From e4368e69b1088ea3345932b9109a20a5c0d83de7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 12 Jan 2022 12:25:50 +0100 Subject: [PATCH 1/4] moved nuke implementation from avalon --- openpype/hosts/nuke/api/__init__.py | 182 ++---- openpype/hosts/nuke/api/actions.py | 5 +- openpype/hosts/nuke/api/command.py | 135 ++++ openpype/hosts/nuke/api/lib.py | 616 ++++++++++++++++-- openpype/hosts/nuke/api/menu.py | 166 ----- openpype/hosts/nuke/api/pipeline.py | 421 ++++++++++++ openpype/hosts/nuke/api/plugin.py | 67 +- openpype/hosts/nuke/api/utils.py | 5 +- openpype/hosts/nuke/api/workio.py | 55 ++ .../nuke/plugins/create/create_backdrop.py | 15 +- .../nuke/plugins/create/create_camera.py | 12 +- .../hosts/nuke/plugins/create/create_gizmo.py | 26 +- .../hosts/nuke/plugins/create/create_model.py | 12 +- .../hosts/nuke/plugins/create/create_read.py | 13 +- .../plugins/create/create_write_prerender.py | 11 +- .../plugins/create/create_write_render.py | 11 +- .../nuke/plugins/create/create_write_still.py | 11 +- .../plugins/inventory/repair_old_loaders.py | 9 +- .../plugins/inventory/select_containers.py | 4 +- .../hosts/nuke/plugins/load/load_backdrop.py | 40 +- .../nuke/plugins/load/load_camera_abc.py | 18 +- openpype/hosts/nuke/plugins/load/load_clip.py | 13 +- .../hosts/nuke/plugins/load/load_effects.py | 17 +- .../nuke/plugins/load/load_effects_ip.py | 17 +- .../hosts/nuke/plugins/load/load_gizmo.py | 23 +- .../hosts/nuke/plugins/load/load_gizmo_ip.py | 31 +- .../hosts/nuke/plugins/load/load_image.py | 17 +- .../hosts/nuke/plugins/load/load_model.py | 15 +- .../nuke/plugins/load/load_script_precomp.py | 17 +- .../nuke/plugins/publish/extract_backdrop.py | 25 +- .../nuke/plugins/publish/extract_camera.py | 10 +- .../nuke/plugins/publish/extract_gizmo.py | 20 +- .../nuke/plugins/publish/extract_model.py | 13 +- .../plugins/publish/extract_ouput_node.py | 2 +- .../publish/extract_review_data_lut.py | 6 +- .../publish/extract_review_data_mov.py | 6 +- .../plugins/publish/extract_slate_frame.py | 4 +- .../nuke/plugins/publish/extract_thumbnail.py | 4 +- .../plugins/publish/precollect_instances.py | 9 +- .../plugins/publish/precollect_workfile.py | 13 +- .../nuke/plugins/publish/validate_backdrop.py | 6 +- .../nuke/plugins/publish/validate_gizmo.py | 6 +- .../publish/validate_instance_in_context.py | 13 +- .../plugins/publish/validate_write_legacy.py | 5 +- .../plugins/publish/validate_write_nodes.py | 15 +- openpype/hosts/nuke/startup/init.py | 2 + openpype/hosts/nuke/startup/menu.py | 15 +- 47 files changed, 1588 insertions(+), 570 deletions(-) create mode 100644 openpype/hosts/nuke/api/command.py delete mode 100644 openpype/hosts/nuke/api/menu.py create mode 100644 openpype/hosts/nuke/api/pipeline.py create mode 100644 openpype/hosts/nuke/api/workio.py diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index 1567189ed1e..d3b7f74d6df 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -1,130 +1,52 @@ -import os -import nuke - -import avalon.api -import pyblish.api -import openpype -from . import lib, menu - -log = openpype.api.Logger().get_logger(__name__) - -AVALON_CONFIG = os.getenv("AVALON_CONFIG", "pype") -HOST_DIR = os.path.dirname(os.path.abspath(openpype.hosts.nuke.__file__)) -PLUGINS_DIR = os.path.join(HOST_DIR, "plugins") -PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish") -LOAD_PATH = os.path.join(PLUGINS_DIR, "load") -CREATE_PATH = os.path.join(PLUGINS_DIR, "create") -INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory") - - -# registering pyblish gui regarding settings in presets -if os.getenv("PYBLISH_GUI", None): - pyblish.api.register_gui(os.getenv("PYBLISH_GUI", None)) - - -def reload_config(): - """Attempt to reload pipeline at run-time. - - CAUTION: This is primarily for development and debugging purposes. - - """ - - import importlib - - for module in ( - "{}.api".format(AVALON_CONFIG), - "{}.hosts.nuke.api.actions".format(AVALON_CONFIG), - "{}.hosts.nuke.api.menu".format(AVALON_CONFIG), - "{}.hosts.nuke.api.plugin".format(AVALON_CONFIG), - "{}.hosts.nuke.api.lib".format(AVALON_CONFIG), - ): - log.info("Reloading module: {}...".format(module)) - - module = importlib.import_module(module) - - try: - importlib.reload(module) - except AttributeError as e: - from importlib import reload - log.warning("Cannot reload module: {}".format(e)) - reload(module) - - -def install(): - ''' Installing all requarements for Nuke host - ''' - - # remove all registred callbacks form avalon.nuke - from avalon import pipeline - pipeline._registered_event_handlers.clear() - - log.info("Registering Nuke plug-ins..") - pyblish.api.register_plugin_path(PUBLISH_PATH) - avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH) - avalon.api.register_plugin_path(avalon.api.Creator, CREATE_PATH) - avalon.api.register_plugin_path(avalon.api.InventoryAction, INVENTORY_PATH) - - # Register Avalon event for workfiles loading. - avalon.api.on("workio.open_file", lib.check_inventory_versions) - avalon.api.on("taskChanged", menu.change_context_label) - - pyblish.api.register_callback( - "instanceToggled", on_pyblish_instance_toggled) - workfile_settings = lib.WorkfileSettings() - # Disable all families except for the ones we explicitly want to see - family_states = [ - "write", - "review", - "nukenodes", - "model", - "gizmo" - ] - - avalon.api.data["familiesStateDefault"] = False - avalon.api.data["familiesStateToggled"] = family_states - - # Set context settings. - nuke.addOnCreate(workfile_settings.set_context_settings, nodeClass="Root") - nuke.addOnCreate(workfile_settings.set_favorites, nodeClass="Root") - nuke.addOnCreate(lib.process_workfile_builder, nodeClass="Root") - nuke.addOnCreate(lib.launch_workfiles_app, nodeClass="Root") - menu.install() - - -def uninstall(): - '''Uninstalling host's integration - ''' - log.info("Deregistering Nuke plug-ins..") - pyblish.api.deregister_plugin_path(PUBLISH_PATH) - avalon.api.deregister_plugin_path(avalon.api.Loader, LOAD_PATH) - avalon.api.deregister_plugin_path(avalon.api.Creator, CREATE_PATH) - - pyblish.api.deregister_callback( - "instanceToggled", on_pyblish_instance_toggled) - - reload_config() - menu.uninstall() - - -def on_pyblish_instance_toggled(instance, old_value, new_value): - """Toggle node passthrough states on instance toggles.""" - - log.info("instance toggle: {}, old_value: {}, new_value:{} ".format( - instance, old_value, new_value)) - - from avalon.nuke import ( - viewer_update_and_undo_stop, - add_publish_knob - ) - - # Whether instances should be passthrough based on new value - - with viewer_update_and_undo_stop(): - n = instance[0] - try: - n["publish"].value() - except ValueError: - n = add_publish_knob(n) - log.info(" `Publish` knob was added to write node..") - - n["publish"].setValue(new_value) +from .workio import ( + file_extensions, + has_unsaved_changes, + save_file, + open_file, + current_file, + work_root, +) + +from .command import ( + reset_frame_range, + get_handles, + reset_resolution, + viewer_update_and_undo_stop +) + +from .plugin import OpenPypeCreator +from .pipeline import ( + install, + uninstall, + + ls, + + containerise, + parse_container, + update_container, +) + + +__all__ = ( + "file_extensions", + "has_unsaved_changes", + "save_file", + "open_file", + "current_file", + "work_root", + + "reset_frame_range", + "get_handles", + "reset_resolution", + "viewer_update_and_undo_stop", + + "OpenPypeCreator", + "install", + "uninstall", + + "ls", + + "containerise", + "parse_container", + "update_container", +) diff --git a/openpype/hosts/nuke/api/actions.py b/openpype/hosts/nuke/api/actions.py index fd18c787c4a..c4a6f0fb840 100644 --- a/openpype/hosts/nuke/api/actions.py +++ b/openpype/hosts/nuke/api/actions.py @@ -1,12 +1,11 @@ import pyblish.api -from avalon.nuke.lib import ( +from openpype.api import get_errored_instances_from_context +from .lib import ( reset_selection, select_nodes ) -from openpype.api import get_errored_instances_from_context - class SelectInvalidAction(pyblish.api.Action): """Select invalid nodes in Nuke when plug-in failed. diff --git a/openpype/hosts/nuke/api/command.py b/openpype/hosts/nuke/api/command.py new file mode 100644 index 00000000000..212d4757c68 --- /dev/null +++ b/openpype/hosts/nuke/api/command.py @@ -0,0 +1,135 @@ +import logging +import contextlib +import nuke + +from avalon import api, io + + +log = logging.getLogger(__name__) + + +def reset_frame_range(): + """ Set frame range to current asset + Also it will set a Viewer range with + displayed handles + """ + + fps = float(api.Session.get("AVALON_FPS", 25)) + + nuke.root()["fps"].setValue(fps) + name = api.Session["AVALON_ASSET"] + asset = io.find_one({"name": name, "type": "asset"}) + asset_data = asset["data"] + + handles = get_handles(asset) + + frame_start = int(asset_data.get( + "frameStart", + asset_data.get("edit_in"))) + + frame_end = int(asset_data.get( + "frameEnd", + asset_data.get("edit_out"))) + + if not all([frame_start, frame_end]): + missing = ", ".join(["frame_start", "frame_end"]) + msg = "'{}' are not set for asset '{}'!".format(missing, name) + log.warning(msg) + nuke.message(msg) + return + + frame_start -= handles + frame_end += handles + + nuke.root()["first_frame"].setValue(frame_start) + nuke.root()["last_frame"].setValue(frame_end) + + # setting active viewers + vv = nuke.activeViewer().node() + vv["frame_range_lock"].setValue(True) + vv["frame_range"].setValue("{0}-{1}".format( + int(asset_data["frameStart"]), + int(asset_data["frameEnd"])) + ) + + +def get_handles(asset): + """ Gets handles data + + Arguments: + asset (dict): avalon asset entity + + Returns: + handles (int) + """ + data = asset["data"] + if "handles" in data and data["handles"] is not None: + return int(data["handles"]) + + parent_asset = None + if "visualParent" in data: + vp = data["visualParent"] + if vp is not None: + parent_asset = io.find_one({"_id": io.ObjectId(vp)}) + + if parent_asset is None: + parent_asset = io.find_one({"_id": io.ObjectId(asset["parent"])}) + + if parent_asset is not None: + return get_handles(parent_asset) + else: + return 0 + + +def reset_resolution(): + """Set resolution to project resolution.""" + project = io.find_one({"type": "project"}) + p_data = project["data"] + + width = p_data.get("resolution_width", + p_data.get("resolutionWidth")) + height = p_data.get("resolution_height", + p_data.get("resolutionHeight")) + + if not all([width, height]): + missing = ", ".join(["width", "height"]) + msg = "No resolution information `{0}` found for '{1}'.".format( + missing, + project["name"]) + log.warning(msg) + nuke.message(msg) + return + + current_width = nuke.root()["format"].value().width() + current_height = nuke.root()["format"].value().height() + + if width != current_width or height != current_height: + + fmt = None + for f in nuke.formats(): + if f.width() == width and f.height() == height: + fmt = f.name() + + if not fmt: + nuke.addFormat( + "{0} {1} {2}".format(int(width), int(height), project["name"]) + ) + fmt = project["name"] + + nuke.root()["format"].setValue(fmt) + + +@contextlib.contextmanager +def viewer_update_and_undo_stop(): + """Lock viewer from updating and stop recording undo steps""" + try: + # stop active viewer to update any change + viewer = nuke.activeViewer() + if viewer: + viewer.stop() + else: + log.warning("No available active Viewer") + nuke.Undo.disable() + yield + finally: + nuke.Undo.enable() diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index e36a5aa5baf..0508de9f1dd 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -3,15 +3,15 @@ import sys import six import platform +import contextlib from collections import OrderedDict +import clique + +import nuke from avalon import api, io, lib -import avalon.nuke -from avalon.nuke import lib as anlib -from avalon.nuke import ( - save_file, open_file -) + from openpype.api import ( Logger, Anatomy, @@ -28,21 +28,476 @@ from openpype.settings import get_project_settings from openpype.modules import ModulesManager -import nuke +from .workio import ( + save_file, + open_file +) + +log = Logger.get_logger(__name__) + +_NODE_TAB_NAME = "{}".format(os.getenv("AVALON_LABEL") or "Avalon") +AVALON_LABEL = os.getenv("AVALON_LABEL") or "Avalon" +AVALON_TAB = "{}".format(AVALON_LABEL) +AVALON_DATA_GROUP = "{}DataGroup".format(AVALON_LABEL.capitalize()) +EXCLUDED_KNOB_TYPE_ON_READ = ( + 20, # Tab Knob + 26, # Text Knob (But for backward compatibility, still be read + # if value is not an empty string.) +) + + +class Context: + main_window = None + context_label = None + project_name = os.getenv("AVALON_PROJECT") + workfiles_launched = False + # Seems unused + _project_doc = None + + +class Knobby(object): + """For creating knob which it's type isn't mapped in `create_knobs` + + Args: + type (string): Nuke knob type name + value: Value to be set with `Knob.setValue`, put `None` if not required + flags (list, optional): Knob flags to be set with `Knob.setFlag` + *args: Args other than knob name for initializing knob class + + """ + + def __init__(self, type, value, flags=None, *args): + self.type = type + self.value = value + self.flags = flags or [] + self.args = args + + def create(self, name, nice=None): + knob_cls = getattr(nuke, self.type) + knob = knob_cls(name, nice, *self.args) + if self.value is not None: + knob.setValue(self.value) + for flag in self.flags: + knob.setFlag(flag) + return knob + + +def create_knobs(data, tab=None): + """Create knobs by data + + Depending on the type of each dict value and creates the correct Knob. + + Mapped types: + bool: nuke.Boolean_Knob + int: nuke.Int_Knob + float: nuke.Double_Knob + list: nuke.Enumeration_Knob + six.string_types: nuke.String_Knob + + dict: If it's a nested dict (all values are dict), will turn into + A tabs group. Or just a knobs group. + + Args: + data (dict): collection of attributes and their value + tab (string, optional): Knobs' tab name + + Returns: + list: A list of `nuke.Knob` objects + + """ + 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) + + # Turn key-value pairs into knobs + knobs = list() + + if tab: + knobs.append(nuke.Tab_Knob(tab)) + + for key, value in data.items(): + # Knob name + if isinstance(key, tuple): + name, nice = key + else: + name, nice = key, nice_naming(key) + + # Create knob by value type + if isinstance(value, Knobby): + knobby = value + knob = knobby.create(name, nice) + + elif isinstance(value, float): + knob = nuke.Double_Knob(name, nice) + knob.setValue(value) + + elif isinstance(value, bool): + knob = nuke.Boolean_Knob(name, nice) + knob.setValue(value) + knob.setFlag(nuke.STARTLINE) + + elif isinstance(value, int): + knob = nuke.Int_Knob(name, nice) + knob.setValue(value) + + elif isinstance(value, six.string_types): + knob = nuke.String_Knob(name, nice) + knob.setValue(value) + + elif isinstance(value, list): + knob = nuke.Enumeration_Knob(name, nice, value) + + elif isinstance(value, dict): + if all(isinstance(v, dict) for v in value.values()): + # Create a group of tabs + begain = nuke.BeginTabGroup_Knob() + end = nuke.EndTabGroup_Knob() + begain.setName(name) + end.setName(name + "_End") + knobs.append(begain) + for k, v in value.items(): + knobs += create_knobs(v, tab=k) + knobs.append(end) + else: + # Create a group of knobs + knobs.append(nuke.Tab_Knob( + name, nice, nuke.TABBEGINCLOSEDGROUP)) + knobs += create_knobs(value) + knobs.append( + nuke.Tab_Knob(name + "_End", nice, nuke.TABENDGROUP)) + continue + + else: + raise TypeError("Unsupported type: %r" % type(value)) + + knobs.append(knob) + + return knobs + + +def imprint(node, data, tab=None): + """Store attributes with value on node + + Parse user data into Node knobs. + Use `collections.OrderedDict` to ensure knob order. + + Args: + node(nuke.Node): node object from Nuke + data(dict): collection of attributes and their value -from .utils import set_context_favorites + Returns: + None + + Examples: + ``` + import nuke + from avalon.nuke import lib + + node = nuke.createNode("NoOp") + data = { + # Regular type of attributes + "myList": ["x", "y", "z"], + "myBool": True, + "myFloat": 0.1, + "myInt": 5, + + # Creating non-default imprint type of knob + "MyFilePath": lib.Knobby("File_Knob", "/file/path"), + "divider": lib.Knobby("Text_Knob", ""), + + # Manual nice knob naming + ("my_knob", "Nice Knob Name"): "some text", + + # dict type will be created as knob group + "KnobGroup": { + "knob1": 5, + "knob2": "hello", + "knob3": ["a", "b"], + }, + + # Nested dict will be created as tab group + "TabGroup": { + "tab1": {"count": 5}, + "tab2": {"isGood": True}, + "tab3": {"direction": ["Left", "Right"]}, + }, + } + lib.imprint(node, data, tab="Demo") + + ``` -log = Logger().get_logger(__name__) + """ + for knob in create_knobs(data, tab): + node.addKnob(knob) -opnl = sys.modules[__name__] -opnl._project = None -opnl.project_name = os.getenv("AVALON_PROJECT") -opnl.workfiles_launched = False -opnl._node_tab_name = "{}".format(os.getenv("AVALON_LABEL") or "Avalon") + +def add_publish_knob(node): + """Add Publish knob to node + + Arguments: + node (nuke.Node): nuke node to be processed + + Returns: + node (nuke.Node): processed nuke node + + """ + if "publish" not in node.knobs(): + body = OrderedDict() + body[("divd", "Publishing")] = Knobby("Text_Knob", '') + body["publish"] = True + imprint(node, body) + return node + + +def set_avalon_knob_data(node, data=None, prefix="avalon:"): + """ Sets data into nodes's avalon knob + + Arguments: + node (nuke.Node): Nuke node to imprint with data, + data (dict, optional): Data to be imprinted into AvalonTab + prefix (str, optional): filtering prefix + + Returns: + node (nuke.Node) + + Examples: + data = { + 'asset': 'sq020sh0280', + 'family': 'render', + 'subset': 'subsetMain' + } + """ + data = data or dict() + create = OrderedDict() + + tab_name = AVALON_TAB + editable = ["asset", "subset", "name", "namespace"] + + existed_knobs = node.knobs() + + for key, value in data.items(): + knob_name = prefix + key + gui_name = key + + if knob_name in existed_knobs: + # Set value + try: + node[knob_name].setValue(value) + except TypeError: + node[knob_name].setValue(str(value)) + else: + # New knob + name = (knob_name, gui_name) # Hide prefix on GUI + if key in editable: + create[name] = value + else: + create[name] = Knobby("String_Knob", + str(value), + flags=[nuke.READ_ONLY]) + if tab_name in existed_knobs: + tab_name = None + else: + tab = OrderedDict() + warn = Knobby("Text_Knob", "Warning! Do not change following data!") + divd = Knobby("Text_Knob", "") + head = [ + (("warn", ""), warn), + (("divd", ""), divd), + ] + tab[AVALON_DATA_GROUP] = OrderedDict(head + list(create.items())) + create = tab + + imprint(node, create, tab=tab_name) + return node + + +def get_avalon_knob_data(node, prefix="avalon:"): + """ Gets a data from nodes's avalon knob + + Arguments: + node (obj): Nuke node to search for data, + prefix (str, optional): filtering prefix + + Returns: + data (dict) + """ + + # check if lists + if not isinstance(prefix, list): + prefix = list([prefix]) + + data = dict() + + # loop prefix + for p in prefix: + # check if the node is avalon tracked + if AVALON_TAB not in node.knobs(): + continue + try: + # check if data available on the node + test = node[AVALON_DATA_GROUP].value() + log.debug("Only testing if data avalable: `{}`".format(test)) + 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) + + # get data from filtered knobs + data.update({k.replace(p, ''): node[k].value() + for k in node.knobs().keys() + if p in k}) + + return data + + +def fix_data_for_node_create(data): + """Fixing data to be used for nuke knobs + """ + for k, v in data.items(): + if isinstance(v, six.text_type): + data[k] = str(v) + if str(v).startswith("0x"): + data[k] = int(v, 16) + return data + + +def add_write_node(name, **kwarg): + """Adding nuke write node + + Arguments: + name (str): nuke node name + kwarg (attrs): data for nuke knobs + + Returns: + node (obj): nuke write node + """ + frame_range = kwarg.get("frame_range", None) + + w = nuke.createNode( + "Write", + "name {}".format(name)) + + w["file"].setValue(kwarg["file"]) + + for k, v in kwarg.items(): + if "frame_range" in k: + continue + log.info([k, v]) + try: + w[k].setValue(v) + except KeyError as e: + log.debug(e) + continue + + if frame_range: + w["use_limit"].setValue(True) + w["first"].setValue(frame_range[0]) + w["last"].setValue(frame_range[1]) + + return w + + +def read(node): + """Return user-defined knobs from given `node` + + Args: + node (nuke.Node): Nuke node object + + Returns: + list: A list of nuke.Knob object + + """ + def compat_prefixed(knob_name): + if knob_name.startswith("avalon:"): + return knob_name[len("avalon:"):] + elif knob_name.startswith("ak:"): + return knob_name[len("ak:"):] + else: + return knob_name + + data = dict() + + pattern = ("(?<=addUserKnob {)" + "([0-9]*) (\\S*)" # Matching knob type and knob name + "(?=[ |}])") + tcl_script = node.writeKnobs(nuke.WRITE_USER_KNOB_DEFS) + result = re.search(pattern, tcl_script) + + if result: + first_user_knob = result.group(2) + # Collect user knobs from the end of the knob list + for knob in reversed(node.allKnobs()): + knob_name = knob.name() + if not knob_name: + # Ignore unnamed knob + continue + + knob_type = nuke.knob(knob.fullyQualifiedName(), type=True) + value = knob.value() + + if ( + knob_type not in EXCLUDED_KNOB_TYPE_ON_READ or + # For compating read-only string data that imprinted + # by `nuke.Text_Knob`. + (knob_type == 26 and value) + ): + key = compat_prefixed(knob_name) + data[key] = value + + if knob_name == first_user_knob: + break + + return data + + +def get_node_path(path, padding=4): + """Get filename for the Nuke write with padded number as '#' + + Arguments: + path (str): The path to render to. + + Returns: + tuple: head, padding, tail (extension) + + Examples: + >>> get_frame_path("test.exr") + ('test', 4, '.exr') + + >>> get_frame_path("filename.#####.tif") + ('filename.', 5, '.tif') + + >>> get_frame_path("foobar##.tif") + ('foobar', 2, '.tif') + + >>> get_frame_path("foobar_%08d.tif") + ('foobar_', 8, '.tif') + """ + filename, ext = os.path.splitext(path) + + # Find a final number group + if '%' in filename: + match = re.match('.*?(%[0-9]+d)$', filename) + if match: + padding = int(match.group(1).replace('%', '').replace('d', '')) + # remove number from end since fusion + # will swap it with the frame number + filename = filename.replace(match.group(1), '') + elif '#' in filename: + match = re.match('.*?(#+)$', filename) + + if match: + padding = len(match.group(1)) + # remove number from end since fusion + # will swap it with the frame number + filename = filename.replace(match.group(1), '') + + return filename, padding, ext def get_nuke_imageio_settings(): - return get_anatomy_settings(opnl.project_name)["imageio"]["nuke"] + return get_anatomy_settings(Context.project_name)["imageio"]["nuke"] def get_created_node_imageio_setting(**kwarg): @@ -103,14 +558,15 @@ def check_inventory_versions(): and check if the node is having actual version. If not then it will color it to red. """ + from .pipeline import parse_container + # get all Loader nodes by avalon attribute metadata for each in nuke.allNodes(): - container = avalon.nuke.parse_container(each) + container = parse_container(each) if container: node = nuke.toNode(container["objectName"]) - avalon_knob_data = avalon.nuke.read( - node) + avalon_knob_data = read(node) # get representation from io representation = io.find_one({ @@ -163,11 +619,10 @@ def writes_version_sync(): for each in nuke.allNodes(filter="Write"): # check if the node is avalon tracked - if opnl._node_tab_name not in each.knobs(): + if _NODE_TAB_NAME not in each.knobs(): continue - avalon_knob_data = avalon.nuke.read( - each) + avalon_knob_data = read(each) try: if avalon_knob_data['families'] not in ["render"]: @@ -209,14 +664,14 @@ def check_subsetname_exists(nodes, subset_name): bool: True of False """ return next((True for n in nodes - if subset_name in avalon.nuke.read(n).get("subset", "")), + if subset_name in read(n).get("subset", "")), False) def get_render_path(node): ''' Generate Render path from presets regarding avalon knob data ''' - data = {'avalon': avalon.nuke.read(node)} + data = {'avalon': read(node)} data_preset = { "nodeclass": data['avalon']['family'], "families": [data['avalon']['families']], @@ -385,7 +840,7 @@ def create_write_node(name, data, input=None, prenodes=None, for knob in imageio_writes["knobs"]: _data.update({knob["name"]: knob["value"]}) - _data = anlib.fix_data_for_node_create(_data) + _data = fix_data_for_node_create(_data) log.debug("_data: `{}`".format(_data)) @@ -466,7 +921,7 @@ def create_write_node(name, data, input=None, prenodes=None, prev_node = now_node # creating write node - write_node = now_node = anlib.add_write_node( + write_node = now_node = add_write_node( "inside_{}".format(name), **_data ) @@ -484,8 +939,8 @@ def create_write_node(name, data, input=None, prenodes=None, now_node.setInput(0, prev_node) # imprinting group node - anlib.set_avalon_knob_data(GN, data["avalon"]) - anlib.add_publish_knob(GN) + set_avalon_knob_data(GN, data["avalon"]) + add_publish_knob(GN) add_rendering_knobs(GN, farm) if review: @@ -537,7 +992,7 @@ def create_write_node(name, data, input=None, prenodes=None, add_deadline_tab(GN) # open the our Tab as default - GN[opnl._node_tab_name].setFlag(0) + GN[_NODE_TAB_NAME].setFlag(0) # set tile color tile_color = _data.get("tile_color", "0xff0000ff") @@ -663,7 +1118,7 @@ def __init__(self, root_node=None, nodes=None, **kwargs): - opnl._project = kwargs.get( + Context._project_doc = kwargs.get( "project") or io.find_one({"type": "project"}) self._asset = kwargs.get("asset_name") or api.Session["AVALON_ASSET"] self._asset_entity = get_asset(self._asset) @@ -804,8 +1259,6 @@ def set_writes_colorspace(self): ''' Adds correct colorspace to write node dict ''' - from avalon.nuke import read - for node in nuke.allNodes(filter="Group"): # get data from avalon knob @@ -1005,7 +1458,7 @@ def reset_frame_range_handles(self): node['frame_range_lock'].setValue(True) # adding handle_start/end to root avalon knob - if not anlib.set_avalon_knob_data(self._root_node, { + if not set_avalon_knob_data(self._root_node, { "handleStart": int(handle_start), "handleEnd": int(handle_end) }): @@ -1089,6 +1542,8 @@ def set_context_settings(self): self.set_colorspace() def set_favorites(self): + from .utils import set_context_favorites + work_dir = os.getenv("AVALON_WORKDIR") asset = os.getenv("AVALON_ASSET") favorite_items = OrderedDict() @@ -1096,9 +1551,9 @@ def set_favorites(self): # project # get project's root and split to parts projects_root = os.path.normpath(work_dir.split( - opnl.project_name)[0]) + Context.project_name)[0]) # add project name - project_dir = os.path.join(projects_root, opnl.project_name) + "/" + project_dir = os.path.join(projects_root, Context.project_name) + "/" # add to favorites favorite_items.update({"Project dir": project_dir.replace("\\", "/")}) @@ -1145,8 +1600,7 @@ def get_write_node_template_attr(node): ''' # get avalon data from node data = dict() - data['avalon'] = avalon.nuke.read( - node) + data['avalon'] = read(node) data_preset = { "nodeclass": data['avalon']['family'], "families": [data['avalon']['families']], @@ -1167,7 +1621,7 @@ def get_write_node_template_attr(node): if k not in ["_id", "_previous"]} # fix badly encoded data - return anlib.fix_data_for_node_create(correct_data) + return fix_data_for_node_create(correct_data) def get_dependent_nodes(nodes): @@ -1274,13 +1728,53 @@ def find_free_space_to_paste_nodes( return xpos, ypos +@contextlib.contextmanager +def maintained_selection(): + """Maintain selection during context + + Example: + >>> with maintained_selection(): + ... node['selected'].setValue(True) + >>> print(node['selected'].value()) + False + """ + previous_selection = nuke.selectedNodes() + try: + yield + finally: + # unselect all selection in case there is some + current_seletion = nuke.selectedNodes() + [n['selected'].setValue(False) for n in current_seletion] + # and select all previously selected nodes + if previous_selection: + [n['selected'].setValue(True) for n in previous_selection] + + +def reset_selection(): + """Deselect all selected nodes""" + for node in nuke.selectedNodes(): + node["selected"].setValue(False) + + +def select_nodes(nodes): + """Selects all inputed nodes + + Arguments: + nodes (list): nuke nodes to be selected + """ + assert isinstance(nodes, (list, tuple)), "nodes has to be list or tuple" + + for node in nodes: + node["selected"].setValue(True) + + def launch_workfiles_app(): '''Function letting start workfiles after start of host ''' from openpype.lib import ( env_value_to_bool ) - from avalon.nuke.pipeline import get_main_window + from .pipeline import get_main_window # get all imortant settings open_at_start = env_value_to_bool( @@ -1291,8 +1785,8 @@ def launch_workfiles_app(): if not open_at_start: return - if not opnl.workfiles_launched: - opnl.workfiles_launched = True + if not Context.workfiles_launched: + Context.workfiles_launched = True main_window = get_main_window() host_tools.show_workfiles(parent=main_window) @@ -1378,7 +1872,7 @@ def recreate_instance(origin_node, avalon_data=None): knobs_wl = ["render", "publish", "review", "ypos", "use_limit", "first", "last"] # get data from avalon knobs - data = anlib.get_avalon_knob_data( + data = get_avalon_knob_data( origin_node) # add input data to avalon data @@ -1494,3 +1988,45 @@ def dirmap_file_name_filter(file_name): if os.path.exists(dirmap_processor.file_name): return dirmap_processor.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 diff --git a/openpype/hosts/nuke/api/menu.py b/openpype/hosts/nuke/api/menu.py deleted file mode 100644 index 86293edb990..00000000000 --- a/openpype/hosts/nuke/api/menu.py +++ /dev/null @@ -1,166 +0,0 @@ -import os -import nuke -from avalon.nuke.pipeline import get_main_window - -from .lib import WorkfileSettings -from openpype.api import Logger, BuildWorkfile, get_current_project_settings -from openpype.tools.utils import host_tools - - -log = Logger().get_logger(__name__) - -menu_label = os.environ["AVALON_LABEL"] -context_label = None - - -def change_context_label(*args): - global context_label - menubar = nuke.menu("Nuke") - menu = menubar.findItem(menu_label) - - label = "{0}, {1}".format( - os.environ["AVALON_ASSET"], os.environ["AVALON_TASK"] - ) - - rm_item = [ - (i, item) for i, item in enumerate(menu.items()) - if context_label in item.name() - ][0] - - menu.removeItem(rm_item[1].name()) - - context_action = menu.addCommand( - label, - index=(rm_item[0]) - ) - context_action.setEnabled(False) - - log.info("Task label changed from `{}` to `{}`".format( - context_label, label)) - - context_label = label - - - -def install(): - from openpype.hosts.nuke.api import reload_config - - global context_label - - # uninstall original avalon menu - uninstall() - - main_window = get_main_window() - menubar = nuke.menu("Nuke") - menu = menubar.addMenu(menu_label) - - label = "{0}, {1}".format( - os.environ["AVALON_ASSET"], os.environ["AVALON_TASK"] - ) - context_label = label - context_action = menu.addCommand(label) - context_action.setEnabled(False) - - menu.addSeparator() - menu.addCommand( - "Work Files...", - lambda: host_tools.show_workfiles(parent=main_window) - ) - - menu.addSeparator() - menu.addCommand( - "Create...", - lambda: host_tools.show_creator(parent=main_window) - ) - menu.addCommand( - "Load...", - lambda: host_tools.show_loader( - parent=main_window, - use_context=True - ) - ) - menu.addCommand( - "Publish...", - lambda: host_tools.show_publish(parent=main_window) - ) - menu.addCommand( - "Manage...", - lambda: host_tools.show_scene_inventory(parent=main_window) - ) - - menu.addSeparator() - menu.addCommand( - "Set Resolution", - lambda: WorkfileSettings().reset_resolution() - ) - menu.addCommand( - "Set Frame Range", - lambda: WorkfileSettings().reset_frame_range_handles() - ) - menu.addCommand( - "Set Colorspace", - lambda: WorkfileSettings().set_colorspace() - ) - menu.addCommand( - "Apply All Settings", - lambda: WorkfileSettings().set_context_settings() - ) - - menu.addSeparator() - menu.addCommand( - "Build Workfile", - lambda: BuildWorkfile().process() - ) - - menu.addSeparator() - menu.addCommand( - "Experimental tools...", - lambda: host_tools.show_experimental_tools_dialog(parent=main_window) - ) - - # add reload pipeline only in debug mode - if bool(os.getenv("NUKE_DEBUG")): - menu.addSeparator() - menu.addCommand("Reload Pipeline", reload_config) - - # adding shortcuts - add_shortcuts_from_presets() - - -def uninstall(): - - 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 add_shortcuts_from_presets(): - menubar = nuke.menu("Nuke") - nuke_presets = get_current_project_settings()["nuke"]["general"] - - if nuke_presets.get("menu"): - menu_label_mapping = { - "manage": "Manage...", - "create": "Create...", - "load": "Load...", - "build_workfile": "Build Workfile", - "publish": "Publish..." - } - - for command_name, shortcut_str in nuke_presets.get("menu").items(): - log.info("menu_name `{}` | menu_label `{}`".format( - command_name, menu_label - )) - log.info("Adding Shortcut `{}` to `{}`".format( - shortcut_str, command_name - )) - try: - menu = menubar.findItem(menu_label) - item_label = menu_label_mapping[command_name] - menuitem = menu.findItem(item_label) - menuitem.setShortcut(shortcut_str) - except AttributeError as e: - log.error(e) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py new file mode 100644 index 00000000000..c47187666bc --- /dev/null +++ b/openpype/hosts/nuke/api/pipeline.py @@ -0,0 +1,421 @@ +import os +import importlib +from collections import OrderedDict + +import nuke + +import pyblish.api +import avalon.api +from avalon import pipeline + +import openpype +from openpype.api import ( + Logger, + BuildWorkfile, + get_current_project_settings +) +from openpype.tools.utils import host_tools + +from .command import viewer_update_and_undo_stop +from .lib import ( + add_publish_knob, + WorkfileSettings, + process_workfile_builder, + launch_workfiles_app, + check_inventory_versions, + set_avalon_knob_data, + read, + Context +) + +log = Logger.get_logger(__name__) + +AVALON_CONFIG = os.getenv("AVALON_CONFIG", "pype") +HOST_DIR = os.path.dirname(os.path.abspath(openpype.hosts.nuke.__file__)) +PLUGINS_DIR = os.path.join(HOST_DIR, "plugins") +PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish") +LOAD_PATH = os.path.join(PLUGINS_DIR, "load") +CREATE_PATH = os.path.join(PLUGINS_DIR, "create") +INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory") + +MENU_LABEL = os.environ["AVALON_LABEL"] + + +# registering pyblish gui regarding settings in presets +if os.getenv("PYBLISH_GUI", None): + pyblish.api.register_gui(os.getenv("PYBLISH_GUI", None)) + + +def get_main_window(): + """Acquire Nuke's main window""" + if Context.main_window is None: + from Qt import QtWidgets + + top_widgets = QtWidgets.QApplication.topLevelWidgets() + name = "Foundry::UI::DockMainWindow" + for widget in top_widgets: + if ( + widget.inherits("QMainWindow") + and widget.metaObject().className() == name + ): + Context.main_window = widget + break + return Context.main_window + + +def reload_config(): + """Attempt to reload pipeline at run-time. + + CAUTION: This is primarily for development and debugging purposes. + + """ + + for module in ( + "{}.api".format(AVALON_CONFIG), + "{}.hosts.nuke.api.actions".format(AVALON_CONFIG), + "{}.hosts.nuke.api.menu".format(AVALON_CONFIG), + "{}.hosts.nuke.api.plugin".format(AVALON_CONFIG), + "{}.hosts.nuke.api.lib".format(AVALON_CONFIG), + ): + log.info("Reloading module: {}...".format(module)) + + module = importlib.import_module(module) + + try: + importlib.reload(module) + except AttributeError as e: + from importlib import reload + log.warning("Cannot reload module: {}".format(e)) + 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) + avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH) + avalon.api.register_plugin_path(avalon.api.Creator, CREATE_PATH) + avalon.api.register_plugin_path(avalon.api.InventoryAction, INVENTORY_PATH) + + # Register Avalon event for workfiles loading. + avalon.api.on("workio.open_file", check_inventory_versions) + avalon.api.on("taskChanged", change_context_label) + + pyblish.api.register_callback( + "instanceToggled", on_pyblish_instance_toggled) + workfile_settings = WorkfileSettings() + # Disable all families except for the ones we explicitly want to see + family_states = [ + "write", + "review", + "nukenodes", + "model", + "gizmo" + ] + + avalon.api.data["familiesStateDefault"] = False + avalon.api.data["familiesStateToggled"] = family_states + + # 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") + nuke.addOnCreate(launch_workfiles_app, nodeClass="Root") + _install_menu() + + +def uninstall(): + '''Uninstalling host's integration + ''' + log.info("Deregistering Nuke plug-ins..") + pyblish.deregister_host("nuke") + pyblish.api.deregister_plugin_path(PUBLISH_PATH) + avalon.api.deregister_plugin_path(avalon.api.Loader, LOAD_PATH) + avalon.api.deregister_plugin_path(avalon.api.Creator, CREATE_PATH) + + pyblish.api.deregister_callback( + "instanceToggled", on_pyblish_instance_toggled) + + reload_config() + _uninstall_menu() + + +def _install_menu(): + # uninstall original avalon menu + main_window = get_main_window() + menubar = nuke.menu("Nuke") + menu = menubar.addMenu(MENU_LABEL) + + label = "{0}, {1}".format( + os.environ["AVALON_ASSET"], os.environ["AVALON_TASK"] + ) + Context.context_label = label + context_action = menu.addCommand(label) + context_action.setEnabled(False) + + menu.addSeparator() + menu.addCommand( + "Work Files...", + lambda: host_tools.show_workfiles(parent=main_window) + ) + + menu.addSeparator() + menu.addCommand( + "Create...", + lambda: host_tools.show_creator(parent=main_window) + ) + menu.addCommand( + "Load...", + lambda: host_tools.show_loader( + parent=main_window, + use_context=True + ) + ) + menu.addCommand( + "Publish...", + lambda: host_tools.show_publish(parent=main_window) + ) + menu.addCommand( + "Manage...", + lambda: host_tools.show_scene_inventory(parent=main_window) + ) + + menu.addSeparator() + menu.addCommand( + "Set Resolution", + lambda: WorkfileSettings().reset_resolution() + ) + menu.addCommand( + "Set Frame Range", + lambda: WorkfileSettings().reset_frame_range_handles() + ) + menu.addCommand( + "Set Colorspace", + lambda: WorkfileSettings().set_colorspace() + ) + menu.addCommand( + "Apply All Settings", + lambda: WorkfileSettings().set_context_settings() + ) + + menu.addSeparator() + menu.addCommand( + "Build Workfile", + lambda: BuildWorkfile().process() + ) + + menu.addSeparator() + menu.addCommand( + "Experimental tools...", + lambda: host_tools.show_experimental_tools_dialog(parent=main_window) + ) + + # add reload pipeline only in debug mode + if bool(os.getenv("NUKE_DEBUG")): + menu.addSeparator() + menu.addCommand("Reload Pipeline", reload_config) + + # adding shortcuts + 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(*args): + menubar = nuke.menu("Nuke") + menu = menubar.findItem(MENU_LABEL) + + label = "{0}, {1}".format( + os.environ["AVALON_ASSET"], os.environ["AVALON_TASK"] + ) + + rm_item = [ + (i, item) for i, item in enumerate(menu.items()) + if Context.context_label in item.name() + ][0] + + menu.removeItem(rm_item[1].name()) + + context_action = menu.addCommand( + label, + index=(rm_item[0]) + ) + context_action.setEnabled(False) + + log.info("Task label changed from `{}` to `{}`".format( + Context.context_label, label)) + + +def add_shortcuts_from_presets(): + menubar = nuke.menu("Nuke") + nuke_presets = get_current_project_settings()["nuke"]["general"] + + if nuke_presets.get("menu"): + menu_label_mapping = { + "manage": "Manage...", + "create": "Create...", + "load": "Load...", + "build_workfile": "Build Workfile", + "publish": "Publish..." + } + + for command_name, shortcut_str in nuke_presets.get("menu").items(): + log.info("menu_name `{}` | menu_label `{}`".format( + command_name, MENU_LABEL + )) + log.info("Adding Shortcut `{}` to `{}`".format( + shortcut_str, command_name + )) + try: + menu = menubar.findItem(MENU_LABEL) + item_label = menu_label_mapping[command_name] + menuitem = menu.findItem(item_label) + menuitem.setShortcut(shortcut_str) + except AttributeError as e: + log.error(e) + + +def on_pyblish_instance_toggled(instance, old_value, new_value): + """Toggle node passthrough states on instance toggles.""" + + log.info("instance toggle: {}, old_value: {}, new_value:{} ".format( + instance, old_value, new_value)) + + # Whether instances should be passthrough based on new value + + with viewer_update_and_undo_stop(): + n = instance[0] + try: + n["publish"].value() + except ValueError: + n = add_publish_knob(n) + log.info(" `Publish` knob was added to write node..") + + n["publish"].setValue(new_value) + + +def containerise(node, + name, + namespace, + context, + loader=None, + data=None): + """Bundle `node` into an assembly and imprint it with metadata + + Containerisation enables a tracking of version, author and origin + for loaded assets. + + Arguments: + node (nuke.Node): Nuke's node object to imprint as container + name (str): Name of resulting assembly + namespace (str): Namespace under which to host container + context (dict): Asset information + loader (str, optional): Name of node used to produce this container. + + Returns: + node (nuke.Node): containerised nuke's node object + + """ + data = OrderedDict( + [ + ("schema", "openpype:container-2.0"), + ("id", pipeline.AVALON_CONTAINER_ID), + ("name", name), + ("namespace", namespace), + ("loader", str(loader)), + ("representation", context["representation"]["_id"]), + ], + + **data or dict() + ) + + set_avalon_knob_data(node, data) + + return node + + +def parse_container(node): + """Returns containerised data of a node + + Reads the imprinted data from `containerise`. + + Arguments: + node (nuke.Node): Nuke's node object to read imprinted data + + Returns: + dict: The container schema data for this container node. + + """ + data = read(node) + + # (TODO) Remove key validation when `ls` has re-implemented. + # + # If not all required data return the empty container + required = ["schema", "id", "name", + "namespace", "loader", "representation"] + if not all(key in data for key in required): + return + + # Store the node's name + data["objectName"] = node["name"].value() + + return data + + +def update_container(node, keys=None): + """Returns node with updateted containder data + + Arguments: + node (nuke.Node): The node in Nuke to imprint as container, + keys (dict, optional): data which should be updated + + Returns: + node (nuke.Node): nuke node with updated container data + + Raises: + TypeError on given an invalid container node + + """ + keys = keys or dict() + + container = parse_container(node) + if not container: + raise TypeError("Not a valid container node.") + + container.update(keys) + node = set_avalon_knob_data(node, container) + + return node + + +def ls(): + """List available containers. + + This function is used by the Container Manager in Nuke. You'll + need to implement a for-loop that then *yields* one Container at + a time. + + See the `container.json` schema for details on how it should look, + and the Maya equivalent, which is in `avalon.maya.pipeline` + """ + all_nodes = nuke.allNodes(recurseGroups=False) + + # TODO: add readgeo, readcamera, readimage + 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 diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 82299dd354b..66b42f7bb1e 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -2,23 +2,30 @@ import random import string -import avalon.nuke -from avalon.nuke import lib as anlib -from avalon import api +import nuke + +import avalon.api from openpype.api import ( get_current_project_settings, PypeCreatorMixin ) -from .lib import check_subsetname_exists -import nuke +from .lib import ( + Knobby, + check_subsetname_exists, + reset_selection, + maintained_selection, + set_avalon_knob_data, + add_publish_knob +) -class PypeCreator(PypeCreatorMixin, avalon.nuke.pipeline.Creator): - """Pype Nuke Creator class wrapper - """ +class OpenPypeCreator(PypeCreatorMixin, avalon.api.Creator): + """Pype Nuke Creator class wrapper""" + node_color = "0xdfea5dff" + def __init__(self, *args, **kwargs): - super(PypeCreator, self).__init__(*args, **kwargs) + super(OpenPypeCreator, self).__init__(*args, **kwargs) self.presets = get_current_project_settings()["nuke"]["create"].get( self.__class__.__name__, {} ) @@ -31,6 +38,38 @@ def __init__(self, *args, **kwargs): raise NameError("`{0}: {1}".format(__name__, msg)) return + def process(self): + from nukescripts import autoBackdrop + + instance = None + + if (self.options or {}).get("useSelection"): + + nodes = nuke.selectedNodes() + if not nodes: + nuke.message("Please select nodes that you " + "wish to add to a container") + return + + elif len(nodes) == 1: + # only one node is selected + instance = nodes[0] + + if not instance: + # Not using selection or multiple nodes selected + bckd_node = autoBackdrop() + bckd_node["tile_color"].setValue(int(self.node_color, 16)) + bckd_node["note_font_size"].setValue(24) + bckd_node["label"].setValue("[{}]".format(self.name)) + + instance = bckd_node + + # add avalon knobs + set_avalon_knob_data(instance, self.data) + add_publish_knob(instance) + + return instance + def get_review_presets_config(): settings = get_current_project_settings() @@ -48,7 +87,7 @@ def get_review_presets_config(): return [str(name) for name, _prop in outputs.items()] -class NukeLoader(api.Loader): +class NukeLoader(avalon.api.Loader): container_id_knob = "containerId" container_id = None @@ -74,7 +113,7 @@ def set_as_member(self, node): node[self.container_id_knob].setValue(source_id) else: HIDEN_FLAG = 0x00040000 - _knob = anlib.Knobby( + _knob = Knobby( "String_Knob", self.container_id, flags=[ @@ -183,7 +222,7 @@ def get_view_input_process_node(self): Returns: nuke.Node: copy node of Input Process node """ - anlib.reset_selection() + reset_selection() ipn_orig = None for v in nuke.allNodes(filter="Viewer"): ip = v["input_process"].getValue() @@ -196,7 +235,7 @@ def get_view_input_process_node(self): # copy selected to clipboard nuke.nodeCopy("%clipboard%") # reset selection - anlib.reset_selection() + reset_selection() # paste node and selection is on it only nuke.nodePaste("%clipboard%") # assign to variable @@ -396,7 +435,7 @@ def render(self, render_node_name): def save_file(self): import shutil - with anlib.maintained_selection(): + with maintained_selection(): self.log.info("Saving nodes as file... ") # create nk path path = os.path.splitext(self.path)[0] + ".nk" diff --git a/openpype/hosts/nuke/api/utils.py b/openpype/hosts/nuke/api/utils.py index e43c11a380a..f8f248357b3 100644 --- a/openpype/hosts/nuke/api/utils.py +++ b/openpype/hosts/nuke/api/utils.py @@ -1,7 +1,8 @@ import os import nuke -from avalon.nuke import lib as anlib + from openpype.api import resources +from .lib import maintained_selection def set_context_favorites(favorites=None): @@ -55,7 +56,7 @@ def bake_gizmos_recursively(in_group=nuke.Root()): is_group (nuke.Node)[optonal]: group node or all nodes """ # preserve selection after all is done - with anlib.maintained_selection(): + with maintained_selection(): # jump to the group with in_group: for node in nuke.allNodes(): diff --git a/openpype/hosts/nuke/api/workio.py b/openpype/hosts/nuke/api/workio.py new file mode 100644 index 00000000000..dbc24fdc9b0 --- /dev/null +++ b/openpype/hosts/nuke/api/workio.py @@ -0,0 +1,55 @@ +"""Host API required Work Files tool""" +import os +import nuke +import avalon.api + + +def file_extensions(): + return avalon.api.HOST_WORKFILE_EXTENSIONS["nuke"] + + +def has_unsaved_changes(): + return nuke.root().modified() + + +def save_file(filepath): + path = filepath.replace("\\", "/") + nuke.scriptSaveAs(path) + nuke.Root()["name"].setValue(path) + nuke.Root()["project_directory"].setValue(os.path.dirname(path)) + nuke.Root().setModified(False) + + +def open_file(filepath): + filepath = filepath.replace("\\", "/") + + # To remain in the same window, we have to clear the script and read + # in the contents of the workfile. + nuke.scriptClear() + nuke.scriptReadFile(filepath) + nuke.Root()["name"].setValue(filepath) + nuke.Root()["project_directory"].setValue(os.path.dirname(filepath)) + nuke.Root().setModified(False) + return True + + +def current_file(): + current_file = nuke.root().name() + + # Unsaved current file + if current_file == 'Root': + return None + + return os.path.normpath(current_file).replace("\\", "/") + + +def work_root(session): + + work_dir = session["AVALON_WORKDIR"] + scene_dir = session.get("AVALON_SCENEDIR") + if scene_dir: + path = os.path.join(work_dir, scene_dir) + else: + path = work_dir + + return os.path.normpath(path).replace("\\", "/") diff --git a/openpype/hosts/nuke/plugins/create/create_backdrop.py b/openpype/hosts/nuke/plugins/create/create_backdrop.py index cda2629587e..0c11b3f2740 100644 --- a/openpype/hosts/nuke/plugins/create/create_backdrop.py +++ b/openpype/hosts/nuke/plugins/create/create_backdrop.py @@ -1,9 +1,12 @@ -from avalon.nuke import lib as anlib -from openpype.hosts.nuke.api import plugin import nuke +from openpype.hosts.nuke.api import plugin +from openpype.hosts.nuke.api.lib import ( + select_nodes, + set_avalon_knob_data +) -class CreateBackdrop(plugin.PypeCreator): +class CreateBackdrop(plugin.OpenPypeCreator): """Add Publishable Backdrop""" name = "nukenodes" @@ -25,14 +28,14 @@ def process(self): nodes = self.nodes if len(nodes) >= 1: - anlib.select_nodes(nodes) + 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 = anlib.set_avalon_knob_data(bckd_node, self.data) + instance = set_avalon_knob_data(bckd_node, self.data) return instance else: @@ -48,6 +51,6 @@ def process(self): bckd_node["note_font_size"].setValue(24) bckd_node["label"].setValue("[{}]".format(self.name)) # add avalon knobs - instance = anlib.set_avalon_knob_data(bckd_node, self.data) + instance = set_avalon_knob_data(bckd_node, self.data) return instance diff --git a/openpype/hosts/nuke/plugins/create/create_camera.py b/openpype/hosts/nuke/plugins/create/create_camera.py index 359086d48f1..3b13c80dc4c 100644 --- a/openpype/hosts/nuke/plugins/create/create_camera.py +++ b/openpype/hosts/nuke/plugins/create/create_camera.py @@ -1,9 +1,11 @@ -from avalon.nuke import lib as anlib -from openpype.hosts.nuke.api import plugin import nuke +from openpype.hosts.nuke.api import plugin +from openpype.hosts.nuke.api.lib import ( + set_avalon_knob_data +) -class CreateCamera(plugin.PypeCreator): +class CreateCamera(plugin.OpenPypeCreator): """Add Publishable Backdrop""" name = "camera" @@ -36,7 +38,7 @@ def process(self): # change node color n["tile_color"].setValue(int(self.node_color, 16)) # add avalon knobs - anlib.set_avalon_knob_data(n, data) + set_avalon_knob_data(n, data) return True else: msg = str("Please select nodes you " @@ -49,5 +51,5 @@ def process(self): camera_node = nuke.createNode("Camera2") camera_node["tile_color"].setValue(int(self.node_color, 16)) # add avalon knobs - instance = anlib.set_avalon_knob_data(camera_node, self.data) + instance = set_avalon_knob_data(camera_node, self.data) return instance diff --git a/openpype/hosts/nuke/plugins/create/create_gizmo.py b/openpype/hosts/nuke/plugins/create/create_gizmo.py index c59713cff15..de73623a1e2 100644 --- a/openpype/hosts/nuke/plugins/create/create_gizmo.py +++ b/openpype/hosts/nuke/plugins/create/create_gizmo.py @@ -1,9 +1,14 @@ -from avalon.nuke import lib as anlib -from openpype.hosts.nuke.api import plugin import nuke +from openpype.hosts.nuke.api import plugin +from openpype.hosts.nuke.api.lib import ( + maintained_selection, + select_nodes, + set_avalon_knob_data +) + -class CreateGizmo(plugin.PypeCreator): +class CreateGizmo(plugin.OpenPypeCreator): """Add Publishable "gizmo" group The name is symbolically gizmo as presumably @@ -28,13 +33,13 @@ def process(self): nodes = self.nodes self.log.info(len(nodes)) if len(nodes) == 1: - anlib.select_nodes(nodes) + 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 anlib.set_avalon_knob_data(node, self.data) + return set_avalon_knob_data(node, self.data) else: msg = ("Please select a group node " "you wish to publish as the gizmo") @@ -42,7 +47,7 @@ def process(self): nuke.message(msg) if len(nodes) >= 2: - anlib.select_nodes(nodes) + select_nodes(nodes) nuke.makeGroup() gizmo_node = nuke.selectedNode() gizmo_node["name"].setValue("{}_GZM".format(self.name)) @@ -57,16 +62,15 @@ def process(self): "- create User knobs on the group") # add avalon knobs - return anlib.set_avalon_knob_data(gizmo_node, self.data) + return set_avalon_knob_data(gizmo_node, self.data) else: - msg = ("Please select nodes you " - "wish to add to the gizmo") + msg = "Please select nodes you wish to add to the gizmo" self.log.error(msg) nuke.message(msg) return else: - with anlib.maintained_selection(): + 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)) @@ -80,4 +84,4 @@ def process(self): "- create User knobs on the group") # add avalon knobs - return anlib.set_avalon_knob_data(gizmo_node, self.data) + return set_avalon_knob_data(gizmo_node, self.data) diff --git a/openpype/hosts/nuke/plugins/create/create_model.py b/openpype/hosts/nuke/plugins/create/create_model.py index 4e30860e050..15a4e3ab8a0 100644 --- a/openpype/hosts/nuke/plugins/create/create_model.py +++ b/openpype/hosts/nuke/plugins/create/create_model.py @@ -1,9 +1,11 @@ -from avalon.nuke import lib as anlib -from openpype.hosts.nuke.api import plugin import nuke +from openpype.hosts.nuke.api import plugin +from openpype.hosts.nuke.api.lib import ( + set_avalon_knob_data +) -class CreateModel(plugin.PypeCreator): +class CreateModel(plugin.OpenPypeCreator): """Add Publishable Model Geometry""" name = "model" @@ -68,7 +70,7 @@ def process(self): # change node color n["tile_color"].setValue(int(self.node_color, 16)) # add avalon knobs - anlib.set_avalon_knob_data(n, data) + set_avalon_knob_data(n, data) return True else: msg = str("Please select nodes you " @@ -81,5 +83,5 @@ def process(self): model_node = nuke.createNode("WriteGeo") model_node["tile_color"].setValue(int(self.node_color, 16)) # add avalon knobs - instance = anlib.set_avalon_knob_data(model_node, self.data) + instance = set_avalon_knob_data(model_node, self.data) return instance diff --git a/openpype/hosts/nuke/plugins/create/create_read.py b/openpype/hosts/nuke/plugins/create/create_read.py index bf5de233467..bdc67add428 100644 --- a/openpype/hosts/nuke/plugins/create/create_read.py +++ b/openpype/hosts/nuke/plugins/create/create_read.py @@ -1,13 +1,16 @@ from collections import OrderedDict + +import nuke + import avalon.api -import avalon.nuke from openpype import api as pype from openpype.hosts.nuke.api import plugin - -import nuke +from openpype.hosts.nuke.api.lib import ( + set_avalon_knob_data +) -class CrateRead(plugin.PypeCreator): +class CrateRead(plugin.OpenPypeCreator): # change this to template preset name = "ReadCopy" label = "Create Read Copy" @@ -45,7 +48,7 @@ def process(self): continue avalon_data = self.data avalon_data['subset'] = "{}".format(self.name) - avalon.nuke.lib.set_avalon_knob_data(node, avalon_data) + set_avalon_knob_data(node, avalon_data) node['tile_color'].setValue(16744935) count_reads += 1 diff --git a/openpype/hosts/nuke/plugins/create/create_write_prerender.py b/openpype/hosts/nuke/plugins/create/create_write_prerender.py index 1b925014adf..3285e5f92d6 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_prerender.py +++ b/openpype/hosts/nuke/plugins/create/create_write_prerender.py @@ -1,11 +1,12 @@ from collections import OrderedDict -from openpype.hosts.nuke.api import ( - plugin, - lib) + import nuke +from openpype.hosts.nuke.api import plugin +from openpype.hosts.nuke.api.lib import create_write_node + -class CreateWritePrerender(plugin.PypeCreator): +class CreateWritePrerender(plugin.OpenPypeCreator): # change this to template preset name = "WritePrerender" label = "Create Write Prerender" @@ -98,7 +99,7 @@ def process(self): self.log.info("write_data: {}".format(write_data)) - write_node = lib.create_write_node( + write_node = create_write_node( self.data["subset"], write_data, input=selected_node, diff --git a/openpype/hosts/nuke/plugins/create/create_write_render.py b/openpype/hosts/nuke/plugins/create/create_write_render.py index 5f13fddf4e9..a9c4b5341e5 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_render.py +++ b/openpype/hosts/nuke/plugins/create/create_write_render.py @@ -1,11 +1,12 @@ from collections import OrderedDict -from openpype.hosts.nuke.api import ( - plugin, - lib) + import nuke +from openpype.hosts.nuke.api import plugin +from openpype.hosts.nuke.api.lib import create_write_node + -class CreateWriteRender(plugin.PypeCreator): +class CreateWriteRender(plugin.OpenPypeCreator): # change this to template preset name = "WriteRender" label = "Create Write Render" @@ -119,7 +120,7 @@ def process(self): } ] - write_node = lib.create_write_node( + write_node = create_write_node( self.data["subset"], write_data, input=selected_node, diff --git a/openpype/hosts/nuke/plugins/create/create_write_still.py b/openpype/hosts/nuke/plugins/create/create_write_still.py index eebb5613c3e..0037b64ce3c 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_still.py +++ b/openpype/hosts/nuke/plugins/create/create_write_still.py @@ -1,11 +1,12 @@ from collections import OrderedDict -from openpype.hosts.nuke.api import ( - plugin, - lib) + import nuke +from openpype.hosts.nuke.api import plugin +from openpype.hosts.nuke.api.lib import create_write_node + -class CreateWriteStill(plugin.PypeCreator): +class CreateWriteStill(plugin.OpenPypeCreator): # change this to template preset name = "WriteStillFrame" label = "Create Write Still Image" @@ -108,7 +109,7 @@ def process(self): } ] - write_node = lib.create_write_node( + write_node = create_write_node( self.name, write_data, input=selected_node, diff --git a/openpype/hosts/nuke/plugins/inventory/repair_old_loaders.py b/openpype/hosts/nuke/plugins/inventory/repair_old_loaders.py index e7ae51fa86c..49405fd2134 100644 --- a/openpype/hosts/nuke/plugins/inventory/repair_old_loaders.py +++ b/openpype/hosts/nuke/plugins/inventory/repair_old_loaders.py @@ -1,7 +1,6 @@ from avalon import api, style -from avalon.nuke import lib as anlib -from openpype.api import ( - Logger) +from openpype.api import Logger +from openpype.hosts.nuke.api.lib import set_avalon_knob_data class RepairOldLoaders(api.InventoryAction): @@ -10,7 +9,7 @@ class RepairOldLoaders(api.InventoryAction): icon = "gears" color = style.colors.alert - log = Logger().get_logger(__name__) + log = Logger.get_logger(__name__) def process(self, containers): import nuke @@ -34,4 +33,4 @@ def process(self, containers): }) node["name"].setValue(new_name) # get data from avalon knob - anlib.set_avalon_knob_data(node, cdata) + set_avalon_knob_data(node, cdata) diff --git a/openpype/hosts/nuke/plugins/inventory/select_containers.py b/openpype/hosts/nuke/plugins/inventory/select_containers.py index bd00983172a..3f174b3562c 100644 --- a/openpype/hosts/nuke/plugins/inventory/select_containers.py +++ b/openpype/hosts/nuke/plugins/inventory/select_containers.py @@ -1,4 +1,5 @@ from avalon import api +from openpype.hosts.nuke.api.commands import viewer_update_and_undo_stop class SelectContainers(api.InventoryAction): @@ -9,11 +10,10 @@ class SelectContainers(api.InventoryAction): def process(self, containers): import nuke - import avalon.nuke nodes = [nuke.toNode(i["objectName"]) for i in containers] - with avalon.nuke.viewer_update_and_undo_stop(): + with viewer_update_and_undo_stop(): # clear previous_selection [n['selected'].setValue(False) for n in nodes] # Select tool diff --git a/openpype/hosts/nuke/plugins/load/load_backdrop.py b/openpype/hosts/nuke/plugins/load/load_backdrop.py index 9148260e9e8..a2bd4589483 100644 --- a/openpype/hosts/nuke/plugins/load/load_backdrop.py +++ b/openpype/hosts/nuke/plugins/load/load_backdrop.py @@ -1,9 +1,18 @@ from avalon import api, style, io import nuke import nukescripts -from openpype.hosts.nuke.api import lib as pnlib -from avalon.nuke import lib as anlib -from avalon.nuke import containerise, update_container + +from openpype.hosts.nuke.api.lib import ( + find_free_space_to_paste_nodes, + maintained_selection, + reset_selection, + select_nodes, + get_avalon_knob_data, + set_avalon_knob_data +) +from openpype.hosts.nuke.api.commands import viewer_update_and_undo_stop +from openpype.hosts.nuke.api import containerise, update_container + class LoadBackdropNodes(api.Loader): """Loading Published Backdrop nodes (workfile, nukenodes)""" @@ -66,12 +75,12 @@ def load(self, context, name, namespace, data): # Get mouse position n = nuke.createNode("NoOp") xcursor, ycursor = (n.xpos(), n.ypos()) - anlib.reset_selection() + reset_selection() nuke.delete(n) bdn_frame = 50 - with anlib.maintained_selection(): + with maintained_selection(): # add group from nk nuke.nodePaste(file) @@ -81,11 +90,13 @@ def load(self, context, name, namespace, data): nodes = nuke.selectedNodes() # get pointer position in DAG - xpointer, ypointer = pnlib.find_free_space_to_paste_nodes(nodes, direction="right", offset=200+bdn_frame) + xpointer, ypointer = find_free_space_to_paste_nodes( + nodes, direction="right", offset=200 + bdn_frame + ) # reset position to all nodes and replace inputs and output for n in nodes: - anlib.reset_selection() + reset_selection() xpos = (n.xpos() - xcursor) + xpointer ypos = (n.ypos() - ycursor) + ypointer n.setXYpos(xpos, ypos) @@ -108,7 +119,7 @@ def load(self, context, name, namespace, data): d.setInput(index, dot) # remove Input node - anlib.reset_selection() + reset_selection() nuke.delete(n) continue @@ -127,15 +138,15 @@ def load(self, context, name, namespace, data): dot.setInput(0, dep) # remove Input node - anlib.reset_selection() + reset_selection() nuke.delete(n) continue else: new_nodes.append(n) # reselect nodes with new Dot instead of Inputs and Output - anlib.reset_selection() - anlib.select_nodes(new_nodes) + reset_selection() + select_nodes(new_nodes) # place on backdrop bdn = nukescripts.autoBackdrop() @@ -208,16 +219,16 @@ def update(self, container, representation): # just in case we are in group lets jump out of it nuke.endGroup() - with anlib.maintained_selection(): + with maintained_selection(): xpos = GN.xpos() ypos = GN.ypos() - avalon_data = anlib.get_avalon_knob_data(GN) + avalon_data = get_avalon_knob_data(GN) nuke.delete(GN) # add group from nk nuke.nodePaste(file) GN = nuke.selectedNode() - anlib.set_avalon_knob_data(GN, avalon_data) + set_avalon_knob_data(GN, avalon_data) GN.setXYpos(xpos, ypos) GN["name"].setValue(object_name) @@ -243,7 +254,6 @@ def switch(self, container, representation): self.update(container, representation) def remove(self, container): - from avalon.nuke import viewer_update_and_undo_stop node = nuke.toNode(container['objectName']) with viewer_update_and_undo_stop(): nuke.delete(node) diff --git a/openpype/hosts/nuke/plugins/load/load_camera_abc.py b/openpype/hosts/nuke/plugins/load/load_camera_abc.py index 377d60e84b8..b9d4bb358f5 100644 --- a/openpype/hosts/nuke/plugins/load/load_camera_abc.py +++ b/openpype/hosts/nuke/plugins/load/load_camera_abc.py @@ -1,8 +1,15 @@ -from avalon import api, io -from avalon.nuke import lib as anlib -from avalon.nuke import containerise, update_container import nuke +from avalon import api, io +from openpype.hosts.nuke.api import ( + containerise, + update_container, + viewer_update_and_undo_stop +) +from openpype.hosts.nuke.api.lib import ( + maintained_selection +) + class AlembicCameraLoader(api.Loader): """ @@ -43,7 +50,7 @@ def load(self, context, name, namespace, data): # getting file path file = self.fname.replace("\\", "/") - with anlib.maintained_selection(): + with maintained_selection(): camera_node = nuke.createNode( "Camera2", "name {} file {} read_from_file True".format( @@ -122,7 +129,7 @@ def update(self, container, representation): # getting file path file = api.get_representation_path(representation).replace("\\", "/") - with anlib.maintained_selection(): + with maintained_selection(): camera_node = nuke.toNode(object_name) camera_node['selected'].setValue(True) @@ -181,7 +188,6 @@ def switch(self, container, representation): self.update(container, representation) def remove(self, container): - from avalon.nuke import viewer_update_and_undo_stop node = nuke.toNode(container['objectName']) with viewer_update_and_undo_stop(): nuke.delete(node) diff --git a/openpype/hosts/nuke/plugins/load/load_clip.py b/openpype/hosts/nuke/plugins/load/load_clip.py index 9ce72c05196..712cdf213fc 100644 --- a/openpype/hosts/nuke/plugins/load/load_clip.py +++ b/openpype/hosts/nuke/plugins/load/load_clip.py @@ -3,13 +3,13 @@ from avalon import api, io from openpype.hosts.nuke.api.lib import ( - get_imageio_input_colorspace + get_imageio_input_colorspace, + maintained_selection ) -from avalon.nuke import ( +from openpype.hosts.nuke.api import ( containerise, update_container, - viewer_update_and_undo_stop, - maintained_selection + viewer_update_and_undo_stop ) from openpype.hosts.nuke.api import plugin @@ -280,9 +280,6 @@ def update(self, container, representation): self.set_as_member(read_node) def remove(self, container): - - from avalon.nuke import viewer_update_and_undo_stop - read_node = nuke.toNode(container['objectName']) assert read_node.Class() == "Read", "Must be Read" @@ -378,4 +375,4 @@ def _get_node_name(self, representation): "class_name": self.__class__.__name__ } - return self.node_name_template.format(**name_data) \ No newline at end of file + return self.node_name_template.format(**name_data) diff --git a/openpype/hosts/nuke/plugins/load/load_effects.py b/openpype/hosts/nuke/plugins/load/load_effects.py index 8ba1b6b7c18..8b8867febab 100644 --- a/openpype/hosts/nuke/plugins/load/load_effects.py +++ b/openpype/hosts/nuke/plugins/load/load_effects.py @@ -1,7 +1,12 @@ -from avalon import api, style, io -import nuke import json from collections import OrderedDict +import nuke +from avalon import api, style, io +from openpype.hosts.nuke.api import ( + containerise, + update_container, + viewer_update_and_undo_stop +) class LoadEffects(api.Loader): @@ -30,9 +35,6 @@ def load(self, context, name, namespace, data): Returns: nuke node: containerised nuke node object """ - # import dependencies - from avalon.nuke import containerise - # get main variables version = context['version'] version_data = version.get("data", {}) @@ -138,10 +140,6 @@ def update(self, container, representation): inputs: """ - - from avalon.nuke import ( - update_container - ) # get main variables # Get version from io version = io.find_one({ @@ -338,7 +336,6 @@ def switch(self, container, representation): self.update(container, representation) def remove(self, container): - from avalon.nuke import viewer_update_and_undo_stop node = nuke.toNode(container['objectName']) with viewer_update_and_undo_stop(): nuke.delete(node) diff --git a/openpype/hosts/nuke/plugins/load/load_effects_ip.py b/openpype/hosts/nuke/plugins/load/load_effects_ip.py index d0cab26842e..7948cbba9a5 100644 --- a/openpype/hosts/nuke/plugins/load/load_effects_ip.py +++ b/openpype/hosts/nuke/plugins/load/load_effects_ip.py @@ -1,8 +1,15 @@ -from avalon import api, style, io -import nuke import json from collections import OrderedDict + +import nuke + +from avalon import api, style, io from openpype.hosts.nuke.api import lib +from openpype.hosts.nuke.api import ( + containerise, + update_container, + viewer_update_and_undo_stop +) class LoadEffectsInputProcess(api.Loader): @@ -30,8 +37,6 @@ def load(self, context, name, namespace, data): Returns: nuke node: containerised nuke node object """ - # import dependencies - from avalon.nuke import containerise # get main variables version = context['version'] @@ -142,9 +147,6 @@ def update(self, container, representation): """ - from avalon.nuke import ( - update_container - ) # get main variables # Get version from io version = io.find_one({ @@ -355,7 +357,6 @@ def switch(self, container, representation): self.update(container, representation) def remove(self, container): - from avalon.nuke import viewer_update_and_undo_stop node = nuke.toNode(container['objectName']) with viewer_update_and_undo_stop(): nuke.delete(node) diff --git a/openpype/hosts/nuke/plugins/load/load_gizmo.py b/openpype/hosts/nuke/plugins/load/load_gizmo.py index c6228b95f64..f549623b88d 100644 --- a/openpype/hosts/nuke/plugins/load/load_gizmo.py +++ b/openpype/hosts/nuke/plugins/load/load_gizmo.py @@ -1,7 +1,15 @@ -from avalon import api, style, io import nuke -from avalon.nuke import lib as anlib -from avalon.nuke import containerise, update_container +from avalon import api, style, io +from openpype.hosts.nuke.api.lib import ( + maintained_selection, + get_avalon_knob_data, + set_avalon_knob_data +) +from openpype.hosts.nuke.api import ( + containerise, + update_container, + viewer_update_and_undo_stop +) class LoadGizmo(api.Loader): @@ -61,7 +69,7 @@ def load(self, context, name, namespace, data): # just in case we are in group lets jump out of it nuke.endGroup() - with anlib.maintained_selection(): + with maintained_selection(): # add group from nk nuke.nodePaste(file) @@ -122,16 +130,16 @@ def update(self, container, representation): # just in case we are in group lets jump out of it nuke.endGroup() - with anlib.maintained_selection(): + with maintained_selection(): xpos = GN.xpos() ypos = GN.ypos() - avalon_data = anlib.get_avalon_knob_data(GN) + avalon_data = get_avalon_knob_data(GN) nuke.delete(GN) # add group from nk nuke.nodePaste(file) GN = nuke.selectedNode() - anlib.set_avalon_knob_data(GN, avalon_data) + set_avalon_knob_data(GN, avalon_data) GN.setXYpos(xpos, ypos) GN["name"].setValue(object_name) @@ -157,7 +165,6 @@ def switch(self, container, representation): self.update(container, representation) def remove(self, container): - from avalon.nuke import viewer_update_and_undo_stop node = nuke.toNode(container['objectName']) with viewer_update_and_undo_stop(): nuke.delete(node) diff --git a/openpype/hosts/nuke/plugins/load/load_gizmo_ip.py b/openpype/hosts/nuke/plugins/load/load_gizmo_ip.py index 5ca101d6cb6..4f174466731 100644 --- a/openpype/hosts/nuke/plugins/load/load_gizmo_ip.py +++ b/openpype/hosts/nuke/plugins/load/load_gizmo_ip.py @@ -1,8 +1,16 @@ from avalon import api, style, io import nuke -from openpype.hosts.nuke.api import lib as pnlib -from avalon.nuke import lib as anlib -from avalon.nuke import containerise, update_container +from openpype.hosts.nuke.api.lib import ( + maintained_selection, + create_backdrop, + get_avalon_knob_data, + set_avalon_knob_data +) +from openpype.hosts.nuke.api import ( + containerise, + update_container, + viewer_update_and_undo_stop +) class LoadGizmoInputProcess(api.Loader): @@ -62,7 +70,7 @@ def load(self, context, name, namespace, data): # just in case we are in group lets jump out of it nuke.endGroup() - with anlib.maintained_selection(): + with maintained_selection(): # add group from nk nuke.nodePaste(file) @@ -128,16 +136,16 @@ def update(self, container, representation): # just in case we are in group lets jump out of it nuke.endGroup() - with anlib.maintained_selection(): + with maintained_selection(): xpos = GN.xpos() ypos = GN.ypos() - avalon_data = anlib.get_avalon_knob_data(GN) + avalon_data = get_avalon_knob_data(GN) nuke.delete(GN) # add group from nk nuke.nodePaste(file) GN = nuke.selectedNode() - anlib.set_avalon_knob_data(GN, avalon_data) + set_avalon_knob_data(GN, avalon_data) GN.setXYpos(xpos, ypos) GN["name"].setValue(object_name) @@ -197,8 +205,12 @@ def connect_active_viewer(self, group_node): viewer["input_process_node"].setValue(group_node_name) # put backdrop under - pnlib.create_backdrop(label="Input Process", layer=2, - nodes=[viewer, group_node], color="0x7c7faaff") + create_backdrop( + label="Input Process", + layer=2, + nodes=[viewer, group_node], + color="0x7c7faaff" + ) return True @@ -234,7 +246,6 @@ def switch(self, container, representation): self.update(container, representation) def remove(self, container): - from avalon.nuke import viewer_update_and_undo_stop node = nuke.toNode(container['objectName']) with viewer_update_and_undo_stop(): nuke.delete(node) diff --git a/openpype/hosts/nuke/plugins/load/load_image.py b/openpype/hosts/nuke/plugins/load/load_image.py index 02a5b55c187..427167ca981 100644 --- a/openpype/hosts/nuke/plugins/load/load_image.py +++ b/openpype/hosts/nuke/plugins/load/load_image.py @@ -7,6 +7,11 @@ from openpype.hosts.nuke.api.lib import ( get_imageio_input_colorspace ) +from openpype.hosts.nuke.api import ( + containerise, + update_container, + viewer_update_and_undo_stop +) class LoadImage(api.Loader): @@ -46,10 +51,6 @@ def get_representations(cls): return cls.representations + cls._representations def load(self, context, name, namespace, options): - from avalon.nuke import ( - containerise, - viewer_update_and_undo_stop - ) self.log.info("__ options: `{}`".format(options)) frame_number = options.get("frame_number", 1) @@ -154,11 +155,6 @@ def update(self, container, representation): inputs: """ - - from avalon.nuke import ( - update_container - ) - node = nuke.toNode(container["objectName"]) frame_number = node["first"].value() @@ -234,9 +230,6 @@ def update(self, container, representation): self.log.info("udated to version: {}".format(version.get("name"))) def remove(self, container): - - from avalon.nuke import viewer_update_and_undo_stop - node = nuke.toNode(container['objectName']) assert node.Class() == "Read", "Must be Read" diff --git a/openpype/hosts/nuke/plugins/load/load_model.py b/openpype/hosts/nuke/plugins/load/load_model.py index 15fa4fa35c7..8c8dc7f37d8 100644 --- a/openpype/hosts/nuke/plugins/load/load_model.py +++ b/openpype/hosts/nuke/plugins/load/load_model.py @@ -1,7 +1,11 @@ -from avalon import api, io -from avalon.nuke import lib as anlib -from avalon.nuke import containerise, update_container import nuke +from avalon import api, io +from openpype.hosts.nuke.api.lib import maintained_selection +from openpype.hosts.nuke.api import ( + containerise, + update_container, + viewer_update_and_undo_stop +) class AlembicModelLoader(api.Loader): @@ -43,7 +47,7 @@ def load(self, context, name, namespace, data): # getting file path file = self.fname.replace("\\", "/") - with anlib.maintained_selection(): + with maintained_selection(): model_node = nuke.createNode( "ReadGeo2", "name {} file {} ".format( @@ -122,7 +126,7 @@ def update(self, container, representation): # getting file path file = api.get_representation_path(representation).replace("\\", "/") - with anlib.maintained_selection(): + with maintained_selection(): model_node = nuke.toNode(object_name) model_node['selected'].setValue(True) @@ -181,7 +185,6 @@ def switch(self, container, representation): self.update(container, representation) def remove(self, container): - from avalon.nuke import viewer_update_and_undo_stop node = nuke.toNode(container['objectName']) with viewer_update_and_undo_stop(): nuke.delete(node) diff --git a/openpype/hosts/nuke/plugins/load/load_script_precomp.py b/openpype/hosts/nuke/plugins/load/load_script_precomp.py index 7444dd6e96f..8489283e8c1 100644 --- a/openpype/hosts/nuke/plugins/load/load_script_precomp.py +++ b/openpype/hosts/nuke/plugins/load/load_script_precomp.py @@ -1,6 +1,11 @@ -from avalon import api, style, io -from avalon.nuke import get_avalon_knob_data import nuke +from avalon import api, style, io +from openpype.hosts.nuke.api.lib import get_avalon_knob_data +from openpype.hosts.nuke.api import ( + containerise, + update_container, + viewer_update_and_undo_stop +) class LinkAsGroup(api.Loader): @@ -15,8 +20,6 @@ class LinkAsGroup(api.Loader): color = style.colors.alert def load(self, context, name, namespace, data): - - from avalon.nuke import containerise # for k, v in context.items(): # log.info("key: `{}`, value: {}\n".format(k, v)) version = context['version'] @@ -103,11 +106,6 @@ def update(self, container, representation): inputs: """ - - from avalon.nuke import ( - update_container - ) - node = nuke.toNode(container['objectName']) root = api.get_representation_path(representation).replace("\\", "/") @@ -155,7 +153,6 @@ def update(self, container, representation): self.log.info("udated to version: {}".format(version.get("name"))) def remove(self, container): - from avalon.nuke import viewer_update_and_undo_stop node = nuke.toNode(container['objectName']) with viewer_update_and_undo_stop(): nuke.delete(node) diff --git a/openpype/hosts/nuke/plugins/publish/extract_backdrop.py b/openpype/hosts/nuke/plugins/publish/extract_backdrop.py index 0747c15ea78..0a2df0898e2 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/extract_backdrop.py @@ -1,9 +1,16 @@ -import pyblish.api -from avalon.nuke import lib as anlib -from openpype.hosts.nuke.api import lib as pnlib -import nuke import os + +import nuke + +import pyblish.api + import openpype +from openpype.hosts.nuke.api.lib import ( + maintained_selection, + reset_selection, + select_nodes +) + class ExtractBackdropNode(openpype.api.Extractor): """Extracting content of backdrop nodes @@ -27,7 +34,7 @@ def process(self, instance): path = os.path.join(stagingdir, filename) # maintain selection - with anlib.maintained_selection(): + with maintained_selection(): # all connections outside of backdrop connections_in = instance.data["nodeConnectionsIn"] connections_out = instance.data["nodeConnectionsOut"] @@ -44,7 +51,7 @@ def process(self, instance): nodes.append(inpn) tmp_nodes.append(inpn) - anlib.reset_selection() + reset_selection() # connect output node for n, output in connections_out.items(): @@ -58,11 +65,11 @@ def process(self, instance): opn.autoplace() nodes.append(opn) tmp_nodes.append(opn) - anlib.reset_selection() + reset_selection() # select nodes to copy - anlib.reset_selection() - anlib.select_nodes(nodes) + reset_selection() + select_nodes(nodes) # create tmp nk file # save file to the path nuke.nodeCopy(path) diff --git a/openpype/hosts/nuke/plugins/publish/extract_camera.py b/openpype/hosts/nuke/plugins/publish/extract_camera.py index bc50dac108a..942cdc537d4 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_camera.py +++ b/openpype/hosts/nuke/plugins/publish/extract_camera.py @@ -1,10 +1,12 @@ -import nuke import os import math +from pprint import pformat + +import nuke + import pyblish.api import openpype.api -from avalon.nuke import lib as anlib -from pprint import pformat +from openpype.hosts.nuke.api.lib import maintained_selection class ExtractCamera(openpype.api.Extractor): @@ -52,7 +54,7 @@ def process(self, instance): filename = subset + ".{}".format(extension) file_path = os.path.join(staging_dir, filename).replace("\\", "/") - with anlib.maintained_selection(): + with maintained_selection(): # bake camera with axeses onto word coordinate XYZ rm_n = bakeCameraWithAxeses( nuke.toNode(instance.data["name"]), output_range) diff --git a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py index 78bf9c998df..2d5bfdeb5e6 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py @@ -1,9 +1,15 @@ -import pyblish.api -from avalon.nuke import lib as anlib -from openpype.hosts.nuke.api import utils as pnutils -import nuke import os +import nuke + +import pyblish.api + import openpype +from openpype.hosts.nuke.api import utils as pnutils +from openpype.hosts.nuke.api.lib import ( + maintained_selection, + reset_selection, + select_nodes +) class ExtractGizmo(openpype.api.Extractor): @@ -26,17 +32,17 @@ def process(self, instance): path = os.path.join(stagingdir, filename) # maintain selection - with anlib.maintained_selection(): + with maintained_selection(): orig_grpn_name = orig_grpn.name() tmp_grpn_name = orig_grpn_name + "_tmp" # select original group node - anlib.select_nodes([orig_grpn]) + select_nodes([orig_grpn]) # copy to clipboard nuke.nodeCopy("%clipboard%") # reset selection to none - anlib.reset_selection() + reset_selection() # paste clipboard nuke.nodePaste("%clipboard%") diff --git a/openpype/hosts/nuke/plugins/publish/extract_model.py b/openpype/hosts/nuke/plugins/publish/extract_model.py index 43214bf3e92..0375263338e 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_model.py +++ b/openpype/hosts/nuke/plugins/publish/extract_model.py @@ -1,9 +1,12 @@ -import nuke import os +from pprint import pformat +import nuke import pyblish.api import openpype.api -from avalon.nuke import lib as anlib -from pprint import pformat +from openpype.hosts.nuke.api.lib import ( + maintained_selection, + select_nodes +) class ExtractModel(openpype.api.Extractor): @@ -49,9 +52,9 @@ def process(self, instance): filename = subset + ".{}".format(extension) file_path = os.path.join(staging_dir, filename).replace("\\", "/") - with anlib.maintained_selection(): + with maintained_selection(): # select model node - anlib.select_nodes([model_node]) + select_nodes([model_node]) # create write geo node wg_n = nuke.createNode("WriteGeo") diff --git a/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py b/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py index c3a6a3b1675..e38927c3a7a 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py +++ b/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py @@ -1,6 +1,6 @@ import nuke import pyblish.api -from avalon.nuke import maintained_selection +from openpype.hosts.nuke.api.lib import maintained_selection class CreateOutputNode(pyblish.api.ContextPlugin): diff --git a/openpype/hosts/nuke/plugins/publish/extract_review_data_lut.py b/openpype/hosts/nuke/plugins/publish/extract_review_data_lut.py index 8ba746a3c47..4cf2fd7d9fc 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_review_data_lut.py +++ b/openpype/hosts/nuke/plugins/publish/extract_review_data_lut.py @@ -1,8 +1,8 @@ import os import pyblish.api -from avalon.nuke import lib as anlib -from openpype.hosts.nuke.api import plugin import openpype +from openpype.hosts.nuke.api import plugin +from openpype.hosts.nuke.api.lib import maintained_selection class ExtractReviewDataLut(openpype.api.Extractor): @@ -37,7 +37,7 @@ def process(self, instance): "StagingDir `{0}`...".format(instance.data["stagingDir"])) # generate data - with anlib.maintained_selection(): + with maintained_selection(): exporter = plugin.ExporterReviewLut( self, instance ) diff --git a/openpype/hosts/nuke/plugins/publish/extract_review_data_mov.py b/openpype/hosts/nuke/plugins/publish/extract_review_data_mov.py index 32962b57a66..13d23ffb9cf 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_review_data_mov.py +++ b/openpype/hosts/nuke/plugins/publish/extract_review_data_mov.py @@ -1,8 +1,8 @@ import os import pyblish.api -from avalon.nuke import lib as anlib -from openpype.hosts.nuke.api import plugin import openpype +from openpype.hosts.nuke.api import plugin +from openpype.hosts.nuke.api.lib import maintained_selection class ExtractReviewDataMov(openpype.api.Extractor): @@ -41,7 +41,7 @@ def process(self, instance): self.log.info(self.outputs) # generate data - with anlib.maintained_selection(): + with maintained_selection(): generated_repres = [] for o_name, o_data in self.outputs.items(): f_families = o_data["filter"]["families"] diff --git a/openpype/hosts/nuke/plugins/publish/extract_slate_frame.py b/openpype/hosts/nuke/plugins/publish/extract_slate_frame.py index 0f68680742d..50e5f995f4f 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_slate_frame.py +++ b/openpype/hosts/nuke/plugins/publish/extract_slate_frame.py @@ -1,8 +1,8 @@ import os import nuke -from avalon.nuke import lib as anlib import pyblish.api import openpype +from openpype.hosts.nuke.api.lib import maintained_selection class ExtractSlateFrame(openpype.api.Extractor): @@ -25,7 +25,7 @@ def process(self, instance): else: self.viewer_lut_raw = False - with anlib.maintained_selection(): + with maintained_selection(): self.log.debug("instance: {}".format(instance)) self.log.debug("instance.data[families]: {}".format( instance.data["families"])) diff --git a/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py b/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py index 0c9af664355..ef6d486ca2d 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py @@ -1,9 +1,9 @@ import sys import os import nuke -from avalon.nuke import lib as anlib import pyblish.api import openpype +from openpype.hosts.nuke.api.lib import maintained_selection if sys.version_info[0] >= 3: @@ -30,7 +30,7 @@ def process(self, instance): if "render.farm" in instance.data["families"]: return - with anlib.maintained_selection(): + with maintained_selection(): self.log.debug("instance: {}".format(instance)) self.log.debug("instance.data[families]: {}".format( instance.data["families"])) diff --git a/openpype/hosts/nuke/plugins/publish/precollect_instances.py b/openpype/hosts/nuke/plugins/publish/precollect_instances.py index 5c30df9a62f..97ddef0a596 100644 --- a/openpype/hosts/nuke/plugins/publish/precollect_instances.py +++ b/openpype/hosts/nuke/plugins/publish/precollect_instances.py @@ -1,7 +1,10 @@ import nuke import pyblish.api from avalon import io, api -from avalon.nuke import lib as anlib +from openpype.hosts.nuke.api.lib import ( + add_publish_knob, + get_avalon_knob_data +) @pyblish.api.log @@ -39,7 +42,7 @@ def process(self, context): self.log.warning(E) # get data from avalon knob - avalon_knob_data = anlib.get_avalon_knob_data( + avalon_knob_data = get_avalon_knob_data( node, ["avalon:", "ak:"]) self.log.debug("avalon_knob_data: {}".format(avalon_knob_data)) @@ -115,7 +118,7 @@ def process(self, context): # get publish knob value if "publish" not in node.knobs(): - anlib.add_publish_knob(node) + add_publish_knob(node) # sync workfile version _families_test = [family] + families diff --git a/openpype/hosts/nuke/plugins/publish/precollect_workfile.py b/openpype/hosts/nuke/plugins/publish/precollect_workfile.py index 0e27273ceb9..a2d1c80628f 100644 --- a/openpype/hosts/nuke/plugins/publish/precollect_workfile.py +++ b/openpype/hosts/nuke/plugins/publish/precollect_workfile.py @@ -1,8 +1,13 @@ +import os + import nuke + import pyblish.api -import os import openpype.api as pype -from avalon.nuke import lib as anlib +from openpype.hosts.nuke.api.lib import ( + add_publish_knob, + get_avalon_knob_data +) class CollectWorkfile(pyblish.api.ContextPlugin): @@ -17,9 +22,9 @@ def process(self, context): current_file = os.path.normpath(nuke.root().name()) - knob_data = anlib.get_avalon_knob_data(root) + knob_data = get_avalon_knob_data(root) - anlib.add_publish_knob(root) + add_publish_knob(root) family = "workfile" task = os.getenv("AVALON_TASK", None) diff --git a/openpype/hosts/nuke/plugins/publish/validate_backdrop.py b/openpype/hosts/nuke/plugins/publish/validate_backdrop.py index f280ad4af13..7694c3d2bab 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/validate_backdrop.py @@ -1,6 +1,6 @@ -import pyblish -from avalon.nuke import lib as anlib import nuke +import pyblish +from openpype.hosts.nuke.api.lib import maintained_selection class SelectCenterInNodeGraph(pyblish.api.Action): @@ -28,7 +28,7 @@ def process(self, context, plugin): all_yC = list() # maintain selection - with anlib.maintained_selection(): + with maintained_selection(): # collect all failed nodes xpos and ypos for instance in instances: bdn = instance[0] diff --git a/openpype/hosts/nuke/plugins/publish/validate_gizmo.py b/openpype/hosts/nuke/plugins/publish/validate_gizmo.py index 9c94ea88ef9..d0d930f50c7 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 avalon.nuke import lib as anlib import nuke +import pyblish +from openpype.hosts.nuke.api.lib import maintained_selection class OpenFailedGroupNode(pyblish.api.Action): @@ -25,7 +25,7 @@ def process(self, context, plugin): instances = pyblish.api.instances_by_plugin(failed, plugin) # maintain selection - with anlib.maintained_selection(): + with maintained_selection(): # collect all failed nodes xpos and ypos for instance in instances: grpn = instance[0] diff --git a/openpype/hosts/nuke/plugins/publish/validate_instance_in_context.py b/openpype/hosts/nuke/plugins/publish/validate_instance_in_context.py index ddf46a08734..842f74b6f67 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_instance_in_context.py +++ b/openpype/hosts/nuke/plugins/publish/validate_instance_in_context.py @@ -6,8 +6,11 @@ import pyblish.api import openpype.api -import avalon.nuke.lib -import openpype.hosts.nuke.api as nuke_api +from openpype.hosts.nuke.api.lib import ( + recreate_instance, + reset_selection, + select_nodes +) class SelectInvalidInstances(pyblish.api.Action): @@ -47,12 +50,12 @@ def process(self, context, plugin): self.deselect() def select(self, instances): - avalon.nuke.lib.select_nodes( + select_nodes( [nuke.toNode(str(x)) for x in instances] ) def deselect(self): - avalon.nuke.lib.reset_selection() + reset_selection() class RepairSelectInvalidInstances(pyblish.api.Action): @@ -82,7 +85,7 @@ def process(self, context, plugin): context_asset = context.data["assetEntity"]["name"] for instance in instances: origin_node = instance[0] - nuke_api.lib.recreate_instance( + recreate_instance( origin_node, avalon_data={"asset": context_asset} ) diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_legacy.py b/openpype/hosts/nuke/plugins/publish/validate_write_legacy.py index ba34ec83383..a73bed8eddc 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_legacy.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_legacy.py @@ -1,13 +1,12 @@ -import toml import os +import toml import nuke from avalon import api -import re import pyblish.api import openpype.api -from avalon.nuke import get_avalon_knob_data +from openpype.hosts.nuke.api.lib import get_avalon_knob_data class ValidateWriteLegacy(pyblish.api.InstancePlugin): diff --git a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py index 732f321b859..c0d5c8f4027 100644 --- a/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py +++ b/openpype/hosts/nuke/plugins/publish/validate_write_nodes.py @@ -1,8 +1,11 @@ import os import pyblish.api import openpype.utils -import openpype.hosts.nuke.lib as nukelib -import avalon.nuke +from openpype.hosts.nuke.api.lib import ( + get_write_node_template_attr, + get_node_path +) + @pyblish.api.log class RepairNukeWriteNodeAction(pyblish.api.Action): @@ -15,7 +18,7 @@ def process(self, context, plugin): for instance in instances: node = instance[1] - correct_data = nukelib.get_write_node_template_attr(node) + correct_data = get_write_node_template_attr(node) for k, v in correct_data.items(): node[k].setValue(v) self.log.info("Node attributes were fixed") @@ -34,14 +37,14 @@ class ValidateNukeWriteNode(pyblish.api.InstancePlugin): def process(self, instance): node = instance[1] - correct_data = nukelib.get_write_node_template_attr(node) + correct_data = get_write_node_template_attr(node) check = [] for k, v in correct_data.items(): if k is 'file': padding = len(v.split('#')) - ref_path = avalon.nuke.lib.get_node_path(v, padding) - n_path = avalon.nuke.lib.get_node_path(node[k].value(), padding) + ref_path = get_node_path(v, padding) + n_path = get_node_path(node[k].value(), padding) isnt = False for i, p in enumerate(ref_path): if str(n_path[i]) not in str(p): diff --git a/openpype/hosts/nuke/startup/init.py b/openpype/hosts/nuke/startup/init.py index 0ea5d1ad7dd..d7560814bf2 100644 --- a/openpype/hosts/nuke/startup/init.py +++ b/openpype/hosts/nuke/startup/init.py @@ -1,2 +1,4 @@ +import nuke + # default write mov nuke.knobDefault('Write.mov.colorspace', 'sRGB') diff --git a/openpype/hosts/nuke/startup/menu.py b/openpype/hosts/nuke/startup/menu.py index b7ed35b3b48..2cac6d09e79 100644 --- a/openpype/hosts/nuke/startup/menu.py +++ b/openpype/hosts/nuke/startup/menu.py @@ -1,14 +1,19 @@ +import nuke +import avalon.api + +from openpype.api import Logger +from openpype.hosts.nuke import api from openpype.hosts.nuke.api.lib import ( on_script_load, check_inventory_versions, - WorkfileSettings + WorkfileSettings, + dirmap_file_name_filter ) -import nuke -from openpype.api import Logger -from openpype.hosts.nuke.api.lib import dirmap_file_name_filter +log = Logger.get_logger(__name__) + -log = Logger().get_logger(__name__) +avalon.api.install(api) # fix ffmpeg settings on script nuke.addOnScriptLoad(on_script_load) From 26d8304fd9704f04bd9ac076d193dc1646e4a38b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 12 Jan 2022 12:27:09 +0100 Subject: [PATCH 2/4] removed avalon nuke path from add implementation environments --- openpype/hosts/nuke/__init__.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/openpype/hosts/nuke/__init__.py b/openpype/hosts/nuke/__init__.py index 366f704dd8d..60b37ce1ddd 100644 --- a/openpype/hosts/nuke/__init__.py +++ b/openpype/hosts/nuke/__init__.py @@ -6,10 +6,7 @@ def add_implementation_envs(env, _app): # Add requirements to NUKE_PATH pype_root = os.environ["OPENPYPE_REPOS_ROOT"] new_nuke_paths = [ - os.path.join(pype_root, "openpype", "hosts", "nuke", "startup"), - os.path.join( - pype_root, "repos", "avalon-core", "setup", "nuke", "nuke_path" - ) + os.path.join(pype_root, "openpype", "hosts", "nuke", "startup") ] old_nuke_path = env.get("NUKE_PATH") or "" for path in old_nuke_path.split(os.pathsep): From 9980aa90fa196eb07e57ea7155b7ce98469d81e9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 12 Jan 2022 12:32:21 +0100 Subject: [PATCH 3/4] fix default value of function argument --- openpype/hosts/nuke/api/utils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/utils.py b/openpype/hosts/nuke/api/utils.py index f8f248357b3..205b23efe64 100644 --- a/openpype/hosts/nuke/api/utils.py +++ b/openpype/hosts/nuke/api/utils.py @@ -49,12 +49,14 @@ def gizmo_is_nuke_default(gizmo): return gizmo.filename().startswith(plug_dir) -def bake_gizmos_recursively(in_group=nuke.Root()): +def bake_gizmos_recursively(in_group=None): """Converting a gizmo to group Argumets: is_group (nuke.Node)[optonal]: group node or all nodes """ + if in_group is None: + in_group = nuke.Root() # preserve selection after all is done with maintained_selection(): # jump to the group From 8eded893aafa1f1cb62bc5e371ae01c39d58d6a6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 19 Jan 2022 16:45:52 +0100 Subject: [PATCH 4/4] fixed mising 'maintained_selection' --- openpype/hosts/nuke/api/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index d3b7f74d6df..f7ebcb41da4 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -25,6 +25,9 @@ parse_container, update_container, ) +from .lib import ( + maintained_selection +) __all__ = ( @@ -49,4 +52,6 @@ "containerise", "parse_container", "update_container", + + "maintained_selection", )