Merge branch 'develop' into enhancement/Nuke_Autosave_from_prefs

This commit is contained in:
Jakub Ježek 2023-08-07 14:50:02 +02:00 committed by GitHub
commit cf42ad1535
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
1277 changed files with 56541 additions and 25693 deletions

View file

@ -42,8 +42,10 @@ from openpype.pipeline.template_data import get_template_data_with_names
from openpype.pipeline import (
get_current_project_name,
discover_legacy_creator_plugins,
legacy_io,
Anatomy,
get_current_host_name,
get_current_project_name,
get_current_asset_name,
)
from openpype.pipeline.context_tools import (
get_current_project_asset,
@ -422,10 +424,13 @@ def add_publish_knob(node):
return node
@deprecated
@deprecated("openpype.hosts.nuke.api.lib.set_node_data")
def set_avalon_knob_data(node, data=None, prefix="avalon:"):
"""[DEPRECATED] Sets data into nodes's avalon knob
This function is still used but soon will be deprecated.
Use `set_node_data` instead.
Arguments:
node (nuke.Node): Nuke node to imprint with data,
data (dict, optional): Data to be imprinted into AvalonTab
@ -485,10 +490,13 @@ def set_avalon_knob_data(node, data=None, prefix="avalon:"):
return node
@deprecated
@deprecated("openpype.hosts.nuke.api.lib.get_node_data")
def get_avalon_knob_data(node, prefix="avalon:", create=True):
"""[DEPRECATED] Gets a data from nodes's avalon knob
This function is still used but soon will be deprecated.
Use `get_node_data` instead.
Arguments:
node (obj): Nuke node to search for data,
prefix (str, optional): filtering prefix
@ -970,7 +978,7 @@ def check_inventory_versions():
if not repre_ids:
return
project_name = legacy_io.active_project()
project_name = get_current_project_name()
# Find representations based on found containers
repre_docs = get_representations(
project_name,
@ -1128,11 +1136,15 @@ def format_anatomy(data):
anatomy = Anatomy()
log.debug("__ anatomy.templates: {}".format(anatomy.templates))
padding = int(
anatomy.templates["render"].get(
"frame_padding"
padding = None
if "frame_padding" in anatomy.templates.keys():
padding = int(anatomy.templates["frame_padding"])
elif "render" in anatomy.templates.keys():
padding = int(
anatomy.templates["render"].get(
"frame_padding"
)
)
)
version = data.get("version", None)
if not version:
@ -1142,7 +1154,7 @@ def format_anatomy(data):
project_name = anatomy.project_name
asset_name = data["asset"]
task_name = data["task"]
host_name = os.environ["AVALON_APP"]
host_name = get_current_host_name()
context_data = get_template_data_with_names(
project_name, asset_name, task_name, host_name
)
@ -1470,7 +1482,7 @@ def create_write_node_legacy(
if knob["name"] == "file_type":
representation = knob["value"]
host_name = os.environ.get("AVALON_APP")
host_name = get_current_host_name()
try:
data.update({
"app": host_name,
@ -1693,7 +1705,7 @@ def create_write_node_legacy(
knob_value = float(knob_value)
if knob_type == "bool":
knob_value = bool(knob_value)
if knob_type in ["2d_vector", "3d_vector"]:
if knob_type in ["2d_vector", "3d_vector", "color", "box"]:
knob_value = list(knob_value)
GN[knob_name].setValue(knob_value)
@ -1709,7 +1721,7 @@ def set_node_knobs_from_settings(node, knob_settings, **kwargs):
Args:
node (nuke.Node): nuke node
knob_settings (list): list of dict. Keys are `type`, `name`, `value`
kwargs (dict)[optional]: keys for formatable knob settings
kwargs (dict)[optional]: keys for formattable knob settings
"""
for knob in knob_settings:
log.debug("__ knob: {}".format(pformat(knob)))
@ -1726,7 +1738,7 @@ def set_node_knobs_from_settings(node, knob_settings, **kwargs):
)
continue
# first deal with formatable knob settings
# first deal with formattable knob settings
if knob_type == "formatable":
template = knob["template"]
to_type = knob["to_type"]
@ -1735,8 +1747,8 @@ def set_node_knobs_from_settings(node, knob_settings, **kwargs):
**kwargs
)
except KeyError as msg:
log.warning("__ msg: {}".format(msg))
raise KeyError(msg)
raise KeyError(
"Not able to format expression: {}".format(msg))
# convert value to correct type
if to_type == "2d_vector":
@ -1775,8 +1787,8 @@ def convert_knob_value_to_correct_type(knob_type, knob_value):
knob_value = knob_value
elif knob_type == "color_gui":
knob_value = color_gui_to_int(knob_value)
elif knob_type in ["2d_vector", "3d_vector", "color"]:
knob_value = [float(v) for v in knob_value]
elif knob_type in ["2d_vector", "3d_vector", "color", "box"]:
knob_value = [float(val_) for val_ in knob_value]
return knob_value
@ -1929,15 +1941,18 @@ class WorkfileSettings(object):
def __init__(self, root_node=None, nodes=None, **kwargs):
project_doc = kwargs.get("project")
if project_doc is None:
project_name = legacy_io.active_project()
project_name = get_current_project_name()
project_doc = get_project(project_name)
else:
project_name = project_doc["name"]
Context._project_doc = project_doc
self._project_name = project_name
self._asset = (
kwargs.get("asset_name")
or legacy_io.Session["AVALON_ASSET"]
or get_current_asset_name()
)
self._asset_entity = get_current_project_asset(self._asset)
self._asset_entity = get_asset_by_name(project_name, self._asset)
self._root_node = root_node or nuke.root()
self._nodes = self.get_nodes(nodes=nodes)
@ -2195,7 +2210,6 @@ Reopening Nuke should synchronize these paths and resolve any discrepancies.
continue
preset_clrsp = input["colorspace"]
log.debug(preset_clrsp)
if preset_clrsp is not None:
current = n["colorspace"].value()
future = str(preset_clrsp)
@ -2330,7 +2344,7 @@ Reopening Nuke should synchronize these paths and resolve any discrepancies.
def reset_resolution(self):
"""Set resolution to project resolution."""
log.info("Resetting resolution")
project_name = legacy_io.active_project()
project_name = get_current_project_name()
asset_data = self._asset_entity["data"]
format_data = {
@ -2409,7 +2423,7 @@ Reopening Nuke should synchronize these paths and resolve any discrepancies.
from .utils import set_context_favorites
work_dir = os.getenv("AVALON_WORKDIR")
asset = os.getenv("AVALON_ASSET")
asset = get_current_asset_name()
favorite_items = OrderedDict()
# project
@ -2677,7 +2691,15 @@ def _launch_workfile_app():
host_tools.show_workfiles(parent=None, on_top=True)
@deprecated("openpype.hosts.nuke.api.lib.start_workfile_template_builder")
def process_workfile_builder():
""" [DEPRECATED] Process workfile builder on nuke start
This function is deprecated and will be removed in future versions.
Use settings for `project_settings/nuke/templated_workfile_build` which are
supported by api `start_workfile_template_builder()`.
"""
# to avoid looping of the callback, remove it!
nuke.removeOnCreate(process_workfile_builder, nodeClass="Root")
@ -2686,11 +2708,6 @@ def process_workfile_builder():
workfile_builder = project_settings["nuke"].get(
"workfile_builder", {})
# get all imortant settings
openlv_on = env_value_to_bool(
env_key="AVALON_OPEN_LAST_WORKFILE",
default=None)
# get settings
createfv_on = workfile_builder.get("create_first_version") or None
builder_on = workfile_builder.get("builder_on_start") or None
@ -2731,20 +2748,15 @@ def process_workfile_builder():
save_file(last_workfile_path)
return
# skip opening of last version if it is not enabled
if not openlv_on or not os.path.exists(last_workfile_path):
return
log.info("Opening last workfile...")
# open workfile
open_file(last_workfile_path)
def start_workfile_template_builder():
from .workfile_template_builder import (
build_workfile_template
)
# remove callback since it would be duplicating the workfile
nuke.removeOnCreate(start_workfile_template_builder, nodeClass="Root")
# to avoid looping of the callback, remove it!
log.info("Starting workfile template builder...")
try:
@ -2752,8 +2764,6 @@ def start_workfile_template_builder():
except TemplateProfileNotFound:
log.warning("Template profile not found. Skipping...")
# remove callback since it would be duplicating the workfile
nuke.removeOnCreate(start_workfile_template_builder, nodeClass="Root")
@deprecated
def recreate_instance(origin_node, avalon_data=None):
@ -2832,7 +2842,8 @@ def add_scripts_menu():
return
# load configuration of custom menu
project_settings = get_project_settings(os.getenv("AVALON_PROJECT"))
project_name = get_current_project_name()
project_settings = get_project_settings(project_name)
config = project_settings["nuke"]["scriptsmenu"]["definition"]
_menu = project_settings["nuke"]["scriptsmenu"]["name"]
@ -2850,7 +2861,8 @@ def add_scripts_menu():
def add_scripts_gizmo():
# load configuration of custom menu
project_settings = get_project_settings(os.getenv("AVALON_PROJECT"))
project_name = get_current_project_name()
project_settings = get_project_settings(project_name)
platform_name = platform.system().lower()
for gizmo_settings in project_settings["nuke"]["gizmo"]:

View file

@ -2,7 +2,7 @@ import nuke
import os
import importlib
from collections import OrderedDict
from collections import OrderedDict, defaultdict
import pyblish.api
@ -20,6 +20,8 @@ from openpype.pipeline import (
register_creator_plugin_path,
register_inventory_action_path,
AVALON_CONTAINER_ID,
get_current_asset_name,
get_current_task_name,
)
from openpype.pipeline.workfile import BuildWorkfile
from openpype.tools.utils import host_tools
@ -32,6 +34,7 @@ from .lib import (
get_main_window,
add_publish_knob,
WorkfileSettings,
# TODO: remove this once workfile builder will be removed
process_workfile_builder,
start_workfile_template_builder,
launch_workfiles_app,
@ -153,11 +156,18 @@ def add_nuke_callbacks():
"""
nuke_settings = get_current_project_settings()["nuke"]
workfile_settings = WorkfileSettings()
# Set context settings.
nuke.addOnCreate(
workfile_settings.set_context_settings, nodeClass="Root")
# adding favorites to file browser
nuke.addOnCreate(workfile_settings.set_favorites, nodeClass="Root")
# template builder callbacks
nuke.addOnCreate(start_workfile_template_builder, nodeClass="Root")
# TODO: remove this callback once workfile builder will be removed
nuke.addOnCreate(process_workfile_builder, nodeClass="Root")
# fix ffmpeg settings on script
@ -167,11 +177,12 @@ def add_nuke_callbacks():
nuke.addOnScriptLoad(check_inventory_versions)
nuke.addOnScriptSave(check_inventory_versions)
# # set apply all workfile settings on script load and save
# set apply all workfile settings on script load and save
nuke.addOnScriptLoad(WorkfileSettings().set_context_settings)
if nuke_settings["nuke-dirmap"]["enabled"]:
log.info("Added Nuke's dirmaping callback ...")
log.info("Added Nuke's dir-mapping callback ...")
# Add dirmap for file paths.
nuke.addFilenameFilter(dirmap_file_name_filter)
@ -211,6 +222,13 @@ def _show_workfiles():
host_tools.show_workfiles(parent=None, on_top=False)
def get_context_label():
return "{0}, {1}".format(
get_current_asset_name(),
get_current_task_name()
)
def _install_menu():
"""Install Avalon menu into Nuke's main menu bar."""
@ -220,9 +238,7 @@ def _install_menu():
menu = menubar.addMenu(MENU_LABEL)
if not ASSIST:
label = "{0}, {1}".format(
os.environ["AVALON_ASSET"], os.environ["AVALON_TASK"]
)
label = get_context_label()
Context.context_label = label
context_action = menu.addCommand(label)
context_action.setEnabled(False)
@ -338,9 +354,7 @@ def change_context_label():
menubar = nuke.menu("Nuke")
menu = menubar.findItem(MENU_LABEL)
label = "{0}, {1}".format(
os.environ["AVALON_ASSET"], os.environ["AVALON_TASK"]
)
label = get_context_label()
rm_item = [
(i, item) for i, item in enumerate(menu.items())
@ -532,7 +546,10 @@ def list_instances(creator_id=None):
Returns:
(list) of dictionaries matching instances format
"""
listed_instances = []
instances_by_order = defaultdict(list)
subset_instances = []
instance_ids = set()
for node in nuke.allNodes(recurseGroups=True):
if node.Class() in ["Viewer", "Dot"]:
@ -558,9 +575,57 @@ def list_instances(creator_id=None):
if creator_id and instance_data["creator_identifier"] != creator_id:
continue
listed_instances.append((node, instance_data))
if instance_data["instance_id"] in instance_ids:
instance_data.pop("instance_id")
else:
instance_ids.add(instance_data["instance_id"])
return listed_instances
# node name could change, so update subset name data
_update_subset_name_data(instance_data, node)
if "render_order" not in node.knobs():
subset_instances.append((node, instance_data))
continue
order = int(node["render_order"].value())
instances_by_order[order].append((node, instance_data))
# Sort instances based on order attribute or subset name.
# TODO: remove in future Publisher enhanced with sorting
ordered_instances = []
for key in sorted(instances_by_order.keys()):
instances_by_subset = defaultdict(list)
for node, data_ in instances_by_order[key]:
instances_by_subset[data_["subset"]].append((node, data_))
for subkey in sorted(instances_by_subset.keys()):
ordered_instances.extend(instances_by_subset[subkey])
instances_by_subset = defaultdict(list)
for node, data_ in subset_instances:
instances_by_subset[data_["subset"]].append((node, data_))
for key in sorted(instances_by_subset.keys()):
ordered_instances.extend(instances_by_subset[key])
return ordered_instances
def _update_subset_name_data(instance_data, node):
"""Update subset name data in instance data.
Args:
instance_data (dict): instance creator data
node (nuke.Node): nuke node
"""
# make sure node name is subset name
old_subset_name = instance_data["subset"]
old_variant = instance_data["variant"]
subset_name_root = old_subset_name.replace(old_variant, "")
new_subset_name = node.name()
new_variant = new_subset_name.replace(subset_name_root, "")
instance_data["subset"] = new_subset_name
instance_data["variant"] = new_variant
def remove_instance(instance):

View file

@ -19,7 +19,7 @@ from openpype.pipeline import (
CreatorError,
Creator as NewCreator,
CreatedInstance,
legacy_io
get_current_task_name
)
from .lib import (
INSTANCE_DATA_KNOB,
@ -212,9 +212,15 @@ class NukeCreator(NewCreator):
created_instance["creator_attributes"].pop(key)
def update_instances(self, update_list):
for created_inst, _changes in update_list:
for created_inst, changes in update_list:
instance_node = created_inst.transient_data["node"]
# update instance node name if subset name changed
if "subset" in changes.changed_keys:
instance_node["name"].setValue(
changes["subset"].new_value
)
# in case node is not existing anymore (user erased it manually)
try:
instance_node.fullName()
@ -256,6 +262,17 @@ class NukeWriteCreator(NukeCreator):
family = "write"
icon = "sign-out"
def get_linked_knobs(self):
linked_knobs = []
if "channels" in self.instance_attributes:
linked_knobs.append("channels")
if "ordered" in self.instance_attributes:
linked_knobs.append("render_order")
if "use_range_limit" in self.instance_attributes:
linked_knobs.extend(["___", "first", "last", "use_limit"])
return linked_knobs
def integrate_links(self, node, outputs=True):
# skip if no selection
if not self.selected_node:
@ -824,41 +841,6 @@ class ExporterReviewMov(ExporterReview):
add_tags = []
self.publish_on_farm = farm
read_raw = kwargs["read_raw"]
# TODO: remove this when `reformat_nodes_config`
# is changed in settings
reformat_node_add = kwargs["reformat_node_add"]
reformat_node_config = kwargs["reformat_node_config"]
# TODO: make this required in future
reformat_nodes_config = kwargs.get("reformat_nodes_config", {})
# TODO: remove this once deprecated is removed
# make sure only reformat_nodes_config is used in future
if reformat_node_add and reformat_nodes_config.get("enabled"):
self.log.warning(
"`reformat_node_add` is deprecated. "
"Please use only `reformat_nodes_config` instead.")
reformat_nodes_config = None
# TODO: reformat code when backward compatibility is not needed
# warning if reformat_nodes_config is not set
if not reformat_nodes_config:
self.log.warning(
"Please set `reformat_nodes_config` in settings. "
"Using `reformat_node_config` instead."
)
reformat_nodes_config = {
"enabled": reformat_node_add,
"reposition_nodes": [
{
"node_class": "Reformat",
"knobs": reformat_node_config
}
]
}
bake_viewer_process = kwargs["bake_viewer_process"]
bake_viewer_input_process_node = kwargs[
"bake_viewer_input_process"]
@ -897,6 +879,7 @@ class ExporterReviewMov(ExporterReview):
self._shift_to_previous_node_and_temp(subset, r_node, "Read... `{}`")
# add reformat node
reformat_nodes_config = kwargs["reformat_nodes_config"]
if reformat_nodes_config["enabled"]:
reposition_nodes = reformat_nodes_config["reposition_nodes"]
for reposition_node in reposition_nodes:
@ -955,7 +938,11 @@ class ExporterReviewMov(ExporterReview):
except Exception:
self.log.info("`mov64_codec` knob was not found")
write_node["mov64_write_timecode"].setValue(1)
try:
write_node["mov64_write_timecode"].setValue(1)
except Exception:
self.log.info("`mov64_write_timecode` knob was not found")
write_node["raw"].setValue(1)
# connect
write_node.setInput(0, self.previous_node)
@ -1173,7 +1160,7 @@ def convert_to_valid_instaces():
from openpype.hosts.nuke.api import workio
task_name = legacy_io.Session["AVALON_TASK"]
task_name = get_current_task_name()
# save into new workfile
current_file = workio.current_file()

View file

@ -25,7 +25,8 @@ from .lib import (
select_nodes,
duplicate_node,
node_tempfile,
get_main_window
get_main_window,
WorkfileSettings,
)
PLACEHOLDER_SET = "PLACEHOLDERS_SET"
@ -955,6 +956,9 @@ def build_workfile_template(*args, **kwargs):
builder = NukeTemplateBuilder(registered_host())
builder.build_template(*args, **kwargs)
# set all settings to shot context default
WorkfileSettings().set_context_settings()
def update_workfile_template(*args):
builder = NukeTemplateBuilder(registered_host())