From 2811eaddb8696ab3816370f9f78699d8dfa9795c Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Sun, 28 Apr 2024 22:00:21 +0100 Subject: [PATCH 01/34] Working version --- client/ayon_core/hosts/nuke/api/pipeline.py | 6 + .../hosts/nuke/api/push_to_project.py | 116 ++++++++++++++++++ .../tools/push_to_project/control.py | 5 +- .../ayon_core/tools/push_to_project/main.py | 16 ++- .../tools/push_to_project/ui/window.py | 43 +++++-- 5 files changed, 170 insertions(+), 16 deletions(-) create mode 100644 client/ayon_core/hosts/nuke/api/push_to_project.py diff --git a/client/ayon_core/hosts/nuke/api/pipeline.py b/client/ayon_core/hosts/nuke/api/pipeline.py index 0d44aba2f9..23d06c4609 100644 --- a/client/ayon_core/hosts/nuke/api/pipeline.py +++ b/client/ayon_core/hosts/nuke/api/pipeline.py @@ -68,6 +68,7 @@ from .workio import ( current_file ) from .constants import ASSIST +from . import push_to_project log = Logger.get_logger(__name__) @@ -339,6 +340,11 @@ def _install_menu(): lambda: update_placeholder() ) + menu.addCommand( + "Push to Project", + lambda: push_to_project.main() + ) + menu.addSeparator() menu.addCommand( "Experimental tools...", diff --git a/client/ayon_core/hosts/nuke/api/push_to_project.py b/client/ayon_core/hosts/nuke/api/push_to_project.py new file mode 100644 index 0000000000..a67a032179 --- /dev/null +++ b/client/ayon_core/hosts/nuke/api/push_to_project.py @@ -0,0 +1,116 @@ +from collections import defaultdict +import shutil +import os + +from ayon_api import get_project, get_folder_by_id, get_task_by_id +from ayon_core.settings import get_ayon_settings, get_project_settings +from ayon_core.pipeline import Anatomy, registered_host +from ayon_core.pipeline.template_data import get_template_data +from ayon_core.pipeline.workfile import get_workdir_with_workdir_data +from ayon_core.tools.push_to_project.main import main_show + +from .utils import bake_gizmos_recursively + +import nuke + + +def bake_container(container): + """Bake containers to read nodes.""" + + node = container["node"] + + # Fetch knobs to remove in order. + knobs_to_remove = [] + remove = False + for count in range(0, node.numKnobs()): + knob = node.knob(count) + + # All knobs from "OpenPype" tab knob onwards. + if knob.name() == "AYON": + remove = True + + if remove: + knobs_to_remove.append(knob) + + # Dont remove knobs from "containerId" onwards. + if knob.name() == "containerId": + remove = False + + # Knobs needs to be remove in reverse order, because child knobs needs to + # be remove first. + for knob in reversed(knobs_to_remove): + node.removeKnob(knob) + + node["tile_color"].setValue(0) + + +def main(): + context = main_show("", "", False, True) + + if context is None: + return + + # Get workfile path to save to. + project_name = context["project_name"] + project = get_project(project_name) + folder = get_folder_by_id(project_name, context["folder_id"]) + task = get_task_by_id(project_name, context["task_id"]) + host = registered_host() + ayon_settings = get_ayon_settings() + project_settings = get_project_settings(project_name) + anatomy = Anatomy(project_name) + + workdir_data = get_template_data( + project, folder, task, host.name, ayon_settings + ) + + workdir = get_workdir_with_workdir_data( + workdir_data, + project_name, + anatomy, + project_settings=project_settings + ) + + # Save current workfile. + current_file = host.current_file() + host.save_file(current_file) + + for container in host.ls(): + bake_container(container) + + # Bake gizmos. + bake_gizmos_recursively() + + # Copy all read node files to "resources" folder next to workfile and + # change file path. + first_frame = int(nuke.root()["first_frame"].value()) + last_frame = int(nuke.root()["last_frame"].value()) + files_by_node_name = defaultdict(set) + nodes_by_name = {} + for count in range(first_frame, last_frame + 1): + nuke.frame(count) + for node in nuke.allNodes(filter="Read"): + files_by_node_name[node.name()].add( + nuke.filename(node, nuke.REPLACE) + ) + nodes_by_name[node.name()] = node + + resources_dir = os.path.join(workdir, "resources") + for name, files in files_by_node_name.items(): + dir = os.path.join(resources_dir, name) + if not os.path.exists(dir): + os.makedirs(dir) + + for f in files: + shutil.copy(f, os.path.join(dir, os.path.basename(f))) + + node = nodes_by_name[name] + path = node["file"].value().replace(os.path.dirname(f), dir) + node["file"].setValue(path.replace("\\", "/")) + + # Save current workfile to new context. + basename = os.path.basename(current_file) + host.save_file(os.path.join(workdir, basename)) + + # Open current contex workfile. + host.open_file(current_file) diff --git a/client/ayon_core/tools/push_to_project/control.py b/client/ayon_core/tools/push_to_project/control.py index 58447a8389..96792a2e9b 100644 --- a/client/ayon_core/tools/push_to_project/control.py +++ b/client/ayon_core/tools/push_to_project/control.py @@ -169,13 +169,16 @@ class PushToContextController: return self._integrate_model.get_item_status(item_id) # Processing methods - def submit(self, wait=True): + def submit(self, wait=True, context_only=False): if not self._submission_enabled: return if self._process_thread is not None: return + if context_only: + return + item_id = self._integrate_model.create_process_item( self._src_project_name, self._src_version_id, diff --git a/client/ayon_core/tools/push_to_project/main.py b/client/ayon_core/tools/push_to_project/main.py index a6ff38c16f..d230f6a660 100644 --- a/client/ayon_core/tools/push_to_project/main.py +++ b/client/ayon_core/tools/push_to_project/main.py @@ -4,14 +4,20 @@ from ayon_core.tools.utils import get_ayon_qt_app from ayon_core.tools.push_to_project.ui import PushToContextSelectWindow -def main_show(project_name, version_id): - app = get_ayon_qt_app() - - window = PushToContextSelectWindow() +def main_show(project_name, version_id, library_filter, context_only): + window = PushToContextSelectWindow( + library_filter=library_filter, context_only=context_only + ) window.show() window.set_source(project_name, version_id) - app.exec_() + if __name__ == "__main__": + app = get_ayon_qt_app() + app.exec_() + else: + window.exec_() + + return window.context @click.command() diff --git a/client/ayon_core/tools/push_to_project/ui/window.py b/client/ayon_core/tools/push_to_project/ui/window.py index 4d64509afd..2a26388221 100644 --- a/client/ayon_core/tools/push_to_project/ui/window.py +++ b/client/ayon_core/tools/push_to_project/ui/window.py @@ -14,12 +14,16 @@ from ayon_core.tools.push_to_project.control import ( ) -class PushToContextSelectWindow(QtWidgets.QWidget): - def __init__(self, controller=None): +class PushToContextSelectWindow(QtWidgets.QDialog): + def __init__( + self, controller=None, library_filter=True, context_only=False + ): super(PushToContextSelectWindow, self).__init__() if controller is None: controller = PushToContextController() self._controller = controller + self.context_only = context_only + self.context = None self.setWindowTitle("Push to project (select context)") self.setWindowIcon(QtGui.QIcon(get_app_icon_path())) @@ -45,7 +49,9 @@ class PushToContextSelectWindow(QtWidgets.QWidget): projects_combobox = ProjectsCombobox(controller, context_widget) projects_combobox.set_select_item_visible(True) - projects_combobox.set_standard_filter_enabled(True) + projects_combobox.set_standard_filter_enabled(False) + if library_filter: + projects_combobox.set_standard_filter_enabled(True) context_splitter = QtWidgets.QSplitter( QtCore.Qt.Vertical, context_widget @@ -89,13 +95,13 @@ class PushToContextSelectWindow(QtWidgets.QWidget): # --- Buttons widget --- btns_widget = QtWidgets.QWidget(self) cancel_btn = QtWidgets.QPushButton("Cancel", btns_widget) - publish_btn = QtWidgets.QPushButton("Publish", btns_widget) + push_btn = QtWidgets.QPushButton("Push", btns_widget) btns_layout = QtWidgets.QHBoxLayout(btns_widget) btns_layout.setContentsMargins(0, 0, 0, 0) btns_layout.addStretch(1) btns_layout.addWidget(cancel_btn, 0) - btns_layout.addWidget(publish_btn, 0) + btns_layout.addWidget(push_btn, 0) sep_1 = SeparatorWidget(parent=main_context_widget) sep_2 = SeparatorWidget(parent=main_context_widget) @@ -160,7 +166,7 @@ class PushToContextSelectWindow(QtWidgets.QWidget): variant_input.textChanged.connect(self._on_variant_change) comment_input.textChanged.connect(self._on_comment_change) - publish_btn.clicked.connect(self._on_select_click) + push_btn.clicked.connect(self._on_select_click) cancel_btn.clicked.connect(self._on_close_click) overlay_close_btn.clicked.connect(self._on_close_click) overlay_try_btn.clicked.connect(self._on_try_again_click) @@ -206,7 +212,7 @@ class PushToContextSelectWindow(QtWidgets.QWidget): self._folder_name_input = folder_name_input self._comment_input = comment_input - self._publish_btn = publish_btn + self._push_btn = push_btn self._overlay_widget = overlay_widget self._overlay_close_btn = overlay_close_btn @@ -234,7 +240,7 @@ class PushToContextSelectWindow(QtWidgets.QWidget): self._variant_is_valid = None self._folder_is_valid = None - publish_btn.setEnabled(False) + push_btn.setEnabled(False) overlay_close_btn.setVisible(False) overlay_try_btn.setVisible(False) @@ -372,13 +378,30 @@ class PushToContextSelectWindow(QtWidgets.QWidget): set_style_property(self._variant_input, "state", state) def _on_submission_change(self, event): - self._publish_btn.setEnabled(event["enabled"]) + self._push_btn.setEnabled(event["enabled"]) def _on_close_click(self): self.close() def _on_select_click(self): - self._process_item_id = self._controller.submit(wait=False) + result = self._controller.submit( + wait=True, context_only=self.context_only + ) + + if self.context_only: + user_values = self._controller.get_user_values() + selection_model = self._controller._selection_model + self.context = { + "project_name": selection_model._project_name, + "folder_id": selection_model._folder_id, + "task_id": selection_model._task_id, + "variant": user_values["variant"], + "comment": user_values["comment"], + "folder_name": user_values["new_folder_name"] + } + self.close() + + self._process_item = result def _on_try_again_click(self): self._process_item_id = None From e0ad6af4fb841a5ca923e0fa59295ce4880f48aa Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Tue, 30 Apr 2024 16:34:28 +0100 Subject: [PATCH 02/34] Update client/ayon_core/hosts/nuke/api/push_to_project.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/hosts/nuke/api/push_to_project.py | 1 - 1 file changed, 1 deletion(-) diff --git a/client/ayon_core/hosts/nuke/api/push_to_project.py b/client/ayon_core/hosts/nuke/api/push_to_project.py index a67a032179..b58dd99734 100644 --- a/client/ayon_core/hosts/nuke/api/push_to_project.py +++ b/client/ayon_core/hosts/nuke/api/push_to_project.py @@ -56,7 +56,6 @@ def main(): folder = get_folder_by_id(project_name, context["folder_id"]) task = get_task_by_id(project_name, context["task_id"]) host = registered_host() - ayon_settings = get_ayon_settings() project_settings = get_project_settings(project_name) anatomy = Anatomy(project_name) From 81a75f7788f3debd781a851a48c23ce539ba1f36 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Tue, 30 Apr 2024 16:34:42 +0100 Subject: [PATCH 03/34] Update client/ayon_core/hosts/nuke/api/push_to_project.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/hosts/nuke/api/push_to_project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/nuke/api/push_to_project.py b/client/ayon_core/hosts/nuke/api/push_to_project.py index b58dd99734..cd7e522d06 100644 --- a/client/ayon_core/hosts/nuke/api/push_to_project.py +++ b/client/ayon_core/hosts/nuke/api/push_to_project.py @@ -60,7 +60,7 @@ def main(): anatomy = Anatomy(project_name) workdir_data = get_template_data( - project, folder, task, host.name, ayon_settings + project, folder, task, host.name, project_settings ) workdir = get_workdir_with_workdir_data( From 5f858139a7ffb57f65a93d904fc7c71cfb408094 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Tue, 30 Apr 2024 16:34:51 +0100 Subject: [PATCH 04/34] Update client/ayon_core/hosts/nuke/api/push_to_project.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/hosts/nuke/api/push_to_project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/nuke/api/push_to_project.py b/client/ayon_core/hosts/nuke/api/push_to_project.py index cd7e522d06..75ce08fb71 100644 --- a/client/ayon_core/hosts/nuke/api/push_to_project.py +++ b/client/ayon_core/hosts/nuke/api/push_to_project.py @@ -25,7 +25,7 @@ def bake_container(container): for count in range(0, node.numKnobs()): knob = node.knob(count) - # All knobs from "OpenPype" tab knob onwards. + # All knobs from "AYON" tab knob onwards. if knob.name() == "AYON": remove = True From 7411f2181c8ae4ec6e31639eb588e693b3f9554a Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Tue, 30 Apr 2024 16:35:53 +0100 Subject: [PATCH 05/34] Update client/ayon_core/hosts/nuke/api/push_to_project.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/hosts/nuke/api/push_to_project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/nuke/api/push_to_project.py b/client/ayon_core/hosts/nuke/api/push_to_project.py index 75ce08fb71..2f14f4e5f4 100644 --- a/client/ayon_core/hosts/nuke/api/push_to_project.py +++ b/client/ayon_core/hosts/nuke/api/push_to_project.py @@ -26,7 +26,7 @@ def bake_container(container): knob = node.knob(count) # All knobs from "AYON" tab knob onwards. - if knob.name() == "AYON": + if knob.name() == MENU_LABEL: remove = True if remove: From 80f340cb6ce2cd3ab1bd51238660c36d6f32db31 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Tue, 30 Apr 2024 16:49:13 +0100 Subject: [PATCH 06/34] Separate show method --- .../hosts/nuke/api/push_to_project.py | 7 ++++--- .../ayon_core/tools/push_to_project/main.py | 20 +++++++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/client/ayon_core/hosts/nuke/api/push_to_project.py b/client/ayon_core/hosts/nuke/api/push_to_project.py index 2f14f4e5f4..b26e7f9aff 100644 --- a/client/ayon_core/hosts/nuke/api/push_to_project.py +++ b/client/ayon_core/hosts/nuke/api/push_to_project.py @@ -3,13 +3,14 @@ import shutil import os from ayon_api import get_project, get_folder_by_id, get_task_by_id -from ayon_core.settings import get_ayon_settings, get_project_settings +from ayon_core.settings import get_project_settings from ayon_core.pipeline import Anatomy, registered_host from ayon_core.pipeline.template_data import get_template_data from ayon_core.pipeline.workfile import get_workdir_with_workdir_data -from ayon_core.tools.push_to_project.main import main_show +from ayon_core.tools.push_to_project.main import show from .utils import bake_gizmos_recursively +from .lib import MENU_LABEL import nuke @@ -45,7 +46,7 @@ def bake_container(container): def main(): - context = main_show("", "", False, True) + context = show("", "", False, True) if context is None: return diff --git a/client/ayon_core/tools/push_to_project/main.py b/client/ayon_core/tools/push_to_project/main.py index d230f6a660..bfb921a2b7 100644 --- a/client/ayon_core/tools/push_to_project/main.py +++ b/client/ayon_core/tools/push_to_project/main.py @@ -4,22 +4,26 @@ from ayon_core.tools.utils import get_ayon_qt_app from ayon_core.tools.push_to_project.ui import PushToContextSelectWindow -def main_show(project_name, version_id, library_filter, context_only): +def show(project_name, version_id, library_filter, context_only): window = PushToContextSelectWindow( library_filter=library_filter, context_only=context_only ) window.show() window.set_source(project_name, version_id) - - if __name__ == "__main__": - app = get_ayon_qt_app() - app.exec_() - else: - window.exec_() - + window.exec_() return window.context +def main_show(project_name, version_id): + app = get_ayon_qt_app() + + window = PushToContextSelectWindow() + window.show() + window.set_source(project_name, version_id) + + app.exec_() + + @click.command() @click.option("--project", help="Source project name") @click.option("--version", help="Source version id") From 5564f07a37aba1688b2e7e5b7988ceacfc4314c0 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Tue, 7 May 2024 14:09:39 +0100 Subject: [PATCH 07/34] Use context_dialog --- client/ayon_core/hosts/nuke/api/push_to_project.py | 4 ++-- client/ayon_core/tools/context_dialog/__init__.py | 3 ++- client/ayon_core/tools/context_dialog/window.py | 14 +++++++++++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/client/ayon_core/hosts/nuke/api/push_to_project.py b/client/ayon_core/hosts/nuke/api/push_to_project.py index b26e7f9aff..7d6bfa0f32 100644 --- a/client/ayon_core/hosts/nuke/api/push_to_project.py +++ b/client/ayon_core/hosts/nuke/api/push_to_project.py @@ -7,7 +7,7 @@ from ayon_core.settings import get_project_settings from ayon_core.pipeline import Anatomy, registered_host from ayon_core.pipeline.template_data import get_template_data from ayon_core.pipeline.workfile import get_workdir_with_workdir_data -from ayon_core.tools.push_to_project.main import show +from ayon_core.tools.context_dialog import show from .utils import bake_gizmos_recursively from .lib import MENU_LABEL @@ -46,7 +46,7 @@ def bake_container(container): def main(): - context = show("", "", False, True) + context = show() if context is None: return diff --git a/client/ayon_core/tools/context_dialog/__init__.py b/client/ayon_core/tools/context_dialog/__init__.py index 4fb912fb62..66920c583c 100644 --- a/client/ayon_core/tools/context_dialog/__init__.py +++ b/client/ayon_core/tools/context_dialog/__init__.py @@ -1,7 +1,8 @@ -from .window import ContextDialog, main +from .window import ContextDialog, main, show __all__ = ( "ContextDialog", "main", + "show" ) diff --git a/client/ayon_core/tools/context_dialog/window.py b/client/ayon_core/tools/context_dialog/window.py index 828d771142..f235aa85d8 100644 --- a/client/ayon_core/tools/context_dialog/window.py +++ b/client/ayon_core/tools/context_dialog/window.py @@ -343,7 +343,7 @@ class ContextDialogController: def store_output(self): if not self._output_path: - return + return self.get_selected_context() dirpath = os.path.dirname(self._output_path) os.makedirs(dirpath, exist_ok=True) @@ -791,3 +791,15 @@ def main( window.show() app.exec_() controller.store_output() + + +def show( + strict=True +): + controller = ContextDialogController() + controller.set_strict(strict) + window = ContextDialog(controller=controller) + window.show() + window.exec_() + + return controller.store_output() From 7dd6f28e8dda2e41b4443577e1456aa415cf160a Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Tue, 7 May 2024 14:12:39 +0100 Subject: [PATCH 08/34] Revert changes to push_to_project --- .../tools/push_to_project/control.py | 5 +-- .../ayon_core/tools/push_to_project/main.py | 10 ----- .../tools/push_to_project/ui/window.py | 43 +++++-------------- 3 files changed, 11 insertions(+), 47 deletions(-) diff --git a/client/ayon_core/tools/push_to_project/control.py b/client/ayon_core/tools/push_to_project/control.py index 96792a2e9b..58447a8389 100644 --- a/client/ayon_core/tools/push_to_project/control.py +++ b/client/ayon_core/tools/push_to_project/control.py @@ -169,16 +169,13 @@ class PushToContextController: return self._integrate_model.get_item_status(item_id) # Processing methods - def submit(self, wait=True, context_only=False): + def submit(self, wait=True): if not self._submission_enabled: return if self._process_thread is not None: return - if context_only: - return - item_id = self._integrate_model.create_process_item( self._src_project_name, self._src_version_id, diff --git a/client/ayon_core/tools/push_to_project/main.py b/client/ayon_core/tools/push_to_project/main.py index bfb921a2b7..a6ff38c16f 100644 --- a/client/ayon_core/tools/push_to_project/main.py +++ b/client/ayon_core/tools/push_to_project/main.py @@ -4,16 +4,6 @@ from ayon_core.tools.utils import get_ayon_qt_app from ayon_core.tools.push_to_project.ui import PushToContextSelectWindow -def show(project_name, version_id, library_filter, context_only): - window = PushToContextSelectWindow( - library_filter=library_filter, context_only=context_only - ) - window.show() - window.set_source(project_name, version_id) - window.exec_() - return window.context - - def main_show(project_name, version_id): app = get_ayon_qt_app() diff --git a/client/ayon_core/tools/push_to_project/ui/window.py b/client/ayon_core/tools/push_to_project/ui/window.py index 2a26388221..4d64509afd 100644 --- a/client/ayon_core/tools/push_to_project/ui/window.py +++ b/client/ayon_core/tools/push_to_project/ui/window.py @@ -14,16 +14,12 @@ from ayon_core.tools.push_to_project.control import ( ) -class PushToContextSelectWindow(QtWidgets.QDialog): - def __init__( - self, controller=None, library_filter=True, context_only=False - ): +class PushToContextSelectWindow(QtWidgets.QWidget): + def __init__(self, controller=None): super(PushToContextSelectWindow, self).__init__() if controller is None: controller = PushToContextController() self._controller = controller - self.context_only = context_only - self.context = None self.setWindowTitle("Push to project (select context)") self.setWindowIcon(QtGui.QIcon(get_app_icon_path())) @@ -49,9 +45,7 @@ class PushToContextSelectWindow(QtWidgets.QDialog): projects_combobox = ProjectsCombobox(controller, context_widget) projects_combobox.set_select_item_visible(True) - projects_combobox.set_standard_filter_enabled(False) - if library_filter: - projects_combobox.set_standard_filter_enabled(True) + projects_combobox.set_standard_filter_enabled(True) context_splitter = QtWidgets.QSplitter( QtCore.Qt.Vertical, context_widget @@ -95,13 +89,13 @@ class PushToContextSelectWindow(QtWidgets.QDialog): # --- Buttons widget --- btns_widget = QtWidgets.QWidget(self) cancel_btn = QtWidgets.QPushButton("Cancel", btns_widget) - push_btn = QtWidgets.QPushButton("Push", btns_widget) + publish_btn = QtWidgets.QPushButton("Publish", btns_widget) btns_layout = QtWidgets.QHBoxLayout(btns_widget) btns_layout.setContentsMargins(0, 0, 0, 0) btns_layout.addStretch(1) btns_layout.addWidget(cancel_btn, 0) - btns_layout.addWidget(push_btn, 0) + btns_layout.addWidget(publish_btn, 0) sep_1 = SeparatorWidget(parent=main_context_widget) sep_2 = SeparatorWidget(parent=main_context_widget) @@ -166,7 +160,7 @@ class PushToContextSelectWindow(QtWidgets.QDialog): variant_input.textChanged.connect(self._on_variant_change) comment_input.textChanged.connect(self._on_comment_change) - push_btn.clicked.connect(self._on_select_click) + publish_btn.clicked.connect(self._on_select_click) cancel_btn.clicked.connect(self._on_close_click) overlay_close_btn.clicked.connect(self._on_close_click) overlay_try_btn.clicked.connect(self._on_try_again_click) @@ -212,7 +206,7 @@ class PushToContextSelectWindow(QtWidgets.QDialog): self._folder_name_input = folder_name_input self._comment_input = comment_input - self._push_btn = push_btn + self._publish_btn = publish_btn self._overlay_widget = overlay_widget self._overlay_close_btn = overlay_close_btn @@ -240,7 +234,7 @@ class PushToContextSelectWindow(QtWidgets.QDialog): self._variant_is_valid = None self._folder_is_valid = None - push_btn.setEnabled(False) + publish_btn.setEnabled(False) overlay_close_btn.setVisible(False) overlay_try_btn.setVisible(False) @@ -378,30 +372,13 @@ class PushToContextSelectWindow(QtWidgets.QDialog): set_style_property(self._variant_input, "state", state) def _on_submission_change(self, event): - self._push_btn.setEnabled(event["enabled"]) + self._publish_btn.setEnabled(event["enabled"]) def _on_close_click(self): self.close() def _on_select_click(self): - result = self._controller.submit( - wait=True, context_only=self.context_only - ) - - if self.context_only: - user_values = self._controller.get_user_values() - selection_model = self._controller._selection_model - self.context = { - "project_name": selection_model._project_name, - "folder_id": selection_model._folder_id, - "task_id": selection_model._task_id, - "variant": user_values["variant"], - "comment": user_values["comment"], - "folder_name": user_values["new_folder_name"] - } - self.close() - - self._process_item = result + self._process_item_id = self._controller.submit(wait=False) def _on_try_again_click(self): self._process_item_id = None From 2082214b356671d9a28854ad7ee2a32e2509d1db Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Tue, 7 May 2024 21:11:29 +0100 Subject: [PATCH 09/34] BigRoy feedback --- client/ayon_core/hosts/nuke/api/push_to_project.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/hosts/nuke/api/push_to_project.py b/client/ayon_core/hosts/nuke/api/push_to_project.py index 7d6bfa0f32..fde26bfe81 100644 --- a/client/ayon_core/hosts/nuke/api/push_to_project.py +++ b/client/ayon_core/hosts/nuke/api/push_to_project.py @@ -7,7 +7,7 @@ from ayon_core.settings import get_project_settings from ayon_core.pipeline import Anatomy, registered_host from ayon_core.pipeline.template_data import get_template_data from ayon_core.pipeline.workfile import get_workdir_with_workdir_data -from ayon_core.tools.context_dialog import show +from ayon_core.tools import context_dialog from .utils import bake_gizmos_recursively from .lib import MENU_LABEL @@ -46,7 +46,7 @@ def bake_container(container): def main(): - context = show() + context = context_dialog.show() if context is None: return From 92f9fda546c09f097479bc3fc9db1fd642ced0e5 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Thu, 23 May 2024 23:02:28 +0100 Subject: [PATCH 10/34] Update client/ayon_core/tools/context_dialog/window.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/tools/context_dialog/window.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/client/ayon_core/tools/context_dialog/window.py b/client/ayon_core/tools/context_dialog/window.py index f235aa85d8..532bfe878e 100644 --- a/client/ayon_core/tools/context_dialog/window.py +++ b/client/ayon_core/tools/context_dialog/window.py @@ -793,13 +793,10 @@ def main( controller.store_output() -def show( - strict=True -): +def ask_for_context(strict=True): controller = ContextDialogController() controller.set_strict(strict) window = ContextDialog(controller=controller) - window.show() window.exec_() - return controller.store_output() + return controller.get_selected_context() From f73d0a544d746ad1dd8f252c11720404912eb271 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Thu, 23 May 2024 23:02:34 +0100 Subject: [PATCH 11/34] Update client/ayon_core/tools/context_dialog/window.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/tools/context_dialog/window.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/tools/context_dialog/window.py b/client/ayon_core/tools/context_dialog/window.py index 532bfe878e..ea5fdfbaec 100644 --- a/client/ayon_core/tools/context_dialog/window.py +++ b/client/ayon_core/tools/context_dialog/window.py @@ -343,7 +343,7 @@ class ContextDialogController: def store_output(self): if not self._output_path: - return self.get_selected_context() + return dirpath = os.path.dirname(self._output_path) os.makedirs(dirpath, exist_ok=True) From 71471cf72592d8a155a2384ff07a84c8a182df54 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 23 May 2024 23:07:02 +0100 Subject: [PATCH 12/34] Fixes for ask_for_context --- client/ayon_core/hosts/nuke/api/push_to_project.py | 2 +- client/ayon_core/tools/context_dialog/__init__.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/hosts/nuke/api/push_to_project.py b/client/ayon_core/hosts/nuke/api/push_to_project.py index fde26bfe81..f145ed652b 100644 --- a/client/ayon_core/hosts/nuke/api/push_to_project.py +++ b/client/ayon_core/hosts/nuke/api/push_to_project.py @@ -46,7 +46,7 @@ def bake_container(container): def main(): - context = context_dialog.show() + context = context_dialog.ask_for_context() if context is None: return diff --git a/client/ayon_core/tools/context_dialog/__init__.py b/client/ayon_core/tools/context_dialog/__init__.py index 66920c583c..8a77a46109 100644 --- a/client/ayon_core/tools/context_dialog/__init__.py +++ b/client/ayon_core/tools/context_dialog/__init__.py @@ -1,8 +1,8 @@ -from .window import ContextDialog, main, show +from .window import ContextDialog, main, ask_for_context __all__ = ( "ContextDialog", "main", - "show" + "ask_for_context" ) From 9e181340c4f5ab2e1843787353daa48b581b4b0a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 7 Jun 2024 18:09:57 +0200 Subject: [PATCH 13/34] Remove deprecated ExtractReviewDataMov settings and related code. Refactor ExtractReviewIntermediates settings. --- .../publish/extract_review_intermediates.py | 23 ------ .../nuke/server/settings/publish_plugins.py | 72 ------------------- 2 files changed, 95 deletions(-) diff --git a/server_addon/nuke/client/ayon_nuke/plugins/publish/extract_review_intermediates.py b/server_addon/nuke/client/ayon_nuke/plugins/publish/extract_review_intermediates.py index b7bb911347..48c9988c5b 100644 --- a/server_addon/nuke/client/ayon_nuke/plugins/publish/extract_review_intermediates.py +++ b/server_addon/nuke/client/ayon_nuke/plugins/publish/extract_review_intermediates.py @@ -28,29 +28,6 @@ class ExtractReviewIntermediates(publish.Extractor): viewer_lut_raw = None outputs = {} - @classmethod - def apply_settings(cls, project_settings): - """Apply the settings from the deprecated - ExtractReviewDataMov plugin for backwards compatibility - """ - nuke_publish = project_settings["nuke"]["publish"] - deprecated_setting = nuke_publish["ExtractReviewDataMov"] - current_setting = nuke_publish.get("ExtractReviewIntermediates") - if not deprecated_setting["enabled"] and ( - not current_setting["enabled"] - ): - cls.enabled = False - - if deprecated_setting["enabled"]: - # Use deprecated settings if they are still enabled - cls.viewer_lut_raw = deprecated_setting["viewer_lut_raw"] - cls.outputs = deprecated_setting["outputs"] - elif current_setting is None: - pass - elif current_setting["enabled"]: - cls.viewer_lut_raw = current_setting["viewer_lut_raw"] - cls.outputs = current_setting["outputs"] - def process(self, instance): # TODO 'families' should not be included for filtering of outputs families = set(instance.data["families"]) diff --git a/server_addon/nuke/server/settings/publish_plugins.py b/server_addon/nuke/server/settings/publish_plugins.py index 6c37ecd37a..c06d60abc8 100644 --- a/server_addon/nuke/server/settings/publish_plugins.py +++ b/server_addon/nuke/server/settings/publish_plugins.py @@ -155,18 +155,6 @@ class IntermediateOutputModel(BaseSettingsModel): title="Custom tags", default_factory=list) -class ExtractReviewDataMovModel(BaseSettingsModel): - """[deprecated] use Extract Review Data Baking - Streams instead. - """ - enabled: bool = SettingsField(title="Enabled") - viewer_lut_raw: bool = SettingsField(title="Viewer lut raw") - outputs: list[IntermediateOutputModel] = SettingsField( - default_factory=list, - title="Baking streams" - ) - - class ExtractReviewIntermediatesModel(BaseSettingsModel): enabled: bool = SettingsField(title="Enabled") viewer_lut_raw: bool = SettingsField(title="Viewer lut raw") @@ -259,10 +247,6 @@ class PublishPluginsModel(BaseSettingsModel): title="Extract Review Data Lut", default_factory=ExtractReviewDataLutModel ) - ExtractReviewDataMov: ExtractReviewDataMovModel = SettingsField( - title="Extract Review Data Mov", - default_factory=ExtractReviewDataMovModel - ) ExtractReviewIntermediates: ExtractReviewIntermediatesModel = ( SettingsField( title="Extract Review Intermediates", @@ -332,62 +316,6 @@ DEFAULT_PUBLISH_PLUGIN_SETTINGS = { "ExtractReviewDataLut": { "enabled": False }, - "ExtractReviewDataMov": { - "enabled": False, - "viewer_lut_raw": False, - "outputs": [ - { - "name": "baking", - "publish": False, - "filter": { - "task_types": [], - "product_types": [], - "product_names": [] - }, - "read_raw": False, - "viewer_process_override": "", - "bake_viewer_process": True, - "bake_viewer_input_process": True, - "reformat_nodes_config": { - "enabled": False, - "reposition_nodes": [ - { - "node_class": "Reformat", - "knobs": [ - { - "type": "text", - "name": "type", - "text": "to format" - }, - { - "type": "text", - "name": "format", - "text": "HD_1080" - }, - { - "type": "text", - "name": "filter", - "text": "Lanczos6" - }, - { - "type": "boolean", - "name": "black_outside", - "boolean": True - }, - { - "type": "boolean", - "name": "pbb", - "boolean": False - } - ] - } - ] - }, - "extension": "mov", - "add_custom_tags": [] - } - ] - }, "ExtractReviewIntermediates": { "enabled": True, "viewer_lut_raw": False, From 6ecff1924e1f4cc5c69f4727cf92ee7838dbd3be Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 7 Jun 2024 18:10:13 +0200 Subject: [PATCH 14/34] Update version numbers to 0.2.3 in package and addon files. --- server_addon/nuke/client/ayon_nuke/version.py | 2 +- server_addon/nuke/package.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server_addon/nuke/client/ayon_nuke/version.py b/server_addon/nuke/client/ayon_nuke/version.py index 1130392592..2262afb410 100644 --- a/server_addon/nuke/client/ayon_nuke/version.py +++ b/server_addon/nuke/client/ayon_nuke/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring AYON addon 'nuke' version.""" -__version__ = "0.2.2" +__version__ = "0.2.3" diff --git a/server_addon/nuke/package.py b/server_addon/nuke/package.py index 9081205c44..7347d21b35 100644 --- a/server_addon/nuke/package.py +++ b/server_addon/nuke/package.py @@ -1,6 +1,6 @@ name = "nuke" title = "Nuke" -version = "0.2.2" +version = "0.2.3" client_dir = "ayon_nuke" From 67b59f9af48ab927c0e4cc1cfe7903cefcdf98d1 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 7 Jun 2024 18:10:38 +0200 Subject: [PATCH 15/34] introducing new baking targeting Added ColorspaceConfigurationModel for baking target selection and override in various settings to enhance flexibility and customization. --- server_addon/nuke/server/settings/common.py | 50 +++++++++++++++++++ server_addon/nuke/server/settings/imageio.py | 21 +++++--- .../nuke/server/settings/publish_plugins.py | 40 ++++++++++++--- 3 files changed, 95 insertions(+), 16 deletions(-) diff --git a/server_addon/nuke/server/settings/common.py b/server_addon/nuke/server/settings/common.py index e0ee2b7b3d..50313fa5ef 100644 --- a/server_addon/nuke/server/settings/common.py +++ b/server_addon/nuke/server/settings/common.py @@ -133,3 +133,53 @@ class KnobModel(BaseSettingsModel): "", title="Expression" ) + + +colorspace_types_enum = [ + {"value": "colorspace", "label": "Use Colorspace"}, + {"value": "display_view", "label": "Use Display & View"}, +] + + +class DisplayAndViewProfileModel(BaseSettingsModel): + _layout = "expanded" + + display: str = SettingsField( + "", + title="Display", + description="What display to use", + ) + + view: str = SettingsField( + "", + title="View", + description="What view to use", + ) + + +class ColorspaceConfigurationModel(BaseSettingsModel): + enabled: bool = SettingsField( + False, + title="Enabled", + description="Enable baking target (colorspace or display/view)", + ) + + type: str = SettingsField( + "colorspace", + title="Target baking type", + description="Switch between different knob types", + enum_resolver=lambda: colorspace_types_enum, + conditionalEnum=True, + ) + + colorspace: str = SettingsField( + "", + title="Colorspace", + description="What colorspace name to use", + ) + + display_view: DisplayAndViewProfileModel = SettingsField( + title="Display & View", + description="What display & view to use", + default_factory=DisplayAndViewProfileModel, + ) diff --git a/server_addon/nuke/server/settings/imageio.py b/server_addon/nuke/server/settings/imageio.py index 9cdb0bf1d7..93433f3f54 100644 --- a/server_addon/nuke/server/settings/imageio.py +++ b/server_addon/nuke/server/settings/imageio.py @@ -6,8 +6,10 @@ from ayon_server.settings import ( ensure_unique_names, ) -from .common import KnobModel - +from .common import ( + KnobModel, + ColorspaceConfigurationModel, +) class NodesModel(BaseSettingsModel): _layout = "expanded" @@ -198,12 +200,10 @@ class ImageIOSettings(BaseSettingsModel): Creation of new viewer node at knob viewerProcess""" ) - """# TODO: enhance settings with host api: - to restructure settings for simplification. - - now: nuke/imageio/baking/viewerProcess - future: nuke/imageio/baking - """ + baking_target: ColorspaceConfigurationModel = SettingsField( + default_factory=ColorspaceConfigurationModel, + title="Baking Target Colorspace" + ) baking: ViewProcessModel = SettingsField( default_factory=ViewProcessModel, title="Baking", @@ -235,6 +235,11 @@ DEFAULT_IMAGEIO_SETTINGS = { "viewerProcess": "ACES/sRGB", "output_transform": "ACES/sRGB" }, + "baking_target": { + "enabled": False, + "type": "colorspace", + "colorspace": "" + }, "baking": { "viewerProcess": "ACES/Rec.709", "output_transform": "ACES/Rec.709" diff --git a/server_addon/nuke/server/settings/publish_plugins.py b/server_addon/nuke/server/settings/publish_plugins.py index c06d60abc8..1373b3b13d 100644 --- a/server_addon/nuke/server/settings/publish_plugins.py +++ b/server_addon/nuke/server/settings/publish_plugins.py @@ -5,7 +5,11 @@ from ayon_server.settings import ( ensure_unique_names, task_types_enum ) -from .common import KnobModel, validate_json_dict +from .common import ( + KnobModel, + ColorspaceConfigurationModel, + validate_json_dict, +) def nuke_render_publish_types_enum(): @@ -130,19 +134,30 @@ class IntermediateOutputModel(BaseSettingsModel): title="Filter", default_factory=BakingStreamFilterModel) read_raw: bool = SettingsField( False, - title="Read raw switch" - ) - viewer_process_override: str = SettingsField( - "", - title="Viewer process override" + title="Input read node RAW switch" ) bake_viewer_process: bool = SettingsField( True, - title="Bake viewer process" + title="Bake viewer process", + section="Baking target", + ) + colorspace_override: ColorspaceConfigurationModel = SettingsField( + title="Target baking colorspace override", + description="Override Baking target with colorspace or display/view", + default_factory=ColorspaceConfigurationModel + ) + viewer_process_override: str = SettingsField( + "", + title="Viewer process override", + description=( + "[DEPRECATED - use 'Target baking colorspace override'] " + "Override viewer process node (LUT)" + ), ) bake_viewer_input_process: bool = SettingsField( True, - title="Bake viewer input process node (LUT)" + title="Bake viewer input process node (LUT)", + section="Baking additional", ) reformat_nodes_config: ReformatNodesConfigModel = SettingsField( default_factory=ReformatNodesConfigModel, @@ -330,6 +345,15 @@ DEFAULT_PUBLISH_PLUGIN_SETTINGS = { }, "read_raw": False, "viewer_process_override": "", + "colorspace_override": { + "enabled": False, + "type": "colorspace", + "colorspace": "", + "display_view": { + "display": "", + "view": "" + } + }, "bake_viewer_process": True, "bake_viewer_input_process": True, "reformat_nodes_config": { From 35e180149b4e6a2a8bcc1aff61cd95b253cddfb8 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 7 Jun 2024 18:19:18 +0200 Subject: [PATCH 16/34] Update descriptions for 'View' and 'Colorspace' settings. Add deprecation notice for 'Baking' setting in ImageIOSettings. - Update descriptions for 'View' and 'Colorspace' settings to include information about using Anatomy context tokens. - Add a deprecation notice for the 'Baking' setting in ImageIOSettings, recommending the use of 'Baking Target Colorspace'. --- server_addon/nuke/server/settings/common.py | 10 ++++++++-- server_addon/nuke/server/settings/imageio.py | 5 +++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/server_addon/nuke/server/settings/common.py b/server_addon/nuke/server/settings/common.py index 50313fa5ef..54884ac828 100644 --- a/server_addon/nuke/server/settings/common.py +++ b/server_addon/nuke/server/settings/common.py @@ -153,7 +153,10 @@ class DisplayAndViewProfileModel(BaseSettingsModel): view: str = SettingsField( "", title="View", - description="What view to use", + description=( + "What view to use. Anatomy context tokens can " + "be used to dynamically set the value." + ), ) @@ -175,7 +178,10 @@ class ColorspaceConfigurationModel(BaseSettingsModel): colorspace: str = SettingsField( "", title="Colorspace", - description="What colorspace name to use", + description=( + "What colorspace name to use. Anatomy context tokens can " + "be used to dynamically set the value." + ), ) display_view: DisplayAndViewProfileModel = SettingsField( diff --git a/server_addon/nuke/server/settings/imageio.py b/server_addon/nuke/server/settings/imageio.py index 93433f3f54..08686a08e8 100644 --- a/server_addon/nuke/server/settings/imageio.py +++ b/server_addon/nuke/server/settings/imageio.py @@ -207,8 +207,9 @@ class ImageIOSettings(BaseSettingsModel): baking: ViewProcessModel = SettingsField( default_factory=ViewProcessModel, title="Baking", - description="""Baking profile is used during - publishing baked colorspace data at knob viewerProcess""" + description="""[DEPRECATED - use 'Baking Target Colorspace' instead] + Baking profile is used during + publishing baked colorspace data at knob viewerProcess""", ) workfile: WorkfileColorspaceSettings = SettingsField( From 3b73a8881dbd7fe66e35a7cd389635c60b1053fa Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 10 Jun 2024 10:48:29 +0200 Subject: [PATCH 17/34] working on settings patching --- server_addon/nuke/server/__init__.py | 18 ++++++++-- server_addon/nuke/server/settings/__init__.py | 3 ++ .../nuke/server/settings/conversion.py | 34 +++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 server_addon/nuke/server/settings/conversion.py diff --git a/server_addon/nuke/server/__init__.py b/server_addon/nuke/server/__init__.py index aeb5e36675..0806ea8e87 100644 --- a/server_addon/nuke/server/__init__.py +++ b/server_addon/nuke/server/__init__.py @@ -1,8 +1,12 @@ -from typing import Type +from typing import Type, Any from ayon_server.addons import BaseServerAddon -from .settings import NukeSettings, DEFAULT_VALUES +from .settings import ( + NukeSettings, + DEFAULT_VALUES, + convert_settings_overrides +) class NukeAddon(BaseServerAddon): @@ -11,3 +15,13 @@ class NukeAddon(BaseServerAddon): async def get_default_settings(self): settings_model_cls = self.get_settings_model() return settings_model_cls(**DEFAULT_VALUES) + + async def convert_settings_overrides( + self, + source_version: str, + overrides: dict[str, Any], + ) -> dict[str, Any]: + convert_settings_overrides(source_version, overrides) + # Use super conversion + return await super().convert_settings_overrides( + source_version, overrides) diff --git a/server_addon/nuke/server/settings/__init__.py b/server_addon/nuke/server/settings/__init__.py index 1e58865395..da79b947f7 100644 --- a/server_addon/nuke/server/settings/__init__.py +++ b/server_addon/nuke/server/settings/__init__.py @@ -2,9 +2,12 @@ from .main import ( NukeSettings, DEFAULT_VALUES, ) +from .conversion import convert_settings_overrides __all__ = ( "NukeSettings", "DEFAULT_VALUES", + + "convert_settings_overrides", ) diff --git a/server_addon/nuke/server/settings/conversion.py b/server_addon/nuke/server/settings/conversion.py new file mode 100644 index 0000000000..e88cee884d --- /dev/null +++ b/server_addon/nuke/server/settings/conversion.py @@ -0,0 +1,34 @@ +from typing import Any + +from .publish_plugins import DEFAULT_PUBLISH_VALUES + + +def _convert_imageio_configs_0_2_2(overrides): + """Image IO settings had changed. + + 0.2.2. is the latest version using the old way. + """ + pass + + +def _convert_extract_intermediate_files_0_2_2(publish_overrides): + """Extract intermediate files settings had changed. + + 0.2.2. is the latest version using the old way. + """ + pass + + +def _convert_publish_plugins(overrides): + if "publish" not in overrides: + return + _convert_extract_intermediate_files_0_2_2(overrides["publish"]) + + +def convert_settings_overrides( + source_version: str, + overrides: dict[str, Any], +) -> dict[str, Any]: + _convert_imageio_configs_0_2_2(overrides) + _convert_publish_plugins(overrides) + return overrides From 7cb23851e1e986a9c0731305ba155c6d52638343 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 11 Jun 2024 11:56:56 +0200 Subject: [PATCH 18/34] cleanup PYTHONPATH from existing addons on update --- client/ayon_core/tools/tray/tray.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/client/ayon_core/tools/tray/tray.py b/client/ayon_core/tools/tray/tray.py index eca87eb11d..c0b90dd764 100644 --- a/client/ayon_core/tools/tray/tray.py +++ b/client/ayon_core/tools/tray/tray.py @@ -182,7 +182,27 @@ class TrayManager: }: envs.pop(key, None) + # Remove any existing addon path from 'PYTHONPATH' + addons_dir = os.environ.get("AYON_ADDONS_DIR", "") + if addons_dir: + addons_dir = os.path.normpath(addons_dir) + addons_dir = addons_dir.lower() + + pythonpath = envs.get("PYTHONPATH") or "" + new_python_paths = [] + for path in pythonpath.split(os.pathsep): + if not path: + continue + path = os.path.normpath(path) + if path.lower().startswith(addons_dir): + continue + new_python_paths.append(path) + + envs["PYTHONPATH"] = os.pathsep.join(new_python_paths) + + # Start new process run_detached_process(args, env=envs) + # Exit current tray process self.exit() def exit(self): From 66994e81ca16db06911cb9ea8fcaf2e2896e7821 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Wed, 12 Jun 2024 16:53:43 +0300 Subject: [PATCH 19/34] Get the type name from the HDA definition --- .../client/ayon_houdini/plugins/load/load_hda.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py b/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py index b04e211aa4..233ec91ced 100644 --- a/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py +++ b/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py @@ -28,14 +28,17 @@ class HdaLoader(plugin.HoudiniLoader): # Get the root node obj = hou.node("/obj") - # Create a unique name - counter = 1 namespace = namespace or context["folder"]["name"] - formatted = "{}_{}".format(namespace, name) if namespace else name - node_name = "{0}_{1:03d}".format(formatted, counter) + node_name = "{}_{}".format(namespace, name) if namespace else name hou.hda.installFile(file_path) - hda_node = obj.createNode(name, node_name) + + # Get the type name from the HDA definition. + hda_defs = hou.hda.definitionsInFile(file_path) + for hda_def in hda_defs: + type_name = hda_def.nodeTypeName() + + hda_node = obj.createNode(type_name, node_name) self[:] = [hda_node] From 92c000aabf9051bceb3764027c3afe299fb528dc Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Wed, 12 Jun 2024 16:54:31 +0300 Subject: [PATCH 20/34] create HDA with unique type name --- .../ayon_houdini/plugins/create/create_hda.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py b/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py index 6a1adce8cc..af7862b3ff 100644 --- a/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py +++ b/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py @@ -2,7 +2,11 @@ """Creator plugin for creating publishable Houdini Digital Assets.""" import ayon_api -from ayon_core.pipeline import CreatorError +from ayon_core.pipeline import ( + CreatorError, + get_current_project_name, + get_current_folder_path, +) from ayon_houdini.api import plugin import hou @@ -56,8 +60,18 @@ class CreateHDA(plugin.HoudiniCreator): raise CreatorError( "cannot create hda from node {}".format(to_hda)) + # Pick a unique type name for HDA product per folder path per project. + type_name = ( + "{project_name}{folder_path}_{node_name}".format( + project_name=get_current_project_name(), + folder_path=get_current_folder_path().replace("/","_"), + node_name=node_name + ) + ) + hda_node = to_hda.createDigitalAsset( - name=node_name, + name=type_name, + description=node_name, hda_file_name="$HIP/{}.hda".format(node_name) ) hda_node.layoutChildren() From f464d190321d4c2289eb92c98c95eeb44eb0de53 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Wed, 12 Jun 2024 18:15:04 +0300 Subject: [PATCH 21/34] use the folder_path argument instead of get_current_folder_path() --- .../houdini/client/ayon_houdini/plugins/create/create_hda.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py b/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py index af7862b3ff..694bc4f3c3 100644 --- a/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py +++ b/server_addon/houdini/client/ayon_houdini/plugins/create/create_hda.py @@ -4,8 +4,7 @@ import ayon_api from ayon_core.pipeline import ( CreatorError, - get_current_project_name, - get_current_folder_path, + get_current_project_name ) from ayon_houdini.api import plugin import hou @@ -64,7 +63,7 @@ class CreateHDA(plugin.HoudiniCreator): type_name = ( "{project_name}{folder_path}_{node_name}".format( project_name=get_current_project_name(), - folder_path=get_current_folder_path().replace("/","_"), + folder_path=folder_path.replace("/","_"), node_name=node_name ) ) From cc6c24c9829558679f41cb41427d5a938bccfa47 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Wed, 12 Jun 2024 18:29:38 +0300 Subject: [PATCH 22/34] use the first hda_def instead of using a for loop --- .../houdini/client/ayon_houdini/plugins/load/load_hda.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py b/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py index 233ec91ced..fad9281c08 100644 --- a/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py +++ b/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py @@ -35,9 +35,10 @@ class HdaLoader(plugin.HoudiniLoader): # Get the type name from the HDA definition. hda_defs = hou.hda.definitionsInFile(file_path) - for hda_def in hda_defs: - type_name = hda_def.nodeTypeName() + if not hda_defs: + raise RuntimeError(f"No HDA definitions found in file: {file_path}") + type_name = hda_defs[0].nodeTypeName() hda_node = obj.createNode(type_name, node_name) self[:] = [hda_node] From 84616064dcaf4b5ed5301e0083a8e06c4ebea833 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 13 Jun 2024 15:30:20 +0200 Subject: [PATCH 23/34] settings conversions Refactor settings conversions for better viewer configuration handling. - Added `_isGroup` attribute to models - Implemented functions to extract display and viewer from strings - Updated conversion functions for imageio settings --- server_addon/nuke/server/settings/common.py | 6 +- .../nuke/server/settings/conversion.py | 117 +++++++- server_addon/nuke/server/settings/imageio.py | 250 ++++++------------ .../nuke/server/settings/publish_plugins.py | 10 - 4 files changed, 203 insertions(+), 180 deletions(-) diff --git a/server_addon/nuke/server/settings/common.py b/server_addon/nuke/server/settings/common.py index 54884ac828..2ddbc3ca26 100644 --- a/server_addon/nuke/server/settings/common.py +++ b/server_addon/nuke/server/settings/common.py @@ -161,10 +161,14 @@ class DisplayAndViewProfileModel(BaseSettingsModel): class ColorspaceConfigurationModel(BaseSettingsModel): + _isGroup: bool = True + enabled: bool = SettingsField( False, title="Enabled", - description="Enable baking target (colorspace or display/view)", + description=( + "Enable baking target (colorspace or display/view)." + ), ) type: str = SettingsField( diff --git a/server_addon/nuke/server/settings/conversion.py b/server_addon/nuke/server/settings/conversion.py index e88cee884d..3e1ca3a0a9 100644 --- a/server_addon/nuke/server/settings/conversion.py +++ b/server_addon/nuke/server/settings/conversion.py @@ -1,6 +1,94 @@ +import re from typing import Any -from .publish_plugins import DEFAULT_PUBLISH_VALUES +from .publish_plugins import DEFAULT_PUBLISH_PLUGIN_SETTINGS + + +def _get_viewer_config_from_string(input_string): + """Convert string to display and viewer string + + Args: + input_string (str): string with viewer + + Raises: + IndexError: if more then one slash in input string + IndexError: if missing closing bracket + + Returns: + tuple[str]: display, viewer + """ + display = None + viewer = input_string + # check if () or / or \ in name + if "/" in viewer: + split = viewer.split("/") + + # rise if more then one column + if len(split) > 2: + raise IndexError( + "Viewer Input string is not correct. " + f"More then two `/` slashes! {input_string}" + ) + + viewer = split[1] + display = split[0] + elif "(" in viewer: + pattern = r"([\w\d\s\.\-]+).*[(](.*)[)]" + result_ = re.findall(pattern, viewer) + try: + result_ = result_.pop() + display = str(result_[1]).rstrip() + viewer = str(result_[0]).rstrip() + except IndexError as e: + raise IndexError( + "Viewer Input string is not correct. " + f"Missing bracket! {input_string}" + ) from e + + return (display, viewer) + + +def _convert_imageio_baking_0_2_2(overrides): + if "baking" not in overrides: + return + + baking_view_process = overrides["baking"].get("viewerProcess") + + if baking_view_process is None: + return + + display, view = _get_viewer_config_from_string(baking_view_process) + + overrides["baking_target"] = { + "enabled": True, + "type": "display_view", + "display_view": { + "display": display, + "view": view, + }, + } + + +def _convert_viewers_0_2_2(overrides): + if "viewer" not in overrides: + return + + viewer = overrides["viewer"] + + if "viewerProcess" in viewer: + viewer_process = viewer["viewerProcess"] + display, view = _get_viewer_config_from_string(viewer_process) + viewer.update({ + "display": display, + "view": view, + }) + if "output_transform" in viewer: + output_transform = viewer["output_transform"] + display, view = _get_viewer_config_from_string(output_transform) + overrides["monitor"] = { + "display": display, + "view": view, + } def _convert_imageio_configs_0_2_2(overrides): @@ -8,7 +96,13 @@ def _convert_imageio_configs_0_2_2(overrides): 0.2.2. is the latest version using the old way. """ - pass + if "imageio" not in overrides: + return + + imageio_overrides = overrides["imageio"] + + _convert_imageio_baking_0_2_2(imageio_overrides) + _convert_viewers_0_2_2(imageio_overrides) def _convert_extract_intermediate_files_0_2_2(publish_overrides): @@ -16,7 +110,24 @@ def _convert_extract_intermediate_files_0_2_2(publish_overrides): 0.2.2. is the latest version using the old way. """ - pass + # override can be either `display/view` or `view (display)` + if "ExtractReviewIntermediates" in publish_overrides: + extract_review_intermediates = publish_overrides[ + "ExtractReviewIntermediates"] + + for output in extract_review_intermediates.get("outputs", []): + if viewer_process_override := output.get("viewer_process_override"): + display, view = _get_viewer_config_from_string( + viewer_process_override) + + output["colorspace_override"] = { + "enabled": True, + "type": "display_view", + "display_view": { + "display": display, + "view": view, + }, + } def _convert_publish_plugins(overrides): diff --git a/server_addon/nuke/server/settings/imageio.py b/server_addon/nuke/server/settings/imageio.py index 08686a08e8..34deb351ed 100644 --- a/server_addon/nuke/server/settings/imageio.py +++ b/server_addon/nuke/server/settings/imageio.py @@ -11,6 +11,7 @@ from .common import ( ColorspaceConfigurationModel, ) + class NodesModel(BaseSettingsModel): _layout = "expanded" plugins: list[str] = SettingsField( @@ -54,6 +55,8 @@ class OverrideNodesModel(NodesModel): class NodesSetting(BaseSettingsModel): + _isGroup: bool = True + required_nodes: list[RequiredNodesModel] = SettingsField( title="Plugin required", default_factory=list @@ -85,6 +88,8 @@ def ocio_configs_switcher_enum(): class WorkfileColorspaceSettings(BaseSettingsModel): """Nuke workfile colorspace preset. """ + _isGroup: bool = True + color_management: Literal["Nuke", "OCIO"] = SettingsField( title="Color Management Workflow" ) @@ -127,6 +132,8 @@ class ReadColorspaceRulesItems(BaseSettingsModel): class RegexInputsModel(BaseSettingsModel): + _isGroup: bool = True + inputs: list[ReadColorspaceRulesItems] = SettingsField( default_factory=list, title="Inputs" @@ -134,15 +141,44 @@ class RegexInputsModel(BaseSettingsModel): class ViewProcessModel(BaseSettingsModel): - viewerProcess: str = SettingsField( - title="Viewer Process Name" + _isGroup: bool = True + + display: str = SettingsField( + "", + title="Display", + description="What display to use", ) - output_transform: str = SettingsField( - title="Output Transform" + view: str = SettingsField( + "", + title="View", + description=( + "What view to use. Anatomy context tokens can " + "be used to dynamically set the value." + ), + ) + + +class MonitorProcessModel(BaseSettingsModel): + _isGroup: bool = True + + display: str = SettingsField( + "", + title="Display", + description="What display to use", + ) + view: str = SettingsField( + "", + title="View", + description=( + "What view to use. Anatomy context tokens can " + "be used to dynamically set the value." + ), ) class ImageIOConfigModel(BaseSettingsModel): + _isGroup: bool = True + override_global_config: bool = SettingsField( False, title="Override global OCIO config" @@ -161,6 +197,8 @@ class ImageIOFileRuleModel(BaseSettingsModel): class ImageIOFileRulesModel(BaseSettingsModel): + _isGroup: bool = True + activate_host_rules: bool = SettingsField(False) rules: list[ImageIOFileRuleModel] = SettingsField( default_factory=list, @@ -175,14 +213,7 @@ class ImageIOFileRulesModel(BaseSettingsModel): class ImageIOSettings(BaseSettingsModel): """Nuke color management project settings. """ - _isGroup: bool = True - """# TODO: enhance settings with host api: - to restructure settings for simplification. - - now: nuke/imageio/viewer/viewerProcess - future: nuke/imageio/viewer - """ activate_host_color_management: bool = SettingsField( True, title="Enable Color Management") ocio_config: ImageIOConfigModel = SettingsField( @@ -199,18 +230,14 @@ class ImageIOSettings(BaseSettingsModel): description="""Viewer profile is used during Creation of new viewer node at knob viewerProcess""" ) - + monitor: MonitorProcessModel = SettingsField( + default_factory=MonitorProcessModel, + title="Monitor OUT" + ) baking_target: ColorspaceConfigurationModel = SettingsField( default_factory=ColorspaceConfigurationModel, title="Baking Target Colorspace" ) - baking: ViewProcessModel = SettingsField( - default_factory=ViewProcessModel, - title="Baking", - description="""[DEPRECATED - use 'Baking Target Colorspace' instead] - Baking profile is used during - publishing baked colorspace data at knob viewerProcess""", - ) workfile: WorkfileColorspaceSettings = SettingsField( default_factory=WorkfileColorspaceSettings, @@ -232,18 +259,12 @@ class ImageIOSettings(BaseSettingsModel): DEFAULT_IMAGEIO_SETTINGS = { - "viewer": { - "viewerProcess": "ACES/sRGB", - "output_transform": "ACES/sRGB" - }, + "viewer": {"display": "ACES", "view": "sRGB"}, + "monitor": {"display": "ACES", "view": "Rec.709"}, "baking_target": { - "enabled": False, + "enabled": True, "type": "colorspace", - "colorspace": "" - }, - "baking": { - "viewerProcess": "ACES/Rec.709", - "output_transform": "ACES/Rec.709" + "colorspace": "Output - Rec.709", }, "workfile": { "color_management": "OCIO", @@ -254,170 +275,67 @@ DEFAULT_IMAGEIO_SETTINGS = { "int_8_lut": "role_matte_paint", "int_16_lut": "role_texture_paint", "log_lut": "role_compositing_log", - "float_lut": "role_scene_linear" + "float_lut": "role_scene_linear", }, "nodes": { "required_nodes": [ { - "plugins": [ - "CreateWriteRender" - ], + "plugins": ["CreateWriteRender"], "nuke_node_class": "Write", "knobs": [ - { - "type": "text", - "name": "file_type", - "text": "exr" - }, - { - "type": "text", - "name": "datatype", - "text": "16 bit half" - }, - { - "type": "text", - "name": "compression", - "text": "Zip (1 scanline)" - }, - { - "type": "boolean", - "name": "autocrop", - "boolean": True - }, + {"type": "text", "name": "file_type", "text": "exr"}, + {"type": "text", "name": "datatype", "text": "16 bit half"}, + {"type": "text", "name": "compression", "text": "Zip (1 scanline)"}, + {"type": "boolean", "name": "autocrop", "boolean": True}, { "type": "color_gui", "name": "tile_color", - "color_gui": [ - 186, - 35, - 35 - ] + "color_gui": [186, 35, 35], }, - { - "type": "text", - "name": "channels", - "text": "rgb" - }, - { - "type": "text", - "name": "colorspace", - "text": "scene_linear" - }, - { - "type": "boolean", - "name": "create_directories", - "boolean": True - } - ] + {"type": "text", "name": "channels", "text": "rgb"}, + {"type": "text", "name": "colorspace", "text": "scene_linear"}, + {"type": "boolean", "name": "create_directories", "boolean": True}, + ], }, { - "plugins": [ - "CreateWritePrerender" - ], + "plugins": ["CreateWritePrerender"], "nuke_node_class": "Write", "knobs": [ - { - "type": "text", - "name": "file_type", - "text": "exr" - }, - { - "type": "text", - "name": "datatype", - "text": "16 bit half" - }, - { - "type": "text", - "name": "compression", - "text": "Zip (1 scanline)" - }, - { - "type": "boolean", - "name": "autocrop", - "boolean": True - }, + {"type": "text", "name": "file_type", "text": "exr"}, + {"type": "text", "name": "datatype", "text": "16 bit half"}, + {"type": "text", "name": "compression", "text": "Zip (1 scanline)"}, + {"type": "boolean", "name": "autocrop", "boolean": True}, { "type": "color_gui", "name": "tile_color", - "color_gui": [ - 171, - 171, - 10 - ] + "color_gui": [171, 171, 10], }, - { - "type": "text", - "name": "channels", - "text": "rgb" - }, - { - "type": "text", - "name": "colorspace", - "text": "scene_linear" - }, - { - "type": "boolean", - "name": "create_directories", - "boolean": True - } - ] + {"type": "text", "name": "channels", "text": "rgb"}, + {"type": "text", "name": "colorspace", "text": "scene_linear"}, + {"type": "boolean", "name": "create_directories", "boolean": True}, + ], }, { - "plugins": [ - "CreateWriteImage" - ], + "plugins": ["CreateWriteImage"], "nuke_node_class": "Write", "knobs": [ - { - "type": "text", - "name": "file_type", - "text": "tiff" - }, - { - "type": "text", - "name": "datatype", - "text": "16 bit" - }, - { - "type": "text", - "name": "compression", - "text": "Deflate" - }, + {"type": "text", "name": "file_type", "text": "tiff"}, + {"type": "text", "name": "datatype", "text": "16 bit"}, + {"type": "text", "name": "compression", "text": "Deflate"}, { "type": "color_gui", "name": "tile_color", - "color_gui": [ - 56, - 162, - 7 - ] + "color_gui": [56, 162, 7], }, - { - "type": "text", - "name": "channels", - "text": "rgb" - }, - { - "type": "text", - "name": "colorspace", - "text": "texture_paint" - }, - { - "type": "boolean", - "name": "create_directories", - "boolean": True - } - ] - } + {"type": "text", "name": "channels", "text": "rgb"}, + {"type": "text", "name": "colorspace", "text": "texture_paint"}, + {"type": "boolean", "name": "create_directories", "boolean": True}, + ], + }, ], - "override_nodes": [] + "override_nodes": [], }, "regex_inputs": { - "inputs": [ - { - "regex": "(beauty).*(?=.exr)", - "colorspace": "linear" - } - ] - } + "inputs": [{"regex": "(beauty).*(?=.exr)", "colorspace": "linear"}] + }, } diff --git a/server_addon/nuke/server/settings/publish_plugins.py b/server_addon/nuke/server/settings/publish_plugins.py index 1373b3b13d..2c92d6f02a 100644 --- a/server_addon/nuke/server/settings/publish_plugins.py +++ b/server_addon/nuke/server/settings/publish_plugins.py @@ -146,14 +146,6 @@ class IntermediateOutputModel(BaseSettingsModel): description="Override Baking target with colorspace or display/view", default_factory=ColorspaceConfigurationModel ) - viewer_process_override: str = SettingsField( - "", - title="Viewer process override", - description=( - "[DEPRECATED - use 'Target baking colorspace override'] " - "Override viewer process node (LUT)" - ), - ) bake_viewer_input_process: bool = SettingsField( True, title="Bake viewer input process node (LUT)", @@ -278,7 +270,6 @@ class PublishPluginsModel(BaseSettingsModel): section="Integrators" ) - DEFAULT_PUBLISH_PLUGIN_SETTINGS = { "CollectInstanceData": { "sync_workfile_version_on_product_types": [ @@ -344,7 +335,6 @@ DEFAULT_PUBLISH_PLUGIN_SETTINGS = { "product_names": [] }, "read_raw": False, - "viewer_process_override": "", "colorspace_override": { "enabled": False, "type": "colorspace", From 2d13f9787f3cfb4ee466f48b41841a303910aee2 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 13 Jun 2024 17:27:23 +0200 Subject: [PATCH 24/34] Update set_viewers_colorspace method to handle imageio_nuke dictionary, refactor ExporterReviewMov class to support different colorspaces for baking, and adjust settings in PublishPluginsModel. --- server_addon/nuke/client/ayon_nuke/api/lib.py | 58 ++++++------- .../nuke/client/ayon_nuke/api/plugin.py | 83 ++++++++++++------- .../nuke/server/settings/publish_plugins.py | 1 + 3 files changed, 83 insertions(+), 59 deletions(-) diff --git a/server_addon/nuke/client/ayon_nuke/api/lib.py b/server_addon/nuke/client/ayon_nuke/api/lib.py index 09dab4687a..3906777c95 100644 --- a/server_addon/nuke/client/ayon_nuke/api/lib.py +++ b/server_addon/nuke/client/ayon_nuke/api/lib.py @@ -1509,36 +1509,30 @@ class WorkfileSettings(object): for filter in nodes_filter: return [n for n in self._nodes if filter in n.Class()] - def set_viewers_colorspace(self, viewer_dict): + def set_viewers_colorspace(self, imageio_nuke): ''' Adds correct colorspace to viewer Arguments: - viewer_dict (dict): adjustments from presets + imageio_nuke (dict): nuke colorspace configurations ''' - if not isinstance(viewer_dict, dict): - msg = "set_viewers_colorspace(): argument should be dictionary" - log.error(msg) - nuke.message(msg) - return + viewer_config = imageio_nuke["viewer"] + monitor_config = imageio_nuke["monitor"] filter_knobs = [ "viewerProcess", "wipe_position", "monitorOutOutputTransform" ] - - display, viewer = get_viewer_config_from_string( - viewer_dict["viewerProcess"] - ) viewer_process = create_viewer_profile_string( - viewer, display, path_like=False - ) - display, viewer = get_viewer_config_from_string( - viewer_dict["output_transform"] + viewer_config["view"], + viewer_config["display"], + path_like=False, ) output_transform = create_viewer_profile_string( - viewer, display, path_like=False + monitor_config["view"], + monitor_config["display"], + path_like=False, ) erased_viewers = [] for v in nuke.allNodes(filter="Viewer"): @@ -1547,8 +1541,10 @@ class WorkfileSettings(object): if viewer_process not in v["viewerProcess"].value(): copy_inputs = v.dependencies() - copy_knobs = {k: v[k].value() for k in v.knobs() - if k not in filter_knobs} + copy_knobs = { + k: v[k].value() for k in v.knobs() + if k not in filter_knobs + } # delete viewer with wrong settings erased_viewers.append(v["name"].value()) @@ -1590,12 +1586,12 @@ class WorkfileSettings(object): if not config_data: # no ocio config found and no custom path used if self._root_node["colorManagement"].value() \ - not in color_management: + not in color_management: self._root_node["colorManagement"].setValue(color_management) # second set ocio version if self._root_node["OCIO_config"].value() \ - not in native_ocio_config: + not in native_ocio_config: self._root_node["OCIO_config"].setValue(native_ocio_config) else: @@ -1623,21 +1619,25 @@ class WorkfileSettings(object): if correct_settings: self._set_ocio_config_path_to_workfile(config_data) + workfile_settings_output = {} # get monitor lut from settings respecting Nuke version differences monitor_lut_data = self._get_monitor_settings( workfile_settings["monitor_out_lut"], workfile_settings["monitor_lut"] ) - monitor_lut_data.update({ - "workingSpaceLUT": workfile_settings["working_space"], - "int8Lut": workfile_settings["int_8_lut"], - "int16Lut": workfile_settings["int_16_lut"], - "logLut": workfile_settings["log_lut"], - "floatLut": workfile_settings["float_lut"] - }) + workfile_settings_output |= monitor_lut_data + workfile_settings_output.update( + { + "workingSpaceLUT": workfile_settings["working_space"], + "int8Lut": workfile_settings["int_8_lut"], + "int16Lut": workfile_settings["int_16_lut"], + "logLut": workfile_settings["log_lut"], + "floatLut": workfile_settings["float_lut"], + } + ) # then set the rest - for knob, value_ in monitor_lut_data.items(): + for knob, value_ in workfile_settings_output.items(): # skip unfilled ocio config path # it will be dict in value if isinstance(value_, dict): @@ -1972,7 +1972,7 @@ Reopening Nuke should synchronize these paths and resolve any discrepancies. log.info("Setting colorspace to viewers...") try: - self.set_viewers_colorspace(nuke_colorspace["viewer"]) + self.set_viewers_colorspace(nuke_colorspace) except AttributeError as _error: msg = "Set Colorspace to viewer error: {}".format(_error) nuke.message(msg) diff --git a/server_addon/nuke/client/ayon_nuke/api/plugin.py b/server_addon/nuke/client/ayon_nuke/api/plugin.py index 4f05cd41b9..3e8da03af6 100644 --- a/server_addon/nuke/client/ayon_nuke/api/plugin.py +++ b/server_addon/nuke/client/ayon_nuke/api/plugin.py @@ -1,3 +1,4 @@ +import dis import nuke import re import os @@ -638,12 +639,18 @@ class ExporterReview(object): from . import lib as opnlib nuke_imageio = opnlib.get_nuke_imageio_settings() - # TODO: this is only securing backward compatibility lets remove - # this once all projects's anatomy are updated to newer config - if "baking" in nuke_imageio.keys(): - return nuke_imageio["baking"]["viewerProcess"] + if ( + "baking_target" in nuke_imageio.keys() + and nuke_imageio["baking_target"]["enabled"] + ): + return nuke_imageio["baking_target"] else: - return nuke_imageio["viewer"]["viewerProcess"] + # viewer is having display and view keys only and it is + # display_view type + return { + "type": "display_view", + "display_view": nuke_imageio["viewer"], + } class ExporterReviewLut(ExporterReview): @@ -861,16 +868,16 @@ class ExporterReviewMov(ExporterReview): bake_viewer_process = kwargs["bake_viewer_process"] bake_viewer_input_process_node = kwargs[ "bake_viewer_input_process"] - viewer_process_override = kwargs[ - "viewer_process_override"] - baking_view_profile = ( - viewer_process_override or self.get_imageio_baking_profile()) + colorspace_override = kwargs["colorspace_override"] + + baking_colorspace = self.get_imageio_baking_profile() + if colorspace_override["enabled"]: + baking_colorspace = colorspace_override["colorspace"] fps = self.instance.context.data["fps"] - self.log.debug(">> baking_view_profile `{}`".format( - baking_view_profile)) + self.log.debug(f">> baking_view_profile `{baking_colorspace}`") add_custom_tags = kwargs.get("add_custom_tags", []) @@ -932,32 +939,50 @@ class ExporterReviewMov(ExporterReview): if not self.viewer_lut_raw: # OCIODisplay - dag_node = nuke.createNode("OCIODisplay") + if baking_colorspace["type"] == "display_view": + display_view = baking_colorspace["display_view"] - # assign display - display, viewer = get_viewer_config_from_string( - str(baking_view_profile) - ) - if display: - dag_node["display"].setValue(display) + message = "OCIODisplay... '{}'" + node = nuke.createNode("OCIODisplay") - # assign viewer - dag_node["view"].setValue(viewer) + # assign display + display = display_view["display"] + view = display_view["view"] - if config_data: - # convert display and view to colorspace - colorspace = get_display_view_colorspace_name( - config_path=config_data["path"], - display=display, - view=viewer + if display: + node["display"].setValue(display) + + # assign viewer + node["view"].setValue(view) + if config_data: + # convert display and view to colorspace + colorspace = get_display_view_colorspace_name( + config_path=config_data["path"], + display=display, view=view + ) + # OCIOColorSpace + elif baking_colorspace["type"] == "colorspace": + baking_colorspace = baking_colorspace["colorspace"] + node = nuke.createNode("OCIOColorSpace") + message = "OCIOColorSpace... '{}'" + node["in_colorspace"].setValue(colorspace) + node["out_colorspace"].setValue(baking_colorspace) + colorspace = baking_colorspace + + else: + raise ValueError( + "Invalid baking color space type: " + f"{baking_colorspace['type']}" ) self._connect_to_above_nodes( - dag_node, product_name, "OCIODisplay... `{}`" + node, product_name, message ) + # Write node write_node = nuke.createNode("Write") - self.log.debug("Path: {}".format(self.path)) + self.log.debug(f"Path: {self.path}") + write_node["file"].setValue(str(self.path)) write_node["file_type"].setValue(str(self.ext)) write_node["channels"].setValue(str(self.color_channels)) @@ -1020,8 +1045,6 @@ class ExporterReviewMov(ExporterReview): nuke.scriptSave() return self.data - - def _shift_to_previous_node_and_temp(self, product_name, node, message): self._temp_nodes[product_name].append(node) self.previous_node = node self.log.debug(message.format(self._temp_nodes[product_name])) diff --git a/server_addon/nuke/server/settings/publish_plugins.py b/server_addon/nuke/server/settings/publish_plugins.py index 2c92d6f02a..c52c9e9c84 100644 --- a/server_addon/nuke/server/settings/publish_plugins.py +++ b/server_addon/nuke/server/settings/publish_plugins.py @@ -270,6 +270,7 @@ class PublishPluginsModel(BaseSettingsModel): section="Integrators" ) + DEFAULT_PUBLISH_PLUGIN_SETTINGS = { "CollectInstanceData": { "sync_workfile_version_on_product_types": [ From f8e928f36c388b2335b421477fbea38fd2832ae5 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Thu, 13 Jun 2024 19:37:48 +0300 Subject: [PATCH 25/34] raise LoadError instead of RuntimeError --- .../houdini/client/ayon_houdini/plugins/load/load_hda.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py b/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py index fad9281c08..5738ba7fab 100644 --- a/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py +++ b/server_addon/houdini/client/ayon_houdini/plugins/load/load_hda.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import os from ayon_core.pipeline import get_representation_path +from ayon_core.pipeline.load import LoadError from ayon_houdini.api import ( pipeline, plugin @@ -36,7 +37,7 @@ class HdaLoader(plugin.HoudiniLoader): # Get the type name from the HDA definition. hda_defs = hou.hda.definitionsInFile(file_path) if not hda_defs: - raise RuntimeError(f"No HDA definitions found in file: {file_path}") + raise LoadError(f"No HDA definitions found in file: {file_path}") type_name = hda_defs[0].nodeTypeName() hda_node = obj.createNode(type_name, node_name) From 5e4bc0b51b0c81b14c2859fda61acae1e23bf3be Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 13 Jun 2024 22:55:36 +0200 Subject: [PATCH 26/34] Formatting of display and view profiles with anatomy data. Remove unused imports, refactor knob creation and updating functions, improve logging messages for better clarity, update --- server_addon/nuke/client/ayon_nuke/api/lib.py | 67 +++++++------------ .../nuke/client/ayon_nuke/api/plugin.py | 31 +++++++-- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/server_addon/nuke/client/ayon_nuke/api/lib.py b/server_addon/nuke/client/ayon_nuke/api/lib.py index 3906777c95..490205dff3 100644 --- a/server_addon/nuke/client/ayon_nuke/api/lib.py +++ b/server_addon/nuke/client/ayon_nuke/api/lib.py @@ -1,5 +1,4 @@ import os -from pprint import pformat import re import json import six @@ -37,6 +36,7 @@ from ayon_core.pipeline import ( get_current_host_name, get_current_project_name, get_current_folder_path, + get_current_task_name, AYON_INSTANCE_ID, AVALON_INSTANCE_ID, ) @@ -154,15 +154,9 @@ def set_node_data(node, knobname, data): """ # if exists then update data if knobname in node.knobs(): - log.debug("Updating knobname `{}` on node `{}`".format( - knobname, node.name() - )) update_node_data(node, knobname, data) return - log.debug("Creating knobname `{}` on node `{}`".format( - knobname, node.name() - )) # else create new knob_value = JSON_PREFIX + json.dumps(data) knob = nuke.String_Knob(knobname) @@ -514,10 +508,8 @@ def get_avalon_knob_data(node, prefix="avalon:", create=True): try: # check if data available on the node test = node[DATA_GROUP_KEY].value() - log.debug("Only testing if data available: `{}`".format(test)) except NameError as e: # if it doesn't then create it - log.debug("Creating avalon knob: `{}`".format(e)) if create: node = set_avalon_knob_data(node) return get_avalon_knob_data(node) @@ -678,8 +670,6 @@ def get_imageio_node_setting(node_class, plugin_name, product_name): imageio_node = node break - log.debug("__ imageio_node: {}".format(imageio_node)) - if not imageio_node: return @@ -690,8 +680,6 @@ def get_imageio_node_setting(node_class, plugin_name, product_name): product_name, imageio_node["knobs"] ) - - log.info("ImageIO node: {}".format(imageio_node)) return imageio_node @@ -706,8 +694,6 @@ def get_imageio_node_override_setting( # find matching override node override_imageio_node = None for onode in override_nodes: - log.debug("__ onode: {}".format(onode)) - log.debug("__ productName: {}".format(product_name)) if node_class not in onode["nuke_node_class"]: continue @@ -727,7 +713,6 @@ def get_imageio_node_override_setting( override_imageio_node = onode break - log.debug("__ override_imageio_node: {}".format(override_imageio_node)) # add overrides to imageio_node if override_imageio_node: # get all knob names in imageio_node @@ -740,7 +725,6 @@ def get_imageio_node_override_setting( for knob in knobs_settings: # add missing knobs into imageio_node if oknob_name not in knob_names: - log.debug("_ adding knob: `{}`".format(oknob)) knobs_settings.append(oknob) knob_names.append(oknob_name) continue @@ -750,9 +734,6 @@ def get_imageio_node_override_setting( knob_type = knob["type"] # override matching knob name - log.debug( - "_ overriding knob: `{}` > `{}`".format(knob, oknob) - ) if not oknob_value: # remove original knob if no value found in oknob knobs_settings.remove(knob) @@ -923,7 +904,6 @@ def writes_version_sync(): new_version = "v" + str("{" + ":0>{}".format(padding) + "}").format( int(rootVersion) ) - log.debug("new_version: {}".format(new_version)) except Exception: return @@ -936,13 +916,11 @@ def writes_version_sync(): try: if avalon_knob_data["families"] not in ["render"]: - log.debug(avalon_knob_data["families"]) continue node_file = each["file"].value() node_version = "v" + get_version_from_path(node_file) - log.debug("node_version: {}".format(node_version)) node_new_file = node_file.replace(node_version, new_version) each["file"].setValue(node_new_file) @@ -1332,7 +1310,6 @@ def set_node_knobs_from_settings(node, knob_settings, **kwargs): kwargs (dict)[optional]: keys for formattable knob settings """ for knob in knob_settings: - log.debug("__ knob: {}".format(pformat(knob))) knob_name = knob["name"] if knob_name not in node.knobs(): continue @@ -1486,13 +1463,17 @@ class WorkfileSettings(object): Context._project_entity = project_entity self._project_name = project_name self._folder_path = get_current_folder_path() + self._task_name = get_current_task_name() self._folder_entity = ayon_api.get_folder_by_path( project_name, self._folder_path ) self._root_node = root_node or nuke.root() self._nodes = self.get_nodes(nodes=nodes) - self.data = kwargs + context_data = get_template_data_with_names( + project_name, self._folder_path, self._task_name, "nuke" + ) + self.formatting_data = context_data def get_nodes(self, nodes=None, nodes_filter=None): @@ -1516,23 +1497,16 @@ class WorkfileSettings(object): imageio_nuke (dict): nuke colorspace configurations ''' - viewer_config = imageio_nuke["viewer"] - monitor_config = imageio_nuke["monitor"] - filter_knobs = [ "viewerProcess", "wipe_position", "monitorOutOutputTransform" ] - viewer_process = create_viewer_profile_string( - viewer_config["view"], - viewer_config["display"], - path_like=False, + viewer_process = self._display_and_view_formatted( + imageio_nuke["viewer"] ) - output_transform = create_viewer_profile_string( - monitor_config["view"], - monitor_config["display"], - path_like=False, + output_transform = self._display_and_view_formatted( + imageio_nuke["monitor"] ) erased_viewers = [] for v in nuke.allNodes(filter="Viewer"): @@ -1570,6 +1544,21 @@ class WorkfileSettings(object): "Attention! Viewer nodes {} were erased." "It had wrong color profile".format(erased_viewers)) + def _display_and_view_formatted(self, view_profile): + """ Format display and view profile string + + Args: + view_profile (dict): view and display profile + + Returns: + str: formatted display and view profile string + """ + display_view = create_viewer_profile_string( + view_profile["view"], view_profile["display"], path_like=False + ) + # format any template tokens used in the string + return StringTemplate(display_view).format_strict(self.formatting_data) + def set_root_colorspace(self, imageio_host): ''' Adds correct colorspace to root @@ -1646,7 +1635,6 @@ class WorkfileSettings(object): if not value_: continue self._root_node[knob].setValue(str(value_)) - log.debug("nuke.root()['{}'] changed to: {}".format(knob, value_)) def _get_monitor_settings(self, viewer_lut, monitor_lut): """ Get monitor settings from viewer and monitor lut @@ -1889,8 +1877,6 @@ Reopening Nuke should synchronize these paths and resolve any discrepancies. elif node_data: nuke_imageio_writes = get_write_node_template_attr(node) - log.debug("nuke_imageio_writes: `{}`".format(nuke_imageio_writes)) - if not nuke_imageio_writes: return @@ -1938,7 +1924,6 @@ Reopening Nuke should synchronize these paths and resolve any discrepancies. "to": future } - log.debug(changes) if changes: msg = "Read nodes are not set to correct colorspace:\n\n" for nname, knobs in changes.items(): @@ -2653,8 +2638,6 @@ class NukeDirmap(HostDirmap): def dirmap_routine(self, source_path, destination_path): source_path = source_path.lower().replace(os.sep, '/') destination_path = destination_path.lower().replace(os.sep, '/') - log.debug("Map: {} with: {}->{}".format(self.file_name, - source_path, destination_path)) if platform.system().lower() == "windows": self.file_name = self.file_name.lower().replace( source_path, destination_path) diff --git a/server_addon/nuke/client/ayon_nuke/api/plugin.py b/server_addon/nuke/client/ayon_nuke/api/plugin.py index 3e8da03af6..129ac45361 100644 --- a/server_addon/nuke/client/ayon_nuke/api/plugin.py +++ b/server_addon/nuke/client/ayon_nuke/api/plugin.py @@ -13,6 +13,7 @@ from ayon_core.lib import ( BoolDef, EnumDef ) +from ayon_core.lib import StringTemplate from ayon_core.pipeline import ( LoaderPlugin, CreatorError, @@ -39,7 +40,6 @@ from .lib import ( set_node_data, get_node_data, get_view_process_node, - get_viewer_config_from_string, get_filenames_without_hash, link_knobs ) @@ -797,6 +797,7 @@ class ExporterReviewMov(ExporterReview): self.viewer_lut_raw = klass.viewer_lut_raw self.write_colorspace = instance.data["colorspace"] self.color_channels = instance.data["color_channels"] + self.formatting_data = instance.data["anatomyData"] self.name = name or "baked" self.ext = ext or "mov" @@ -869,11 +870,11 @@ class ExporterReviewMov(ExporterReview): bake_viewer_input_process_node = kwargs[ "bake_viewer_input_process"] - colorspace_override = kwargs["colorspace_override"] - baking_colorspace = self.get_imageio_baking_profile() + + colorspace_override = kwargs["colorspace_override"] if colorspace_override["enabled"]: - baking_colorspace = colorspace_override["colorspace"] + baking_colorspace = colorspace_override fps = self.instance.context.data["fps"] @@ -945,27 +946,41 @@ class ExporterReviewMov(ExporterReview): message = "OCIODisplay... '{}'" node = nuke.createNode("OCIODisplay") - # assign display + # assign display and view display = display_view["display"] view = display_view["view"] + # display could not be set in nuke_default config if display: + # format display string with anatomy data + display = StringTemplate(display).format_strict( + self.formatting_data + ) node["display"].setValue(display) + # format view string with anatomy data + view = StringTemplate(view).format_strict( + self.formatting_data) # assign viewer node["view"].setValue(view) + if config_data: # convert display and view to colorspace colorspace = get_display_view_colorspace_name( config_path=config_data["path"], display=display, view=view ) + # OCIOColorSpace elif baking_colorspace["type"] == "colorspace": baking_colorspace = baking_colorspace["colorspace"] + # format colorspace string with anatomy data + baking_colorspace = StringTemplate( + baking_colorspace).format_strict(self.formatting_data) node = nuke.createNode("OCIOColorSpace") message = "OCIOColorSpace... '{}'" - node["in_colorspace"].setValue(colorspace) + # no need to set input colorspace since it is driven by + # working colorspace node["out_colorspace"].setValue(baking_colorspace) colorspace = baking_colorspace @@ -1041,10 +1056,12 @@ class ExporterReviewMov(ExporterReview): self.log.debug("Representation... `{}`".format(self.data)) - self.clean_nodes(product_name) + # self.clean_nodes(product_name) nuke.scriptSave() return self.data + + def _shift_to_previous_node_and_temp(self, product_name, node, message): self._temp_nodes[product_name].append(node) self.previous_node = node self.log.debug(message.format(self._temp_nodes[product_name])) From eb672f534f8b2ec9ef439d833b68fd66bcea3974 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 13 Jun 2024 23:16:28 +0200 Subject: [PATCH 27/34] linting fixes --- server_addon/nuke/client/ayon_nuke/api/lib.py | 4 ++-- server_addon/nuke/client/ayon_nuke/api/plugin.py | 15 ++++++--------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/server_addon/nuke/client/ayon_nuke/api/lib.py b/server_addon/nuke/client/ayon_nuke/api/lib.py index 490205dff3..e8c2023cf9 100644 --- a/server_addon/nuke/client/ayon_nuke/api/lib.py +++ b/server_addon/nuke/client/ayon_nuke/api/lib.py @@ -507,8 +507,8 @@ def get_avalon_knob_data(node, prefix="avalon:", create=True): # check if the node is avalon tracked try: # check if data available on the node - test = node[DATA_GROUP_KEY].value() - except NameError as e: + _ = node[DATA_GROUP_KEY].value() + except NameError: # if it doesn't then create it if create: node = set_avalon_knob_data(node) diff --git a/server_addon/nuke/client/ayon_nuke/api/plugin.py b/server_addon/nuke/client/ayon_nuke/api/plugin.py index 129ac45361..ed4be3c4a8 100644 --- a/server_addon/nuke/client/ayon_nuke/api/plugin.py +++ b/server_addon/nuke/client/ayon_nuke/api/plugin.py @@ -1,4 +1,3 @@ -import dis import nuke import re import os @@ -845,7 +844,7 @@ class ExporterReviewMov(ExporterReview): with maintained_selection(): self.log.info("Saving nodes as file... ") # create nk path - path = os.path.splitext(self.path)[0] + ".nk" + path = f"{os.path.splitext(self.path)[0]}.nk" # save file to the path if not os.path.exists(os.path.dirname(path)): os.makedirs(os.path.dirname(path)) @@ -882,8 +881,7 @@ class ExporterReviewMov(ExporterReview): add_custom_tags = kwargs.get("add_custom_tags", []) - self.log.info( - "__ add_custom_tags: `{0}`".format(add_custom_tags)) + self.log.info(f"__ add_custom_tags: `{add_custom_tags}`") product_name = self.instance.data["productName"] self._temp_nodes[product_name] = [] @@ -1021,12 +1019,11 @@ class ExporterReviewMov(ExporterReview): self.log.info("`mov64_write_timecode` knob was not found") write_node["raw"].setValue(1) + # connect write_node.setInput(0, self.previous_node) self._temp_nodes[product_name].append(write_node) - self.log.debug("Write... `{}`".format( - self._temp_nodes[product_name]) - ) + self.log.debug(f"Write... `{self._temp_nodes[product_name]}`") # ---------- end nodes creation # ---------- render or save to nk @@ -1054,9 +1051,9 @@ class ExporterReviewMov(ExporterReview): colorspace=colorspace, ) - self.log.debug("Representation... `{}`".format(self.data)) + self.log.debug(f"Representation... `{self.data}`") - # self.clean_nodes(product_name) + self.clean_nodes(product_name) nuke.scriptSave() return self.data From 87ecae829e98d31a2d7b664ee3060074eee64ce2 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 13 Jun 2024 23:17:26 +0200 Subject: [PATCH 28/34] linting fix --- server_addon/nuke/server/settings/conversion.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/server_addon/nuke/server/settings/conversion.py b/server_addon/nuke/server/settings/conversion.py index 3e1ca3a0a9..192b3f4d13 100644 --- a/server_addon/nuke/server/settings/conversion.py +++ b/server_addon/nuke/server/settings/conversion.py @@ -1,8 +1,6 @@ import re from typing import Any -from .publish_plugins import DEFAULT_PUBLISH_PLUGIN_SETTINGS - def _get_viewer_config_from_string(input_string): """Convert string to display and viewer string From 8c5f46dc13c22c0612936374126c2db81e9c747f Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Jun 2024 11:41:11 +0200 Subject: [PATCH 29/34] Refactor saving and opening workfiles, display push message. - Refactored saving and opening workfiles in `main()` function. - Display a message indicating the pushed workfile path after pushing to project. --- .../nuke/client/ayon_nuke/api/push_to_project.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/server_addon/nuke/client/ayon_nuke/api/push_to_project.py b/server_addon/nuke/client/ayon_nuke/api/push_to_project.py index f145ed652b..852e5d0e31 100644 --- a/server_addon/nuke/client/ayon_nuke/api/push_to_project.py +++ b/server_addon/nuke/client/ayon_nuke/api/push_to_project.py @@ -70,7 +70,6 @@ def main(): anatomy, project_settings=project_settings ) - # Save current workfile. current_file = host.current_file() host.save_file(current_file) @@ -109,8 +108,11 @@ def main(): node["file"].setValue(path.replace("\\", "/")) # Save current workfile to new context. - basename = os.path.basename(current_file) - host.save_file(os.path.join(workdir, basename)) + pushed_workfile = os.path.join( + workdir, os.path.basename(current_file)) + host.save_file(pushed_workfile) - # Open current contex workfile. + # Open current context workfile. host.open_file(current_file) + + nuke.message(f"Pushed to project: \n{pushed_workfile}") From 9f85d4a2405648d672c6178a9ae5b693ebdb6a96 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Jun 2024 11:41:29 +0200 Subject: [PATCH 30/34] Remove unnecessary callback for workfile builder in pipeline.py. Improve script load settings. --- server_addon/nuke/client/ayon_nuke/api/pipeline.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/server_addon/nuke/client/ayon_nuke/api/pipeline.py b/server_addon/nuke/client/ayon_nuke/api/pipeline.py index 8a9b5cb666..edf1e2dc03 100644 --- a/server_addon/nuke/client/ayon_nuke/api/pipeline.py +++ b/server_addon/nuke/client/ayon_nuke/api/pipeline.py @@ -160,9 +160,6 @@ def add_nuke_callbacks(): # 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 nuke.addOnScriptLoad(on_script_load) From 4c8a6f07ff1df67c849b1d2f009c9be412494ddc Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Jun 2024 11:42:42 +0200 Subject: [PATCH 31/34] Remove unused process_workfile_builder function from pipeline module The commit removes the unused process_workfile_builder function from the pipeline module. --- server_addon/nuke/client/ayon_nuke/api/pipeline.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/server_addon/nuke/client/ayon_nuke/api/pipeline.py b/server_addon/nuke/client/ayon_nuke/api/pipeline.py index edf1e2dc03..2ba430c272 100644 --- a/server_addon/nuke/client/ayon_nuke/api/pipeline.py +++ b/server_addon/nuke/client/ayon_nuke/api/pipeline.py @@ -37,8 +37,6 @@ from .lib import ( INSTANCE_DATA_KNOB, get_main_window, WorkfileSettings, - # TODO: remove this once workfile builder will be removed - process_workfile_builder, start_workfile_template_builder, launch_workfiles_app, check_inventory_versions, From 0e1c0c506fcb45ce4eddfc76312ce3b7f7e0d0ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Fri, 14 Jun 2024 12:22:30 +0200 Subject: [PATCH 32/34] Update server_addon/nuke/client/ayon_nuke/api/lib.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- server_addon/nuke/client/ayon_nuke/api/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server_addon/nuke/client/ayon_nuke/api/lib.py b/server_addon/nuke/client/ayon_nuke/api/lib.py index e8c2023cf9..905521255f 100644 --- a/server_addon/nuke/client/ayon_nuke/api/lib.py +++ b/server_addon/nuke/client/ayon_nuke/api/lib.py @@ -1614,7 +1614,7 @@ class WorkfileSettings(object): workfile_settings["monitor_out_lut"], workfile_settings["monitor_lut"] ) - workfile_settings_output |= monitor_lut_data + workfile_settings_output.update(monitor_lut_data) workfile_settings_output.update( { "workingSpaceLUT": workfile_settings["working_space"], From a33758792cdf228324280661c6759130706d12ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Fri, 14 Jun 2024 12:22:42 +0200 Subject: [PATCH 33/34] Update server_addon/nuke/client/ayon_nuke/api/plugin.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- server_addon/nuke/client/ayon_nuke/api/plugin.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/server_addon/nuke/client/ayon_nuke/api/plugin.py b/server_addon/nuke/client/ayon_nuke/api/plugin.py index ed4be3c4a8..fc30f328c7 100644 --- a/server_addon/nuke/client/ayon_nuke/api/plugin.py +++ b/server_addon/nuke/client/ayon_nuke/api/plugin.py @@ -638,10 +638,7 @@ class ExporterReview(object): from . import lib as opnlib nuke_imageio = opnlib.get_nuke_imageio_settings() - if ( - "baking_target" in nuke_imageio.keys() - and nuke_imageio["baking_target"]["enabled"] - ): + if nuke_imageio["baking_target"]["enabled"]: return nuke_imageio["baking_target"] else: # viewer is having display and view keys only and it is From 768afdb2d83ea5078ae731a5fe6d066254a2e4aa Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 14 Jun 2024 12:25:11 +0200 Subject: [PATCH 34/34] Update imageio and viewer settings to version 0.2.3, refactor functions for consistency. --- server_addon/nuke/server/settings/conversion.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/server_addon/nuke/server/settings/conversion.py b/server_addon/nuke/server/settings/conversion.py index 192b3f4d13..2e9e07e354 100644 --- a/server_addon/nuke/server/settings/conversion.py +++ b/server_addon/nuke/server/settings/conversion.py @@ -46,7 +46,7 @@ def _get_viewer_config_from_string(input_string): return (display, viewer) -def _convert_imageio_baking_0_2_2(overrides): +def _convert_imageio_baking_0_2_3(overrides): if "baking" not in overrides: return @@ -67,7 +67,7 @@ def _convert_imageio_baking_0_2_2(overrides): } -def _convert_viewers_0_2_2(overrides): +def _convert_viewers_0_2_3(overrides): if "viewer" not in overrides: return @@ -89,7 +89,7 @@ def _convert_viewers_0_2_2(overrides): } -def _convert_imageio_configs_0_2_2(overrides): +def _convert_imageio_configs_0_2_3(overrides): """Image IO settings had changed. 0.2.2. is the latest version using the old way. @@ -99,11 +99,11 @@ def _convert_imageio_configs_0_2_2(overrides): imageio_overrides = overrides["imageio"] - _convert_imageio_baking_0_2_2(imageio_overrides) - _convert_viewers_0_2_2(imageio_overrides) + _convert_imageio_baking_0_2_3(imageio_overrides) + _convert_viewers_0_2_3(imageio_overrides) -def _convert_extract_intermediate_files_0_2_2(publish_overrides): +def _convert_extract_intermediate_files_0_2_3(publish_overrides): """Extract intermediate files settings had changed. 0.2.2. is the latest version using the old way. @@ -131,13 +131,13 @@ def _convert_extract_intermediate_files_0_2_2(publish_overrides): def _convert_publish_plugins(overrides): if "publish" not in overrides: return - _convert_extract_intermediate_files_0_2_2(overrides["publish"]) + _convert_extract_intermediate_files_0_2_3(overrides["publish"]) def convert_settings_overrides( source_version: str, overrides: dict[str, Any], ) -> dict[str, Any]: - _convert_imageio_configs_0_2_2(overrides) + _convert_imageio_configs_0_2_3(overrides) _convert_publish_plugins(overrides) return overrides