From 7c705eded6c715d478dfccbc796c107fdeb0fa9b Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Tue, 9 May 2023 15:53:38 +0200 Subject: [PATCH 001/112] add open template for maya --- openpype/hosts/maya/api/menu.py | 30 ++++++++++------ .../maya/api/workfile_template_builder.py | 34 +++++++++++++++++++ 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/maya/api/menu.py b/openpype/hosts/maya/api/menu.py index 5284c0249d..91d5b06f80 100644 --- a/openpype/hosts/maya/api/menu.py +++ b/openpype/hosts/maya/api/menu.py @@ -19,6 +19,7 @@ from .workfile_template_builder import ( update_placeholder, build_workfile_template, update_workfile_template, + open_template, ) log = logging.getLogger(__name__) @@ -158,16 +159,6 @@ def install(): tearOff=True, parent=MENU_NAME ) - cmds.menuItem( - "Create Placeholder", - parent=builder_menu, - command=create_placeholder - ) - cmds.menuItem( - "Update Placeholder", - parent=builder_menu, - command=update_placeholder - ) cmds.menuItem( "Build Workfile from template", parent=builder_menu, @@ -178,6 +169,25 @@ def install(): parent=builder_menu, command=update_workfile_template ) + cmds.menuItem( + divider=True, + parent=builder_menu + ) + cmds.menuItem( + "Open Template", + parent=builder_menu, + command=open_template, + ) + cmds.menuItem( + "Create Placeholder", + parent=builder_menu, + command=create_placeholder + ) + cmds.menuItem( + "Update Placeholder", + parent=builder_menu, + command=update_placeholder + ) cmds.setParent(MENU_NAME, menu=True) diff --git a/openpype/hosts/maya/api/workfile_template_builder.py b/openpype/hosts/maya/api/workfile_template_builder.py index d65e4c74d2..3342a86b70 100644 --- a/openpype/hosts/maya/api/workfile_template_builder.py +++ b/openpype/hosts/maya/api/workfile_template_builder.py @@ -1,4 +1,5 @@ import json +import os from maya import cmds @@ -24,6 +25,36 @@ class MayaTemplateBuilder(AbstractTemplateBuilder): use_legacy_creators = True + def open_template(self): + """Open template in current scene. + """ + template_preset = self.get_template_preset() + template_path = template_preset["path"] + + if not os.path.exists(template_path): + cmds.confirmDialog( + title="Warning", + message="Template doesn't exist: {}".format(template_path), + button=["OK"], + defaultButton="OK", + ) + return + + result = cmds.confirmDialog( + title="Warning", + message="Opening a template will clear the current scene.", + button=["OK", "Cancel"], + defaultButton="OK", + cancelButton="Cancel", + dismissString="Cancel", + ) + + if result != "OK": + return + + print("opening template {}".format(template_path)) + cmds.file(template_path, open=True, force=True) + def import_template(self, path): """Import template into current scene. Block if a template is already loaded. @@ -298,6 +329,9 @@ def update_workfile_template(*args): builder = MayaTemplateBuilder(registered_host()) builder.rebuild_template() +def open_template(*args): + builder = MayaTemplateBuilder(registered_host()) + builder.open_template() def create_placeholder(*args): host = registered_host() From 24f6cfca306033041da8c8c1c9bb79c4922335d4 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Tue, 9 May 2023 15:54:40 +0200 Subject: [PATCH 002/112] add abstracmethod --- .../pipeline/workfile/workfile_template_builder.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index a3d7340367..d234866b00 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -533,6 +533,17 @@ class AbstractTemplateBuilder(object): self.clear_shared_populate_data() + @abstractmethod + def open_template(self, template_path): + """Open template file in default application. + + Args: + template_path (str): Fullpath for current task and + host's template file. + """ + + pass + @abstractmethod def import_template(self, template_path): """ From 36fd0f9b9c709127d6a52964185068529ed31b64 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Tue, 9 May 2023 15:59:11 +0200 Subject: [PATCH 003/112] add open template for nuke --- openpype/hosts/nuke/api/pipeline.py | 7 ++++- .../nuke/api/workfile_template_builder.py | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index d649ffae7f..b45a9dfe7c 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -49,6 +49,7 @@ from .workfile_template_builder import ( NukePlaceholderLoadPlugin, NukePlaceholderCreatePlugin, build_workfile_template, + open_template, create_placeholder, update_placeholder, ) @@ -288,7 +289,7 @@ def _install_menu(): lambda: BuildWorkfile().process() ) - menu_template = menu.addMenu("Template Builder") # creating template menu + menu_template = menu.addMenu("Template Builder") menu_template.addCommand( "Build Workfile from template", lambda: build_workfile_template() @@ -296,6 +297,10 @@ def _install_menu(): if not ASSIST: menu_template.addSeparator() + menu_template.addCommand( + "Open template", + lambda: open_template() + ) menu_template.addCommand( "Create Place Holder", lambda: create_placeholder() diff --git a/openpype/hosts/nuke/api/workfile_template_builder.py b/openpype/hosts/nuke/api/workfile_template_builder.py index 72d4ffb476..2303ab7fbb 100644 --- a/openpype/hosts/nuke/api/workfile_template_builder.py +++ b/openpype/hosts/nuke/api/workfile_template_builder.py @@ -1,4 +1,5 @@ import collections +import os import nuke from openpype.pipeline import registered_host from openpype.pipeline.workfile.workfile_template_builder import ( @@ -33,6 +34,30 @@ PLACEHOLDER_SET = "PLACEHOLDERS_SET" class NukeTemplateBuilder(AbstractTemplateBuilder): """Concrete implementation of AbstractTemplateBuilder for nuke""" + def open_template(self): + """Open template in current scene. + + Args: + path (str): A path to current template (usually given by + get_template_preset implementation) + """ + + template_preset = self.get_template_preset() + template_path = template_preset["path"] + + if not os.path.exists(template_path): + nuke.message("Template doesn't exist: {}".format(template_path)) + return + + result = nuke.ask( + "This will replace current scene with template. Continue?" + ) + if not result: + return + + print("opening template {}".format(template_path)) + nuke.scriptOpen(template_path) + def import_template(self, path): """Import template into current scene. Block if a template is already loaded. @@ -960,6 +985,11 @@ def update_workfile_template(*args): builder.rebuild_template() +def open_template(*args): + builder = NukeTemplateBuilder(registered_host()) + builder.open_template() + + def create_placeholder(*args): host = registered_host() builder = NukeTemplateBuilder(host) From bebaeee66a626196f4cb99df4728a7fa3f5b8010 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Tue, 9 May 2023 16:21:14 +0200 Subject: [PATCH 004/112] fix linter --- openpype/hosts/maya/api/workfile_template_builder.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/hosts/maya/api/workfile_template_builder.py b/openpype/hosts/maya/api/workfile_template_builder.py index 3342a86b70..7b7c6a1fe4 100644 --- a/openpype/hosts/maya/api/workfile_template_builder.py +++ b/openpype/hosts/maya/api/workfile_template_builder.py @@ -329,10 +329,12 @@ def update_workfile_template(*args): builder = MayaTemplateBuilder(registered_host()) builder.rebuild_template() + def open_template(*args): builder = MayaTemplateBuilder(registered_host()) builder.open_template() + def create_placeholder(*args): host = registered_host() builder = MayaTemplateBuilder(host) From 9c4f1f6035139b7c6bf6873de21bb599c3025a80 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Thu, 11 May 2023 14:08:16 +0200 Subject: [PATCH 005/112] catch exception to display the message for users --- .../maya/api/workfile_template_builder.py | 20 ++++++++++----- .../nuke/api/workfile_template_builder.py | 25 +++++++++++++------ 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/openpype/hosts/maya/api/workfile_template_builder.py b/openpype/hosts/maya/api/workfile_template_builder.py index 7b7c6a1fe4..4393ac4cf3 100644 --- a/openpype/hosts/maya/api/workfile_template_builder.py +++ b/openpype/hosts/maya/api/workfile_template_builder.py @@ -1,5 +1,4 @@ import json -import os from maya import cmds @@ -10,6 +9,9 @@ from openpype.pipeline.workfile.workfile_template_builder import ( PlaceholderPlugin, LoadPlaceholderItem, PlaceholderLoadMixin, + TemplateLoadFailed, + TemplateNotFound, + TemplateProfileNotFound, ) from openpype.tools.workfile_template_build import ( WorkfileBuildPlaceholderDialog, @@ -28,13 +30,19 @@ class MayaTemplateBuilder(AbstractTemplateBuilder): def open_template(self): """Open template in current scene. """ - template_preset = self.get_template_preset() - template_path = template_preset["path"] - if not os.path.exists(template_path): + try: + template_preset = self.get_template_preset() + template_path = template_preset["path"] + + except ( + TemplateNotFound, + TemplateProfileNotFound, + TemplateLoadFailed + ) as e: cmds.confirmDialog( - title="Warning", - message="Template doesn't exist: {}".format(template_path), + title="Error", + message="An error has occurred:\n{}".format(e), button=["OK"], defaultButton="OK", ) diff --git a/openpype/hosts/nuke/api/workfile_template_builder.py b/openpype/hosts/nuke/api/workfile_template_builder.py index 2303ab7fbb..82502f3eba 100644 --- a/openpype/hosts/nuke/api/workfile_template_builder.py +++ b/openpype/hosts/nuke/api/workfile_template_builder.py @@ -1,5 +1,4 @@ import collections -import os import nuke from openpype.pipeline import registered_host from openpype.pipeline.workfile.workfile_template_builder import ( @@ -8,7 +7,10 @@ from openpype.pipeline.workfile.workfile_template_builder import ( LoadPlaceholderItem, CreatePlaceholderItem, PlaceholderLoadMixin, - PlaceholderCreateMixin + PlaceholderCreateMixin, + TemplateNotFound, + TemplateLoadFailed, + TemplateProfileNotFound, ) from openpype.tools.workfile_template_build import ( WorkfileBuildPlaceholderDialog, @@ -27,7 +29,9 @@ from .lib import ( duplicate_node, node_tempfile, ) - +from .workio import ( + open_file, +) PLACEHOLDER_SET = "PLACEHOLDERS_SET" @@ -42,11 +46,16 @@ class NukeTemplateBuilder(AbstractTemplateBuilder): get_template_preset implementation) """ - template_preset = self.get_template_preset() - template_path = template_preset["path"] + try: + template_preset = self.get_template_preset() + template_path = template_preset["path"] - if not os.path.exists(template_path): - nuke.message("Template doesn't exist: {}".format(template_path)) + except ( + TemplateNotFound, + TemplateProfileNotFound, + TemplateLoadFailed + ) as e: + nuke.critical("An error has occurred:\n{}".format(e)) return result = nuke.ask( @@ -56,7 +65,7 @@ class NukeTemplateBuilder(AbstractTemplateBuilder): return print("opening template {}".format(template_path)) - nuke.scriptOpen(template_path) + open_file(template_path) def import_template(self, path): """Import template into current scene. From 961d7abf235ce628fcb33b74a4190b4409904940 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Thu, 11 May 2023 14:13:37 +0200 Subject: [PATCH 006/112] fix indent --- openpype/hosts/maya/api/workfile_template_builder.py | 8 ++++---- openpype/hosts/nuke/api/workfile_template_builder.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/maya/api/workfile_template_builder.py b/openpype/hosts/maya/api/workfile_template_builder.py index 4393ac4cf3..b93132164a 100644 --- a/openpype/hosts/maya/api/workfile_template_builder.py +++ b/openpype/hosts/maya/api/workfile_template_builder.py @@ -36,10 +36,10 @@ class MayaTemplateBuilder(AbstractTemplateBuilder): template_path = template_preset["path"] except ( - TemplateNotFound, - TemplateProfileNotFound, - TemplateLoadFailed - ) as e: + TemplateNotFound, + TemplateProfileNotFound, + TemplateLoadFailed + ) as e: cmds.confirmDialog( title="Error", message="An error has occurred:\n{}".format(e), diff --git a/openpype/hosts/nuke/api/workfile_template_builder.py b/openpype/hosts/nuke/api/workfile_template_builder.py index 82502f3eba..d0d34e36f3 100644 --- a/openpype/hosts/nuke/api/workfile_template_builder.py +++ b/openpype/hosts/nuke/api/workfile_template_builder.py @@ -51,10 +51,10 @@ class NukeTemplateBuilder(AbstractTemplateBuilder): template_path = template_preset["path"] except ( - TemplateNotFound, - TemplateProfileNotFound, - TemplateLoadFailed - ) as e: + TemplateNotFound, + TemplateProfileNotFound, + TemplateLoadFailed + ) as e: nuke.critical("An error has occurred:\n{}".format(e)) return From 3e2c82d42f19cfd15cdb5acc7da00f23bb657ac9 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Tue, 16 May 2023 17:58:19 +0200 Subject: [PATCH 007/112] Use Qt for popup message --- .../nuke/api/workfile_template_builder.py | 36 +-------------- .../workfile/workfile_template_builder.py | 44 +++++++++++++++++-- openpype/widgets/message_window.py | 25 ++++++++--- 3 files changed, 61 insertions(+), 44 deletions(-) diff --git a/openpype/hosts/nuke/api/workfile_template_builder.py b/openpype/hosts/nuke/api/workfile_template_builder.py index d0d34e36f3..038270ea69 100644 --- a/openpype/hosts/nuke/api/workfile_template_builder.py +++ b/openpype/hosts/nuke/api/workfile_template_builder.py @@ -8,9 +8,6 @@ from openpype.pipeline.workfile.workfile_template_builder import ( CreatePlaceholderItem, PlaceholderLoadMixin, PlaceholderCreateMixin, - TemplateNotFound, - TemplateLoadFailed, - TemplateProfileNotFound, ) from openpype.tools.workfile_template_build import ( WorkfileBuildPlaceholderDialog, @@ -29,44 +26,13 @@ from .lib import ( duplicate_node, node_tempfile, ) -from .workio import ( - open_file, -) + PLACEHOLDER_SET = "PLACEHOLDERS_SET" class NukeTemplateBuilder(AbstractTemplateBuilder): """Concrete implementation of AbstractTemplateBuilder for nuke""" - def open_template(self): - """Open template in current scene. - - Args: - path (str): A path to current template (usually given by - get_template_preset implementation) - """ - - try: - template_preset = self.get_template_preset() - template_path = template_preset["path"] - - except ( - TemplateNotFound, - TemplateProfileNotFound, - TemplateLoadFailed - ) as e: - nuke.critical("An error has occurred:\n{}".format(e)) - return - - result = nuke.ask( - "This will replace current scene with template. Continue?" - ) - if not result: - return - - print("opening template {}".format(template_path)) - open_file(template_path) - def import_template(self, path): """Import template into current scene. Block if a template is already loaded. diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index d234866b00..9cab9af9b7 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -37,7 +37,12 @@ from openpype.lib import ( attribute_definitions, ) from openpype.lib.attribute_definitions import get_attributes_keys -from openpype.pipeline import legacy_io, Anatomy +from openpype.pipeline import ( + legacy_io, + Anatomy, + registered_host, + get_current_host_name, +) from openpype.pipeline.load import ( get_loaders_by_name, get_contexts_for_repre_docs, @@ -533,16 +538,47 @@ class AbstractTemplateBuilder(object): self.clear_shared_populate_data() - @abstractmethod - def open_template(self, template_path): + def open_template(self): """Open template file in default application. Args: template_path (str): Fullpath for current task and host's template file. """ + from openpype.widgets import message_window - pass + module_name = 'openpype.hosts.{}.api.lib'.format(get_current_host_name()) + api_lib = __import__(module_name, fromlist=['get_main_window']) + main_window = api_lib.get_main_window() + + try: + template_preset = self.get_template_preset() + template_path = template_preset["path"] + + except ( + TemplateNotFound, + TemplateProfileNotFound, + TemplateLoadFailed + ) as e: + message_window.message( + title="Template Load Failed", + message=str(e), + parent= main_window, + level="critical" + ) + return + + result = message_window.message( + title="Opening template", + message="Caution! This will overwrite your current scene.\n"\ + "Do you want to continue?", + parent= main_window, + level="ask", + ) + + if result: + host = registered_host() + host.open_file(template_path) @abstractmethod def import_template(self, template_path): diff --git a/openpype/widgets/message_window.py b/openpype/widgets/message_window.py index c207702f74..59bbd5bf52 100644 --- a/openpype/widgets/message_window.py +++ b/openpype/widgets/message_window.py @@ -13,12 +13,16 @@ class Window(QtWidgets.QWidget): self.message = message self.level = level + self.setWindowTitle(self.title) + if self.level == "info": self._info() elif self.level == "warning": self._warning() elif self.level == "critical": self._critical() + elif self.level == "ask": + self._ask() def _info(self): self.setWindowTitle(self.title) @@ -28,23 +32,32 @@ class Window(QtWidgets.QWidget): self.exit() def _warning(self): - self.setWindowTitle(self.title) rc = QtWidgets.QMessageBox.warning( self, self.title, self.message) if rc: self.exit() def _critical(self): - self.setWindowTitle(self.title) rc = QtWidgets.QMessageBox.critical( self, self.title, self.message) if rc: self.exit() + def _ask(self): + self.answer = None + rc = QtWidgets.QMessageBox.question( + self, + self.title, + self.message, + QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No + ) + self.answer = False + if rc == QtWidgets.QMessageBox.Yes: + self.answer = True + self.exit() + def exit(self): self.hide() - # self.parent.exec_() - # self.parent.hide() return @@ -78,7 +91,9 @@ def message(title=None, message=None, level="info", parent=None): except Exception: # skip all possible issues that may happen feature is not crutial log.warning("Couldn't center message.", exc_info=True) - # sys.exit(app.exec_()) + + if level == "ask": + return ex.answer class ScrollMessageBox(QtWidgets.QDialog): From 083dc5db830b5b958857655ac3976b2ba58e2a37 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Tue, 16 May 2023 18:00:13 +0200 Subject: [PATCH 008/112] Remove code from maya lib --- .../maya/api/workfile_template_builder.py | 39 ------------------- 1 file changed, 39 deletions(-) diff --git a/openpype/hosts/maya/api/workfile_template_builder.py b/openpype/hosts/maya/api/workfile_template_builder.py index b93132164a..561d085b08 100644 --- a/openpype/hosts/maya/api/workfile_template_builder.py +++ b/openpype/hosts/maya/api/workfile_template_builder.py @@ -9,9 +9,6 @@ from openpype.pipeline.workfile.workfile_template_builder import ( PlaceholderPlugin, LoadPlaceholderItem, PlaceholderLoadMixin, - TemplateLoadFailed, - TemplateNotFound, - TemplateProfileNotFound, ) from openpype.tools.workfile_template_build import ( WorkfileBuildPlaceholderDialog, @@ -27,42 +24,6 @@ class MayaTemplateBuilder(AbstractTemplateBuilder): use_legacy_creators = True - def open_template(self): - """Open template in current scene. - """ - - try: - template_preset = self.get_template_preset() - template_path = template_preset["path"] - - except ( - TemplateNotFound, - TemplateProfileNotFound, - TemplateLoadFailed - ) as e: - cmds.confirmDialog( - title="Error", - message="An error has occurred:\n{}".format(e), - button=["OK"], - defaultButton="OK", - ) - return - - result = cmds.confirmDialog( - title="Warning", - message="Opening a template will clear the current scene.", - button=["OK", "Cancel"], - defaultButton="OK", - cancelButton="Cancel", - dismissString="Cancel", - ) - - if result != "OK": - return - - print("opening template {}".format(template_path)) - cmds.file(template_path, open=True, force=True) - def import_template(self, path): """Import template into current scene. Block if a template is already loaded. From 873c9d9a03c519143acf1fc80b649f5e79237481 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Tue, 16 May 2023 18:11:06 +0200 Subject: [PATCH 009/112] Fix linter --- .../workfile/workfile_template_builder.py | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index 9cab9af9b7..1f56962eee 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -547,7 +547,9 @@ class AbstractTemplateBuilder(object): """ from openpype.widgets import message_window - module_name = 'openpype.hosts.{}.api.lib'.format(get_current_host_name()) + module_name = 'openpype.hosts.{}.api.lib'.format( + get_current_host_name() + ) api_lib = __import__(module_name, fromlist=['get_main_window']) main_window = api_lib.get_main_window() @@ -561,19 +563,19 @@ class AbstractTemplateBuilder(object): TemplateLoadFailed ) as e: message_window.message( - title="Template Load Failed", - message=str(e), - parent= main_window, - level="critical" + title = "Template Load Failed", + message = str(e), + parent = main_window, + level = "critical" ) return result = message_window.message( - title="Opening template", - message="Caution! This will overwrite your current scene.\n"\ + title = "Opening template", + message = "Caution! This will overwrite your current scene.\n"\ "Do you want to continue?", - parent= main_window, - level="ask", + parent = main_window, + level = "ask", ) if result: From 9676dec82da733a204ecb926ba05b7ae3b7a16d4 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Wed, 17 May 2023 11:22:05 +0200 Subject: [PATCH 010/112] Fix linter --- .../workfile/workfile_template_builder.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index 1f56962eee..54018b71b6 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -563,19 +563,19 @@ class AbstractTemplateBuilder(object): TemplateLoadFailed ) as e: message_window.message( - title = "Template Load Failed", - message = str(e), - parent = main_window, - level = "critical" + title="Template Load Failed", + message=str(e), + parent=main_window, + level="critical" ) return result = message_window.message( - title = "Opening template", - message = "Caution! This will overwrite your current scene.\n"\ - "Do you want to continue?", - parent = main_window, - level = "ask", + title="Opening template", + message="Caution! This will overwrite your current scene.\n" + "Do you want to continue?", + parent=main_window, + level="ask", ) if result: From 5acb386ea594ba1a6296b47241e0154dbed6ea07 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Tue, 23 May 2023 15:58:01 +0200 Subject: [PATCH 011/112] use self.host --- openpype/pipeline/workfile/workfile_template_builder.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index 54018b71b6..d56bf84757 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -40,7 +40,6 @@ from openpype.lib.attribute_definitions import get_attributes_keys from openpype.pipeline import ( legacy_io, Anatomy, - registered_host, get_current_host_name, ) from openpype.pipeline.load import ( @@ -579,8 +578,7 @@ class AbstractTemplateBuilder(object): ) if result: - host = registered_host() - host.open_file(template_path) + self.host.open_file(template_path) @abstractmethod def import_template(self, template_path): From ebfc0a339a553186b3624a337ee388c374367bba Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Wed, 24 May 2023 10:16:20 +0200 Subject: [PATCH 012/112] remove get_current_host_name method --- .../pipeline/workfile/workfile_template_builder.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index d56bf84757..fabf3652f9 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -37,11 +37,7 @@ from openpype.lib import ( attribute_definitions, ) from openpype.lib.attribute_definitions import get_attributes_keys -from openpype.pipeline import ( - legacy_io, - Anatomy, - get_current_host_name, -) +from openpype.pipeline import legacy_io, Anatomy from openpype.pipeline.load import ( get_loaders_by_name, get_contexts_for_repre_docs, @@ -546,9 +542,7 @@ class AbstractTemplateBuilder(object): """ from openpype.widgets import message_window - module_name = 'openpype.hosts.{}.api.lib'.format( - get_current_host_name() - ) + module_name = 'openpype.hosts.{}.api.lib'.format(self.host_name) api_lib = __import__(module_name, fromlist=['get_main_window']) main_window = api_lib.get_main_window() From 7402662161441640ba10df0d0d47556a3310eae4 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 30 Oct 2023 23:12:14 +0100 Subject: [PATCH 013/112] Remove `shelf` class and shelf build on maya `userSetup.py` --- openpype/hosts/maya/api/lib.py | 113 ----------------------- openpype/hosts/maya/startup/userSetup.py | 19 ---- 2 files changed, 132 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 7c49c837e9..f7eaf358fe 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -2921,119 +2921,6 @@ def fix_incompatible_containers(): "ReferenceLoader", type="string") -def _null(*args): - pass - - -class shelf(): - '''A simple class to build shelves in maya. Since the build method is empty, - it should be extended by the derived class to build the necessary shelf - elements. By default it creates an empty shelf called "customShelf".''' - - ########################################################################### - '''This is an example shelf.''' - # class customShelf(_shelf): - # def build(self): - # self.addButon(label="button1") - # self.addButon("button2") - # self.addButon("popup") - # p = cmds.popupMenu(b=1) - # self.addMenuItem(p, "popupMenuItem1") - # self.addMenuItem(p, "popupMenuItem2") - # sub = self.addSubMenu(p, "subMenuLevel1") - # self.addMenuItem(sub, "subMenuLevel1Item1") - # sub2 = self.addSubMenu(sub, "subMenuLevel2") - # self.addMenuItem(sub2, "subMenuLevel2Item1") - # self.addMenuItem(sub2, "subMenuLevel2Item2") - # self.addMenuItem(sub, "subMenuLevel1Item2") - # self.addMenuItem(p, "popupMenuItem3") - # self.addButon("button3") - # customShelf() - ########################################################################### - - def __init__(self, name="customShelf", iconPath="", preset={}): - self.name = name - - self.iconPath = iconPath - - self.labelBackground = (0, 0, 0, 0) - self.labelColour = (.9, .9, .9) - - self.preset = preset - - self._cleanOldShelf() - cmds.setParent(self.name) - self.build() - - def build(self): - '''This method should be overwritten in derived classes to actually - build the shelf elements. Otherwise, nothing is added to the shelf.''' - for item in self.preset['items']: - if not item.get('command'): - item['command'] = self._null - if item['type'] == 'button': - self.addButon(item['name'], - command=item['command'], - icon=item['icon']) - if item['type'] == 'menuItem': - self.addMenuItem(item['parent'], - item['name'], - command=item['command'], - icon=item['icon']) - if item['type'] == 'subMenu': - self.addMenuItem(item['parent'], - item['name'], - command=item['command'], - icon=item['icon']) - - def addButon(self, label, icon="commandButton.png", - command=_null, doubleCommand=_null): - ''' - Adds a shelf button with the specified label, command, - double click command and image. - ''' - cmds.setParent(self.name) - if icon: - icon = os.path.join(self.iconPath, icon) - print(icon) - cmds.shelfButton(width=37, height=37, image=icon, label=label, - command=command, dcc=doubleCommand, - imageOverlayLabel=label, olb=self.labelBackground, - olc=self.labelColour) - - def addMenuItem(self, parent, label, command=_null, icon=""): - ''' - Adds a shelf button with the specified label, command, - double click command and image. - ''' - if icon: - icon = os.path.join(self.iconPath, icon) - print(icon) - return cmds.menuItem(p=parent, label=label, c=command, i="") - - def addSubMenu(self, parent, label, icon=None): - ''' - Adds a sub menu item with the specified label and icon to - the specified parent popup menu. - ''' - if icon: - icon = os.path.join(self.iconPath, icon) - print(icon) - return cmds.menuItem(p=parent, label=label, i=icon, subMenu=1) - - def _cleanOldShelf(self): - ''' - Checks if the shelf exists and empties it if it does - or creates it if it does not. - ''' - if cmds.shelfLayout(self.name, ex=1): - if cmds.shelfLayout(self.name, q=1, ca=1): - for each in cmds.shelfLayout(self.name, q=1, ca=1): - cmds.deleteUI(each) - else: - cmds.shelfLayout(self.name, p="ShelfLayout") - - def _get_render_instances(): """Return all 'render-like' instances. diff --git a/openpype/hosts/maya/startup/userSetup.py b/openpype/hosts/maya/startup/userSetup.py index f2899cdb37..417f72a59f 100644 --- a/openpype/hosts/maya/startup/userSetup.py +++ b/openpype/hosts/maya/startup/userSetup.py @@ -46,24 +46,5 @@ if bool(int(os.environ.get(key, "0"))): lowestPriority=True ) -# Build a shelf. -shelf_preset = settings['maya'].get('project_shelf') -if shelf_preset: - icon_path = os.path.join( - os.environ['OPENPYPE_PROJECT_SCRIPTS'], - project_name, - "icons") - icon_path = os.path.abspath(icon_path) - - for i in shelf_preset['imports']: - import_string = "from {} import {}".format(project_name, i) - print(import_string) - exec(import_string) - - cmds.evalDeferred( - "mlib.shelf(name=shelf_preset['name'], iconPath=icon_path," - " preset=shelf_preset)" - ) - print("Finished OpenPype usersetup.") From 3d22cce9792dbdef1da19da75ff80b852e93472b Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Tue, 30 Jan 2024 10:08:03 +0000 Subject: [PATCH 014/112] Refactor Refactored UI code out of pipeline. --- .../maya/api/workfile_template_builder.py | 4 +- .../nuke/api/workfile_template_builder.py | 4 +- .../workfile/workfile_template_builder.py | 43 ++----------------- .../tools/workfile_template_build/__init__.py | 3 ++ openpype/tools/workfile_template_build/lib.py | 29 +++++++++++++ openpype/widgets/message_window.py | 8 ++-- 6 files changed, 44 insertions(+), 47 deletions(-) create mode 100644 openpype/tools/workfile_template_build/lib.py diff --git a/openpype/hosts/maya/api/workfile_template_builder.py b/openpype/hosts/maya/api/workfile_template_builder.py index e91fa839a3..0261d87b36 100644 --- a/openpype/hosts/maya/api/workfile_template_builder.py +++ b/openpype/hosts/maya/api/workfile_template_builder.py @@ -12,6 +12,7 @@ from openpype.pipeline.workfile.workfile_template_builder import ( ) from openpype.tools.workfile_template_build import ( WorkfileBuildPlaceholderDialog, + open_template_ui ) from .lib import read, imprint, get_reference_node, get_main_window @@ -342,8 +343,7 @@ def update_workfile_template(*args): def open_template(*args): - builder = MayaTemplateBuilder(registered_host()) - builder.open_template() + open_template_ui(MayaTemplateBuilder(registered_host()), get_main_window()) def create_placeholder(*args): diff --git a/openpype/hosts/nuke/api/workfile_template_builder.py b/openpype/hosts/nuke/api/workfile_template_builder.py index b07330e5b2..b4c780ec07 100644 --- a/openpype/hosts/nuke/api/workfile_template_builder.py +++ b/openpype/hosts/nuke/api/workfile_template_builder.py @@ -11,6 +11,7 @@ from openpype.pipeline.workfile.workfile_template_builder import ( ) from openpype.tools.workfile_template_build import ( WorkfileBuildPlaceholderDialog, + open_template_ui ) from .lib import ( find_free_space_to_paste_nodes, @@ -971,8 +972,7 @@ def update_workfile_template(*args): def open_template(*args): - builder = NukeTemplateBuilder(registered_host()) - builder.open_template() + open_template_ui(NukeTemplateBuilder(registered_host()), get_main_window()) def create_placeholder(*args): diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index c6a9a608f3..fffd761d38 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -552,45 +552,10 @@ class AbstractTemplateBuilder(object): self.clear_shared_populate_data() def open_template(self): - """Open template file in default application. - - Args: - template_path (str): Fullpath for current task and - host's template file. - """ - from openpype.widgets import message_window - - module_name = 'openpype.hosts.{}.api.lib'.format(self.host_name) - api_lib = __import__(module_name, fromlist=['get_main_window']) - main_window = api_lib.get_main_window() - - try: - template_preset = self.get_template_preset() - template_path = template_preset["path"] - - except ( - TemplateNotFound, - TemplateProfileNotFound, - TemplateLoadFailed - ) as e: - message_window.message( - title="Template Load Failed", - message=str(e), - parent=main_window, - level="critical" - ) - return - - result = message_window.message( - title="Opening template", - message="Caution! This will overwrite your current scene.\n" - "Do you want to continue?", - parent=main_window, - level="ask", - ) - - if result: - self.host.open_file(template_path) + """Open template file with registered host.""" + template_preset = self.get_template_preset() + template_path = template_preset["path"] + self.host.open_file(template_path) @abstractmethod def import_template(self, template_path): diff --git a/openpype/tools/workfile_template_build/__init__.py b/openpype/tools/workfile_template_build/__init__.py index 82a22aea50..ad94ebcf79 100644 --- a/openpype/tools/workfile_template_build/__init__.py +++ b/openpype/tools/workfile_template_build/__init__.py @@ -1,5 +1,8 @@ from .window import WorkfileBuildPlaceholderDialog +from .lib import open_template_ui __all__ = ( "WorkfileBuildPlaceholderDialog", + + "open_template_ui" ) diff --git a/openpype/tools/workfile_template_build/lib.py b/openpype/tools/workfile_template_build/lib.py new file mode 100644 index 0000000000..13c6fd9a2d --- /dev/null +++ b/openpype/tools/workfile_template_build/lib.py @@ -0,0 +1,29 @@ +import traceback + +from openpype.widgets import message_window + + +def open_template_ui(builder, main_window): + """Open template from `builder` + + Asks user about overwriting current scene and feedsback exceptions. + """ + + result = message_window.message( + title="Opening template", + message="Caution! This will overwrite your current scene.\n" + "Do you want to continue?", + parent=main_window, + level="question", + ) + + if result: + try: + builder.open_template() + except Exception: + message_window.message( + title="Template Load Failed", + message="".join(traceback.format_exc()), + parent=main_window, + level="critical" + ) diff --git a/openpype/widgets/message_window.py b/openpype/widgets/message_window.py index 59bbd5bf52..940d530565 100644 --- a/openpype/widgets/message_window.py +++ b/openpype/widgets/message_window.py @@ -21,8 +21,8 @@ class Window(QtWidgets.QWidget): self._warning() elif self.level == "critical": self._critical() - elif self.level == "ask": - self._ask() + elif self.level == "question": + self._question() def _info(self): self.setWindowTitle(self.title) @@ -43,7 +43,7 @@ class Window(QtWidgets.QWidget): if rc: self.exit() - def _ask(self): + def _question(self): self.answer = None rc = QtWidgets.QMessageBox.question( self, @@ -92,7 +92,7 @@ def message(title=None, message=None, level="info", parent=None): # skip all possible issues that may happen feature is not crutial log.warning("Couldn't center message.", exc_info=True) - if level == "ask": + if level == "question": return ex.answer From c3e81c131f65e8e464852db21991aad89dff22b3 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 2 Feb 2024 08:38:49 +0000 Subject: [PATCH 015/112] Move open template to Maya menu.py --- openpype/hosts/maya/api/menu.py | 12 ++++++++---- openpype/hosts/maya/api/workfile_template_builder.py | 7 +------ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/maya/api/menu.py b/openpype/hosts/maya/api/menu.py index f71c30ce15..18cac34a4a 100644 --- a/openpype/hosts/maya/api/menu.py +++ b/openpype/hosts/maya/api/menu.py @@ -9,7 +9,8 @@ import maya.cmds as cmds from openpype.pipeline import ( get_current_asset_name, - get_current_task_name + get_current_task_name, + registered_host ) from openpype.pipeline.workfile import BuildWorkfile from openpype.tools.utils import host_tools @@ -21,9 +22,10 @@ from .workfile_template_builder import ( create_placeholder, update_placeholder, build_workfile_template, - update_workfile_template, - open_template, + update_workfile_template ) +from openpype.tools.workfile_template_build import open_template_ui +from .workfile_template_builder import MayaTemplateBuilder log = logging.getLogger(__name__) @@ -185,7 +187,9 @@ def install(project_settings): cmds.menuItem( "Open Template", parent=builder_menu, - command=open_template, + command=lambda *args: open_template_ui( + MayaTemplateBuilder(registered_host()), get_main_window() + ), ) cmds.menuItem( "Create Placeholder", diff --git a/openpype/hosts/maya/api/workfile_template_builder.py b/openpype/hosts/maya/api/workfile_template_builder.py index 0261d87b36..aadf1cc21e 100644 --- a/openpype/hosts/maya/api/workfile_template_builder.py +++ b/openpype/hosts/maya/api/workfile_template_builder.py @@ -11,8 +11,7 @@ from openpype.pipeline.workfile.workfile_template_builder import ( PlaceholderLoadMixin, ) from openpype.tools.workfile_template_build import ( - WorkfileBuildPlaceholderDialog, - open_template_ui + WorkfileBuildPlaceholderDialog ) from .lib import read, imprint, get_reference_node, get_main_window @@ -342,10 +341,6 @@ def update_workfile_template(*args): builder.rebuild_template() -def open_template(*args): - open_template_ui(MayaTemplateBuilder(registered_host()), get_main_window()) - - def create_placeholder(*args): host = registered_host() builder = MayaTemplateBuilder(host) From 98f69448de6ddd1f74572774368423fc998aaf45 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 2 Feb 2024 08:45:44 +0000 Subject: [PATCH 016/112] Remove open_template --- openpype/hosts/nuke/api/pipeline.py | 8 ++++++-- openpype/hosts/nuke/api/workfile_template_builder.py | 7 +------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/nuke/api/pipeline.py b/openpype/hosts/nuke/api/pipeline.py index 3d6f3b9423..6bd7e3fb96 100644 --- a/openpype/hosts/nuke/api/pipeline.py +++ b/openpype/hosts/nuke/api/pipeline.py @@ -22,9 +22,11 @@ from openpype.pipeline import ( AVALON_CONTAINER_ID, get_current_asset_name, get_current_task_name, + registered_host, ) from openpype.pipeline.workfile import BuildWorkfile from openpype.tools.utils import host_tools +from openpype.tools.workfile_template_build import open_template_ui from .command import viewer_update_and_undo_stop from .lib import ( @@ -52,9 +54,9 @@ from .workfile_template_builder import ( NukePlaceholderLoadPlugin, NukePlaceholderCreatePlugin, build_workfile_template, - open_template, create_placeholder, update_placeholder, + NukeTemplateBuilder, ) from .workio import ( open_file, @@ -326,7 +328,9 @@ def _install_menu(): menu_template.addSeparator() menu_template.addCommand( "Open template", - lambda: open_template() + lambda: open_template_ui( + NukeTemplateBuilder(registered_host()), get_main_window() + ) ) menu_template.addCommand( "Create Place Holder", diff --git a/openpype/hosts/nuke/api/workfile_template_builder.py b/openpype/hosts/nuke/api/workfile_template_builder.py index b4c780ec07..8159840f32 100644 --- a/openpype/hosts/nuke/api/workfile_template_builder.py +++ b/openpype/hosts/nuke/api/workfile_template_builder.py @@ -10,8 +10,7 @@ from openpype.pipeline.workfile.workfile_template_builder import ( PlaceholderCreateMixin, ) from openpype.tools.workfile_template_build import ( - WorkfileBuildPlaceholderDialog, - open_template_ui + WorkfileBuildPlaceholderDialog ) from .lib import ( find_free_space_to_paste_nodes, @@ -971,10 +970,6 @@ def update_workfile_template(*args): builder.rebuild_template() -def open_template(*args): - open_template_ui(NukeTemplateBuilder(registered_host()), get_main_window()) - - def create_placeholder(*args): host = registered_host() builder = NukeTemplateBuilder(host) From b58917fefa0940ce3500446d2b25d84c85433bd8 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Mon, 5 Feb 2024 08:17:25 +0000 Subject: [PATCH 017/112] Update openpype/tools/workfile_template_build/lib.py --- openpype/tools/workfile_template_build/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/tools/workfile_template_build/lib.py b/openpype/tools/workfile_template_build/lib.py index 13c6fd9a2d..2f6dfb414f 100644 --- a/openpype/tools/workfile_template_build/lib.py +++ b/openpype/tools/workfile_template_build/lib.py @@ -11,7 +11,7 @@ def open_template_ui(builder, main_window): result = message_window.message( title="Opening template", - message="Caution! This will overwrite your current scene.\n" + message="Caution! You will loose unsaved changes.\n" "Do you want to continue?", parent=main_window, level="question", From f5c38eb8d794fc6f3f3517322a796d18d8036d82 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 5 Feb 2024 10:25:01 +0000 Subject: [PATCH 018/112] Thumbnail subset filtering --- openpype/plugins/publish/extract_thumbnail.py | 30 +++++++++++++++++-- .../defaults/project_settings/global.json | 1 + .../schemas/schema_global_publish.json | 6 ++++ .../core/server/settings/publish_plugins.py | 5 ++++ server_addon/core/server/version.py | 2 +- 5 files changed, 40 insertions(+), 4 deletions(-) diff --git a/openpype/plugins/publish/extract_thumbnail.py b/openpype/plugins/publish/extract_thumbnail.py index 10eb261482..6008b8323d 100644 --- a/openpype/plugins/publish/extract_thumbnail.py +++ b/openpype/plugins/publish/extract_thumbnail.py @@ -2,6 +2,7 @@ import copy import os import subprocess import tempfile +import re import pyblish.api from openpype.lib import ( @@ -14,9 +15,10 @@ from openpype.lib import ( path_to_subprocess_arg, run_subprocess, ) -from openpype.lib.transcoding import convert_colorspace - -from openpype.lib.transcoding import VIDEO_EXTENSIONS +from openpype.lib.transcoding import ( + convert_colorspace, + VIDEO_EXTENSIONS, +) class ExtractThumbnail(pyblish.api.InstancePlugin): @@ -49,6 +51,8 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): # attribute presets from settings oiiotool_defaults = None ffmpeg_args = None + subsets = [] + product_names = [] def process(self, instance): # run main process @@ -103,6 +107,26 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): self.log.debug("Skipping crypto passes.") return + # We only want to process the subsets needed from settings. + def validate_string_against_patterns(input_str, patterns): + for pattern in patterns: + if re.match(pattern, input_str): + return True + return False + + product_names = self.subsets + self.product_names + if product_names: + result = validate_string_against_patterns( + instance.data["subset"], product_names + ) + if not result: + self.log.debug( + "Subset \"{}\" did not match any valid subsets: {}".format( + instance.data["subset"], product_names + ) + ) + return + # first check for any explicitly marked representations for thumbnail explicit_repres = self._get_explicit_repres_for_thumbnail(instance) if explicit_repres: diff --git a/openpype/settings/defaults/project_settings/global.json b/openpype/settings/defaults/project_settings/global.json index bb7e3266bd..782fff1052 100644 --- a/openpype/settings/defaults/project_settings/global.json +++ b/openpype/settings/defaults/project_settings/global.json @@ -70,6 +70,7 @@ }, "ExtractThumbnail": { "enabled": true, + "subsets": [], "integrate_thumbnail": false, "background_color": [ 0, diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json index 64f292a140..226a190dd4 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json @@ -202,6 +202,12 @@ "key": "enabled", "label": "Enabled" }, + { + "type": "list", + "object_type": "text", + "key": "subsets", + "label": "Subsets" + }, { "type": "boolean", "key": "integrate_thumbnail", diff --git a/server_addon/core/server/settings/publish_plugins.py b/server_addon/core/server/settings/publish_plugins.py index 7aa86aafa6..8506801e7e 100644 --- a/server_addon/core/server/settings/publish_plugins.py +++ b/server_addon/core/server/settings/publish_plugins.py @@ -176,6 +176,10 @@ class ExtractThumbnailOIIODefaultsModel(BaseSettingsModel): class ExtractThumbnailModel(BaseSettingsModel): _isGroup = True enabled: bool = SettingsField(True) + product_names: list[str] = SettingsField( + default_factory=list, + title="Product names" + ) integrate_thumbnail: bool = SettingsField( True, title="Integrate Thumbnail Representation" @@ -844,6 +848,7 @@ DEFAULT_PUBLISH_VALUES = { }, "ExtractThumbnail": { "enabled": True, + "product_names": [], "integrate_thumbnail": True, "target_size": { "type": "source" diff --git a/server_addon/core/server/version.py b/server_addon/core/server/version.py index bbab0242f6..1276d0254f 100644 --- a/server_addon/core/server/version.py +++ b/server_addon/core/server/version.py @@ -1 +1 @@ -__version__ = "0.1.4" +__version__ = "0.1.5" From 02b371139a2c671e04cfdff2de5817975cdeb73c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 8 Feb 2024 14:45:14 +0100 Subject: [PATCH 019/112] reduce usage of legay_io --- client/ayon_core/host/host.py | 3 - .../hosts/aftereffects/api/launch_logic.py | 5 +- .../ayon_core/hosts/blender/api/pipeline.py | 3 +- client/ayon_core/hosts/fusion/api/plugin.py | 3 +- client/ayon_core/hosts/maya/api/pipeline.py | 7 +- .../maya/plugins/load/load_arnold_standin.py | 8 +- .../maya/plugins/publish/collect_vrayscene.py | 5 - .../plugins/publish/validate_model_name.py | 1 - .../publish/validate_node_ids_in_database.py | 1 - .../publish/validate_renderlayer_aovs.py | 1 - .../validate_unreal_staticmesh_naming.py | 2 - .../plugins/publish/collect_batch_data.py | 3 - .../hosts/traypublisher/api/pipeline.py | 4 - .../ayon_core/hosts/tvpaint/api/pipeline.py | 6 +- .../plugins/publish/collect_workfile_data.py | 2 - .../publish/collect_sequences_from_job.py | 3 - .../publish/create_publish_royalrender_job.py | 4 - client/ayon_core/pipeline/context_tools.py | 176 +++++++----------- client/ayon_core/pipeline/create/context.py | 15 +- .../ayon_core/pipeline/create/subset_name.py | 3 +- client/ayon_core/pipeline/load/plugins.py | 5 +- .../publish/collect_from_create_context.py | 3 +- .../ayon_core/tools/sceneinventory/control.py | 3 +- client/ayon_core/tools/texture_copy/app.py | 7 +- .../tools/workfile_template_build/window.py | 5 +- 25 files changed, 90 insertions(+), 188 deletions(-) diff --git a/client/ayon_core/host/host.py b/client/ayon_core/host/host.py index 6d129e18d9..2dd98c8126 100644 --- a/client/ayon_core/host/host.py +++ b/client/ayon_core/host/host.py @@ -49,7 +49,6 @@ class HostBase(object): Todo: - move content of 'install_host' as method of this class - register host object - - install legacy_io - install global plugin paths - store registered plugin paths to this object - handle current context (project, asset, task) @@ -133,8 +132,6 @@ class HostBase(object): can be opened multiple workfiles at one moment and change of context can't be caught properly. - Default implementation returns values from 'legacy_io.Session'. - Returns: Dict[str, Union[str, None]]: Context with 3 keys 'project_name', 'asset_name' and 'task_name'. All of them can be 'None'. diff --git a/client/ayon_core/hosts/aftereffects/api/launch_logic.py b/client/ayon_core/hosts/aftereffects/api/launch_logic.py index ad521c2f01..3d09f4d53c 100644 --- a/client/ayon_core/hosts/aftereffects/api/launch_logic.py +++ b/client/ayon_core/hosts/aftereffects/api/launch_logic.py @@ -17,7 +17,7 @@ from qtpy import QtCore from ayon_core.lib import Logger from ayon_core.tests.lib import is_in_tests -from ayon_core.pipeline import install_host, legacy_io +from ayon_core.pipeline import install_host from ayon_core.addon import AddonsManager from ayon_core.tools.utils import host_tools, get_ayon_qt_app from ayon_core.tools.adobe_webserver.app import WebServerTool @@ -298,13 +298,10 @@ class AfterEffectsRoute(WebSocketRoute): log.info("Setting context change") log.info("project {} asset {} ".format(project, asset)) if project: - legacy_io.Session["AVALON_PROJECT"] = project os.environ["AVALON_PROJECT"] = project if asset: - legacy_io.Session["AVALON_ASSET"] = asset os.environ["AVALON_ASSET"] = asset if task: - legacy_io.Session["AVALON_TASK"] = task os.environ["AVALON_TASK"] = task async def read(self): diff --git a/client/ayon_core/hosts/blender/api/pipeline.py b/client/ayon_core/hosts/blender/api/pipeline.py index 6801b1f71b..77731a0fd3 100644 --- a/client/ayon_core/hosts/blender/api/pipeline.py +++ b/client/ayon_core/hosts/blender/api/pipeline.py @@ -19,7 +19,6 @@ from ayon_core.host import ( from ayon_core.client import get_asset_by_name from ayon_core.pipeline import ( schema, - legacy_io, get_current_project_name, get_current_asset_name, register_loader_plugin_path, @@ -380,7 +379,7 @@ def _on_task_changed(): # `directory` attribute, so it opens in that directory (does it?). # https://docs.blender.org/api/blender2.8/bpy.types.Operator.html#calling-a-file-selector # https://docs.blender.org/api/blender2.8/bpy.types.WindowManager.html#bpy.types.WindowManager.fileselect_add - workdir = legacy_io.Session["AVALON_WORKDIR"] + workdir = os.getenv("AVALON_WORKDIR") log.debug("New working directory: %s", workdir) diff --git a/client/ayon_core/hosts/fusion/api/plugin.py b/client/ayon_core/hosts/fusion/api/plugin.py index 12a29d2986..80e194ea68 100644 --- a/client/ayon_core/hosts/fusion/api/plugin.py +++ b/client/ayon_core/hosts/fusion/api/plugin.py @@ -11,7 +11,6 @@ from ayon_core.lib import ( EnumDef, ) from ayon_core.pipeline import ( - legacy_io, Creator, CreatedInstance ) @@ -136,7 +135,7 @@ class GenericCreateSaver(Creator): ext = data["creator_attributes"]["image_format"] # Subset change detected - workdir = os.path.normpath(legacy_io.Session["AVALON_WORKDIR"]) + workdir = os.path.normpath(os.getenv("AVALON_WORKDIR")) formatting_data.update({ "workdir": workdir, "frame": "0" * frame_padding, diff --git a/client/ayon_core/hosts/maya/api/pipeline.py b/client/ayon_core/hosts/maya/api/pipeline.py index 95617cb90a..dc6353618a 100644 --- a/client/ayon_core/hosts/maya/api/pipeline.py +++ b/client/ayon_core/hosts/maya/api/pipeline.py @@ -26,7 +26,6 @@ from ayon_core.lib import ( emit_event ) from ayon_core.pipeline import ( - legacy_io, get_current_project_name, register_loader_plugin_path, register_inventory_action_path, @@ -247,7 +246,7 @@ def _set_project(): None """ - workdir = legacy_io.Session["AVALON_WORKDIR"] + workdir = os.getenv("AVALON_WORKDIR") try: os.makedirs(workdir) @@ -629,7 +628,7 @@ def on_task_changed(): # Run menu.update_menu_task_label() - workdir = legacy_io.Session["AVALON_WORKDIR"] + workdir = os.getenv("AVALON_WORKDIR") if os.path.exists(workdir): log.info("Updating Maya workspace for task change to %s", workdir) _set_project() @@ -678,7 +677,7 @@ def workfile_save_before_xgen(event): import xgenm - current_work_dir = legacy_io.Session["AVALON_WORKDIR"].replace("\\", "/") + current_work_dir = os.getenv("AVALON_WORKDIR").replace("\\", "/") expected_work_dir = event.data["workdir_path"].replace("\\", "/") if current_work_dir == expected_work_dir: return diff --git a/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py b/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py index c690d1c205..97407fbcc2 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py @@ -6,7 +6,6 @@ import maya.cmds as cmds from ayon_core.settings import get_project_settings from ayon_core.pipeline import ( load, - legacy_io, get_representation_path ) from ayon_core.hosts.maya.api.lib import ( @@ -26,11 +25,6 @@ def is_sequence(files): return sequence -def get_current_session_fps(): - session_fps = float(legacy_io.Session.get('AVALON_FPS', 25)) - return convert_to_maya_fps(session_fps) - - class ArnoldStandinLoader(load.LoaderPlugin): """Load as Arnold standin""" @@ -99,7 +93,7 @@ class ArnoldStandinLoader(load.LoaderPlugin): sequence = is_sequence(os.listdir(os.path.dirname(repre_path))) cmds.setAttr(standin_shape + ".useFrameExtension", sequence) - fps = float(version["data"].get("fps"))or get_current_session_fps() + fps = float(version["data"].get("fps")) or 25 cmds.setAttr(standin_shape + ".abcFPS", fps) nodes = [root, standin, standin_shape] diff --git a/client/ayon_core/hosts/maya/plugins/publish/collect_vrayscene.py b/client/ayon_core/hosts/maya/plugins/publish/collect_vrayscene.py index 0efefe72c7..db008cc2be 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/collect_vrayscene.py +++ b/client/ayon_core/hosts/maya/plugins/publish/collect_vrayscene.py @@ -1,13 +1,8 @@ # -*- coding: utf-8 -*- """Collect Vray Scene and prepare it for extraction and publishing.""" -import re - -import maya.app.renderSetup.model.renderSetup as renderSetup -from maya import cmds import pyblish.api -from ayon_core.pipeline import legacy_io from ayon_core.lib import get_formatted_current_time from ayon_core.hosts.maya.api import lib diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_model_name.py b/client/ayon_core/hosts/maya/plugins/publish/validate_model_name.py index 7812877fd3..cf2bbcd77c 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_model_name.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_model_name.py @@ -12,7 +12,6 @@ import ayon_core.hosts.maya.api.action from ayon_core.client.mongo import OpenPypeMongoConnection from ayon_core.hosts.maya.api.shader_definition_editor import ( DEFINITION_FILENAME) -from ayon_core.pipeline import legacy_io from ayon_core.pipeline.publish import ( OptionalPyblishPluginMixin, PublishValidationError, ValidateContentsOrder) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_in_database.py b/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_in_database.py index bf12def5e9..de86ffe575 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_in_database.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_in_database.py @@ -3,7 +3,6 @@ import pyblish.api import ayon_core.hosts.maya.api.action from ayon_core.client import get_assets from ayon_core.hosts.maya.api import lib -from ayon_core.pipeline import legacy_io from ayon_core.pipeline.publish import ( PublishValidationError, ValidatePipelineOrder) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_renderlayer_aovs.py b/client/ayon_core/hosts/maya/plugins/publish/validate_renderlayer_aovs.py index 71cd6d7112..b5bfdcc9ec 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_renderlayer_aovs.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_renderlayer_aovs.py @@ -2,7 +2,6 @@ import pyblish.api import ayon_core.hosts.maya.api.action from ayon_core.client import get_subset_by_name -from ayon_core.pipeline import legacy_io from ayon_core.pipeline.publish import PublishValidationError diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_unreal_staticmesh_naming.py b/client/ayon_core/hosts/maya/plugins/publish/validate_unreal_staticmesh_naming.py index d43e04da60..21ea827f68 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_unreal_staticmesh_naming.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_unreal_staticmesh_naming.py @@ -5,8 +5,6 @@ import re import pyblish.api import ayon_core.hosts.maya.api.action -from ayon_core.pipeline import legacy_io -from ayon_core.settings import get_project_settings from ayon_core.pipeline.publish import ( ValidateContentsOrder, OptionalPyblishPluginMixin, diff --git a/client/ayon_core/hosts/photoshop/plugins/publish/collect_batch_data.py b/client/ayon_core/hosts/photoshop/plugins/publish/collect_batch_data.py index 5e43a021c3..6639040bd7 100644 --- a/client/ayon_core/hosts/photoshop/plugins/publish/collect_batch_data.py +++ b/client/ayon_core/hosts/photoshop/plugins/publish/collect_batch_data.py @@ -17,7 +17,6 @@ import os import pyblish.api -from ayon_core.pipeline import legacy_io from openpype_modules.webpublisher.lib import ( get_batch_asset_task_info, parse_json @@ -71,8 +70,6 @@ class CollectBatchData(pyblish.api.ContextPlugin): os.environ["AVALON_ASSET"] = asset_name os.environ["AVALON_TASK"] = task_name - legacy_io.Session["AVALON_ASSET"] = asset_name - legacy_io.Session["AVALON_TASK"] = task_name context.data["asset"] = asset_name context.data["task"] = task_name diff --git a/client/ayon_core/hosts/traypublisher/api/pipeline.py b/client/ayon_core/hosts/traypublisher/api/pipeline.py index 87177705c9..88fa3239a5 100644 --- a/client/ayon_core/hosts/traypublisher/api/pipeline.py +++ b/client/ayon_core/hosts/traypublisher/api/pipeline.py @@ -7,7 +7,6 @@ import pyblish.api from ayon_core.pipeline import ( register_creator_plugin_path, - legacy_io, ) from ayon_core.host import HostBase, IPublishHost @@ -24,7 +23,6 @@ class TrayPublisherHost(HostBase, IPublishHost): def install(self): os.environ["AVALON_APP"] = self.name - legacy_io.Session["AVALON_APP"] = self.name pyblish.api.register_host("traypublisher") pyblish.api.register_plugin_path(PUBLISH_PATH) @@ -43,8 +41,6 @@ class TrayPublisherHost(HostBase, IPublishHost): # TODO Deregister project specific plugins and register new project # plugins os.environ["AVALON_PROJECT"] = project_name - legacy_io.Session["AVALON_PROJECT"] = project_name - legacy_io.install() HostContext.set_project_name(project_name) diff --git a/client/ayon_core/hosts/tvpaint/api/pipeline.py b/client/ayon_core/hosts/tvpaint/api/pipeline.py index 1360b423b3..d636e68cfa 100644 --- a/client/ayon_core/hosts/tvpaint/api/pipeline.py +++ b/client/ayon_core/hosts/tvpaint/api/pipeline.py @@ -13,7 +13,6 @@ from ayon_core.hosts.tvpaint import TVPAINT_ROOT_DIR from ayon_core.settings import get_current_project_settings from ayon_core.lib import register_event_callback from ayon_core.pipeline import ( - legacy_io, register_loader_plugin_path, register_creator_plugin_path, AVALON_CONTAINER_ID, @@ -66,11 +65,10 @@ class TVPaintHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost): def install(self): """Install TVPaint-specific functionality.""" - log.info("OpenPype - Installing TVPaint integration") - legacy_io.install() + log.info("AYON - Installing TVPaint integration") # Create workdir folder if does not exist yet - workdir = legacy_io.Session["AVALON_WORKDIR"] + workdir = os.getenv("AVALON_WORKDIR") if not os.path.exists(workdir): os.makedirs(workdir) diff --git a/client/ayon_core/hosts/tvpaint/plugins/publish/collect_workfile_data.py b/client/ayon_core/hosts/tvpaint/plugins/publish/collect_workfile_data.py index 9fbf67863a..05ceb143e9 100644 --- a/client/ayon_core/hosts/tvpaint/plugins/publish/collect_workfile_data.py +++ b/client/ayon_core/hosts/tvpaint/plugins/publish/collect_workfile_data.py @@ -4,7 +4,6 @@ import tempfile import pyblish.api -from ayon_core.pipeline import legacy_io from ayon_core.hosts.tvpaint.api.lib import ( execute_george, execute_george_through_file, @@ -90,7 +89,6 @@ class CollectWorkfileData(pyblish.api.ContextPlugin): ("AVALON_TASK", "task_name") ) for env_key, key in key_map: - legacy_io.Session[env_key] = workfile_context[key] os.environ[env_key] = workfile_context[key] self.log.info("Context changed to: {}".format(workfile_context)) diff --git a/client/ayon_core/modules/royalrender/plugins/publish/collect_sequences_from_job.py b/client/ayon_core/modules/royalrender/plugins/publish/collect_sequences_from_job.py index a253a1ec5b..cd34ba9bb3 100644 --- a/client/ayon_core/modules/royalrender/plugins/publish/collect_sequences_from_job.py +++ b/client/ayon_core/modules/royalrender/plugins/publish/collect_sequences_from_job.py @@ -8,8 +8,6 @@ from pprint import pformat import pyblish.api -from ayon_core.pipeline import legacy_io - def collect(root, regex=None, @@ -132,7 +130,6 @@ class CollectSequencesFromJob(pyblish.api.ContextPlugin): session = metadata.get("session") if session: self.log.info("setting session using metadata") - legacy_io.Session.update(session) os.environ.update(session) else: diff --git a/client/ayon_core/modules/royalrender/plugins/publish/create_publish_royalrender_job.py b/client/ayon_core/modules/royalrender/plugins/publish/create_publish_royalrender_job.py index 680795a329..abc8d7dccd 100644 --- a/client/ayon_core/modules/royalrender/plugins/publish/create_publish_royalrender_job.py +++ b/client/ayon_core/modules/royalrender/plugins/publish/create_publish_royalrender_job.py @@ -13,9 +13,6 @@ from ayon_core.modules.royalrender.rr_job import ( get_rr_platform ) from ayon_core.pipeline.publish import KnownPublishError -from ayon_core.pipeline import ( - legacy_io, -) from ayon_core.pipeline.farm.pyblish_functions import ( create_skeleton_instance, create_instances_for_aov, @@ -145,7 +142,6 @@ class CreatePublishRoyalRenderJob(pyblish.api.InstancePlugin, "intent": instance.context.data.get("intent"), "comment": instance.context.data.get("comment"), "job": attr.asdict(rr_job), - "session": legacy_io.Session.copy(), "instances": instances } diff --git a/client/ayon_core/pipeline/context_tools.py b/client/ayon_core/pipeline/context_tools.py index 197b1eb6e6..64d8e1f6d6 100644 --- a/client/ayon_core/pipeline/context_tools.py +++ b/client/ayon_core/pipeline/context_tools.py @@ -29,11 +29,11 @@ from .publish.lib import filter_pyblish_plugins from .anatomy import Anatomy from .template_data import get_template_data_with_names from .workfile import ( + get_workdir, get_workfile_template_key, get_custom_workfile_template_by_string_context, ) from . import ( - legacy_io, register_loader_plugin_path, register_inventory_action_path, register_creator_plugin_path, @@ -116,22 +116,15 @@ def install_host(host): # Make sure global AYON connection has set site id and version get_ayon_server_api_connection() - legacy_io.install() addons_manager = _get_addons_manager() - missing = list() - for key in ("AVALON_PROJECT", "AVALON_ASSET"): - if key not in legacy_io.Session: - missing.append(key) + project_name = os.getenv("AVALON_PROJECT") + if not project_name: + raise ValueError( + "AVALON_PROJECT is missing in environment variables." + ) - assert not missing, ( - "%s missing from environment, %s" % ( - ", ".join(missing), - json.dumps(legacy_io.Session, indent=4, sort_keys=True) - )) - - project_name = legacy_io.Session["AVALON_PROJECT"] - log.info("Activating %s.." % project_name) + log.info("Activating {}..".format(project_name)) # Optional host install function if hasattr(host, "install"): @@ -158,7 +151,6 @@ def install_host(host): print("Registering pyblish target: automated") pyblish.api.register_target("automated") - project_name = os.environ.get("AVALON_PROJECT") host_name = os.environ.get("AVALON_APP") # Give option to handle host installation @@ -256,8 +248,6 @@ def uninstall_host(): deregister_host() - legacy_io.uninstall() - log.info("Successfully uninstalled Avalon!") @@ -482,13 +472,17 @@ def get_template_data_from_session(session=None, system_settings=None): Dict[str, Any]: All available data from session. """ - if session is None: - session = legacy_io.Session - - project_name = session["AVALON_PROJECT"] - asset_name = session["AVALON_ASSET"] - task_name = session["AVALON_TASK"] - host_name = session["AVALON_APP"] + if session is not None: + project_name = session["AVALON_PROJECT"] + asset_name = session["AVALON_ASSET"] + task_name = session["AVALON_TASK"] + host_name = session["AVALON_APP"] + else: + context = get_current_context() + project_name = context["project_name"] + asset_name = context["asset_name"] + task_name = context["task_name"] + host_name = get_current_host_name() return get_template_data_with_names( project_name, asset_name, task_name, host_name, system_settings @@ -529,10 +523,12 @@ def get_workdir_from_session(session=None, template_key=None): str: Workdir path. """ - if session is None: - session = legacy_io.Session - project_name = session["AVALON_PROJECT"] - host_name = session["AVALON_APP"] + if session is not None: + project_name = session["AVALON_PROJECT"] + host_name = session["AVALON_APP"] + else: + project_name = get_current_project_name() + host_name = get_current_host_name() template_data = get_template_data_from_session(session) if not template_key: @@ -556,86 +552,39 @@ def get_custom_workfile_template_from_session( ): """Filter and fill workfile template profiles by current context. - Current context is defined by `legacy_io.Session`. That's why this - function should be used only inside host where context is set and stable. + This function cab be used only inside host where context is set. Args: - session (Union[None, Dict[str, str]]): Session from which are taken + session (Optional[Dict[str, str]]): Session from which are taken data. - project_settings(Dict[str, Any]): Template profiles from settings. + project_settings(Optional[Dict[str, Any]]): Project settings. Returns: str: Path to template or None if none of profiles match current context. (Existence of formatted path is not validated.) """ - if session is None: - session = legacy_io.Session + if session is not None: + project_name = session["AVALON_PROJECT"] + asset_name = session["AVALON_ASSET"] + task_name = session["AVALON_TASK"] + host_name = session["AVALON_APP"] + else: + context = get_current_context() + project_name = context["project_name"] + asset_name = context["asset_name"] + task_name = context["task_name"] + host_name = get_current_host_name() return get_custom_workfile_template_by_string_context( - session["AVALON_PROJECT"], - session["AVALON_ASSET"], - session["AVALON_TASK"], - session["AVALON_APP"], + project_name, + asset_name, + task_name, + host_name, project_settings=project_settings ) -def compute_session_changes( - session, asset_doc, task_name, template_key=None -): - """Compute the changes for a session object on task under asset. - - Function does not change the session object, only returns changes. - - Args: - session (Dict[str, str]): The initial session to compute changes to. - This is required for computing the full Work Directory, as that - also depends on the values that haven't changed. - asset_doc (Dict[str, Any]): Asset document to switch to. - task_name (str): Name of task to switch to. - template_key (Union[str, None]): Prepare workfile template key in - anatomy templates. - - Returns: - Dict[str, str]: Changes in the Session dictionary. - """ - - # Get asset document and asset - if not asset_doc: - task_name = None - asset_name = None - else: - asset_name = get_asset_name_identifier(asset_doc) - - # Detect any changes compared session - mapping = { - "AVALON_ASSET": asset_name, - "AVALON_TASK": task_name, - } - changes = { - key: value - for key, value in mapping.items() - if value != session.get(key) - } - if not changes: - return changes - - # Compute work directory (with the temporary changed session so far) - changed_session = session.copy() - changed_session.update(changes) - - workdir = None - if asset_doc: - workdir = get_workdir_from_session( - changed_session, template_key - ) - - changes["AVALON_WORKDIR"] = workdir - - return changes - - def change_current_context(asset_doc, task_name, template_key=None): """Update active Session to a new task work area. @@ -651,32 +600,47 @@ def change_current_context(asset_doc, task_name, template_key=None): Dict[str, str]: The changed key, values in the current Session. """ - changes = compute_session_changes( - legacy_io.Session, - asset_doc, - task_name, - template_key=template_key - ) + project_name = get_current_project_name() + workdir = None + if asset_doc: + project_doc = get_project(project_name) + host_name = get_current_host_name() + workdir = get_workdir( + project_doc, + asset_doc, + task_name, + host_name, + template_key=template_key + ) + + folder_path = get_asset_name_identifier(asset_doc) + envs = { + "AVALON_PROJECT": project_name, + "AVALON_ASSET": folder_path, + "AVALON_TASK": task_name, + "AVALON_WORKDIR": workdir, + } # Update the Session and environments. Pop from environments all keys with # value set to None. - for key, value in changes.items(): - legacy_io.Session[key] = value + for key, value in envs.items(): if value is None: os.environ.pop(key, None) else: os.environ[key] = value - data = changes.copy() + data = envs.copy() + # Convert env keys to human readable keys - data["project_name"] = legacy_io.Session["AVALON_PROJECT"] - data["asset_name"] = legacy_io.Session["AVALON_ASSET"] - data["task_name"] = legacy_io.Session["AVALON_TASK"] + data["project_name"] = project_name + data["asset_name"] = get_asset_name_identifier(asset_doc) + data["task_name"] = task_name + data["workdir_path"] = workdir # Emit session change emit_event("taskChanged", data) - return changes + return data def get_process_id(): diff --git a/client/ayon_core/pipeline/create/context.py b/client/ayon_core/pipeline/create/context.py index 8990d50324..be685ea2cc 100644 --- a/client/ayon_core/pipeline/create/context.py +++ b/client/ayon_core/pipeline/create/context.py @@ -27,7 +27,7 @@ from ayon_core.lib.attribute_definitions import ( get_default_values, ) from ayon_core.host import IPublishHost, IWorkfileHost -from ayon_core.pipeline import legacy_io, Anatomy +from ayon_core.pipeline import Anatomy from ayon_core.pipeline.plugin_discover import DiscoverResult from .creator_plugins import ( @@ -1684,25 +1684,16 @@ class CreateContext: if isinstance(self.host, IWorkfileHost): workfile_path = self.host.get_current_workfile() - # --- TODO remove these conditions --- - if not project_name: - project_name = legacy_io.Session.get("AVALON_PROJECT") - if not asset_name: - asset_name = legacy_io.Session.get("AVALON_ASSET") - if not task_name: - task_name = legacy_io.Session.get("AVALON_TASK") - # --- return project_name, asset_name, task_name, workfile_path def reset_current_context(self): """Refresh current context. Reset is based on optional host implementation of `get_current_context` - function or using `legacy_io.Session`. + function. Some hosts have ability to change context file without using workfiles - tool but that change is not propagated to 'legacy_io.Session' - nor 'os.environ'. + tool but that change is not propagated to 'os.environ'. Todos: UI: Current context should be also checked on save - compare diff --git a/client/ayon_core/pipeline/create/subset_name.py b/client/ayon_core/pipeline/create/subset_name.py index 3892971ce8..2973b1e54e 100644 --- a/client/ayon_core/pipeline/create/subset_name.py +++ b/client/ayon_core/pipeline/create/subset_name.py @@ -2,7 +2,6 @@ import os from ayon_core.settings import get_project_settings from ayon_core.lib import filter_profiles, prepare_template_data -from ayon_core.pipeline import legacy_io from .constants import DEFAULT_SUBSET_TEMPLATE @@ -135,7 +134,7 @@ def get_subset_name( family = family.rsplit(".", 1)[-1] if project_name is None: - project_name = legacy_io.Session["AVALON_PROJECT"] + project_name = os.environ.get("AVALON_PROJECT") asset_tasks = asset_doc.get("data", {}).get("tasks") or {} task_info = asset_tasks.get(task_name) or {} diff --git a/client/ayon_core/pipeline/load/plugins.py b/client/ayon_core/pipeline/load/plugins.py index e13260d296..fc64edf2ae 100644 --- a/client/ayon_core/pipeline/load/plugins.py +++ b/client/ayon_core/pipeline/load/plugins.py @@ -2,10 +2,7 @@ import os import logging from ayon_core.settings import get_system_settings, get_project_settings -from ayon_core.pipeline import ( - schema, - legacy_io, -) +from ayon_core.pipeline import schema from ayon_core.pipeline.plugin_discover import ( discover, register_plugin, diff --git a/client/ayon_core/plugins/publish/collect_from_create_context.py b/client/ayon_core/plugins/publish/collect_from_create_context.py index d38138b2e9..d8e803a43c 100644 --- a/client/ayon_core/plugins/publish/collect_from_create_context.py +++ b/client/ayon_core/plugins/publish/collect_from_create_context.py @@ -5,7 +5,7 @@ import os import pyblish.api from ayon_core.host import IPublishHost -from ayon_core.pipeline import legacy_io, registered_host +from ayon_core.pipeline import registered_host from ayon_core.pipeline.create import CreateContext @@ -61,7 +61,6 @@ class CollectFromCreateContext(pyblish.api.ContextPlugin): ("AVALON_ASSET", asset_name), ("AVALON_TASK", task_name) ): - legacy_io.Session[key] = value os.environ[key] = value def create_instance( diff --git a/client/ayon_core/tools/sceneinventory/control.py b/client/ayon_core/tools/sceneinventory/control.py index 409f92b506..54e4e9941e 100644 --- a/client/ayon_core/tools/sceneinventory/control.py +++ b/client/ayon_core/tools/sceneinventory/control.py @@ -14,8 +14,7 @@ from .models import SiteSyncModel class SceneInventoryController: """This is a temporary controller for AYON. - Goal of this temporary controller is to provide a way to get current - context instead of using 'AvalonMongoDB' object (or 'legacy_io'). + Goal of this controller is to provide a way to get current context. Also provides (hopefully) cleaner api for site sync. """ diff --git a/client/ayon_core/tools/texture_copy/app.py b/client/ayon_core/tools/texture_copy/app.py index 064f4e5577..9b4406d8e7 100644 --- a/client/ayon_core/tools/texture_copy/app.py +++ b/client/ayon_core/tools/texture_copy/app.py @@ -6,7 +6,7 @@ import speedcopy from ayon_core.client import get_project, get_asset_by_name from ayon_core.lib import Terminal -from ayon_core.pipeline import legacy_io, Anatomy +from ayon_core.pipeline import Anatomy t = Terminal() @@ -16,11 +16,6 @@ texture_extensions = ['.tif', '.tiff', '.jpg', '.jpeg', '.tx', '.png', '.tga', class TextureCopy: - - def __init__(self): - if not legacy_io.Session: - legacy_io.install() - def _get_textures(self, path): textures = [] for dir, subdir, files in os.walk(path): diff --git a/client/ayon_core/tools/workfile_template_build/window.py b/client/ayon_core/tools/workfile_template_build/window.py index 7f95bac60a..ae4946d41d 100644 --- a/client/ayon_core/tools/workfile_template_build/window.py +++ b/client/ayon_core/tools/workfile_template_build/window.py @@ -1,8 +1,9 @@ +import os + from qtpy import QtWidgets from ayon_core import style from ayon_core.lib import Logger -from ayon_core.pipeline import legacy_io from ayon_core.tools.attribute_defs import AttributeDefinitionsWidget @@ -26,7 +27,7 @@ class WorkfileBuildPlaceholderDialog(QtWidgets.QDialog): host_name = getattr(self._host, "name", None) if not host_name: - host_name = legacy_io.Session.get("AVALON_APP") or "NA" + host_name = os.getenv("AVALON_APP") or "NA" self._host_name = host_name plugins_combo = QtWidgets.QComboBox(self) From e40cc563004524b7c576f17c6e83d279f9f17e28 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 8 Feb 2024 14:51:15 +0100 Subject: [PATCH 020/112] don't use legacy_io in farm deadline --- .../publish/submit_aftereffects_deadline.py | 9 ++++-- .../publish/submit_blender_deadline.py | 9 ++++-- .../plugins/publish/submit_fusion_deadline.py | 9 ++++-- .../publish/submit_harmony_deadline.py | 9 ++++-- .../publish/submit_houdini_cache_deadline.py | 9 ++++-- .../publish/submit_houdini_render_deadline.py | 10 +++++-- .../plugins/publish/submit_max_deadline.py | 9 ++++-- .../plugins/publish/submit_maya_deadline.py | 9 ++++-- .../submit_maya_remote_publish_deadline.py | 10 ++++--- .../plugins/publish/submit_nuke_deadline.py | 8 ++++-- .../publish/submit_publish_cache_job.py | 5 ++-- .../plugins/publish/submit_publish_job.py | 5 ++-- .../plugins/publish/collect_rendered_files.py | 28 +++++++++++-------- 13 files changed, 80 insertions(+), 49 deletions(-) diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_aftereffects_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_aftereffects_deadline.py index f7bc5529fb..618b71bbaf 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_aftereffects_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_aftereffects_deadline.py @@ -8,7 +8,6 @@ from ayon_core.lib import ( env_value_to_bool, collect_frames, ) -from ayon_core.pipeline import legacy_io from openpype_modules.deadline import abstract_submit_deadline from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo from ayon_core.tests.lib import is_in_tests @@ -84,13 +83,17 @@ class AfterEffectsSubmitDeadline( "AVALON_PROJECT", "AVALON_ASSET", "AVALON_TASK", + "AVALON_WORKDIR", "AVALON_APP_NAME", "AYON_LOG_NO_COLORS", "IS_TEST" ] - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } for key in keys: value = environment.get(key) if value: diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_blender_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_blender_deadline.py index c8b72ca52b..af864ace5b 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_blender_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_blender_deadline.py @@ -11,7 +11,6 @@ from ayon_core.lib import ( NumberDef, TextDef, ) -from ayon_core.pipeline import legacy_io from ayon_core.pipeline.publish import AYONPyblishPluginMixin from ayon_core.pipeline.farm.tools import iter_expected_files from ayon_core.tests.lib import is_in_tests @@ -106,12 +105,16 @@ class BlenderSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, "AVALON_PROJECT", "AVALON_ASSET", "AVALON_TASK", + "AVALON_WORKDIR", "AVALON_APP_NAME", "IS_TEST" ] - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } for key in keys: value = environment.get(key) diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_fusion_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_fusion_deadline.py index 77505eb623..7aa8546bb6 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_fusion_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_fusion_deadline.py @@ -6,7 +6,6 @@ import requests import pyblish.api -from ayon_core.pipeline import legacy_io from ayon_core.pipeline.publish import ( AYONPyblishPluginMixin ) @@ -224,14 +223,18 @@ class FusionSubmitDeadline( "AVALON_PROJECT", "AVALON_ASSET", "AVALON_TASK", + "AVALON_WORKDIR", "AVALON_APP_NAME", "AYON_LOG_NO_COLORS", "IS_TEST", "AYON_BUNDLE_NAME", ] - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } # to recognize render jobs environment["AYON_RENDER_JOB"] = "1" diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_harmony_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_harmony_deadline.py index f2f1c90559..4d375299fa 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_harmony_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_harmony_deadline.py @@ -10,7 +10,6 @@ from datetime import datetime import attr import pyblish.api -from ayon_core.pipeline import legacy_io from openpype_modules.deadline import abstract_submit_deadline from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo from ayon_core.tests.lib import is_in_tests @@ -277,13 +276,17 @@ class HarmonySubmitDeadline( "AVALON_PROJECT", "AVALON_ASSET", "AVALON_TASK", + "AVALON_WORKDIR", "AVALON_APP_NAME", "AYON_LOG_NO_COLORS" "IS_TEST" ] - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } for key in keys: value = environment.get(key) if value: diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_cache_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_cache_deadline.py index eed930e372..96ee80c4d7 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_cache_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_cache_deadline.py @@ -9,7 +9,6 @@ from ayon_core.lib import ( NumberDef, ) from ayon_core.pipeline import ( - legacy_io, AYONPyblishPluginMixin ) from ayon_core.tests.lib import is_in_tests @@ -102,12 +101,16 @@ class HoudiniCacheSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline "AVALON_PROJECT", "AVALON_ASSET", "AVALON_TASK", + "AVALON_WORKDIR", "AVALON_APP_NAME", "AYON_LOG_NO_COLORS", ] - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } for key in keys: value = environment.get(key) diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_render_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_render_deadline.py index 9988248957..d7a062c9a6 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_render_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_render_deadline.py @@ -5,7 +5,7 @@ from datetime import datetime import pyblish.api -from ayon_core.pipeline import legacy_io, AYONPyblishPluginMixin +from ayon_core.pipeline import AYONPyblishPluginMixin from ayon_core.tests.lib import is_in_tests from openpype_modules.deadline import abstract_submit_deadline from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo @@ -207,12 +207,16 @@ class HoudiniSubmitDeadline( "AVALON_PROJECT", "AVALON_ASSET", "AVALON_TASK", + "AVALON_WORKDIR", "AVALON_APP_NAME", "AYON_LOG_NO_COLORS", ] - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } for key in keys: value = environment.get(key) diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_max_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_max_deadline.py index 0a7c96008e..8908283164 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_max_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_max_deadline.py @@ -9,7 +9,6 @@ from ayon_core.lib import ( NumberDef, ) from ayon_core.pipeline import ( - legacy_io, AYONPyblishPluginMixin ) from ayon_core.pipeline.publish.lib import ( @@ -110,12 +109,16 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, "AVALON_PROJECT", "AVALON_ASSET", "AVALON_TASK", + "AVALON_WORKDIR", "AVALON_APP_NAME", "IS_TEST" ] - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } for key in keys: value = environment.get(key) diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py index 84e6e93e6a..2b7a7cf698 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -29,7 +29,6 @@ from collections import OrderedDict import attr from ayon_core.pipeline import ( - legacy_io, AYONPyblishPluginMixin ) from ayon_core.lib import ( @@ -203,12 +202,16 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, "AVALON_PROJECT", "AVALON_ASSET", "AVALON_TASK", + "AVALON_WORKDIR", "AVALON_APP_NAME", "IS_TEST" ] - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } for key in keys: value = environment.get(key) diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py index 02338c5c32..ed360d84ae 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py @@ -2,7 +2,7 @@ import os import attr from datetime import datetime -from ayon_core.pipeline import legacy_io, PublishXmlValidationError +from ayon_core.pipeline import PublishXmlValidationError from ayon_core.tests.lib import is_in_tests from openpype_modules.deadline import abstract_submit_deadline from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo @@ -98,10 +98,12 @@ class MayaSubmitRemotePublishDeadline( "FTRACK_SERVER" ] - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } - # TODO replace legacy_io with context.data environment["AVALON_PROJECT"] = project_name environment["AVALON_ASSET"] = instance.context.data["asset"] environment["AVALON_TASK"] = instance.context.data["task"] diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_nuke_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_nuke_deadline.py index 9fff8edee6..61a334e184 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_nuke_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_nuke_deadline.py @@ -7,7 +7,6 @@ from datetime import datetime import requests import pyblish.api -from ayon_core.pipeline import legacy_io from ayon_core.pipeline.publish import ( AYONPyblishPluginMixin ) @@ -393,8 +392,11 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin, if self.env_allowed_keys: keys += self.env_allowed_keys - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) + environment = { + key: os.environ[key] + for key in keys + if key in os.environ + } # to recognize render jobs environment["AYON_RENDER_JOB"] = "1" diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_publish_cache_job.py b/client/ayon_core/modules/deadline/plugins/publish/submit_publish_cache_job.py index a90397baa2..38ea31ab7b 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_publish_cache_job.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_publish_cache_job.py @@ -11,8 +11,8 @@ import pyblish.api from ayon_core.client import ( get_last_version_by_subset_name, ) -from ayon_core.pipeline import publish, legacy_io -from ayon_core.lib import EnumDef, is_running_from_build +from ayon_core.pipeline import publish +from ayon_core.lib import EnumDef from ayon_core.tests.lib import is_in_tests from ayon_core.pipeline.version_start import get_versioning_start @@ -370,7 +370,6 @@ class ProcessSubmittedCacheJobOnFarm(pyblish.api.InstancePlugin, "intent": instance.context.data.get("intent"), "comment": instance.context.data.get("comment"), "job": render_job or None, - "session": legacy_io.Session.copy(), "instances": instances } diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_publish_job.py b/client/ayon_core/modules/deadline/plugins/publish/submit_publish_job.py index bd343e103a..c4ab6a2932 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_publish_job.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_publish_job.py @@ -12,8 +12,8 @@ import pyblish.api from ayon_core.client import ( get_last_version_by_subset_name, ) -from ayon_core.pipeline import publish, legacy_io -from ayon_core.lib import EnumDef, is_running_from_build +from ayon_core.pipeline import publish +from ayon_core.lib import EnumDef from ayon_core.tests.lib import is_in_tests from ayon_core.pipeline.version_start import get_versioning_start @@ -604,7 +604,6 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin, "intent": instance.context.data.get("intent"), "comment": instance.context.data.get("comment"), "job": render_job or None, - "session": legacy_io.Session.copy(), "instances": instances } diff --git a/client/ayon_core/plugins/publish/collect_rendered_files.py b/client/ayon_core/plugins/publish/collect_rendered_files.py index 5ffcd669a0..714d790269 100644 --- a/client/ayon_core/plugins/publish/collect_rendered_files.py +++ b/client/ayon_core/plugins/publish/collect_rendered_files.py @@ -12,7 +12,7 @@ import json import pyblish.api -from ayon_core.pipeline import legacy_io, KnownPublishError +from ayon_core.pipeline import KnownPublishError from ayon_core.pipeline.publish.lib import add_repre_files_for_cleanup @@ -165,24 +165,28 @@ class CollectRenderedFiles(pyblish.api.ContextPlugin): path = anatomy.fill_root(path) data = self._load_json(path) assert data, "failed to load json file" - if not session_is_set: - session_data = data["session"] - remapped = anatomy.roots_obj.path_remapper( - session_data["AVALON_WORKDIR"] - ) - if remapped: - session_data["AVALON_WORKDIR"] = remapped - - self.log.debug("Setting session using data from file") - legacy_io.Session.update(session_data) - os.environ.update(session_data) + session_data = data.get("session") + if not session_is_set and session_data: session_is_set = True + self.log.debug("Setting session using data from file") + os.environ.update(session_data) + staging_dir_persistent = self._process_path(data, anatomy) if not staging_dir_persistent: context.data["cleanupFullPaths"].append(path) context.data["cleanupEmptyDirs"].append( os.path.dirname(path) ) + + # Remap workdir if it's set + workdir = os.getenv("AVALON_WORKDIR") + remapped_workdir = None + if workdir: + remapped_workdir = anatomy.roots_obj.path_remapper( + os.getenv("AVALON_WORKDIR") + ) + if remapped_workdir: + os.environ["AVALON_WORKDIR"] = remapped_workdir except Exception as e: self.log.error(e, exc_info=True) raise Exception("Error") from e From acaefb0a71f84186825432bfb3a150cbf3a37e0c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 8 Feb 2024 18:28:25 +0100 Subject: [PATCH 021/112] AssetsWidget does not expect 'dbcon' --- client/ayon_core/hosts/houdini/api/usd.py | 5 +- .../tools/publisher/widgets/assets_widget.py | 9 ++- .../tools/publisher/widgets/create_widget.py | 2 +- client/ayon_core/tools/utils/assets_widget.py | 65 +++++++++---------- 4 files changed, 42 insertions(+), 39 deletions(-) diff --git a/client/ayon_core/hosts/houdini/api/usd.py b/client/ayon_core/hosts/houdini/api/usd.py index e900bc5fac..e9c02a0307 100644 --- a/client/ayon_core/hosts/houdini/api/usd.py +++ b/client/ayon_core/hosts/houdini/api/usd.py @@ -7,7 +7,7 @@ from qtpy import QtWidgets, QtCore, QtGui from ayon_core import style from ayon_core.client import get_asset_by_name -from ayon_core.pipeline import legacy_io, get_current_project_name +from ayon_core.pipeline import get_current_project_name from ayon_core.tools.utils.assets_widget import SingleSelectAssetsWidget from pxr import Sdf @@ -27,7 +27,8 @@ class SelectAssetDialog(QtWidgets.QWidget): self.setWindowTitle("Pick Asset") self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.Popup) - assets_widget = SingleSelectAssetsWidget(legacy_io, parent=self) + assets_widget = SingleSelectAssetsWidget(self) + assets_widget.set_project_name(get_current_project_name(), False) layout = QtWidgets.QHBoxLayout(self) layout.addWidget(assets_widget) diff --git a/client/ayon_core/tools/publisher/widgets/assets_widget.py b/client/ayon_core/tools/publisher/widgets/assets_widget.py index 8a72c03e8b..faad37104d 100644 --- a/client/ayon_core/tools/publisher/widgets/assets_widget.py +++ b/client/ayon_core/tools/publisher/widgets/assets_widget.py @@ -21,7 +21,7 @@ class CreateWidgetAssetsWidget(SingleSelectAssetsWidget): def __init__(self, controller, parent): self._controller = controller - super(CreateWidgetAssetsWidget, self).__init__(None, parent) + super(CreateWidgetAssetsWidget, self).__init__(parent) self.set_refresh_btn_visibility(False) self.set_current_asset_btn_visibility(False) @@ -31,6 +31,9 @@ class CreateWidgetAssetsWidget(SingleSelectAssetsWidget): self._last_filter_height = None + def get_project_name(self): + return self._controller.project_name + def get_selected_asset_name(self): selection_model = self._view.selectionModel() indexes = selection_model.selectedRows() @@ -79,10 +82,10 @@ class CreateWidgetAssetsWidget(SingleSelectAssetsWidget): def update_current_asset(self): # Hide set current asset if there is no one - asset_name = self._get_current_session_asset() + asset_name = self._get_current_asset_name() self.set_current_asset_btn_visibility(bool(asset_name)) - def _get_current_session_asset(self): + def _get_current_asset_name(self): return self._controller.current_asset_name def _create_source_model(self): diff --git a/client/ayon_core/tools/publisher/widgets/create_widget.py b/client/ayon_core/tools/publisher/widgets/create_widget.py index 12135c6891..8eae205882 100644 --- a/client/ayon_core/tools/publisher/widgets/create_widget.py +++ b/client/ayon_core/tools/publisher/widgets/create_widget.py @@ -565,7 +565,7 @@ class CreateWidget(QtWidgets.QWidget): self._last_thumbnail_path = None def _on_current_session_context_request(self): - self._assets_widget.set_current_session_asset() + self._assets_widget.select_current_asset() task_name = self.current_task_name if task_name: self._tasks_widget.select_task_name(task_name) diff --git a/client/ayon_core/tools/utils/assets_widget.py b/client/ayon_core/tools/utils/assets_widget.py index c05f3de850..7bacf3291d 100644 --- a/client/ayon_core/tools/utils/assets_widget.py +++ b/client/ayon_core/tools/utils/assets_widget.py @@ -111,7 +111,6 @@ class _AssetModel(QtGui.QStandardItemModel): 'refreshed' signal. Args: - dbcon (AvalonMongoDB): Ready to use connection to mongo with. parent (QObject): Parent Qt object. """ @@ -128,9 +127,8 @@ class _AssetModel(QtGui.QStandardItemModel): "data.color": 1 } - def __init__(self, dbcon, parent=None): + def __init__(self, parent=None): super(_AssetModel, self).__init__(parent=parent) - self.dbcon = dbcon self._refreshing = False self._doc_fetching_thread = None @@ -142,6 +140,7 @@ class _AssetModel(QtGui.QStandardItemModel): self._item_ids_with_color = set() self._items_by_asset_id = {} + self._project_name = None self._last_project_name = None @property @@ -185,6 +184,16 @@ class _AssetModel(QtGui.QStandardItemModel): return self.get_indexes_by_asset_ids(asset_ids) + def get_project_name(self): + return self._project_name + + def set_project_name(self, project_name, refresh): + if self._project_name == project_name: + return + self._project_name = project_name + if refresh: + self.refresh() + def refresh(self, force=False): """Refresh the data for the model. @@ -197,7 +206,7 @@ class _AssetModel(QtGui.QStandardItemModel): return self.stop_refresh() - project_name = self.dbcon.Session.get("AVALON_PROJECT") + project_name = self._project_name clear_model = False if project_name != self._last_project_name: clear_model = True @@ -216,23 +225,6 @@ class _AssetModel(QtGui.QStandardItemModel): def stop_refresh(self): self._stop_fetch_thread() - def clear_underlines(self): - for asset_id in set(self._item_ids_with_color): - self._item_ids_with_color.remove(asset_id) - item = self._items_by_asset_id.get(asset_id) - if item is not None: - item.setData(None, ASSET_UNDERLINE_COLORS_ROLE) - - def set_underline_colors(self, colors_by_asset_id): - self.clear_underlines() - - for asset_id, colors in colors_by_asset_id.items(): - item = self._items_by_asset_id.get(asset_id) - if item is None: - continue - item.setData(colors, ASSET_UNDERLINE_COLORS_ROLE) - self._item_ids_with_color.add(asset_id) - def _clear_items(self): root_item = self.invisibleRootItem() root_item.removeRows(0, root_item.rowCount()) @@ -357,7 +349,7 @@ class _AssetModel(QtGui.QStandardItemModel): self._doc_fetched.emit() def _fetch_asset_docs(self): - project_name = self.dbcon.current_project() + project_name = self.get_project_name() if not project_name: return [] @@ -392,7 +384,6 @@ class _AssetsWidget(QtWidgets.QWidget): inheritance changes. Args: - dbcon (AvalonMongoDB): Connection to avalon mongo db. parent (QWidget): Parent Qt widget. """ @@ -404,11 +395,9 @@ class _AssetsWidget(QtWidgets.QWidget): # It was double clicked on view double_clicked = QtCore.Signal() - def __init__(self, dbcon, parent=None): + def __init__(self, parent=None): super(_AssetsWidget, self).__init__(parent=parent) - self.dbcon = dbcon - # Tree View model = self._create_source_model() proxy = self._create_proxy_model(model) @@ -477,18 +466,28 @@ class _AssetsWidget(QtWidgets.QWidget): self._model = model self._proxy = proxy self._view = view - self._last_project_name = None self._last_btns_height = None + self._current_asset_name = None + self.model_selection = {} @property def header_widget(self): return self._header_widget + def get_project_name(self): + self._model.get_project_name() + + def set_project_name(self, project_name, refresh=True): + self._model.set_project_name(project_name, refresh) + + def set_current_asset_name(self, asset_name): + self._current_asset_name = asset_name + def _create_source_model(self): - model = _AssetModel(dbcon=self.dbcon, parent=self) + model = _AssetModel(parent=self) model.refreshed.connect(self._on_model_refresh) return model @@ -509,8 +508,8 @@ class _AssetsWidget(QtWidgets.QWidget): def stop_refresh(self): self._model.stop_refresh() - def _get_current_session_asset(self): - return self.dbcon.Session.get("AVALON_ASSET") + def _get_current_asset_name(self): + return self._current_asset_name def _on_current_asset_click(self): """Trigger change of asset to current context asset. @@ -518,10 +517,10 @@ class _AssetsWidget(QtWidgets.QWidget): in differnt way. """ - self.set_current_session_asset() + self.select_current_asset() - def set_current_session_asset(self): - asset_name = self._get_current_session_asset() + def select_current_asset(self): + asset_name = self._get_current_asset_name() if asset_name: self.select_asset_by_name(asset_name) From a6a04bb443c0a9b047de57798c8839dc88f322e6 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 8 Feb 2024 18:55:58 +0100 Subject: [PATCH 022/112] moved TasksWidget to publisher --- .../tools/publisher/widgets/tasks_widget.py | 171 +++++++++- client/ayon_core/tools/utils/tasks_widget.py | 303 ------------------ 2 files changed, 157 insertions(+), 317 deletions(-) delete mode 100644 client/ayon_core/tools/utils/tasks_widget.py diff --git a/client/ayon_core/tools/publisher/widgets/tasks_widget.py b/client/ayon_core/tools/publisher/widgets/tasks_widget.py index 44e290408a..9a1b22b9a5 100644 --- a/client/ayon_core/tools/publisher/widgets/tasks_widget.py +++ b/client/ayon_core/tools/publisher/widgets/tasks_widget.py @@ -1,8 +1,12 @@ -from qtpy import QtCore, QtGui +from qtpy import QtWidgets, QtCore, QtGui -from ayon_core.tools.utils.tasks_widget import TasksWidget, TASK_NAME_ROLE +from ayon_core.tools.utils.views import DeselectableTreeView from ayon_core.tools.utils.lib import get_default_task_icon +TASK_NAME_ROLE = QtCore.Qt.UserRole + 1 +TASK_TYPE_ROLE = QtCore.Qt.UserRole + 2 +TASK_ORDER_ROLE = QtCore.Qt.UserRole + 3 + class TasksModel(QtGui.QStandardItemModel): """Tasks model. @@ -141,15 +145,159 @@ class TasksModel(QtGui.QStandardItemModel): return super(TasksModel, self).headerData(section, orientation, role) -class CreateWidgetTasksWidget(TasksWidget): +class TasksProxyModel(QtCore.QSortFilterProxyModel): + def lessThan(self, x_index, y_index): + x_order = x_index.data(TASK_ORDER_ROLE) + y_order = y_index.data(TASK_ORDER_ROLE) + if x_order is not None and y_order is not None: + if x_order < y_order: + return True + if x_order > y_order: + return False + + elif x_order is None and y_order is not None: + return True + + elif y_order is None and x_order is not None: + return False + + x_name = x_index.data(QtCore.Qt.DisplayRole) + y_name = y_index.data(QtCore.Qt.DisplayRole) + if x_name == y_name: + return True + + if x_name == tuple(sorted((x_name, y_name)))[0]: + return True + return False + + +class CreateWidgetTasksWidget(QtWidgets.QWidget): + """Widget showing active Tasks + + Deprecated: + This widget will be removed soon. Please do not use it in new code. + """ + + task_changed = QtCore.Signal() + def __init__(self, controller, parent): self._controller = controller - super(CreateWidgetTasksWidget, self).__init__(None, parent) self._enabled = None - def _create_source_model(self): - return TasksModel(self._controller) + super(CreateWidgetTasksWidget, self).__init__(parent) + + tasks_view = DeselectableTreeView(self) + tasks_view.setIndentation(0) + tasks_view.setSortingEnabled(True) + tasks_view.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + + header_view = tasks_view.header() + header_view.setSortIndicator(0, QtCore.Qt.AscendingOrder) + + tasks_model = TasksModel(self._controller) + tasks_proxy = TasksProxyModel() + tasks_proxy.setSourceModel(tasks_model) + tasks_view.setModel(tasks_proxy) + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.addWidget(tasks_view) + + selection_model = tasks_view.selectionModel() + selection_model.selectionChanged.connect(self._on_task_change) + + self._tasks_model = tasks_model + self._tasks_proxy = tasks_proxy + self._tasks_view = tasks_view + + self._last_selected_task_name = None + + def refresh(self): + self._tasks_model.refresh() + + def set_asset_id(self, asset_id): + # Try and preserve the last selected task and reselect it + # after switching assets. If there's no currently selected + # asset keep whatever the "last selected" was prior to it. + current = self.get_selected_task_name() + if current: + self._last_selected_task_name = current + + self._tasks_model.set_asset_id(asset_id) + + if self._last_selected_task_name: + self.select_task_name(self._last_selected_task_name) + + # Force a task changed emit. + self.task_changed.emit() + + def _clear_selection(self): + selection_model = self._tasks_view.selectionModel() + selection_model.clearSelection() + + def select_task_name(self, task_name): + """Select a task by name. + + If the task does not exist in the current model then selection is only + cleared. + + Args: + task_name (str): Name of the task to select. + + """ + task_view_model = self._tasks_view.model() + if not task_view_model: + return + + # Clear selection + selection_model = self._tasks_view.selectionModel() + selection_model.clearSelection() + + # Select the task + mode = ( + QtCore.QItemSelectionModel.Select + | QtCore.QItemSelectionModel.Rows + ) + for row in range(task_view_model.rowCount()): + index = task_view_model.index(row, 0) + name = index.data(TASK_NAME_ROLE) + if name == task_name: + selection_model.select(index, mode) + + # Set the currently active index + self._tasks_view.setCurrentIndex(index) + break + + last_selected_task_name = self.get_selected_task_name() + if last_selected_task_name: + self._last_selected_task_name = last_selected_task_name + + if not self._enabled: + current = self.get_selected_task_name() + if current: + self._last_selected_task_name = current + self._clear_selection() + + def get_selected_task_name(self): + """Return name of task at current index (selected) + + Returns: + str: Name of the current task. + + """ + index = self._tasks_view.currentIndex() + selection_model = self._tasks_view.selectionModel() + if index.isValid() and selection_model.isSelected(index): + return index.data(TASK_NAME_ROLE) + return None + + def get_selected_task_type(self): + index = self._tasks_view.currentIndex() + selection_model = self._tasks_view.selectionModel() + if index.isValid() and selection_model.isSelected(index): + return index.data(TASK_TYPE_ROLE) + return None def set_asset_name(self, asset_name): current = self.get_selected_task_name() @@ -163,14 +311,6 @@ class CreateWidgetTasksWidget(TasksWidget): # Force a task changed emit. self.task_changed.emit() - def select_task_name(self, task_name): - super(CreateWidgetTasksWidget, self).select_task_name(task_name) - if not self._enabled: - current = self.get_selected_task_name() - if current: - self._last_selected_task_name = current - self._clear_selection() - def set_enabled(self, enabled): self._enabled = enabled if not enabled: @@ -181,3 +321,6 @@ class CreateWidgetTasksWidget(TasksWidget): elif self._last_selected_task_name is not None: self.select_task_name(self._last_selected_task_name) + + def _on_task_change(self): + self.task_changed.emit() diff --git a/client/ayon_core/tools/utils/tasks_widget.py b/client/ayon_core/tools/utils/tasks_widget.py deleted file mode 100644 index 12e074f910..0000000000 --- a/client/ayon_core/tools/utils/tasks_widget.py +++ /dev/null @@ -1,303 +0,0 @@ -from qtpy import QtWidgets, QtCore, QtGui -import qtawesome - -from ayon_core.client import ( - get_project, - get_asset_by_id, -) -from ayon_core.style import get_disabled_entity_icon_color -from ayon_core.tools.utils.lib import get_task_icon - -from .views import DeselectableTreeView - - -TASK_NAME_ROLE = QtCore.Qt.UserRole + 1 -TASK_TYPE_ROLE = QtCore.Qt.UserRole + 2 -TASK_ORDER_ROLE = QtCore.Qt.UserRole + 3 -TASK_ASSIGNEE_ROLE = QtCore.Qt.UserRole + 4 - - -class _TasksModel(QtGui.QStandardItemModel): - """A model listing the tasks combined for a list of assets""" - - def __init__(self, dbcon, parent=None): - super(_TasksModel, self).__init__(parent=parent) - self.dbcon = dbcon - self.setHeaderData( - 0, QtCore.Qt.Horizontal, "Tasks", QtCore.Qt.DisplayRole - ) - - self._no_tasks_icon = qtawesome.icon( - "fa.exclamation-circle", - color=get_disabled_entity_icon_color() - ) - self._cached_icons = {} - self._project_doc = {} - - self._empty_tasks_item = None - self._last_asset_id = None - self._loaded_project_name = None - - def _context_is_valid(self): - if self._get_current_project(): - return True - return False - - def refresh(self): - self._refresh_project_doc() - self.set_asset_id(self._last_asset_id) - - def _refresh_project_doc(self): - # Get the project configured icons from database - project_doc = {} - if self._context_is_valid(): - project_name = self.dbcon.active_project() - project_doc = get_project(project_name) - - self._loaded_project_name = self._get_current_project() - self._project_doc = project_doc - - def headerData(self, section, orientation, role=None): - if role is None: - role = QtCore.Qt.EditRole - # Show nice labels in the header - if section == 0: - if ( - role in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole) - and orientation == QtCore.Qt.Horizontal - ): - return "Tasks" - - return super(_TasksModel, self).headerData(section, orientation, role) - - def _get_current_project(self): - return self.dbcon.Session.get("AVALON_PROJECT") - - def set_asset_id(self, asset_id): - asset_doc = None - if asset_id and self._context_is_valid(): - project_name = self._get_current_project() - asset_doc = get_asset_by_id( - project_name, asset_id, fields=["data.tasks"] - ) - self._set_asset(asset_doc) - - def _get_empty_task_item(self): - if self._empty_tasks_item is None: - item = QtGui.QStandardItem("No task") - item.setData(self._no_tasks_icon, QtCore.Qt.DecorationRole) - item.setFlags(QtCore.Qt.NoItemFlags) - self._empty_tasks_item = item - return self._empty_tasks_item - - def _set_asset(self, asset_doc): - """Set assets to track by their database id - - Arguments: - asset_doc (dict): Asset document from MongoDB. - """ - if self._loaded_project_name != self._get_current_project(): - self._refresh_project_doc() - - asset_tasks = {} - self._last_asset_id = None - if asset_doc: - asset_tasks = asset_doc.get("data", {}).get("tasks") or {} - self._last_asset_id = asset_doc["_id"] - - root_item = self.invisibleRootItem() - root_item.removeRows(0, root_item.rowCount()) - - items = [] - - for task_name, task_info in asset_tasks.items(): - task_type = task_info.get("type") - task_order = task_info.get("order") - icon = get_task_icon(self._project_doc, asset_doc, task_name) - - task_assignees = set() - assignees_data = task_info.get("assignees") or [] - for assignee in assignees_data: - username = assignee.get("username") - if username: - task_assignees.add(username) - - label = "{} ({})".format(task_name, task_type or "type N/A") - item = QtGui.QStandardItem(label) - item.setData(task_name, TASK_NAME_ROLE) - item.setData(task_type, TASK_TYPE_ROLE) - item.setData(task_order, TASK_ORDER_ROLE) - item.setData(task_assignees, TASK_ASSIGNEE_ROLE) - item.setData(icon, QtCore.Qt.DecorationRole) - item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - items.append(item) - - if not items: - item = QtGui.QStandardItem("No task") - item.setData(self._no_tasks_icon, QtCore.Qt.DecorationRole) - item.setFlags(QtCore.Qt.NoItemFlags) - items.append(item) - - root_item.appendRows(items) - - -class _TasksProxyModel(QtCore.QSortFilterProxyModel): - def lessThan(self, x_index, y_index): - x_order = x_index.data(TASK_ORDER_ROLE) - y_order = y_index.data(TASK_ORDER_ROLE) - if x_order is not None and y_order is not None: - if x_order < y_order: - return True - if x_order > y_order: - return False - - elif x_order is None and y_order is not None: - return True - - elif y_order is None and x_order is not None: - return False - - x_name = x_index.data(QtCore.Qt.DisplayRole) - y_name = y_index.data(QtCore.Qt.DisplayRole) - if x_name == y_name: - return True - - if x_name == tuple(sorted((x_name, y_name)))[0]: - return True - return False - - -class TasksWidget(QtWidgets.QWidget): - """Widget showing active Tasks - - Deprecated: - This widget will be removed soon. Please do not use it in new code. - """ - - task_changed = QtCore.Signal() - - def __init__(self, dbcon, parent=None): - self._dbcon = dbcon - - super(TasksWidget, self).__init__(parent) - - tasks_view = DeselectableTreeView(self) - tasks_view.setIndentation(0) - tasks_view.setSortingEnabled(True) - tasks_view.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - - header_view = tasks_view.header() - header_view.setSortIndicator(0, QtCore.Qt.AscendingOrder) - - tasks_model = self._create_source_model() - tasks_proxy = self._create_proxy_model(tasks_model) - tasks_view.setModel(tasks_proxy) - - layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.addWidget(tasks_view) - - selection_model = tasks_view.selectionModel() - selection_model.selectionChanged.connect(self._on_task_change) - - self._tasks_model = tasks_model - self._tasks_proxy = tasks_proxy - self._tasks_view = tasks_view - - self._last_selected_task_name = None - - def _create_source_model(self): - """Create source model of tasks widget. - - Model must have available 'refresh' method and 'set_asset_id' to change - context of asset. - """ - return _TasksModel(self._dbcon) - - def _create_proxy_model(self, source_model): - proxy = _TasksProxyModel() - proxy.setSourceModel(source_model) - return proxy - - def refresh(self): - self._tasks_model.refresh() - - def set_asset_id(self, asset_id): - # Try and preserve the last selected task and reselect it - # after switching assets. If there's no currently selected - # asset keep whatever the "last selected" was prior to it. - current = self.get_selected_task_name() - if current: - self._last_selected_task_name = current - - self._tasks_model.set_asset_id(asset_id) - - if self._last_selected_task_name: - self.select_task_name(self._last_selected_task_name) - - # Force a task changed emit. - self.task_changed.emit() - - def _clear_selection(self): - selection_model = self._tasks_view.selectionModel() - selection_model.clearSelection() - - def select_task_name(self, task_name): - """Select a task by name. - - If the task does not exist in the current model then selection is only - cleared. - - Args: - task (str): Name of the task to select. - - """ - task_view_model = self._tasks_view.model() - if not task_view_model: - return - - # Clear selection - selection_model = self._tasks_view.selectionModel() - selection_model.clearSelection() - - # Select the task - mode = ( - QtCore.QItemSelectionModel.Select - | QtCore.QItemSelectionModel.Rows - ) - for row in range(task_view_model.rowCount()): - index = task_view_model.index(row, 0) - name = index.data(TASK_NAME_ROLE) - if name == task_name: - selection_model.select(index, mode) - - # Set the currently active index - self._tasks_view.setCurrentIndex(index) - break - - last_selected_task_name = self.get_selected_task_name() - if last_selected_task_name: - self._last_selected_task_name = last_selected_task_name - - def get_selected_task_name(self): - """Return name of task at current index (selected) - - Returns: - str: Name of the current task. - - """ - index = self._tasks_view.currentIndex() - selection_model = self._tasks_view.selectionModel() - if index.isValid() and selection_model.isSelected(index): - return index.data(TASK_NAME_ROLE) - return None - - def get_selected_task_type(self): - index = self._tasks_view.currentIndex() - selection_model = self._tasks_view.selectionModel() - if index.isValid() and selection_model.isSelected(index): - return index.data(TASK_TYPE_ROLE) - return None - - def _on_task_change(self): - self.task_changed.emit() From 2e63f282c1b624897857421986e091673018137a Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 8 Feb 2024 19:01:25 +0100 Subject: [PATCH 023/112] disable validation of AVALON_PROJECT environment variable --- client/ayon_core/pipeline/context_tools.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/client/ayon_core/pipeline/context_tools.py b/client/ayon_core/pipeline/context_tools.py index 64d8e1f6d6..fdf4c85660 100644 --- a/client/ayon_core/pipeline/context_tools.py +++ b/client/ayon_core/pipeline/context_tools.py @@ -119,10 +119,12 @@ def install_host(host): addons_manager = _get_addons_manager() project_name = os.getenv("AVALON_PROJECT") - if not project_name: - raise ValueError( - "AVALON_PROJECT is missing in environment variables." - ) + # WARNING: This might be an issue + # - commented out because 'traypublisher' does not have set project + # if not project_name: + # raise ValueError( + # "AVALON_PROJECT is missing in environment variables." + # ) log.info("Activating {}..".format(project_name)) From 4c3f6a5645c68fc091289067e6b66d6f12c164f9 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 8 Feb 2024 19:01:47 +0100 Subject: [PATCH 024/112] use correct function --- client/ayon_core/pipeline/context_tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/pipeline/context_tools.py b/client/ayon_core/pipeline/context_tools.py index fdf4c85660..6986a062d7 100644 --- a/client/ayon_core/pipeline/context_tools.py +++ b/client/ayon_core/pipeline/context_tools.py @@ -159,7 +159,7 @@ def install_host(host): for addon in addons_manager.get_enabled_addons(): addon.on_host_install(host, host_name, project_name) - install_openpype_plugins(project_name, host_name) + install_ayon_plugins(project_name, host_name) def install_ayon_plugins(project_name=None, host_name=None): From e02883dcd41eddc73027aadaa1927c67617efc6c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 8 Feb 2024 19:01:54 +0100 Subject: [PATCH 025/112] removed unused import --- client/ayon_core/pipeline/context_tools.py | 1 - 1 file changed, 1 deletion(-) diff --git a/client/ayon_core/pipeline/context_tools.py b/client/ayon_core/pipeline/context_tools.py index 6986a062d7..339ef9187f 100644 --- a/client/ayon_core/pipeline/context_tools.py +++ b/client/ayon_core/pipeline/context_tools.py @@ -1,7 +1,6 @@ """Core pipeline functionality""" import os -import json import types import logging import platform From eedf7368670efb2a9cee3f0fbc9841ee0b144393 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 8 Feb 2024 19:10:49 +0100 Subject: [PATCH 026/112] removed content of legacy_io --- client/ayon_core/pipeline/legacy_io.py | 97 ++++---------------------- 1 file changed, 12 insertions(+), 85 deletions(-) diff --git a/client/ayon_core/pipeline/legacy_io.py b/client/ayon_core/pipeline/legacy_io.py index cd09da2917..d5b555845b 100644 --- a/client/ayon_core/pipeline/legacy_io.py +++ b/client/ayon_core/pipeline/legacy_io.py @@ -1,109 +1,36 @@ -"""Wrapper around interactions with the database""" - -import os -import sys import logging -import functools - -from . import schema - -module = sys.modules[__name__] +from ayon_core.pipeline import get_current_project_name Session = {} -_is_installed = False log = logging.getLogger(__name__) - -SESSION_CONTEXT_KEYS = ( - # Name of current Project - "AVALON_PROJECT", - # Name of current Asset - "AVALON_ASSET", - # Name of current task - "AVALON_TASK", - # Name of current app - "AVALON_APP", - # Path to working directory - "AVALON_WORKDIR", - # Optional path to scenes directory (see Work Files API) - "AVALON_SCENEDIR" +log.warning( + "DEPRECATION WARNING: 'legacy_io' is deprecated and will be removed in" + " future versions of ayon-core addon." + "\nReading from Session won't give you updated information and changing" + " values won't affect global state of a process." ) def session_data_from_environment(context_keys=False): - session_data = {} - if context_keys: - for key in SESSION_CONTEXT_KEYS: - value = os.environ.get(key) - session_data[key] = value or "" - else: - for key in SESSION_CONTEXT_KEYS: - session_data[key] = None - - for key, default_value in ( - # Name of Avalon in graphical user interfaces - # Use this to customise the visual appearance of Avalon - # to better integrate with your surrounding pipeline - ("AVALON_LABEL", "Avalon"), - - # Used during any connections to the outside world - ("AVALON_TIMEOUT", "1000"), - - # Name of database used in MongoDB - ("AVALON_DB", "avalon"), - ): - value = os.environ.get(key) or default_value - if value is not None: - session_data[key] = value - - return session_data + return {} def is_installed(): - return module._is_installed + return False def install(): - """Establish a persistent connection to the database""" - if is_installed(): - return - - session = session_data_from_environment(context_keys=True) - - session["schema"] = "openpype:session-4.0" - try: - schema.validate(session) - except schema.ValidationError as e: - # TODO(marcus): Make this mandatory - log.warning(e) - - Session.update(session) - - module._is_installed = True + pass def uninstall(): - """Close any connection to the database. - - Deprecated: - This function does nothing should be removed. - """ - module._is_installed = False + pass -def requires_install(func): - @functools.wraps(func) - def decorated(*args, **kwargs): - if not is_installed(): - install() - return func(*args, **kwargs) - return decorated - - -@requires_install def active_project(*args, **kwargs): - return Session["AVALON_PROJECT"] + return get_current_project_name() def current_project(*args, **kwargs): - return Session.get("AVALON_PROJECT") + return get_current_project_name() From 509f2b677e65750fea65ecf8f87df9d06685fe18 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 9 Feb 2024 11:50:35 +0800 Subject: [PATCH 027/112] ported OP PR #6200 to ayon_core --- client/ayon_core/hosts/max/api/pipeline.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/ayon_core/hosts/max/api/pipeline.py b/client/ayon_core/hosts/max/api/pipeline.py index ff5ef0640b..ff0267b39a 100644 --- a/client/ayon_core/hosts/max/api/pipeline.py +++ b/client/ayon_core/hosts/max/api/pipeline.py @@ -60,6 +60,9 @@ class MaxHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost): rt.callbacks.addScript(rt.Name('filePostOpen'), lib.check_colorspace) + rt.callbacks.addScript(rt.Name('postWorkspaceChange'), + self._deferred_menu_creation) + def has_unsaved_changes(self): # TODO: how to get it from 3dsmax? return True From 4e76c9f5dc9282fa65c97faeaf3598f5b9f5e07b Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 9 Feb 2024 08:16:23 +0000 Subject: [PATCH 028/112] Add submodule --- client/ayon_core/hosts/unreal/integration | 1 + 1 file changed, 1 insertion(+) create mode 160000 client/ayon_core/hosts/unreal/integration diff --git a/client/ayon_core/hosts/unreal/integration b/client/ayon_core/hosts/unreal/integration new file mode 160000 index 0000000000..6d2793170e --- /dev/null +++ b/client/ayon_core/hosts/unreal/integration @@ -0,0 +1 @@ +Subproject commit 6d2793170ed57187842f683a943593973abcc337 From 1a9c8f61535046b4966d7e4c6396b210a70201e0 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 9 Feb 2024 08:39:13 +0000 Subject: [PATCH 029/112] Add submodule --- client/ayon_core/hosts/unreal/integration | 1 + 1 file changed, 1 insertion(+) create mode 160000 client/ayon_core/hosts/unreal/integration diff --git a/client/ayon_core/hosts/unreal/integration b/client/ayon_core/hosts/unreal/integration new file mode 160000 index 0000000000..6d2793170e --- /dev/null +++ b/client/ayon_core/hosts/unreal/integration @@ -0,0 +1 @@ +Subproject commit 6d2793170ed57187842f683a943593973abcc337 From ce5a563b4c55dceababeea459d25b3429d9a14be Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 09:56:42 +0100 Subject: [PATCH 030/112] do not convert applications settings --- client/ayon_core/lib/applications.py | 225 ++++++++------------- client/ayon_core/settings/ayon_settings.py | 85 +------- 2 files changed, 91 insertions(+), 219 deletions(-) diff --git a/client/ayon_core/lib/applications.py b/client/ayon_core/lib/applications.py index febdaacdd1..70aa9811c7 100644 --- a/client/ayon_core/lib/applications.py +++ b/client/ayon_core/lib/applications.py @@ -230,29 +230,25 @@ class ApplicationGroup: self.manager = manager self._data = data - self.enabled = data.get("enabled", True) - self.label = data.get("label") or None - self.icon = data.get("icon") or None - self._environment = data.get("environment") or {} + self.enabled = data["enabled"] + self.label = data["label"] or None + self.icon = data["icon"] or None + env = {} + try: + env = json.loads(data["environment"]) + except Exception: + pass + self._environment = env - host_name = data.get("host_name", None) + host_name = data["host_name"] or None self.is_host = host_name is not None self.host_name = host_name - variants = data.get("variants") or {} - key_label_mapping = variants.pop(M_DYNAMIC_KEY_LABEL, {}) - for variant_name, variant_data in variants.items(): - if variant_name in METADATA_KEYS: - continue - - if "variant_label" not in variant_data: - variant_label = key_label_mapping.get(variant_name) - if variant_label: - variant_data["variant_label"] = variant_label - - variants[variant_name] = Application( - variant_name, variant_data, self - ) + settings_variants = data["variants"] + variants = {} + for variant_data in settings_variants: + app_variant = Application(variant_data, self) + variants[app_variant.name] = app_variant self.variants = variants @@ -274,62 +270,56 @@ class Application: Object by itself does nothing special. Args: - name (str): Specific version (or variant) of application. - e.g. "maya2020", "nuke11.3", etc. data (dict): Data for the version containing information about executables, variant label or if is enabled. Only required key is `executables`. group (ApplicationGroup): App group object that created the application and under which application belongs. + """ - - def __init__(self, name, data, group): - self.name = name - self.group = group + def __init__(self, data, group): self._data = data - + name = data["name"] + label = data["label"] or name enabled = False if group.enabled: enabled = data.get("enabled", True) - self.enabled = enabled - self.use_python_2 = data.get("use_python_2", False) - - self.label = data.get("variant_label") or name - self.full_name = "/".join((group.name, name)) if group.label: - full_label = " ".join((group.label, self.label)) + full_label = " ".join((group.label, label)) else: - full_label = self.label - self.full_label = full_label - self._environment = data.get("environment") or {} + full_label = label + env = {} + try: + env = json.loads(data["environment"]) + except Exception: + pass - arguments = data.get("arguments") + arguments = data["arguments"] if isinstance(arguments, dict): arguments = arguments.get(platform.system().lower()) if not arguments: arguments = [] + + _executables = data["executables"].get(platform.system().lower(), []) + executables = [ + ApplicationExecutable(executable) + for executable in _executables + ] + + self.group = group + + self.name = name + self.label = label + self.enabled = enabled + self.use_python_2 = data.get("use_python_2", False) + + self.full_name = "/".join((group.name, name)) + self.full_label = full_label self.arguments = arguments - - if "executables" not in data: - self.executables = [ - UndefinedApplicationExecutable() - ] - return - - _executables = data["executables"] - if isinstance(_executables, dict): - _executables = _executables.get(platform.system().lower()) - - if not _executables: - _executables = [] - - executables = [] - for executable in _executables: - executables.append(ApplicationExecutable(executable)) - self.executables = executables + self._environment = env def __repr__(self): return "<{}> - {}".format(self.__class__.__name__, self.full_name) @@ -384,12 +374,12 @@ class ApplicationManager: """Load applications and tools and store them by their full name. Args: - system_settings (dict): Preloaded system settings. When passed manager + studio_settings (dict): Preloaded studio settings. When passed manager will always use these values. Gives ability to create manager using different settings. """ - def __init__(self, system_settings=None): + def __init__(self, studio_settings=None): self.log = Logger.get_logger(self.__class__.__name__) self.app_groups = {} @@ -397,16 +387,16 @@ class ApplicationManager: self.tool_groups = {} self.tools = {} - self._system_settings = system_settings + self._studio_settings = studio_settings self.refresh() - def set_system_settings(self, system_settings): + def set_studio_settings(self, studio_settings): """Ability to change init system settings. This will trigger refresh of manager. """ - self._system_settings = system_settings + self._studio_settings = studio_settings self.refresh() @@ -417,72 +407,30 @@ class ApplicationManager: self.tool_groups.clear() self.tools.clear() - if self._system_settings is not None: - settings = copy.deepcopy(self._system_settings) + if self._studio_settings is not None: + settings = copy.deepcopy(self._studio_settings) else: settings = get_system_settings( clear_metadata=False, exclude_locals=False ) - all_app_defs = {} + applications_addon_settings = settings["applications"] + # Prepare known applications - app_defs = settings["applications"] - additional_apps = {} + app_defs = applications_addon_settings["applications"] + additional_apps = app_defs.pop("additional_apps") + app_defs.update(additional_apps) + for group_name, variant_defs in app_defs.items(): - if group_name in METADATA_KEYS: - continue - - if group_name == "additional_apps": - additional_apps = variant_defs - else: - all_app_defs[group_name] = variant_defs - - # Prepare additional applications - # - First find dynamic keys that can be used as labels of group - dynamic_keys = {} - for group_name, variant_defs in additional_apps.items(): - if group_name == M_DYNAMIC_KEY_LABEL: - dynamic_keys = variant_defs - break - - # Add additional apps to known applications - for group_name, variant_defs in additional_apps.items(): - if group_name in METADATA_KEYS: - continue - - # Determine group label - label = variant_defs.get("label") - if not label: - # Look for label set in dynamic labels - label = dynamic_keys.get(group_name) - if not label: - label = group_name - variant_defs["label"] = label - - all_app_defs[group_name] = variant_defs - - for group_name, variant_defs in all_app_defs.items(): - if group_name in METADATA_KEYS: - continue - group = ApplicationGroup(group_name, variant_defs, self) self.app_groups[group_name] = group for app in group: self.applications[app.full_name] = app - tools_definitions = settings["tools"]["tool_groups"] - tool_label_mapping = tools_definitions.pop(M_DYNAMIC_KEY_LABEL, {}) - for tool_group_name, tool_group_data in tools_definitions.items(): - if not tool_group_name or tool_group_name in METADATA_KEYS: - continue - - tool_group_label = ( - tool_label_mapping.get(tool_group_name) or tool_group_name - ) - group = EnvironmentToolGroup( - tool_group_name, tool_group_label, tool_group_data, self - ) - self.tool_groups[tool_group_name] = group + tools_definitions = applications_addon_settings["tool_groups"] + for tool_group_data in tools_definitions: + group = EnvironmentToolGroup(tool_group_data, self) + self.tool_groups[group.name] = group for tool in group: self.tools[tool.full_name] = tool @@ -571,30 +519,31 @@ class EnvironmentToolGroup: are same. Args: - name (str): Name of the tool group. - data (dict): Group's information with it's variants. + data (dict): Group information with variants. manager (ApplicationManager): Manager that creates the group. """ - def __init__(self, name, label, data, manager): + def __init__(self, data, manager): + name = data["name"] + label = data["label"] + self.name = name self.label = label self._data = data self.manager = manager - self._environment = data["environment"] - variants = data.get("variants") or {} - label_by_key = variants.pop(M_DYNAMIC_KEY_LABEL, {}) + environment = {} + try: + environment = json.loads(data["environment"]) + except Exception: + pass + self._environment = environment + + variants = data.get("variants") or [] variants_by_name = {} - for variant_name, variant_data in variants.items(): - if variant_name in METADATA_KEYS: - continue - - variant_label = label_by_key.get(variant_name) or variant_name - tool = EnvironmentTool( - variant_name, variant_label, variant_data, self - ) - variants_by_name[variant_name] = tool + for variant_data in variants: + tool = EnvironmentTool(variant_data, self) + variants_by_name[tool.name] = tool self.variants = variants_by_name def __repr__(self): @@ -615,23 +564,25 @@ class EnvironmentTool: Structure of tool information. Args: - name (str): Name of the tool. variant_data (dict): Variant data with environments and host and app variant filters. - group (str): Name of group which wraps tool. + group (EnvironmentToolGroup): Name of group which wraps tool. """ - def __init__(self, name, label, variant_data, group): + def __init__(self, variant_data, group): # Backwards compatibility 3.9.1 - 3.9.2 # - 'variant_data' contained only environments but contain also host # and application variant filters - host_names = variant_data.get("host_names", []) - app_variants = variant_data.get("app_variants", []) + name = variant_data["name"] + label = variant_data["label"] + host_names = variant_data["host_names"] + app_variants = variant_data["app_variants"] - if "environment" in variant_data: - environment = variant_data["environment"] - else: - environment = variant_data + environment = {} + try: + environment = json.loads(variant_data["environment"]) + except Exception: + pass self.host_names = host_names self.app_variants = app_variants diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index ed1199d517..acf5e0bb30 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -72,77 +72,6 @@ def _convert_host_imageio(host_settings): imageio_file_rules["rules"] = new_rules -def _convert_applications_groups(groups, clear_metadata): - environment_key = "environment" - if isinstance(groups, dict): - new_groups = [] - for name, item in groups.items(): - item["name"] = name - new_groups.append(item) - groups = new_groups - - output = {} - group_dynamic_labels = {} - for group in groups: - group_name = group.pop("name") - if "label" in group: - group_dynamic_labels[group_name] = group["label"] - - tool_group_envs = group[environment_key] - if isinstance(tool_group_envs, six.string_types): - group[environment_key] = json.loads(tool_group_envs) - - variants = {} - variant_dynamic_labels = {} - for variant in group.pop("variants"): - variant_name = variant.pop("name") - label = variant.get("label") - if label and label != variant_name: - variant_dynamic_labels[variant_name] = label - variant_envs = variant[environment_key] - if isinstance(variant_envs, six.string_types): - variant[environment_key] = json.loads(variant_envs) - variants[variant_name] = variant - group["variants"] = variants - - if not clear_metadata: - variants["__dynamic_keys_labels__"] = variant_dynamic_labels - output[group_name] = group - - if not clear_metadata: - output["__dynamic_keys_labels__"] = group_dynamic_labels - return output - - -def _convert_applications_system_settings( - ayon_settings, output, clear_metadata -): - # Addon settings - addon_settings = ayon_settings["applications"] - - # Remove project settings - addon_settings.pop("only_available", None) - - # Applications settings - ayon_apps = addon_settings["applications"] - - additional_apps = ayon_apps.pop("additional_apps") - applications = _convert_applications_groups( - ayon_apps, clear_metadata - ) - applications["additional_apps"] = _convert_applications_groups( - additional_apps, clear_metadata - ) - - # Tools settings - tools = _convert_applications_groups( - addon_settings["tool_groups"], clear_metadata - ) - - output["applications"] = applications - output["tools"] = {"tool_groups": tools} - - def _convert_general(ayon_settings, output, default_settings): # TODO get studio name/code core_settings = ayon_settings["core"] @@ -290,7 +219,7 @@ def convert_system_settings(ayon_settings, default_settings, addon_versions): "modules": {} } if "applications" in ayon_settings: - _convert_applications_system_settings(ayon_settings, output, False) + output["applications"] = ayon_settings["applications"] if "core" in ayon_settings: _convert_general(ayon_settings, output, default_settings) @@ -313,15 +242,6 @@ def convert_system_settings(ayon_settings, default_settings, addon_versions): # --------- Project settings --------- -def _convert_applications_project_settings(ayon_settings, output): - if "applications" not in ayon_settings: - return - - output["applications"] = { - "only_available": ayon_settings["applications"]["only_available"] - } - - def _convert_blender_project_settings(ayon_settings, output): if "blender" not in ayon_settings: return @@ -1373,7 +1293,8 @@ def convert_project_settings(ayon_settings, default_settings): output[key] = ayon_settings[key] _convert_host_imageio(output[key]) - _convert_applications_project_settings(ayon_settings, output) + if "applications" in ayon_settings: + output["applications"] = ayon_settings["applications"] _convert_blender_project_settings(ayon_settings, output) _convert_celaction_project_settings(ayon_settings, output) _convert_flame_project_settings(ayon_settings, output) From aabe18ea04de15e0d303a21c305cc8067ce70d6b Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 9 Feb 2024 09:00:39 +0000 Subject: [PATCH 031/112] Increment version --- client/ayon_core/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/version.py b/client/ayon_core/version.py index 914e415b8c..a173569ef3 100644 --- a/client/ayon_core/version.py +++ b/client/ayon_core/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring AYON core addon version.""" -__version__ = "0.2.1-dev.1" +__version__ = "0.2.2" From 4da6f25b47f09ee0ef85dbabcd46b960c1d78823 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 9 Feb 2024 11:02:59 +0200 Subject: [PATCH 032/112] rearrange deadline settings --- .../server/settings/publish_plugins.py | 160 +++++++++--------- server_addon/deadline/server/version.py | 2 +- 2 files changed, 82 insertions(+), 80 deletions(-) diff --git a/server_addon/deadline/server/settings/publish_plugins.py b/server_addon/deadline/server/settings/publish_plugins.py index 8abe59674b..3f5ac3108d 100644 --- a/server_addon/deadline/server/settings/publish_plugins.py +++ b/server_addon/deadline/server/settings/publish_plugins.py @@ -306,36 +306,38 @@ class PublishPluginsModel(BaseSettingsModel): default_factory=ValidateExpectedFilesModel, title="Validate Expected Files" ) - MayaSubmitDeadline: MayaSubmitDeadlineModel = SettingsField( - default_factory=MayaSubmitDeadlineModel, - title="Maya Submit to deadline") - MaxSubmitDeadline: MaxSubmitDeadlineModel = SettingsField( - default_factory=MaxSubmitDeadlineModel, - title="Max Submit to deadline") - FusionSubmitDeadline: FusionSubmitDeadlineModel = SettingsField( - default_factory=FusionSubmitDeadlineModel, - title="Fusion submit to Deadline") - NukeSubmitDeadline: NukeSubmitDeadlineModel = SettingsField( - default_factory=NukeSubmitDeadlineModel, - title="Nuke Submit to deadline") - HarmonySubmitDeadline: HarmonySubmitDeadlineModel = SettingsField( - default_factory=HarmonySubmitDeadlineModel, - title="Harmony Submit to deadline") AfterEffectsSubmitDeadline: AfterEffectsSubmitDeadlineModel = ( SettingsField( default_factory=AfterEffectsSubmitDeadlineModel, - title="After Effects to deadline" + title="After Effects to deadline", + section="Hosts" ) ) - CelactionSubmitDeadline: CelactionSubmitDeadlineModel = SettingsField( - default_factory=CelactionSubmitDeadlineModel, - title="Celaction Submit Deadline") BlenderSubmitDeadline: BlenderSubmitDeadlineModel = SettingsField( default_factory=BlenderSubmitDeadlineModel, title="Blender Submit Deadline") + CelactionSubmitDeadline: CelactionSubmitDeadlineModel = SettingsField( + default_factory=CelactionSubmitDeadlineModel, + title="Celaction Submit Deadline") + FusionSubmitDeadline: FusionSubmitDeadlineModel = SettingsField( + default_factory=FusionSubmitDeadlineModel, + title="Fusion submit to Deadline") + HarmonySubmitDeadline: HarmonySubmitDeadlineModel = SettingsField( + default_factory=HarmonySubmitDeadlineModel, + title="Harmony Submit to deadline") + MaxSubmitDeadline: MaxSubmitDeadlineModel = SettingsField( + default_factory=MaxSubmitDeadlineModel, + title="Max Submit to deadline") + MayaSubmitDeadline: MayaSubmitDeadlineModel = SettingsField( + default_factory=MayaSubmitDeadlineModel, + title="Maya Submit to deadline") + NukeSubmitDeadline: NukeSubmitDeadlineModel = SettingsField( + default_factory=NukeSubmitDeadlineModel, + title="Nuke Submit to deadline") ProcessSubmittedCacheJobOnFarm: ProcessCacheJobFarmModel = SettingsField( default_factory=ProcessCacheJobFarmModel, - title="Process submitted cache Job on farm.") + title="Process submitted cache Job on farm.", + section="Publish Jobs") ProcessSubmittedJobOnFarm: ProcessSubmittedJobOnFarmModel = SettingsField( default_factory=ProcessSubmittedJobOnFarmModel, title="Process submitted job on farm.") @@ -357,6 +359,65 @@ DEFAULT_DEADLINE_PLUGINS_SETTINGS = { "deadline" ] }, + "AfterEffectsSubmitDeadline": { + "enabled": True, + "optional": False, + "active": True, + "use_published": True, + "priority": 50, + "chunk_size": 10000, + "group": "", + "department": "", + "multiprocess": True + }, + "BlenderSubmitDeadline": { + "enabled": True, + "optional": False, + "active": True, + "use_published": True, + "priority": 50, + "chunk_size": 10, + "group": "none", + "job_delay": "00:00:00:00" + }, + "CelactionSubmitDeadline": { + "enabled": True, + "deadline_department": "", + "deadline_priority": 50, + "deadline_pool": "", + "deadline_pool_secondary": "", + "deadline_group": "", + "deadline_chunk_size": 10, + "deadline_job_delay": "00:00:00:00" + }, + "FusionSubmitDeadline": { + "enabled": True, + "optional": False, + "active": True, + "priority": 50, + "chunk_size": 10, + "concurrent_tasks": 1, + "group": "" + }, + "HarmonySubmitDeadline": { + "enabled": True, + "optional": False, + "active": True, + "use_published": True, + "priority": 50, + "chunk_size": 10000, + "group": "", + "department": "" + }, + "MaxSubmitDeadline": { + "enabled": True, + "optional": False, + "active": True, + "use_published": True, + "priority": 50, + "chunk_size": 10, + "group": "none" + }, "MayaSubmitDeadline": { "enabled": True, "optional": False, @@ -376,24 +437,6 @@ DEFAULT_DEADLINE_PLUGINS_SETTINGS = { "pluginInfo": "", "scene_patches": [] }, - "MaxSubmitDeadline": { - "enabled": True, - "optional": False, - "active": True, - "use_published": True, - "priority": 50, - "chunk_size": 10, - "group": "none" - }, - "FusionSubmitDeadline": { - "enabled": True, - "optional": False, - "active": True, - "priority": 50, - "chunk_size": 10, - "concurrent_tasks": 1, - "group": "" - }, "NukeSubmitDeadline": { "enabled": True, "optional": False, @@ -410,47 +453,6 @@ DEFAULT_DEADLINE_PLUGINS_SETTINGS = { "env_search_replace_values": [], "limit_groups": [] }, - "HarmonySubmitDeadline": { - "enabled": True, - "optional": False, - "active": True, - "use_published": True, - "priority": 50, - "chunk_size": 10000, - "group": "", - "department": "" - }, - "AfterEffectsSubmitDeadline": { - "enabled": True, - "optional": False, - "active": True, - "use_published": True, - "priority": 50, - "chunk_size": 10000, - "group": "", - "department": "", - "multiprocess": True - }, - "CelactionSubmitDeadline": { - "enabled": True, - "deadline_department": "", - "deadline_priority": 50, - "deadline_pool": "", - "deadline_pool_secondary": "", - "deadline_group": "", - "deadline_chunk_size": 10, - "deadline_job_delay": "00:00:00:00" - }, - "BlenderSubmitDeadline": { - "enabled": True, - "optional": False, - "active": True, - "use_published": True, - "priority": 50, - "chunk_size": 10, - "group": "none", - "job_delay": "00:00:00:00" - }, "ProcessSubmittedCacheJobOnFarm": { "enabled": True, "deadline_department": "", diff --git a/server_addon/deadline/server/version.py b/server_addon/deadline/server/version.py index 9cb17e7976..c11f861afb 100644 --- a/server_addon/deadline/server/version.py +++ b/server_addon/deadline/server/version.py @@ -1 +1 @@ -__version__ = "0.1.8" +__version__ = "0.1.9" From 6538f5b75d96545d0e0089663f2a6c7454b9e2b1 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Fri, 9 Feb 2024 09:05:31 +0000 Subject: [PATCH 033/112] Update client/ayon_core/hosts/maya/api/menu.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/hosts/maya/api/menu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/maya/api/menu.py b/client/ayon_core/hosts/maya/api/menu.py index e92878e3e5..70347e91b6 100644 --- a/client/ayon_core/hosts/maya/api/menu.py +++ b/client/ayon_core/hosts/maya/api/menu.py @@ -24,7 +24,7 @@ from .workfile_template_builder import ( build_workfile_template, update_workfile_template ) -from openpype.tools.workfile_template_build import open_template_ui +from ayon_core.tools.workfile_template_build import open_template_ui from .workfile_template_builder import MayaTemplateBuilder log = logging.getLogger(__name__) From b245941f158389bebb76522b692816fc3f4a1c9e Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Fri, 9 Feb 2024 09:10:30 +0000 Subject: [PATCH 034/112] Update client/ayon_core/version.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/version.py b/client/ayon_core/version.py index a173569ef3..914e415b8c 100644 --- a/client/ayon_core/version.py +++ b/client/ayon_core/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring AYON core addon version.""" -__version__ = "0.2.2" +__version__ = "0.2.1-dev.1" From c79151e5d7fa8d0d7ecf7e345e377e5612d70c4c Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Fri, 9 Feb 2024 09:10:35 +0000 Subject: [PATCH 035/112] Update client/ayon_core/plugins/publish/extract_thumbnail.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/plugins/publish/extract_thumbnail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_thumbnail.py b/client/ayon_core/plugins/publish/extract_thumbnail.py index 9fbf97b275..f63dbe7f58 100644 --- a/client/ayon_core/plugins/publish/extract_thumbnail.py +++ b/client/ayon_core/plugins/publish/extract_thumbnail.py @@ -113,7 +113,7 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): return True return False - product_names = self.subsets + self.product_names + product_names = self.product_names if product_names: result = validate_string_against_patterns( instance.data["subset"], product_names From 17dd2d1e2780085980f8cb0fe1fef4438c685a0f Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Fri, 9 Feb 2024 09:10:41 +0000 Subject: [PATCH 036/112] Update client/ayon_core/plugins/publish/extract_thumbnail.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/plugins/publish/extract_thumbnail.py | 1 - 1 file changed, 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_thumbnail.py b/client/ayon_core/plugins/publish/extract_thumbnail.py index f63dbe7f58..f3dd8369f3 100644 --- a/client/ayon_core/plugins/publish/extract_thumbnail.py +++ b/client/ayon_core/plugins/publish/extract_thumbnail.py @@ -50,7 +50,6 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): # attribute presets from settings oiiotool_defaults = None ffmpeg_args = None - subsets = [] product_names = [] def process(self, instance): From 1b3ac1f5eba703726f244eeb2ac7e41bde85766a Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 9 Feb 2024 11:37:15 +0000 Subject: [PATCH 037/112] Move question code to open_template_ui --- .../tools/workfile_template_build/lib.py | 21 ++- openpype/widgets/message_window.py | 156 ------------------ 2 files changed, 10 insertions(+), 167 deletions(-) delete mode 100644 openpype/widgets/message_window.py diff --git a/client/ayon_core/tools/workfile_template_build/lib.py b/client/ayon_core/tools/workfile_template_build/lib.py index 2f6dfb414f..de3a0d0084 100644 --- a/client/ayon_core/tools/workfile_template_build/lib.py +++ b/client/ayon_core/tools/workfile_template_build/lib.py @@ -1,6 +1,8 @@ import traceback -from openpype.widgets import message_window +from qtpy import QtWidgets + +from ayon_core.tools.utils.dialogs import show_message_dialog def open_template_ui(builder, main_window): @@ -8,20 +10,17 @@ def open_template_ui(builder, main_window): Asks user about overwriting current scene and feedsback exceptions. """ - - result = message_window.message( - title="Opening template", - message="Caution! You will loose unsaved changes.\n" - "Do you want to continue?", - parent=main_window, - level="question", + result = QtWidgets.QMessageBox.question( + main_window, + "Opening template", + "Caution! You will loose unsaved changes.\nDo you want to continue?", + QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No ) - - if result: + if result == QtWidgets.QMessageBox.Yes: try: builder.open_template() except Exception: - message_window.message( + show_message_dialog( title="Template Load Failed", message="".join(traceback.format_exc()), parent=main_window, diff --git a/openpype/widgets/message_window.py b/openpype/widgets/message_window.py deleted file mode 100644 index 940d530565..0000000000 --- a/openpype/widgets/message_window.py +++ /dev/null @@ -1,156 +0,0 @@ -import sys -import logging -from qtpy import QtWidgets, QtCore - -log = logging.getLogger(__name__) - - -class Window(QtWidgets.QWidget): - def __init__(self, parent, title, message, level): - super(Window, self).__init__() - self.parent = parent - self.title = title - self.message = message - self.level = level - - self.setWindowTitle(self.title) - - if self.level == "info": - self._info() - elif self.level == "warning": - self._warning() - elif self.level == "critical": - self._critical() - elif self.level == "question": - self._question() - - def _info(self): - self.setWindowTitle(self.title) - rc = QtWidgets.QMessageBox.information( - self, self.title, self.message) - if rc: - self.exit() - - def _warning(self): - rc = QtWidgets.QMessageBox.warning( - self, self.title, self.message) - if rc: - self.exit() - - def _critical(self): - rc = QtWidgets.QMessageBox.critical( - self, self.title, self.message) - if rc: - self.exit() - - def _question(self): - self.answer = None - rc = QtWidgets.QMessageBox.question( - self, - self.title, - self.message, - QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No - ) - self.answer = False - if rc == QtWidgets.QMessageBox.Yes: - self.answer = True - self.exit() - - def exit(self): - self.hide() - return - - -def message(title=None, message=None, level="info", parent=None): - """ - Produces centered dialog with specific level denoting severity - Args: - title: (string) dialog title - message: (string) message - level: (string) info|warning|critical - parent: (QtWidgets.QApplication) - - Returns: - None - """ - app = parent - if not app: - app = QtWidgets.QApplication(sys.argv) - - ex = Window(app, title, message, level) - ex.show() - - # Move widget to center of screen - try: - desktop_rect = QtWidgets.QApplication.desktop().availableGeometry(ex) - center = desktop_rect.center() - ex.move( - center.x() - (ex.width() * 0.5), - center.y() - (ex.height() * 0.5) - ) - except Exception: - # skip all possible issues that may happen feature is not crutial - log.warning("Couldn't center message.", exc_info=True) - - if level == "question": - return ex.answer - - -class ScrollMessageBox(QtWidgets.QDialog): - """ - Basic version of scrollable QMessageBox. No other existing dialog - implementation is scrollable. - Args: - icon: - title: - messages: of messages - cancelable: - True if Cancel button should be added - """ - def __init__(self, icon, title, messages, cancelable=False): - super(ScrollMessageBox, self).__init__() - self.setWindowTitle(title) - self.icon = icon - - self.setWindowFlags(QtCore.Qt.WindowTitleHint) - - layout = QtWidgets.QVBoxLayout(self) - - scroll_widget = QtWidgets.QScrollArea(self) - scroll_widget.setWidgetResizable(True) - content_widget = QtWidgets.QWidget(self) - scroll_widget.setWidget(content_widget) - - message_len = 0 - content_layout = QtWidgets.QVBoxLayout(content_widget) - for message in messages: - label_widget = QtWidgets.QLabel(message, content_widget) - content_layout.addWidget(label_widget) - message_len = max(message_len, len(message)) - - # guess size of scrollable area - desktop = QtWidgets.QApplication.desktop() - max_width = desktop.availableGeometry().width() - scroll_widget.setMinimumWidth( - min(max_width, message_len * 6) - ) - layout.addWidget(scroll_widget) - - if not cancelable: # if no specific buttons OK only - buttons = QtWidgets.QDialogButtonBox.Ok - else: - buttons = QtWidgets.QDialogButtonBox.Ok | \ - QtWidgets.QDialogButtonBox.Cancel - - btn_box = QtWidgets.QDialogButtonBox(buttons) - btn_box.accepted.connect(self.accept) - - if cancelable: - btn_box.reject.connect(self.reject) - - btn = QtWidgets.QPushButton('Copy to clipboard') - btn.clicked.connect(lambda: QtWidgets.QApplication. - clipboard().setText("\n".join(messages))) - btn_box.addButton(btn, QtWidgets.QDialogButtonBox.NoRole) - - layout.addWidget(btn_box) - self.show() From 2534ee9cd7c279301fbc68de4cc10efb0c54616f Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 12:57:19 +0100 Subject: [PATCH 038/112] CollectAudio can read AYON settings --- client/ayon_core/plugins/publish/collect_audio.py | 10 +++++----- client/ayon_core/settings/ayon_settings.py | 5 ----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/client/ayon_core/plugins/publish/collect_audio.py b/client/ayon_core/plugins/publish/collect_audio.py index 94477e5578..6da3fd0685 100644 --- a/client/ayon_core/plugins/publish/collect_audio.py +++ b/client/ayon_core/plugins/publish/collect_audio.py @@ -43,7 +43,7 @@ class CollectAudio(pyblish.api.ContextPlugin): "unreal" ] - audio_subset_name = "audioMain" + audio_product_name = "audioMain" def process(self, context): # Fake filtering by family inside context plugin @@ -71,9 +71,9 @@ class CollectAudio(pyblish.api.ContextPlugin): asset_names = set(instances_by_asset_name.keys()) self.log.debug(( - "Searching for audio subset '{subset}' in assets {assets}" + "Searching for audio product '{subset}' in assets {assets}" ).format( - subset=self.audio_subset_name, + subset=self.audio_product_name, assets=", ".join([ '"{}"'.format(asset_name) for asset_name in asset_names @@ -130,11 +130,11 @@ class CollectAudio(pyblish.api.ContextPlugin): } asset_ids = set(asset_id_by_name.values()) - # Query subsets with name define by 'audio_subset_name' attr + # Query subsets with name define by 'audio_product_name' attr # - one or none subsets with the name should be available on an asset subset_docs = get_subsets( project_name, - subset_names=[self.audio_subset_name], + subset_names=[self.audio_product_name], asset_ids=asset_ids, fields=["_id", "parent"] ) diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index acf5e0bb30..11a9f45367 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -1080,11 +1080,6 @@ def _convert_global_project_settings(ayon_settings, output, default_settings): # Publish conversion ayon_publish = ayon_core["publish"] - ayon_collect_audio = ayon_publish["CollectAudio"] - if "audio_product_name" in ayon_collect_audio: - ayon_collect_audio["audio_subset_name"] = ( - ayon_collect_audio.pop("audio_product_name")) - for profile in ayon_publish["ExtractReview"]["profiles"]: if "product_types" in profile: profile["families"] = profile.pop("product_types") From 163d0269e5c9178f8d4d7cbf68f4dadf5ced9c0b Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 12:58:18 +0100 Subject: [PATCH 039/112] ExtractReview can read AYON settings --- .../plugins/publish/extract_review.py | 57 +++++++++++-------- client/ayon_core/settings/ayon_settings.py | 28 --------- server/settings/publish_plugins.py | 8 +-- 3 files changed, 38 insertions(+), 55 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 91d39882ae..a6e0196dc7 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -74,7 +74,7 @@ class ExtractReview(pyblish.api.InstancePlugin): alpha_exts = ["exr", "png", "dpx"] # Preset attributes - profiles = None + profiles = [] def process(self, instance): self.log.debug(str(instance.data["representations"])) @@ -112,7 +112,7 @@ class ExtractReview(pyblish.api.InstancePlugin): self.profiles, { "hosts": host_name, - "families": family, + "product_types": family, }, logger=self.log) if not profile: @@ -719,12 +719,12 @@ class ExtractReview(pyblish.api.InstancePlugin): lut_filters = self.lut_filters(new_repre, instance, ffmpeg_input_args) ffmpeg_video_filters.extend(lut_filters) - bg_alpha = 0 + bg_alpha = 0.0 bg_color = output_def.get("bg_color") if bg_color: bg_red, bg_green, bg_blue, bg_alpha = bg_color - if bg_alpha > 0: + if bg_alpha > 0.0: if not temp_data["input_allow_bg"]: self.log.info(( "Output definition has defined BG color input was" @@ -734,8 +734,7 @@ class ExtractReview(pyblish.api.InstancePlugin): bg_color_hex = "#{0:0>2X}{1:0>2X}{2:0>2X}".format( bg_red, bg_green, bg_blue ) - bg_color_alpha = float(bg_alpha) / 255 - bg_color_str = "{}@{}".format(bg_color_hex, bg_color_alpha) + bg_color_str = "{}@{}".format(bg_color_hex, bg_alpha) self.log.info("Applying BG color {}".format(bg_color_str)) color_args = [ @@ -1060,8 +1059,10 @@ class ExtractReview(pyblish.api.InstancePlugin): # NOTE: value in "-ac" was hardcoded to 2, changed to audio inputs len. # Need to merge audio if there are more than 1 input. if len(audio_inputs) > 1: - audio_out_args.append("-filter_complex amerge") - audio_out_args.append("-ac {}".format(len(audio_inputs))) + audio_out_args.extend([ + "-filter_complex", "amerge", + "-ac", str(len(audio_inputs)) + ]) return audio_in_args, audio_filters, audio_out_args @@ -1079,7 +1080,7 @@ class ExtractReview(pyblish.api.InstancePlugin): fill_color_hex = "{0:0>2X}{1:0>2X}{2:0>2X}".format( f_red, f_green, f_blue ) - fill_color_alpha = float(f_alpha) / 255 + fill_color_alpha = f_alpha line_thickness = letter_box_def["line_thickness"] line_color = letter_box_def["line_color"] @@ -1087,7 +1088,7 @@ class ExtractReview(pyblish.api.InstancePlugin): line_color_hex = "{0:0>2X}{1:0>2X}{2:0>2X}".format( l_red, l_green, l_blue ) - line_color_alpha = float(l_alpha) / 255 + line_color_alpha = l_alpha # test ratios and define if pillar or letter boxes output_ratio = float(output_width) / float(output_height) @@ -1283,8 +1284,12 @@ class ExtractReview(pyblish.api.InstancePlugin): # NOTE Setting only one of `width` or `heigth` is not allowed # - settings value can't have None but has value of 0 - output_width = output_def.get("width") or output_width or None - output_height = output_def.get("height") or output_height or None + output_width = ( + output_def.get("output_width") or output_width or None + ) + output_height = ( + output_def.get("output_height") or output_height or None + ) # Force to use input resolution if output resolution was not defined # in settings. Resolution from instance is not used when # 'use_input_res' is set to 'True'. @@ -1294,7 +1299,12 @@ class ExtractReview(pyblish.api.InstancePlugin): overscan_color_value = "black" overscan_color = output_def.get("overscan_color") if overscan_color: - bg_red, bg_green, bg_blue, _ = overscan_color + if len(overscan_color) == 3: + bg_red, bg_green, bg_blue = overscan_color + else: + # Backwards compatibility + bg_red, bg_green, bg_blue, _ = overscan_color + overscan_color_value = "#{0:0>2X}{1:0>2X}{2:0>2X}".format( bg_red, bg_green, bg_blue ) @@ -1505,12 +1515,13 @@ class ExtractReview(pyblish.api.InstancePlugin): Returns: list: Containg all output definitions matching entered families. """ - outputs = profile.get("outputs") or {} + outputs = profile.get("outputs") if not outputs: - return outputs + return [] filtered_outputs = {} - for filename_suffix, output_def in outputs.items(): + for output_def in outputs: + filename_suffix = output_def["name"] output_filters = output_def.get("filter") # If no filter on output preset, skip filtering and add output # profile for farther processing @@ -1523,16 +1534,16 @@ class ExtractReview(pyblish.api.InstancePlugin): continue # Subsets name filters - subset_filters = [ - subset_filter - for subset_filter in output_filters.get("subsets", []) + product_name_filters = [ + name_filter + for name_filter in output_filters.get("product_names", []) # Skip empty strings - if subset_filter + if name_filter ] - if subset_name and subset_filters: + if subset_name and product_name_filters: match = False - for subset_filter in subset_filters: - compiled = re.compile(subset_filter) + for product_name_filter in product_name_filters: + compiled = re.compile(product_name_filter) if compiled.search(subset_name): match = True break diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 11a9f45367..4a59bb9438 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -1080,34 +1080,6 @@ def _convert_global_project_settings(ayon_settings, output, default_settings): # Publish conversion ayon_publish = ayon_core["publish"] - for profile in ayon_publish["ExtractReview"]["profiles"]: - if "product_types" in profile: - profile["families"] = profile.pop("product_types") - new_outputs = {} - for output_def in profile.pop("outputs"): - name = output_def.pop("name") - new_outputs[name] = output_def - - output_def_filter = output_def["filter"] - if "product_names" in output_def_filter: - output_def_filter["subsets"] = ( - output_def_filter.pop("product_names")) - - for color_key in ("overscan_color", "bg_color"): - output_def[color_key] = _convert_color(output_def[color_key]) - - letter_box = output_def["letter_box"] - for color_key in ("fill_color", "line_color"): - letter_box[color_key] = _convert_color(letter_box[color_key]) - - if "output_width" in output_def: - output_def["width"] = output_def.pop("output_width") - - if "output_height" in output_def: - output_def["height"] = output_def.pop("output_height") - - profile["outputs"] = new_outputs - # ExtractThumbnail plugin ayon_extract_thumbnail = ayon_publish["ExtractThumbnail"] # fix display and view at oiio defaults diff --git a/server/settings/publish_plugins.py b/server/settings/publish_plugins.py index 7aa86aafa6..f1b93b03b5 100644 --- a/server/settings/publish_plugins.py +++ b/server/settings/publish_plugins.py @@ -9,7 +9,7 @@ from ayon_server.settings import ( task_types_enum, ) -from ayon_server.types import ColorRGBA_uint8 +from ayon_server.types import ColorRGB_uint8, ColorRGBA_uint8 class ValidateBaseModel(BaseSettingsModel): @@ -383,8 +383,8 @@ class ExtractReviewOutputDefModel(BaseSettingsModel): "Crop input overscan. See the documentation for more information." ) ) - overscan_color: ColorRGBA_uint8 = SettingsField( - (0, 0, 0, 0.0), + overscan_color: ColorRGB_uint8 = SettingsField( + (0, 0, 0), title="Overscan color", description=( "Overscan color is used when input aspect ratio is not" @@ -896,7 +896,7 @@ DEFAULT_PUBLISH_VALUES = { "single_frame_filter": "single_frame" }, "overscan_crop": "", - "overscan_color": [0, 0, 0, 1.0], + "overscan_color": [0, 0, 0], "width": 1920, "height": 1080, "scale_pixel_aspect": True, From b5f7fb3162195790c762d7cc314a8f277c43e0d0 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 13:00:28 +0100 Subject: [PATCH 040/112] deadline can read AYON settings --- .../plugins/publish/submit_maya_deadline.py | 12 ++++- .../plugins/publish/submit_nuke_deadline.py | 16 ++++--- .../plugins/publish/submit_publish_job.py | 45 +++++++++++++++---- client/ayon_core/settings/ayon_settings.py | 45 +------------------ 4 files changed, 57 insertions(+), 61 deletions(-) diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py index 84e6e93e6a..baa389cb12 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -18,6 +18,7 @@ Attributes: from __future__ import print_function import os +import json import getpass import copy import re @@ -131,8 +132,15 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, cls.group = settings.get("group", cls.group) cls.strict_error_checking = settings.get("strict_error_checking", cls.strict_error_checking) - cls.jobInfo = settings.get("jobInfo", cls.jobInfo) - cls.pluginInfo = settings.get("pluginInfo", cls.pluginInfo) + job_info = settings.get("jobInfo") + if job_info: + job_info = json.loads(job_info) + plugin_info = settings.get("pluginInfo") + if plugin_info: + plugin_info = json.loads(plugin_info) + + cls.jobInfo = job_info or cls.jobInfo + cls.pluginInfo = plugin_info or cls.pluginInfo def get_job_info(self): job_info = DeadlineJobInfo(Plugin="MayaBatch") diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_nuke_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_nuke_deadline.py index 9fff8edee6..ce4fd96da4 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_nuke_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_nuke_deadline.py @@ -40,10 +40,10 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin, concurrent_tasks = 1 group = "" department = "" - limit_groups = {} + limit_groups = [] use_gpu = False env_allowed_keys = [] - env_search_replace_values = {} + env_search_replace_values = [] workfile_dependency = True use_published_workfile = True @@ -402,8 +402,10 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin, # finally search replace in values of any key if self.env_search_replace_values: for key, value in environment.items(): - for _k, _v in self.env_search_replace_values.items(): - environment[key] = value.replace(_k, _v) + for item in self.env_search_replace_values: + environment[key] = value.replace( + item["name"], item["value"] + ) payload["JobInfo"].update({ "EnvironmentKeyValue%d" % index: "{key}={value}".format( @@ -539,8 +541,10 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin, import nuke captured_groups = [] - for lg_name, list_node_class in self.limit_groups.items(): - for node_class in list_node_class: + for limit_group in self.limit_groups: + lg_name = limit_group["name"] + + for node_class in limit_group["value"]: for node in nuke.allNodes(recurseGroups=True): # ignore all nodes not member of defined class if node.Class() not in node_class: diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_publish_job.py b/client/ayon_core/modules/deadline/plugins/publish/submit_publish_job.py index bd343e103a..3e9514204d 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_publish_job.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_publish_job.py @@ -99,12 +99,33 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin, "karma_rop", "vray_rop", "redshift_rop"] - aov_filter = {"maya": [r".*([Bb]eauty).*"], - "blender": [r".*([Bb]eauty).*"], - "aftereffects": [r".*"], # for everything from AE - "harmony": [r".*"], # for everything from AE - "celaction": [r".*"], - "max": [r".*"]} + aov_filter = [ + { + "name": "maya", + "value": [r".*([Bb]eauty).*"] + }, + { + "name": "blender", + "value": [r".*([Bb]eauty).*"] + }, + { + # for everything from AE + "name": "aftereffects", + "value": [r".*"] + }, + { + "name": "harmony", + "value": [r".*"] + }, + { + "name": "celaction", + "value": [r".*"] + }, + { + "name": "max", + "value": [r".*"] + }, + ] environ_keys = [ "FTRACK_API_USER", @@ -506,17 +527,23 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin, self.log.debug("Instance has review explicitly disabled.") do_not_add_review = True + aov_filter = { + item["name"]: item["value"] + for item in self.aov_filter + } if isinstance(instance.data.get("expectedFiles")[0], dict): instances = create_instances_for_aov( instance, instance_skeleton_data, - self.aov_filter, self.skip_integration_repre_list, - do_not_add_review) + aov_filter, + self.skip_integration_repre_list, + do_not_add_review + ) else: representations = prepare_representations( instance_skeleton_data, instance.data.get("expectedFiles"), anatomy, - self.aov_filter, + aov_filter, self.skip_integration_repre_list, do_not_add_review, instance.context, diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 4a59bb9438..bca5198f95 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -951,49 +951,6 @@ def _convert_webpublisher_project_settings(ayon_settings, output): output["webpublisher"] = ayon_webpublisher -def _convert_deadline_project_settings(ayon_settings, output): - if "deadline" not in ayon_settings: - return - - ayon_deadline = ayon_settings["deadline"] - - for key in ("deadline_urls",): - ayon_deadline.pop(key) - - ayon_deadline_publish = ayon_deadline["publish"] - limit_groups = { - item["name"]: item["value"] - for item in ayon_deadline_publish["NukeSubmitDeadline"]["limit_groups"] - } - ayon_deadline_publish["NukeSubmitDeadline"]["limit_groups"] = limit_groups - - maya_submit = ayon_deadline_publish["MayaSubmitDeadline"] - for json_key in ("jobInfo", "pluginInfo"): - src_text = maya_submit.pop(json_key) - try: - value = json.loads(src_text) - except ValueError: - value = {} - maya_submit[json_key] = value - - nuke_submit = ayon_deadline_publish["NukeSubmitDeadline"] - nuke_submit["env_search_replace_values"] = { - item["name"]: item["value"] - for item in nuke_submit.pop("env_search_replace_values") - } - nuke_submit["limit_groups"] = { - item["name"]: item["value"] for item in nuke_submit.pop("limit_groups") - } - - process_subsetted_job = ayon_deadline_publish["ProcessSubmittedJobOnFarm"] - process_subsetted_job["aov_filter"] = { - item["name"]: item["value"] - for item in process_subsetted_job.pop("aov_filter") - } - - output["deadline"] = ayon_deadline - - def _convert_royalrender_project_settings(ayon_settings, output): if "royalrender" not in ayon_settings: return @@ -1254,6 +1211,7 @@ def convert_project_settings(ayon_settings, default_settings): "houdini", "resolve", "unreal", + "deadline", } for key in exact_match: if key in ayon_settings: @@ -1276,7 +1234,6 @@ def convert_project_settings(ayon_settings, default_settings): _convert_traypublisher_project_settings(ayon_settings, output) _convert_webpublisher_project_settings(ayon_settings, output) - _convert_deadline_project_settings(ayon_settings, output) _convert_royalrender_project_settings(ayon_settings, output) _convert_kitsu_project_settings(ayon_settings, output) _convert_shotgrid_project_settings(ayon_settings, output) From aac11597aaf3d54898e9c4428c9358baea139872 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 13:00:55 +0100 Subject: [PATCH 041/112] simplify how applications are applied --- client/ayon_core/settings/ayon_settings.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index bca5198f95..1521a0dc25 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -1211,6 +1211,7 @@ def convert_project_settings(ayon_settings, default_settings): "houdini", "resolve", "unreal", + "applications", "deadline", } for key in exact_match: @@ -1218,8 +1219,6 @@ def convert_project_settings(ayon_settings, default_settings): output[key] = ayon_settings[key] _convert_host_imageio(output[key]) - if "applications" in ayon_settings: - output["applications"] = ayon_settings["applications"] _convert_blender_project_settings(ayon_settings, output) _convert_celaction_project_settings(ayon_settings, output) _convert_flame_project_settings(ayon_settings, output) From 40a5b0e6d9c271c3e6faf8e708d1013a0ae18324 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 13:07:00 +0100 Subject: [PATCH 042/112] photoshop plugins can use AYON settings --- .../plugins/publish/collect_color_coded_instances.py | 6 +++--- .../photoshop/plugins/publish/collect_review.py | 2 -- client/ayon_core/settings/ayon_settings.py | 12 ------------ 3 files changed, 3 insertions(+), 17 deletions(-) diff --git a/client/ayon_core/hosts/photoshop/plugins/publish/collect_color_coded_instances.py b/client/ayon_core/hosts/photoshop/plugins/publish/collect_color_coded_instances.py index e309da62ba..987097f4ff 100644 --- a/client/ayon_core/hosts/photoshop/plugins/publish/collect_color_coded_instances.py +++ b/client/ayon_core/hosts/photoshop/plugins/publish/collect_color_coded_instances.py @@ -42,7 +42,7 @@ class CollectColorCodedInstances(pyblish.api.ContextPlugin): # flattened template cannot subset_template_name = "" create_flatten_image = "no" - flatten_subset_template = "" + flatten_product_name_template = "" def process(self, context): self.log.info("CollectColorCodedInstances") @@ -124,12 +124,12 @@ class CollectColorCodedInstances(pyblish.api.ContextPlugin): if self.create_flatten_image != "no" and publishable_layers: self.log.debug("create_flatten_image") - if not self.flatten_subset_template: + if not self.flatten_product_name_template: self.log.warning("No template for flatten image") return fill_pairs.pop("layer") - subset = self.flatten_subset_template.format( + subset = self.flatten_product_name_template.format( **prepare_template_data(fill_pairs)) first_layer = publishable_layers[0] # dummy layer diff --git a/client/ayon_core/hosts/photoshop/plugins/publish/collect_review.py b/client/ayon_core/hosts/photoshop/plugins/publish/collect_review.py index e487760736..e51dd253ca 100644 --- a/client/ayon_core/hosts/photoshop/plugins/publish/collect_review.py +++ b/client/ayon_core/hosts/photoshop/plugins/publish/collect_review.py @@ -22,8 +22,6 @@ class CollectReview(pyblish.api.ContextPlugin): hosts = ["photoshop"] order = pyblish.api.CollectorOrder + 0.1 - publish = True - def process(self, context): for instance in context: creator_attributes = instance.data["creator_attributes"] diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 1521a0dc25..b90de7946b 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -808,18 +808,6 @@ def _convert_photoshop_project_settings(ayon_settings, output): ayon_photoshop = ayon_settings["photoshop"] _convert_host_imageio(ayon_photoshop) - - ayon_publish_photoshop = ayon_photoshop["publish"] - - ayon_colorcoded = ayon_publish_photoshop["CollectColorCodedInstances"] - if "flatten_product_type_template" in ayon_colorcoded: - ayon_colorcoded["flatten_subset_template"] = ( - ayon_colorcoded.pop("flatten_product_type_template")) - - collect_review = ayon_publish_photoshop["CollectReview"] - if "active" in collect_review: - collect_review["publish"] = collect_review.pop("active") - output["photoshop"] = ayon_photoshop From 94b50b2d96e783eb3706af4a593ed2a73f502f7d Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 13:07:42 +0100 Subject: [PATCH 043/112] cleanup photoshop plugin attributes --- .../plugins/publish/collect_color_coded_instances.py | 3 +-- .../hosts/photoshop/plugins/publish/collect_review.py | 7 +------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/client/ayon_core/hosts/photoshop/plugins/publish/collect_color_coded_instances.py b/client/ayon_core/hosts/photoshop/plugins/publish/collect_color_coded_instances.py index 987097f4ff..236fe878ba 100644 --- a/client/ayon_core/hosts/photoshop/plugins/publish/collect_color_coded_instances.py +++ b/client/ayon_core/hosts/photoshop/plugins/publish/collect_color_coded_instances.py @@ -29,9 +29,8 @@ class CollectColorCodedInstances(pyblish.api.ContextPlugin): Identifier: id (str): "pyblish.avalon.instance" """ - order = pyblish.api.CollectorOrder + 0.100 - label = "Instances" + label = "Collect Color-coded Instances" order = pyblish.api.CollectorOrder hosts = ["photoshop"] targets = ["automated"] diff --git a/client/ayon_core/hosts/photoshop/plugins/publish/collect_review.py b/client/ayon_core/hosts/photoshop/plugins/publish/collect_review.py index e51dd253ca..3a4b7b5828 100644 --- a/client/ayon_core/hosts/photoshop/plugins/publish/collect_review.py +++ b/client/ayon_core/hosts/photoshop/plugins/publish/collect_review.py @@ -6,19 +6,14 @@ Provides: instance -> family ("review") """ -import os - import pyblish.api -from ayon_core.pipeline.create import get_subset_name - class CollectReview(pyblish.api.ContextPlugin): """Adds review to families for instances marked to be reviewable. """ - label = "Collect Review" - label = "Review" + label = "Collect Review Family" hosts = ["photoshop"] order = pyblish.api.CollectorOrder + 0.1 From f6f09ce43b2f1c9b4618bbaf508a8ad643f07dad Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 13:10:19 +0100 Subject: [PATCH 044/112] substance can read shelves from AYON settings --- .../hosts/substancepainter/api/pipeline.py | 17 +++++++++-------- client/ayon_core/settings/ayon_settings.py | 8 -------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/client/ayon_core/hosts/substancepainter/api/pipeline.py b/client/ayon_core/hosts/substancepainter/api/pipeline.py index 2bbcf2aded..03cb22136c 100644 --- a/client/ayon_core/hosts/substancepainter/api/pipeline.py +++ b/client/ayon_core/hosts/substancepainter/api/pipeline.py @@ -240,33 +240,34 @@ class SubstanceHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost): def _install_shelves(self, project_settings): - shelves = project_settings["substancepainter"].get("shelves", {}) + shelves = project_settings["substancepainter"].get("shelves", []) if not shelves: return # Prepare formatting data if we detect any path which might have # template tokens like {asset} in there. formatting_data = {} - has_formatting_entries = any("{" in path for path in shelves.values()) + has_formatting_entries = any("{" in item["value"] for item in shelves) if has_formatting_entries: project_name = self.get_current_project_name() asset_name = self.get_current_asset_name() task_name = self.get_current_asset_name() system_settings = get_system_settings() - formatting_data = get_template_data_with_names(project_name, - asset_name, - task_name, - system_settings) + formatting_data = get_template_data_with_names( + project_name, asset_name, task_name, system_settings + ) anatomy = Anatomy(project_name) formatting_data["root"] = anatomy.roots - for name, path in shelves.items(): - shelf_name = None + for shelve_item in shelves: # Allow formatting with anatomy for the paths + path = shelve_item["value"] if "{" in path: path = StringTemplate.format_template(path, formatting_data) + name = shelve_item["name"] + shelf_name = None try: shelf_name = lib.load_shelf(path, name=name) except ValueError as exc: diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index b90de7946b..726b2147cd 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -817,14 +817,6 @@ def _convert_substancepainter_project_settings(ayon_settings, output): ayon_substance_painter = ayon_settings["substancepainter"] _convert_host_imageio(ayon_substance_painter) - if "shelves" in ayon_substance_painter: - shelves_items = ayon_substance_painter["shelves"] - new_shelves_items = { - item["name"]: item["value"] - for item in shelves_items - } - ayon_substance_painter["shelves"] = new_shelves_items - output["substancepainter"] = ayon_substance_painter From 8fb6e1e4d43b58254f01e2e7957cf8380d7653bd Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 13:14:16 +0100 Subject: [PATCH 045/112] fix photoshop settings --- server_addon/photoshop/server/settings/publish_plugins.py | 6 +++--- server_addon/photoshop/server/version.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server_addon/photoshop/server/settings/publish_plugins.py b/server_addon/photoshop/server/settings/publish_plugins.py index c4a392d490..d04faaf53a 100644 --- a/server_addon/photoshop/server/settings/publish_plugins.py +++ b/server_addon/photoshop/server/settings/publish_plugins.py @@ -62,9 +62,9 @@ class CollectColorCodedInstancesPlugin(BaseSettingsModel): enum_resolver=lambda: create_flatten_image_enum, ) - flatten_product_type_template: str = SettingsField( + flatten_product_name_template: str = SettingsField( "", - title="Subset template for flatten image" + title="Product name template for flatten image" ) color_code_mapping: list[ColorCodeMappings] = SettingsField( @@ -178,7 +178,7 @@ class PhotoshopPublishPlugins(BaseSettingsModel): DEFAULT_PUBLISH_SETTINGS = { "CollectColorCodedInstances": { "create_flatten_image": "no", - "flatten_product_type_template": "", + "flatten_product_name_template": "", "color_code_mapping": [] }, "CollectReview": { diff --git a/server_addon/photoshop/server/version.py b/server_addon/photoshop/server/version.py index a242f0e757..df0c92f1e2 100644 --- a/server_addon/photoshop/server/version.py +++ b/server_addon/photoshop/server/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring addon version.""" -__version__ = "0.1.1" +__version__ = "0.1.2" From 53df65a4127d6fba8cfc4350d6189c55d104055c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 13:14:57 +0100 Subject: [PATCH 046/112] TVPaint can read AYON settings --- client/ayon_core/settings/ayon_settings.py | 23 +------------------ .../server/settings/publish_plugins.py | 8 +++---- server_addon/tvpaint/server/version.py | 2 +- 3 files changed, 6 insertions(+), 27 deletions(-) diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 726b2147cd..e151043afb 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -823,30 +823,9 @@ def _convert_substancepainter_project_settings(ayon_settings, output): def _convert_tvpaint_project_settings(ayon_settings, output): if "tvpaint" not in ayon_settings: return + ayon_tvpaint = ayon_settings["tvpaint"] - _convert_host_imageio(ayon_tvpaint) - - ayon_publish_settings = ayon_tvpaint["publish"] - for plugin_name in ( - "ValidateProjectSettings", - "ValidateMarks", - "ValidateStartFrame", - "ValidateAssetName", - ): - ayon_value = ayon_publish_settings[plugin_name] - for src_key, dst_key in ( - ("action_enabled", "optional"), - ("action_enable", "active"), - ): - if src_key in ayon_value: - ayon_value[dst_key] = ayon_value.pop(src_key) - - extract_sequence_setting = ayon_publish_settings["ExtractSequence"] - extract_sequence_setting["review_bg"] = _convert_color( - extract_sequence_setting["review_bg"] - ) - output["tvpaint"] = ayon_tvpaint diff --git a/server_addon/tvpaint/server/settings/publish_plugins.py b/server_addon/tvpaint/server/settings/publish_plugins.py index 0623524c92..37ad3e0e70 100644 --- a/server_addon/tvpaint/server/settings/publish_plugins.py +++ b/server_addon/tvpaint/server/settings/publish_plugins.py @@ -1,5 +1,5 @@ from ayon_server.settings import BaseSettingsModel, SettingsField -from ayon_server.types import ColorRGBA_uint8 +from ayon_server.types import ColorRGB_uint8 class CollectRenderInstancesModel(BaseSettingsModel): @@ -11,8 +11,8 @@ class CollectRenderInstancesModel(BaseSettingsModel): class ExtractSequenceModel(BaseSettingsModel): """Review BG color is used for whole scene review and for thumbnails.""" # TODO Use alpha color - review_bg: ColorRGBA_uint8 = SettingsField( - (255, 255, 255, 1.0), + review_bg: ColorRGB_uint8 = SettingsField( + (255, 255, 255), title="Review BG color") @@ -100,7 +100,7 @@ DEFAULT_PUBLISH_SETTINGS = { "ignore_render_pass_transparency": False }, "ExtractSequence": { - "review_bg": [255, 255, 255, 1.0] + "review_bg": [255, 255, 255] }, "ValidateProjectSettings": { "enabled": True, diff --git a/server_addon/tvpaint/server/version.py b/server_addon/tvpaint/server/version.py index 485f44ac21..b3f4756216 100644 --- a/server_addon/tvpaint/server/version.py +++ b/server_addon/tvpaint/server/version.py @@ -1 +1 @@ -__version__ = "0.1.1" +__version__ = "0.1.2" From 00e2bebd125615bf31b120aaa452773391245a51 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 14:44:30 +0100 Subject: [PATCH 047/112] blender can use AYON settings --- .../hosts/blender/plugins/publish/extract_playblast.py | 9 ++++++--- .../hosts/blender/plugins/publish/extract_thumbnail.py | 6 ++++-- client/ayon_core/settings/ayon_settings.py | 6 ------ 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/client/ayon_core/hosts/blender/plugins/publish/extract_playblast.py b/client/ayon_core/hosts/blender/plugins/publish/extract_playblast.py index 83e6b26fbe..04fc2c5c39 100644 --- a/client/ayon_core/hosts/blender/plugins/publish/extract_playblast.py +++ b/client/ayon_core/hosts/blender/plugins/publish/extract_playblast.py @@ -1,9 +1,11 @@ import os +import json + import clique +import pyblish.api import bpy -import pyblish.api from ayon_core.pipeline import publish from ayon_core.hosts.blender.api import capture from ayon_core.hosts.blender.api.lib import maintained_time @@ -23,6 +25,8 @@ class ExtractPlayblast(publish.Extractor, publish.OptionalPyblishPluginMixin): optional = True order = pyblish.api.ExtractorOrder + 0.01 + presets = "{}" + def process(self, instance): if not self.is_active(instance.data): return @@ -59,8 +63,7 @@ class ExtractPlayblast(publish.Extractor, publish.OptionalPyblishPluginMixin): self.log.debug(f"Outputting images to {path}") - project_settings = instance.context.data["project_settings"]["blender"] - presets = project_settings["publish"]["ExtractPlayblast"]["presets"] + presets = json.loads(self.presets) preset = presets.get("default") preset.update({ "camera": camera, diff --git a/client/ayon_core/hosts/blender/plugins/publish/extract_thumbnail.py b/client/ayon_core/hosts/blender/plugins/publish/extract_thumbnail.py index 7b445a0113..ec701610ce 100644 --- a/client/ayon_core/hosts/blender/plugins/publish/extract_thumbnail.py +++ b/client/ayon_core/hosts/blender/plugins/publish/extract_thumbnail.py @@ -1,5 +1,6 @@ import os import glob +import json import pyblish.api from ayon_core.pipeline import publish @@ -21,7 +22,7 @@ class ExtractThumbnail(publish.Extractor): hosts = ["blender"] families = ["review"] order = pyblish.api.ExtractorOrder + 0.01 - presets = {} + presets = "{}" def process(self, instance): self.log.debug("Extracting capture..") @@ -44,7 +45,8 @@ class ExtractThumbnail(publish.Extractor): family = instance.data.get("family") isolate = instance.data("isolate", None) - preset = self.presets.get(family, {}) + presets = json.loads(self.presets) + preset = presets.get(family, {}) preset.update({ "camera": camera, diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index e151043afb..e2e569c233 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -248,12 +248,6 @@ def _convert_blender_project_settings(ayon_settings, output): ayon_blender = ayon_settings["blender"] _convert_host_imageio(ayon_blender) - ayon_publish = ayon_blender["publish"] - - for plugin in ("ExtractThumbnail", "ExtractPlayblast"): - plugin_settings = ayon_publish[plugin] - plugin_settings["presets"] = json.loads(plugin_settings["presets"]) - output["blender"] = ayon_blender From 5c0d866c1efa4b194b0b0534ac1dd410042f8ad2 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 14:50:53 +0100 Subject: [PATCH 048/112] fusion is handling AYON settings in code --- client/ayon_core/hosts/fusion/api/plugin.py | 11 ++++++- client/ayon_core/settings/ayon_settings.py | 33 --------------------- 2 files changed, 10 insertions(+), 34 deletions(-) diff --git a/client/ayon_core/hosts/fusion/api/plugin.py b/client/ayon_core/hosts/fusion/api/plugin.py index 12a29d2986..5d7a9dd87d 100644 --- a/client/ayon_core/hosts/fusion/api/plugin.py +++ b/client/ayon_core/hosts/fusion/api/plugin.py @@ -148,7 +148,16 @@ class GenericCreateSaver(Creator): }) # build file path to render - filepath = self.temp_rendering_path_template.format(**formatting_data) + # TODO make sure the keys are available in 'formatting_data' + temp_rendering_path_template = ( + self.temp_rendering_path_template + .replace("{product[name]}", "{subset}") + .replace("{product[type]}", "{family}") + .replace("{folder[name]}", "{asset}") + .replace("{task[name]}", "{task}") + ) + + filepath = temp_rendering_path_template.format(**formatting_data) comp = get_current_comp() tool["Clip"] = comp.ReverseMapPath(os.path.normpath(filepath)) diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index e2e569c233..39b0b117f7 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -324,39 +324,6 @@ def _convert_fusion_project_settings(ayon_settings, output): ayon_fusion = ayon_settings["fusion"] _convert_host_imageio(ayon_fusion) - ayon_imageio_fusion = ayon_fusion["imageio"] - - if "ocioSettings" in ayon_imageio_fusion: - ayon_ocio_setting = ayon_imageio_fusion.pop("ocioSettings") - paths = ayon_ocio_setting.pop("ocioPathModel") - for key, value in tuple(paths.items()): - new_value = [] - if value: - new_value.append(value) - paths[key] = new_value - - ayon_ocio_setting["configFilePath"] = paths - ayon_imageio_fusion["ocio"] = ayon_ocio_setting - elif "ocio" in ayon_imageio_fusion: - paths = ayon_imageio_fusion["ocio"].pop("configFilePath") - for key, value in tuple(paths.items()): - new_value = [] - if value: - new_value.append(value) - paths[key] = new_value - ayon_imageio_fusion["ocio"]["configFilePath"] = paths - - _convert_host_imageio(ayon_imageio_fusion) - - ayon_create_saver = ayon_fusion["create"]["CreateSaver"] - ayon_create_saver["temp_rendering_path_template"] = ( - ayon_create_saver["temp_rendering_path_template"] - .replace("{product[name]}", "{subset}") - .replace("{product[type]}", "{family}") - .replace("{folder[name]}", "{asset}") - .replace("{task[name]}", "{task}") - ) - output["fusion"] = ayon_fusion From cd1ac5c15b8268158ff5a5ad8b64cf31fd25a340 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 15:04:57 +0100 Subject: [PATCH 049/112] maya use render settings from AYON --- .../ayon_core/hosts/maya/api/lib_rendersettings.py | 14 +++++++------- .../hosts/maya/plugins/create/create_render.py | 2 +- .../hosts/maya/plugins/create/create_vrayscene.py | 2 +- .../plugins/publish/validate_render_image_rule.py | 2 +- client/ayon_core/settings/ayon_settings.py | 3 --- 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/lib_rendersettings.py b/client/ayon_core/hosts/maya/api/lib_rendersettings.py index 54ee7888b3..1e2c95ac73 100644 --- a/client/ayon_core/hosts/maya/api/lib_rendersettings.py +++ b/client/ayon_core/hosts/maya/api/lib_rendersettings.py @@ -46,7 +46,7 @@ class RenderSettings(object): project_settings = get_project_settings( get_current_project_name() ) - render_settings = project_settings["maya"]["RenderSettings"] + render_settings = project_settings["maya"]["render_settings"] image_prefixes = { "vray": render_settings["vray_renderer"]["image_prefix"], "arnold": render_settings["arnold_renderer"]["image_prefix"], @@ -82,12 +82,12 @@ class RenderSettings(object): try: aov_separator = self._aov_chars[( self._project_settings["maya"] - ["RenderSettings"] + ["render_settings"] ["aov_separator"] )] except KeyError: aov_separator = "_" - reset_frame = self._project_settings["maya"]["RenderSettings"]["reset_current_frame"] # noqa + reset_frame = self._project_settings["maya"]["render_settings"]["reset_current_frame"] # noqa if reset_frame: start_frame = cmds.getAttr("defaultRenderGlobals.startFrame") @@ -131,7 +131,7 @@ class RenderSettings(object): import maya.mel as mel # noqa: F401 createOptions() - render_settings = self._project_settings["maya"]["RenderSettings"] + render_settings = self._project_settings["maya"]["render_settings"] arnold_render_presets = render_settings["arnold_renderer"] # noqa # Force resetting settings and AOV list to avoid having to deal with # AOV checking logic, for now. @@ -180,7 +180,7 @@ class RenderSettings(object): from maya import cmds # noqa: F401 import maya.mel as mel # noqa: F401 - render_settings = self._project_settings["maya"]["RenderSettings"] + render_settings = self._project_settings["maya"]["render_settings"] redshift_render_presets = render_settings["redshift_renderer"] remove_aovs = render_settings["remove_aovs"] @@ -239,7 +239,7 @@ class RenderSettings(object): rman_render_presets = ( self._project_settings ["maya"] - ["RenderSettings"] + ["render_settings"] ["renderman_renderer"] ) display_filters = rman_render_presets["display_filters"] @@ -304,7 +304,7 @@ class RenderSettings(object): settings = cmds.ls(type="VRaySettingsNode") node = settings[0] if settings else cmds.createNode("VRaySettingsNode") - render_settings = self._project_settings["maya"]["RenderSettings"] + render_settings = self._project_settings["maya"]["render_settings"] vray_render_presets = render_settings["vray_renderer"] # vrayRenderElement remove_aovs = render_settings["remove_aovs"] diff --git a/client/ayon_core/hosts/maya/plugins/create/create_render.py b/client/ayon_core/hosts/maya/plugins/create/create_render.py index f537f249cd..4481836c89 100644 --- a/client/ayon_core/hosts/maya/plugins/create/create_render.py +++ b/client/ayon_core/hosts/maya/plugins/create/create_render.py @@ -35,7 +35,7 @@ class CreateRenderlayer(plugin.RenderlayerCreator): @classmethod def apply_settings(cls, project_settings): - cls.render_settings = project_settings["maya"]["RenderSettings"] + cls.render_settings = project_settings["maya"]["render_settings"] def create(self, subset_name, instance_data, pre_create_data): # Only allow a single render instance to exist diff --git a/client/ayon_core/hosts/maya/plugins/create/create_vrayscene.py b/client/ayon_core/hosts/maya/plugins/create/create_vrayscene.py index 3642f5f689..bc8110eff1 100644 --- a/client/ayon_core/hosts/maya/plugins/create/create_vrayscene.py +++ b/client/ayon_core/hosts/maya/plugins/create/create_vrayscene.py @@ -23,7 +23,7 @@ class CreateVRayScene(plugin.RenderlayerCreator): @classmethod def apply_settings(cls, project_settings): - cls.render_settings = project_settings["maya"]["RenderSettings"] + cls.render_settings = project_settings["maya"]["render_settings"] def create(self, subset_name, instance_data, pre_create_data): # Only allow a single render instance to exist diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_render_image_rule.py b/client/ayon_core/hosts/maya/plugins/publish/validate_render_image_rule.py index 576886072d..efc622c416 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_render_image_rule.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_render_image_rule.py @@ -55,7 +55,7 @@ class ValidateRenderImageRule(pyblish.api.InstancePlugin): if staging_dir: cls.log.debug( "Staging dir found: \"{}\". Ignoring setting from " - "`project_settings/maya/RenderSettings/" + "`project_settings/maya/render_settings/" "default_render_image_folder`.".format(staging_dir) ) return staging_dir diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 39b0b117f7..0c7acc1854 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -333,9 +333,6 @@ def _convert_maya_project_settings(ayon_settings, output): ayon_maya = ayon_settings["maya"] - # Change key of render settings - ayon_maya["RenderSettings"] = ayon_maya.pop("render_settings") - # Convert extensions mapping ayon_maya["ext_mapping"] = { item["name"]: item["value"] From 8d830ae37406ad0ae9df91fc4b4bb250261e1643 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 15:05:38 +0100 Subject: [PATCH 050/112] maya can handle ext_mapping from AYON --- .../maya/plugins/publish/extract_camera_mayaScene.py | 8 +++++--- .../maya/plugins/publish/extract_import_reference.py | 8 +++++--- .../ayon_core/hosts/maya/plugins/publish/extract_look.py | 8 +++++--- .../hosts/maya/plugins/publish/extract_maya_scene_raw.py | 8 +++++--- .../ayon_core/hosts/maya/plugins/publish/extract_model.py | 8 +++++--- .../ayon_core/hosts/maya/plugins/publish/extract_rig.py | 8 +++++--- .../hosts/maya/plugins/publish/extract_yeti_rig.py | 8 +++++--- client/ayon_core/settings/ayon_settings.py | 6 ------ 8 files changed, 35 insertions(+), 27 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_camera_mayaScene.py b/client/ayon_core/hosts/maya/plugins/publish/extract_camera_mayaScene.py index 8ca1fd9d3a..689eed09f8 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/extract_camera_mayaScene.py +++ b/client/ayon_core/hosts/maya/plugins/publish/extract_camera_mayaScene.py @@ -112,9 +112,11 @@ class ExtractCameraMayaScene(publish.Extractor, def process(self, instance): """Plugin entry point.""" # get settings - ext_mapping = ( - instance.context.data["project_settings"]["maya"]["ext_mapping"] - ) + maya_settings = instance.context.data["project_settings"]["maya"] + ext_mapping = { + item["name"]: item["value"] + for item in maya_settings["ext_mapping"] + } if ext_mapping: self.log.debug("Looking in settings for scene type ...") # use extension mapping for first family found diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_import_reference.py b/client/ayon_core/hosts/maya/plugins/publish/extract_import_reference.py index 2a43a30b8d..3fb84c8d83 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/extract_import_reference.py +++ b/client/ayon_core/hosts/maya/plugins/publish/extract_import_reference.py @@ -37,9 +37,11 @@ class ExtractImportReference(publish.Extractor, if not self.is_active(instance.data): return - ext_mapping = ( - instance.context.data["project_settings"]["maya"]["ext_mapping"] - ) + maya_settings = instance.context.data["project_settings"]["maya"] + ext_mapping = { + item["name"]: item["value"] + for item in maya_settings["ext_mapping"] + } if ext_mapping: self.log.debug("Looking in settings for scene type ...") # use extension mapping for first family found diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_look.py b/client/ayon_core/hosts/maya/plugins/publish/extract_look.py index 7f97a7bf82..29390e2c7d 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/extract_look.py +++ b/client/ayon_core/hosts/maya/plugins/publish/extract_look.py @@ -431,9 +431,11 @@ class ExtractLook(publish.Extractor): project settings. """ - ext_mapping = ( - instance.context.data["project_settings"]["maya"]["ext_mapping"] - ) + maya_settings = instance.context.data["project_settings"]["maya"] + ext_mapping = { + item["name"]: item["value"] + for item in maya_settings["ext_mapping"] + } if ext_mapping: self.log.debug("Looking in settings for scene type ...") # use extension mapping for first family found diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_maya_scene_raw.py b/client/ayon_core/hosts/maya/plugins/publish/extract_maya_scene_raw.py index 5045a8d252..cd6f3bab6a 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/extract_maya_scene_raw.py +++ b/client/ayon_core/hosts/maya/plugins/publish/extract_maya_scene_raw.py @@ -43,9 +43,11 @@ class ExtractMayaSceneRaw(publish.Extractor, AYONPyblishPluginMixin): def process(self, instance): """Plugin entry point.""" - ext_mapping = ( - instance.context.data["project_settings"]["maya"]["ext_mapping"] - ) + maya_settings = instance.context.data["project_settings"]["maya"] + ext_mapping = { + item["name"]: item["value"] + for item in maya_settings["ext_mapping"] + } if ext_mapping: self.log.debug("Looking in settings for scene type ...") # use extension mapping for first family found diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_model.py b/client/ayon_core/hosts/maya/plugins/publish/extract_model.py index b6ae4d537a..543af59e8f 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/extract_model.py +++ b/client/ayon_core/hosts/maya/plugins/publish/extract_model.py @@ -35,9 +35,11 @@ class ExtractModel(publish.Extractor, if not self.is_active(instance.data): return - ext_mapping = ( - instance.context.data["project_settings"]["maya"]["ext_mapping"] - ) + maya_settings = instance.context.data["project_settings"]["maya"] + ext_mapping = { + item["name"]: item["value"] + for item in maya_settings["ext_mapping"] + } if ext_mapping: self.log.debug("Looking in settings for scene type ...") # use extension mapping for first family found diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_rig.py b/client/ayon_core/hosts/maya/plugins/publish/extract_rig.py index 13e3d7c6b4..305f4698c6 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/extract_rig.py +++ b/client/ayon_core/hosts/maya/plugins/publish/extract_rig.py @@ -18,9 +18,11 @@ class ExtractRig(publish.Extractor): def process(self, instance): """Plugin entry point.""" - ext_mapping = ( - instance.context.data["project_settings"]["maya"]["ext_mapping"] - ) + maya_settings = instance.context.data["project_settings"]["maya"] + ext_mapping = { + item["name"]: item["value"] + for item in maya_settings["ext_mapping"] + } if ext_mapping: self.log.debug("Looking in settings for scene type ...") # use extension mapping for first family found diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_yeti_rig.py b/client/ayon_core/hosts/maya/plugins/publish/extract_yeti_rig.py index 7387849736..0b67117ebc 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/extract_yeti_rig.py +++ b/client/ayon_core/hosts/maya/plugins/publish/extract_yeti_rig.py @@ -100,9 +100,11 @@ class ExtractYetiRig(publish.Extractor): def process(self, instance): """Plugin entry point.""" - ext_mapping = ( - instance.context.data["project_settings"]["maya"]["ext_mapping"] - ) + maya_settings = instance.context.data["project_settings"]["maya"] + ext_mapping = { + item["name"]: item["value"] + for item in maya_settings["ext_mapping"] + } if ext_mapping: self.log.debug("Looking in settings for scene type ...") # use extension mapping for first family found diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 0c7acc1854..14af455d5b 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -333,12 +333,6 @@ def _convert_maya_project_settings(ayon_settings, output): ayon_maya = ayon_settings["maya"] - # Convert extensions mapping - ayon_maya["ext_mapping"] = { - item["name"]: item["value"] - for item in ayon_maya["ext_mapping"] - } - # Maya dirmap ayon_maya_dirmap = ayon_maya.pop("maya_dirmap") ayon_maya_dirmap_path = ayon_maya_dirmap["paths"] From 2c7da1a6de01c0d7821475c600950bd0626cde65 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 15:09:04 +0100 Subject: [PATCH 051/112] dirmap settings are using AYON settings --- client/ayon_core/host/dirmap.py | 24 ++++++++++----------- client/ayon_core/hosts/maya/api/plugin.py | 2 +- client/ayon_core/hosts/nuke/api/pipeline.py | 2 +- client/ayon_core/settings/ayon_settings.py | 20 ----------------- 4 files changed, 14 insertions(+), 34 deletions(-) diff --git a/client/ayon_core/host/dirmap.py b/client/ayon_core/host/dirmap.py index cecd689a4c..9756657386 100644 --- a/client/ayon_core/host/dirmap.py +++ b/client/ayon_core/host/dirmap.py @@ -92,8 +92,8 @@ class HostDirmap(object): self.on_enable_dirmap() - for k, sp in enumerate(mapping["source-path"]): - dst = mapping["destination-path"][k] + for k, sp in enumerate(mapping["source_path"]): + dst = mapping["destination_path"][k] try: # add trailing slash if missing sp = os.path.join(sp, '') @@ -116,7 +116,7 @@ class HostDirmap(object): continue def get_mappings(self): - """Get translation from source-path to destination-path. + """Get translation from source_path to destination_path. It checks if Site Sync is enabled and user chose to use local site, in that case configuration in Local Settings takes precedence @@ -138,8 +138,8 @@ class HostDirmap(object): if ( not mapping - or not mapping.get("destination-path") - or not mapping.get("source-path") + or not mapping.get("destination_path") + or not mapping.get("source_path") ): return {} self.log.info("Processing directory mapping ...") @@ -154,7 +154,7 @@ class HostDirmap(object): in Local Settings. Returns: - dict : { "source-path": [XXX], "destination-path": [YYYY]} + dict : { "source_path": [XXX], "destination_path": [YYYY]} """ project_name = self.project_name @@ -210,13 +210,13 @@ class HostDirmap(object): continue if os.path.isdir(active_site_dir): - if "destination-path" not in mapping: - mapping["destination-path"] = [] - mapping["destination-path"].append(active_site_dir) + if "destination_path" not in mapping: + mapping["destination_path"] = [] + mapping["destination_path"].append(active_site_dir) - if "source-path" not in mapping: - mapping["source-path"] = [] - mapping["source-path"].append(remote_site_dir) + if "source_path" not in mapping: + mapping["source_path"] = [] + mapping["source_path"].append(remote_site_dir) self.log.debug("local sync mapping:: {}".format(mapping)) return mapping diff --git a/client/ayon_core/hosts/maya/api/plugin.py b/client/ayon_core/hosts/maya/api/plugin.py index c5e3f42d10..e0ff900c01 100644 --- a/client/ayon_core/hosts/maya/api/plugin.py +++ b/client/ayon_core/hosts/maya/api/plugin.py @@ -937,7 +937,7 @@ class ReferenceLoader(Loader): """ settings = get_project_settings(project_name) use_env_var_as_root = (settings["maya"] - ["maya-dirmap"] + ["maya_dirmap"] ["use_env_var_as_root"]) if use_env_var_as_root: anatomy = Anatomy(project_name) diff --git a/client/ayon_core/hosts/nuke/api/pipeline.py b/client/ayon_core/hosts/nuke/api/pipeline.py index bdba0757b6..99bd5616cb 100644 --- a/client/ayon_core/hosts/nuke/api/pipeline.py +++ b/client/ayon_core/hosts/nuke/api/pipeline.py @@ -176,7 +176,7 @@ def add_nuke_callbacks(): nuke.addOnScriptLoad(WorkfileSettings().set_context_settings) - if nuke_settings["nuke-dirmap"]["enabled"]: + if nuke_settings["nuke_dirmap"]["enabled"]: log.info("Added Nuke's dir-mapping callback ...") # Add dirmap for file paths. nuke.addFilenameFilter(dirmap_file_name_filter) diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 14af455d5b..6114b5767c 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -333,17 +333,6 @@ def _convert_maya_project_settings(ayon_settings, output): ayon_maya = ayon_settings["maya"] - # Maya dirmap - ayon_maya_dirmap = ayon_maya.pop("maya_dirmap") - ayon_maya_dirmap_path = ayon_maya_dirmap["paths"] - ayon_maya_dirmap_path["source-path"] = ( - ayon_maya_dirmap_path.pop("source_path") - ) - ayon_maya_dirmap_path["destination-path"] = ( - ayon_maya_dirmap_path.pop("destination_path") - ) - ayon_maya["maya-dirmap"] = ayon_maya_dirmap - # Create plugins ayon_create = ayon_maya["create"] ayon_create_static_mesh = ayon_create["CreateUnrealStaticMesh"] @@ -580,15 +569,6 @@ def _convert_nuke_project_settings(ayon_settings, output): ayon_nuke = ayon_settings["nuke"] - # --- Dirmap --- - dirmap = ayon_nuke.pop("dirmap") - for src_key, dst_key in ( - ("source_path", "source-path"), - ("destination_path", "destination-path"), - ): - dirmap["paths"][dst_key] = dirmap["paths"].pop(src_key) - ayon_nuke["nuke-dirmap"] = dirmap - # --- Load --- ayon_load = ayon_nuke["load"] ayon_load["LoadClip"]["_representations"] = ( From c35bae324373af98722f91c802d49d7fde24f024 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 15:23:01 +0100 Subject: [PATCH 052/112] Validate attributes converts attributes on own --- .../plugins/publish/validate_attributes.py | 18 ++++++++++++------ client/ayon_core/settings/ayon_settings.py | 7 ------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_attributes.py b/client/ayon_core/hosts/maya/plugins/publish/validate_attributes.py index 3dfe2f4f2d..fc39756bf0 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_attributes.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_attributes.py @@ -1,3 +1,4 @@ +import json from collections import defaultdict import pyblish.api @@ -23,19 +24,19 @@ class ValidateAttributes(pyblish.api.InstancePlugin, """ order = ValidateContentsOrder - label = "Attributes" + label = "Validate Attributes" hosts = ["maya"] actions = [RepairAction] optional = True - attributes = None + attributes = "{}" def process(self, instance): if not self.is_active(instance.data): return # Check for preset existence. - if not self.attributes: + if not self.get_attributes_data(): return invalid = self.get_invalid(instance, compute=True) @@ -44,6 +45,10 @@ class ValidateAttributes(pyblish.api.InstancePlugin, "Found attributes with invalid values: {}".format(invalid) ) + @classmethod + def get_attributes_data(cls): + return json.loads(cls.attributes) + @classmethod def get_invalid(cls, instance, compute=False): if compute: @@ -55,21 +60,22 @@ class ValidateAttributes(pyblish.api.InstancePlugin, def get_invalid_attributes(cls, instance): invalid_attributes = [] + attributes_data = cls.get_attributes_data() # Filter families. families = [instance.data["family"]] families += instance.data.get("families", []) - families = set(families) & set(cls.attributes.keys()) + families = set(families) & set(attributes_data.keys()) if not families: return [] # Get all attributes to validate. attributes = defaultdict(dict) for family in families: - if family not in cls.attributes: + if family not in attributes_data: # No attributes to validate for family continue - for preset_attr, preset_value in cls.attributes[family].items(): + for preset_attr, preset_value in attributes_data[family].items(): node_name, attribute_name = preset_attr.split(".", 1) attributes[node_name][attribute_name] = preset_value diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 6114b5767c..a27f071e7c 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -343,13 +343,6 @@ def _convert_maya_project_settings(ayon_settings, output): # --- Publish (START) --- ayon_publish = ayon_maya["publish"] - try: - attributes = json.loads( - ayon_publish["ValidateAttributes"]["attributes"] - ) - except ValueError: - attributes = {} - ayon_publish["ValidateAttributes"]["attributes"] = attributes try: SUFFIX_NAMING_TABLE = json.loads( From 649d6478e083143fcedfa640a47d8c8fc70790fc Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 15:23:28 +0100 Subject: [PATCH 053/112] removed deprecated conversion --- client/ayon_core/settings/ayon_settings.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index a27f071e7c..251fafa597 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -333,14 +333,6 @@ def _convert_maya_project_settings(ayon_settings, output): ayon_maya = ayon_settings["maya"] - # Create plugins - ayon_create = ayon_maya["create"] - ayon_create_static_mesh = ayon_create["CreateUnrealStaticMesh"] - if "static_mesh_prefixes" in ayon_create_static_mesh: - ayon_create_static_mesh["static_mesh_prefix"] = ( - ayon_create_static_mesh.pop("static_mesh_prefixes") - ) - # --- Publish (START) --- ayon_publish = ayon_maya["publish"] From bf4c8c7b3d4e41a7472d076a8e71d8f5568dda3d Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 15:23:52 +0100 Subject: [PATCH 054/112] SUFFIX_NAMING_TABLE is converted in plugin --- .../validate_transform_naming_suffix.py | 67 +++++++++++-------- client/ayon_core/settings/ayon_settings.py | 12 ---- 2 files changed, 40 insertions(+), 39 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_transform_naming_suffix.py b/client/ayon_core/hosts/maya/plugins/publish/validate_transform_naming_suffix.py index 1f8d6b7470..e565866778 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_transform_naming_suffix.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_transform_naming_suffix.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- """Plugin for validating naming conventions.""" +import json from maya import cmds import pyblish.api @@ -35,29 +36,37 @@ class ValidateTransformNamingSuffix(pyblish.api.InstancePlugin, """ order = ValidateContentsOrder - hosts = ['maya'] - families = ['model'] + hosts = ["maya"] + families = ["model"] optional = True - label = 'Suffix Naming Conventions' + label = "Suffix Naming Conventions" actions = [ayon_core.hosts.maya.api.action.SelectInvalidAction] - SUFFIX_NAMING_TABLE = {"mesh": ["_GEO", "_GES", "_GEP", "_OSD"], - "nurbsCurve": ["_CRV"], - "nurbsSurface": ["_NRB"], - "locator": ["_LOC"], - "group": ["_GRP"]} + SUFFIX_NAMING_TABLE = json.dumps({ + "mesh": ["_GEO", "_GES", "_GEP", "_OSD"], + "nurbsCurve": ["_CRV"], + "nurbsSurface": ["_NRB"], + "locator": ["_LOC"], + "group": ["_GRP"] + }) ALLOW_IF_NOT_IN_SUFFIX_TABLE = True @classmethod def get_table_for_invalid(cls): - ss = [] - for k, v in cls.SUFFIX_NAMING_TABLE.items(): - ss.append(" - {}: {}".format(k, ", ".join(v))) + suffix_naming_table = json.loads(cls.SUFFIX_NAMING_TABLE) + ss = [ + " - {}: {}".format(k, ", ".join(v)) + for k, v in suffix_naming_table.items() + ] return "
".join(ss) @staticmethod - def is_valid_name(node_name, shape_type, - SUFFIX_NAMING_TABLE, ALLOW_IF_NOT_IN_SUFFIX_TABLE): + def is_valid_name( + node_name, + shape_type, + suffix_naming_table, + allow_if_not_in_suffix_table + ): """Return whether node's name is correct. The correctness for a transform's suffix is dependent on what @@ -70,18 +79,18 @@ class ValidateTransformNamingSuffix(pyblish.api.InstancePlugin, Args: node_name (str): Node name. shape_type (str): Type of node. - SUFFIX_NAMING_TABLE (dict): Mapping dict for suffixes. - ALLOW_IF_NOT_IN_SUFFIX_TABLE (dict): Filter dict. + suffix_naming_table (dict): Mapping dict for suffixes. + allow_if_not_in_suffix_table (bool): Default output. """ - if shape_type not in SUFFIX_NAMING_TABLE: - return ALLOW_IF_NOT_IN_SUFFIX_TABLE - else: - suffices = SUFFIX_NAMING_TABLE[shape_type] - for suffix in suffices: - if node_name.endswith(suffix): - return True - return False + if shape_type not in suffix_naming_table: + return allow_if_not_in_suffix_table + + suffices = suffix_naming_table[shape_type] + for suffix in suffices: + if node_name.endswith(suffix): + return True + return False @classmethod def get_invalid(cls, instance): @@ -91,9 +100,10 @@ class ValidateTransformNamingSuffix(pyblish.api.InstancePlugin, instance (:class:`pyblish.api.Instance`): published instance. """ - transforms = cmds.ls(instance, type='transform', long=True) + transforms = cmds.ls(instance, type="transform", long=True) invalid = [] + suffix_naming_table = json.loads(cls.SUFFIX_NAMING_TABLE) for transform in transforms: shapes = cmds.listRelatives(transform, shapes=True, @@ -101,9 +111,12 @@ class ValidateTransformNamingSuffix(pyblish.api.InstancePlugin, noIntermediate=True) shape_type = cmds.nodeType(shapes[0]) if shapes else "group" - if not cls.is_valid_name(transform, shape_type, - cls.SUFFIX_NAMING_TABLE, - cls.ALLOW_IF_NOT_IN_SUFFIX_TABLE): + if not cls.is_valid_name( + transform, + shape_type, + suffix_naming_table, + cls.ALLOW_IF_NOT_IN_SUFFIX_TABLE + ): invalid.append(transform) return invalid diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 251fafa597..165e47da1a 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -336,18 +336,6 @@ def _convert_maya_project_settings(ayon_settings, output): # --- Publish (START) --- ayon_publish = ayon_maya["publish"] - try: - SUFFIX_NAMING_TABLE = json.loads( - ayon_publish - ["ValidateTransformNamingSuffix"] - ["SUFFIX_NAMING_TABLE"] - ) - except ValueError: - SUFFIX_NAMING_TABLE = {} - ayon_publish["ValidateTransformNamingSuffix"]["SUFFIX_NAMING_TABLE"] = ( - SUFFIX_NAMING_TABLE - ) - validate_frame_range = ayon_publish["ValidateFrameRange"] if "exclude_product_types" in validate_frame_range: validate_frame_range["exclude_families"] = ( From a657dfac4e3416d6f7e8f6c4560c3844c21522df Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 15:30:53 +0100 Subject: [PATCH 055/112] maya 'ValidateFrameRange' is handling AYON settings --- .../hosts/maya/plugins/publish/validate_frame_range.py | 6 ++++-- client/ayon_core/settings/ayon_settings.py | 5 ----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_frame_range.py b/client/ayon_core/hosts/maya/plugins/publish/validate_frame_range.py index 85cc606b25..d5f99e5563 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_frame_range.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_frame_range.py @@ -39,7 +39,7 @@ class ValidateFrameRange(pyblish.api.InstancePlugin, "yeticache"] optional = True actions = [RepairAction] - exclude_families = [] + exclude_product_types = [] def process(self, instance): if not self.is_active(instance.data): @@ -73,7 +73,9 @@ class ValidateFrameRange(pyblish.api.InstancePlugin, # compare with data on instance errors = [] - if [ef for ef in self.exclude_families + # QUESTION shouldn't this be just: + # 'if instance.data["family"] in self.exclude_product_types:' + if [ef for ef in self.exclude_product_types if instance.data["family"] in ef]: return if (inst_start != frame_start_handle): diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 165e47da1a..9cadb36869 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -336,11 +336,6 @@ def _convert_maya_project_settings(ayon_settings, output): # --- Publish (START) --- ayon_publish = ayon_maya["publish"] - validate_frame_range = ayon_publish["ValidateFrameRange"] - if "exclude_product_types" in validate_frame_range: - validate_frame_range["exclude_families"] = ( - validate_frame_range.pop("exclude_product_types")) - # Extract playblast capture settings validate_rendern_settings = ayon_publish["ValidateRenderSettings"] for key in ( From 6ae8537983ba2d885744ac831a79e95f4b766499 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 15:31:41 +0100 Subject: [PATCH 056/112] maya 'ValidateRenderSettings' can handle AYON settings --- .../plugins/publish/validate_rendersettings.py | 13 ++++++++++--- client/ayon_core/settings/ayon_settings.py | 15 --------------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_rendersettings.py b/client/ayon_core/hosts/maya/plugins/publish/validate_rendersettings.py index ed70d81b63..7f6c0bab1d 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_rendersettings.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_rendersettings.py @@ -281,6 +281,8 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin): # if so, compare its value from the one required. for data in cls.get_nodes(instance, renderer): for node in data["nodes"]: + # Why is captured 'PublishValidationError'? How it can be + # raised by 'cmds.getAttr(...)'? try: render_value = cmds.getAttr( "{}.{}".format(node, data["attribute"]) @@ -310,11 +312,16 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin): @classmethod def get_nodes(cls, instance, renderer): maya_settings = instance.context.data["project_settings"]["maya"] + renderer_key = "{}_render_attributes".format(renderer) validation_settings = ( maya_settings["publish"]["ValidateRenderSettings"].get( - "{}_render_attributes".format(renderer) - ) or [] - ) + renderer_key + ) + ) or [] + validation_settings = [ + (item["type"], item["value"]) + for item in validation_settings + ] result = [] for attr, values in OrderedDict(validation_settings).items(): values = [convert_to_int_or_float(v) for v in values if v] diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 9cadb36869..e9ec2ba650 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -336,21 +336,6 @@ def _convert_maya_project_settings(ayon_settings, output): # --- Publish (START) --- ayon_publish = ayon_maya["publish"] - # Extract playblast capture settings - validate_rendern_settings = ayon_publish["ValidateRenderSettings"] - for key in ( - "arnold_render_attributes", - "vray_render_attributes", - "redshift_render_attributes", - "renderman_render_attributes", - ): - if key not in validate_rendern_settings: - continue - validate_rendern_settings[key] = [ - [item["type"], item["value"]] - for item in validate_rendern_settings[key] - ] - plugin_path_attributes = ayon_publish["ValidatePluginPathAttributes"] plugin_path_attributes["attribute"] = { item["name"]: item["value"] From 43167dbb094dc97124d2ae8239c1f87a0a68cb28 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 15:33:20 +0100 Subject: [PATCH 057/112] maya 'ValidatePluginPathAttributes' can handle AYON settings --- .../plugins/publish/validate_plugin_path_attributes.py | 8 ++++++-- client/ayon_core/settings/ayon_settings.py | 6 ------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_plugin_path_attributes.py b/client/ayon_core/hosts/maya/plugins/publish/validate_plugin_path_attributes.py index d672be6fa0..fd71039e30 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_plugin_path_attributes.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_plugin_path_attributes.py @@ -30,14 +30,18 @@ class ValidatePluginPathAttributes(pyblish.api.InstancePlugin): def get_invalid(cls, instance): invalid = list() - file_attrs = cls.attribute + file_attrs = { + item["name"]: item["value"] + for item in cls.attribute + } if not file_attrs: return invalid # Consider only valid node types to avoid "Unknown object type" warning all_node_types = set(cmds.allNodeTypes()) node_types = [ - key for key in file_attrs.keys() + key + for key in file_attrs.keys() if key in all_node_types ] diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index e9ec2ba650..3d58b8f272 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -336,12 +336,6 @@ def _convert_maya_project_settings(ayon_settings, output): # --- Publish (START) --- ayon_publish = ayon_maya["publish"] - plugin_path_attributes = ayon_publish["ValidatePluginPathAttributes"] - plugin_path_attributes["attribute"] = { - item["name"]: item["value"] - for item in plugin_path_attributes["attribute"] - } - ayon_capture_preset = ayon_publish["ExtractPlayblast"]["capture_preset"] display_options = ayon_capture_preset["DisplayOptions"] for key in ("background", "backgroundBottom", "backgroundTop"): From 1256816f1cf5d8b4ecc840933efd233d386168f3 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 15:56:52 +0100 Subject: [PATCH 058/112] maya 'ExtractPlayblast' can use AYON settings --- client/ayon_core/hosts/maya/api/lib.py | 29 +++++++++----- .../maya/plugins/create/create_review.py | 2 +- .../maya/plugins/publish/collect_review.py | 2 +- client/ayon_core/settings/ayon_settings.py | 39 ------------------- .../maya/server/settings/publish_playblast.py | 35 ++++++++--------- 5 files changed, 38 insertions(+), 69 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/lib.py b/client/ayon_core/hosts/maya/api/lib.py index 7b791c3d51..f46471b94d 100644 --- a/client/ayon_core/hosts/maya/api/lib.py +++ b/client/ayon_core/hosts/maya/api/lib.py @@ -329,7 +329,7 @@ def generate_capture_preset(instance, camera, path, # Update preset with current panel setting # if override_viewport_options is turned off - if not capture_preset["Viewport Options"]["override_viewport_options"]: + if not capture_preset["ViewportOptions"]["override_viewport_options"]: panel_preset = capture.parse_view(preset["panel"]) panel_preset.pop("camera") preset.update(panel_preset) @@ -2937,14 +2937,15 @@ def load_capture_preset(data): options.update(data["Generic"]) options.update(data["Resolution"]) - camera_options.update(data['Camera Options']) + camera_options.update(data["CameraOptions"]) viewport_options.update(data["Renderer"]) # DISPLAY OPTIONS disp_options = {} - for key, value in data['Display Options'].items(): - if key.startswith('background'): + for key, value in data["DisplayOptions"].items(): + if key.startswith("background"): # Convert background, backgroundTop, backgroundBottom colors + if len(value) == 4: # Ignore alpha + convert RGB to float value = [ @@ -2956,7 +2957,7 @@ def load_capture_preset(data): elif key == "displayGradient": disp_options[key] = value - options['display_options'] = disp_options + options["display_options"] = disp_options # Viewport Options has a mixture of Viewport2 Options and Viewport Options # to pass along to capture. So we'll need to differentiate between the two @@ -2981,7 +2982,7 @@ def load_capture_preset(data): "motionBlurShutterOpenFraction", "lineAAEnable" } - for key, value in data['Viewport Options'].items(): + for key, value in data["ViewportOptions"].items(): # There are some keys we want to ignore if key in {"override_viewport_options", "high_quality"}: @@ -4059,10 +4060,10 @@ def get_capture_preset(task_name, task_type, subset, project_settings, log): Args: task_name (str): Task name. - take_type (str): Task type. + task_type (str): Task type. subset (str): Subset name. project_settings (dict): Project settings. - log (object): Logging object. + log (logging.Logger): Logging object. """ capture_preset = None filtering_criteria = { @@ -4091,8 +4092,18 @@ def get_capture_preset(task_name, task_type, subset, project_settings, log): "Falling back to deprecated Extract Playblast capture preset " "because no new style playblast profiles are defined." ) - capture_preset = plugin_settings["capture_preset"] + capture_preset = plugin_settings.get("capture_preset") + if capture_preset: + # Create deepcopy of preset as we'll change the values + capture_preset = copy.deepcopy(capture_preset) + + viewport_options = capture_preset["ViewportOptions"] + # Change 'list' to 'dict' for 'capture.py' + viewport_options["pluginObjects"] = { + item["name"]: item["value"] + for item in viewport_options["pluginObjects"] + } return capture_preset or {} diff --git a/client/ayon_core/hosts/maya/plugins/create/create_review.py b/client/ayon_core/hosts/maya/plugins/create/create_review.py index 6f7c0ca802..3e75b52556 100644 --- a/client/ayon_core/hosts/maya/plugins/create/create_review.py +++ b/client/ayon_core/hosts/maya/plugins/create/create_review.py @@ -75,7 +75,7 @@ class CreateReview(plugin.MayaCreator): "review_width": preset["Resolution"]["width"], "review_height": preset["Resolution"]["height"], "isolate": preset["Generic"]["isolate_view"], - "imagePlane": preset["Viewport Options"]["imagePlane"], + "imagePlane": preset["ViewportOptions"]["imagePlane"], "panZoom": preset["Generic"]["pan_zoom"] } for key, value in mapping.items(): diff --git a/client/ayon_core/hosts/maya/plugins/publish/collect_review.py b/client/ayon_core/hosts/maya/plugins/publish/collect_review.py index 679a21243a..205c871c93 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/collect_review.py +++ b/client/ayon_core/hosts/maya/plugins/publish/collect_review.py @@ -39,7 +39,7 @@ class CollectReview(pyblish.api.InstancePlugin): if display_lights == "project_settings": settings = instance.context.data["project_settings"] settings = settings["maya"]["publish"]["ExtractPlayblast"] - settings = settings["capture_preset"]["Viewport Options"] + settings = settings["capture_preset"]["ViewportOptions"] display_lights = settings["displayLights"] # Collect camera focal length. diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 3d58b8f272..8e4c5abe10 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -336,45 +336,6 @@ def _convert_maya_project_settings(ayon_settings, output): # --- Publish (START) --- ayon_publish = ayon_maya["publish"] - ayon_capture_preset = ayon_publish["ExtractPlayblast"]["capture_preset"] - display_options = ayon_capture_preset["DisplayOptions"] - for key in ("background", "backgroundBottom", "backgroundTop"): - display_options[key] = _convert_color(display_options[key]) - - for src_key, dst_key in ( - ("DisplayOptions", "Display Options"), - ("ViewportOptions", "Viewport Options"), - ("CameraOptions", "Camera Options"), - ): - ayon_capture_preset[dst_key] = ayon_capture_preset.pop(src_key) - - viewport_options = ayon_capture_preset["Viewport Options"] - viewport_options["pluginObjects"] = { - item["name"]: item["value"] - for item in viewport_options["pluginObjects"] - } - - ayon_playblast_settings = ayon_publish["ExtractPlayblast"]["profiles"] - if ayon_playblast_settings: - for setting in ayon_playblast_settings: - capture_preset = setting["capture_preset"] - display_options = capture_preset["DisplayOptions"] - for key in ("background", "backgroundBottom", "backgroundTop"): - display_options[key] = _convert_color(display_options[key]) - - for src_key, dst_key in ( - ("DisplayOptions", "Display Options"), - ("ViewportOptions", "Viewport Options"), - ("CameraOptions", "Camera Options"), - ): - capture_preset[dst_key] = capture_preset.pop(src_key) - - viewport_options = capture_preset["Viewport Options"] - viewport_options["pluginObjects"] = { - item["name"]: item["value"] - for item in viewport_options["pluginObjects"] - } - # Extract Camera Alembic bake attributes try: bake_attributes = json.loads( diff --git a/server_addon/maya/server/settings/publish_playblast.py b/server_addon/maya/server/settings/publish_playblast.py index 0461a18cc8..dcedf3ccc9 100644 --- a/server_addon/maya/server/settings/publish_playblast.py +++ b/server_addon/maya/server/settings/publish_playblast.py @@ -6,7 +6,7 @@ from ayon_server.settings import ( ensure_unique_names, task_types_enum, ) -from ayon_server.types import ColorRGBA_uint8 +from ayon_server.types import ColorRGB_float def hardware_falloff_enum(): @@ -54,17 +54,17 @@ class DisplayOptionsSetting(BaseSettingsModel): override_display: bool = SettingsField( True, title="Override display options" ) - background: ColorRGBA_uint8 = SettingsField( - (125, 125, 125, 1.0), title="Background Color" + background: ColorRGB_float = SettingsField( + (0.5, 0.5, 0.5), title="Background Color" ) displayGradient: bool = SettingsField( True, title="Display background gradient" ) - backgroundTop: ColorRGBA_uint8 = SettingsField( - (125, 125, 125, 1.0), title="Background Top" + backgroundTop: ColorRGB_float = SettingsField( + (0.5, 0.5, 0.5), title="Background Top" ) - backgroundBottom: ColorRGBA_uint8 = SettingsField( - (125, 125, 125, 1.0), title="Background Bottom" + backgroundBottom: ColorRGB_float = SettingsField( + (0.5, 0.5, 0.5), title="Background Bottom" ) @@ -283,22 +283,19 @@ DEFAULT_PLAYBLAST_SETTING = { "DisplayOptions": { "override_display": True, "background": [ - 125, - 125, - 125, - 1.0 + 0.5, + 0.5, + 0.5 ], "backgroundBottom": [ - 125, - 125, - 125, - 1.0 + 0.5, + 0.5, + 0.5 ], "backgroundTop": [ - 125, - 125, - 125, - 1.0 + 0.5, + 0.5, + 0.5 ], "displayGradient": True }, From 6a3b475be5595ddc9a47fabe9febbde15a941836 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 15:57:17 +0100 Subject: [PATCH 059/112] maya 'ExtractCameraAlembic' can use AYON settings --- .../maya/plugins/publish/extract_camera_alembic.py | 8 +++++--- client/ayon_core/settings/ayon_settings.py | 13 ------------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/extract_camera_alembic.py b/client/ayon_core/hosts/maya/plugins/publish/extract_camera_alembic.py index b9561e299e..2be9cfec95 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/extract_camera_alembic.py +++ b/client/ayon_core/hosts/maya/plugins/publish/extract_camera_alembic.py @@ -1,4 +1,5 @@ import os +import json from maya import cmds @@ -21,7 +22,7 @@ class ExtractCameraAlembic(publish.Extractor, label = "Extract Camera (Alembic)" hosts = ["maya"] families = ["camera", "matchmove"] - bake_attributes = [] + bake_attributes = "[]" def process(self, instance): @@ -95,11 +96,12 @@ class ExtractCameraAlembic(publish.Extractor, job_str += ' -file "{0}"'.format(path) + bake_attributes = json.loads(self.bake_attributes) # bake specified attributes in preset - assert isinstance(self.bake_attributes, (list, tuple)), ( + assert isinstance(bake_attributes, list), ( "Attributes to bake must be specified as a list" ) - for attr in self.bake_attributes: + for attr in bake_attributes: self.log.debug("Adding {} attribute".format(attr)) job_str += " -attr {0}".format(attr) diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 8e4c5abe10..f9e674b2c1 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -333,19 +333,6 @@ def _convert_maya_project_settings(ayon_settings, output): ayon_maya = ayon_settings["maya"] - # --- Publish (START) --- - ayon_publish = ayon_maya["publish"] - - # Extract Camera Alembic bake attributes - try: - bake_attributes = json.loads( - ayon_publish["ExtractCameraAlembic"]["bake_attributes"] - ) - except ValueError: - bake_attributes = [] - ayon_publish["ExtractCameraAlembic"]["bake_attributes"] = bake_attributes - - # --- Publish (END) --- for renderer_settings in ayon_maya["RenderSettings"].values(): if ( not isinstance(renderer_settings, dict) From 53b27915d5ff34924da7e8b6b71c12b9ce131aac Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Fri, 9 Feb 2024 15:03:46 +0000 Subject: [PATCH 060/112] Update client/ayon_core/plugins/publish/extract_thumbnail.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/plugins/publish/extract_thumbnail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_thumbnail.py b/client/ayon_core/plugins/publish/extract_thumbnail.py index f3dd8369f3..1471a5fb78 100644 --- a/client/ayon_core/plugins/publish/extract_thumbnail.py +++ b/client/ayon_core/plugins/publish/extract_thumbnail.py @@ -119,7 +119,7 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): ) if not result: self.log.debug( - "Subset \"{}\" did not match any valid subsets: {}".format( + "Product name \"{}\" did not match settings filters: {}".format( instance.data["subset"], product_names ) ) From 6c48e74bd2350bf8a8829d09b7556547f771d5e8 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 16:04:55 +0100 Subject: [PATCH 061/112] additional options for renderer can us AYON settings --- client/ayon_core/hosts/maya/api/lib_rendersettings.py | 3 ++- client/ayon_core/settings/ayon_settings.py | 11 ----------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/lib_rendersettings.py b/client/ayon_core/hosts/maya/api/lib_rendersettings.py index 1e2c95ac73..b8a4d04a10 100644 --- a/client/ayon_core/hosts/maya/api/lib_rendersettings.py +++ b/client/ayon_core/hosts/maya/api/lib_rendersettings.py @@ -390,7 +390,8 @@ class RenderSettings(object): import maya.mel as mel # noqa: F401 for item in additional_attribs: - attribute, value = item + attribute = item["attribute"] + value = item["value"] attribute = str(attribute) # ensure str conversion from settings attribute_type = cmds.getAttr(attribute, type=True) if attribute_type in {"long", "bool"}: diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index f9e674b2c1..5d7a9e0356 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -333,17 +333,6 @@ def _convert_maya_project_settings(ayon_settings, output): ayon_maya = ayon_settings["maya"] - for renderer_settings in ayon_maya["RenderSettings"].values(): - if ( - not isinstance(renderer_settings, dict) - or "additional_options" not in renderer_settings - ): - continue - renderer_settings["additional_options"] = [ - [item["attribute"], item["value"]] - for item in renderer_settings["additional_options"] - ] - # Workfile build ayon_workfile_build = ayon_maya["workfile_build"] for item in ayon_workfile_build["profiles"]: From 0404e27e8eeb5eb598852d946c9d80bb36892dbf Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 16:07:37 +0100 Subject: [PATCH 062/112] added product key to template formatting data --- client/ayon_core/hosts/maya/api/plugin.py | 31 +++++++++++++--------- client/ayon_core/settings/ayon_settings.py | 13 --------- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/plugin.py b/client/ayon_core/hosts/maya/api/plugin.py index e0ff900c01..01ca4f7875 100644 --- a/client/ayon_core/hosts/maya/api/plugin.py +++ b/client/ayon_core/hosts/maya/api/plugin.py @@ -611,33 +611,38 @@ class Loader(LoaderPlugin): options["attach_to_root"] = True custom_naming = self.load_settings[loader_key] - if not custom_naming['namespace']: + if not custom_naming["namespace"]: raise LoadError("No namespace specified in " "Maya ReferenceLoader settings") - elif not custom_naming['group_name']: + elif not custom_naming["group_name"]: self.log.debug("No custom group_name, no group will be created.") options["attach_to_root"] = False - asset = context['asset'] - subset = context['subset'] + asset = context["asset"] + subset = context["subset"] + family = ( + subset["data"].get("family") + or subset["data"]["families"][0] + ) formatting_data = { - "asset_name": asset['name'], - "asset_type": asset['type'], + "asset_name": asset["name"], + "asset_type": asset["type"], "folder": { "name": asset["name"], }, - "subset": subset['name'], - "family": ( - subset['data'].get('family') or - subset['data']['families'][0] - ) + "subset": subset["name"], + "product": { + "name": subset["name"], + "type": family, + }, + "family": family } - custom_namespace = custom_naming['namespace'].format( + custom_namespace = custom_naming["namespace"].format( **formatting_data ) - custom_group_name = custom_naming['group_name'].format( + custom_group_name = custom_naming["group_name"].format( **formatting_data ) diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 5d7a9e0356..1a353a5a64 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -351,19 +351,6 @@ def _convert_maya_project_settings(ayon_settings, output): for key, color in tuple(load_colors.items()): load_colors[key] = _convert_color(color) - reference_loader = ayon_maya_load["reference_loader"] - reference_loader["namespace"] = ( - reference_loader["namespace"] - .replace("{product[name]}", "{subset}") - ) - - if ayon_maya_load.get("import_loader"): - import_loader = ayon_maya_load["import_loader"] - import_loader["namespace"] = ( - import_loader["namespace"] - .replace("{product[name]}", "{subset}") - ) - output["maya"] = ayon_maya From dcd1f0946b6609b2f9264ee7bbbe3999ea3e9e2b Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 16:47:00 +0100 Subject: [PATCH 063/112] use load plugin colors from AYON settings --- client/ayon_core/hosts/maya/api/plugin.py | 34 +++ .../maya/plugins/load/load_arnold_standin.py | 6 +- .../hosts/maya/plugins/load/load_gpucache.py | 10 +- .../maya/plugins/load/load_redshift_proxy.py | 12 +- .../hosts/maya/plugins/load/load_reference.py | 21 +- .../maya/plugins/load/load_vdb_to_arnold.py | 14 +- .../maya/plugins/load/load_vdb_to_redshift.py | 14 +- .../maya/plugins/load/load_vdb_to_vray.py | 13 +- .../hosts/maya/plugins/load/load_vrayproxy.py | 12 +- .../hosts/maya/plugins/load/load_vrayscene.py | 14 +- .../maya/plugins/load/load_yeti_cache.py | 14 +- .../hosts/maya/plugins/load/load_yeti_rig.py | 15 +- client/ayon_core/settings/ayon_settings.py | 7 - server_addon/maya/server/settings/loaders.py | 226 ++++++++++++++---- 14 files changed, 275 insertions(+), 137 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/plugin.py b/client/ayon_core/hosts/maya/api/plugin.py index 01ca4f7875..aba5fd8903 100644 --- a/client/ayon_core/hosts/maya/api/plugin.py +++ b/client/ayon_core/hosts/maya/api/plugin.py @@ -22,6 +22,7 @@ from ayon_core.pipeline import ( LegacyCreator, LoaderPlugin, get_representation_path, + get_current_project_name, ) from ayon_core.pipeline.load import LoadError from ayon_core.client import get_asset_by_name @@ -585,6 +586,39 @@ class RenderlayerCreator(NewCreator, MayaCreatorBase): project_name) +def get_load_color_for_family(family, settings=None): + """Get color for family from settings. + + Args: + family (str): Family name. + settings (Optional[dict]): Settings dictionary. + + Returns: + Union[tuple[float, float, float], None]: RGB color. + + """ + if settings is None: + settings = get_project_settings(get_current_project_name()) + + colors = settings["maya"]["load"]["colors"] + color = colors.get(family) + if not color: + return None + + if len(color) == 3: + red, green, blue = color + elif len(color) == 4: + red, green, blue, _ = color + else: + raise ValueError("Invalid color definition {}".format(str(color))) + + if type(red, int): + red = red / 255.0 + green = green / 255.0 + blue = blue / 255.0 + return red, green, blue + + class Loader(LoaderPlugin): hosts = ["maya"] diff --git a/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py b/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py index c690d1c205..d70a43a8c3 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py @@ -16,6 +16,7 @@ from ayon_core.hosts.maya.api.lib import ( convert_to_maya_fps ) from ayon_core.hosts.maya.api.pipeline import containerise +from ayon_core.hosts.maya.api.plugin import get_load_color_for_family def is_sequence(files): @@ -72,11 +73,12 @@ class ArnoldStandinLoader(load.LoaderPlugin): # Set color. settings = get_project_settings(context["project"]["name"]) - color = settings['maya']['load']['colors'].get('ass') + color = get_load_color_for_family("ass", settings) if color is not None: + red, green, blue = color cmds.setAttr(root + ".useOutlinerColor", True) cmds.setAttr( - root + ".outlinerColor", color[0], color[1], color[2] + root + ".outlinerColor", red, green, blue ) with maintained_selection(): diff --git a/client/ayon_core/hosts/maya/plugins/load/load_gpucache.py b/client/ayon_core/hosts/maya/plugins/load/load_gpucache.py index 00a76d374b..cdaaeeae6a 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_gpucache.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_gpucache.py @@ -9,6 +9,7 @@ from ayon_core.pipeline import ( get_representation_path ) from ayon_core.settings import get_project_settings +from ayon_core.hosts.maya.api.plugin import get_load_color_for_family class GpuCacheLoader(load.LoaderPlugin): @@ -39,13 +40,12 @@ class GpuCacheLoader(load.LoaderPlugin): project_name = context["project"]["name"] settings = get_project_settings(project_name) - colors = settings['maya']['load']['colors'] - c = colors.get('model') - if c is not None: + color = get_load_color_for_family("model", settings) + if color is not None: + red, green, blue = color cmds.setAttr(root + ".useOutlinerColor", 1) cmds.setAttr( - root + ".outlinerColor", - (float(c[0]) / 255), (float(c[1]) / 255), (float(c[2]) / 255) + root + ".outlinerColor", red, green, blue ) # Create transform with shape diff --git a/client/ayon_core/hosts/maya/plugins/load/load_redshift_proxy.py b/client/ayon_core/hosts/maya/plugins/load/load_redshift_proxy.py index dd378602c9..8910d0fcd0 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_redshift_proxy.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_redshift_proxy.py @@ -16,6 +16,7 @@ from ayon_core.hosts.maya.api.lib import ( unique_namespace ) from ayon_core.hosts.maya.api.pipeline import containerise +from ayon_core.hosts.maya.api.plugin import get_load_color_for_family class RedshiftProxyLoader(load.LoaderPlugin): @@ -59,12 +60,13 @@ class RedshiftProxyLoader(load.LoaderPlugin): # colour the group node project_name = context["project"]["name"] settings = get_project_settings(project_name) - colors = settings['maya']['load']['colors'] - c = colors.get(family) - if c is not None: + color = get_load_color_for_family(family, settings) + if color is not None: + red, green, blue = color cmds.setAttr("{0}.useOutlinerColor".format(group_node), 1) - cmds.setAttr("{0}.outlinerColor".format(group_node), - c[0], c[1], c[2]) + cmds.setAttr( + "{0}.outlinerColor".format(group_node), red, green, blue + ) return containerise( name=name, diff --git a/client/ayon_core/hosts/maya/plugins/load/load_reference.py b/client/ayon_core/hosts/maya/plugins/load/load_reference.py index 36bd2e5969..75f42a9fe6 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_reference.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_reference.py @@ -1,4 +1,3 @@ -import os import difflib import contextlib @@ -6,7 +5,7 @@ from maya import cmds import qargparse from ayon_core.settings import get_project_settings -import ayon_core.hosts.maya.api.plugin +from ayon_core.hosts.maya.api import plugin from ayon_core.hosts.maya.api.lib import ( maintained_selection, get_container_members, @@ -87,7 +86,7 @@ def preserve_modelpanel_cameras(container, log=None): cmds.modelPanel(panel, edit=True, camera=new_camera) -class ReferenceLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader): +class ReferenceLoader(plugin.ReferenceLoader): """Reference file""" families = ["model", @@ -185,14 +184,16 @@ class ReferenceLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader): "{}.displayHandle".format(group_name), display_handle ) - colors = settings['maya']['load']['colors'] - c = colors.get(family) - if c is not None: + color = plugin.get_load_color_for_family(family, settings) + if color is not None: + red, green, blue = color cmds.setAttr("{}.useOutlinerColor".format(group_name), 1) - cmds.setAttr("{}.outlinerColor".format(group_name), - (float(c[0]) / 255), - (float(c[1]) / 255), - (float(c[2]) / 255)) + cmds.setAttr( + "{}.outlinerColor".format(group_name), + red, + green, + blue + ) cmds.setAttr( "{}.displayHandle".format(group_name), display_handle diff --git a/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_arnold.py b/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_arnold.py index 98f98330d7..c68fddc60a 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_arnold.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_arnold.py @@ -5,6 +5,7 @@ from ayon_core.pipeline import ( load, get_representation_path ) +from ayon_core.hosts.maya.api.plugin import get_load_color_for_family # TODO aiVolume doesn't automatically set velocity fps correctly, set manual? @@ -50,16 +51,11 @@ class LoadVDBtoArnold(load.LoaderPlugin): project_name = context["project"]["name"] settings = get_project_settings(project_name) - colors = settings['maya']['load']['colors'] - - c = colors.get(family) - if c is not None: + color = get_load_color_for_family(family, settings) + if color is not None: + red, green, blue = color cmds.setAttr(root + ".useOutlinerColor", 1) - cmds.setAttr(root + ".outlinerColor", - (float(c[0]) / 255), - (float(c[1]) / 255), - (float(c[2]) / 255) - ) + cmds.setAttr(root + ".outlinerColor", red, green, blue) # Create VRayVolumeGrid grid_node = cmds.createNode("aiVolume", diff --git a/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_redshift.py b/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_redshift.py index 426e85cf7c..1bc75ae4c6 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_redshift.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_redshift.py @@ -5,6 +5,7 @@ from ayon_core.pipeline import ( load, get_representation_path ) +from ayon_core.hosts.maya.api.plugin import get_load_color_for_family class LoadVDBtoRedShift(load.LoaderPlugin): @@ -69,16 +70,11 @@ class LoadVDBtoRedShift(load.LoaderPlugin): project_name = context["project"]["name"] settings = get_project_settings(project_name) - colors = settings['maya']['load']['colors'] - - c = colors.get(family) - if c is not None: + color = get_load_color_for_family(family, settings) + if color is not None: + red, green, blue = color cmds.setAttr(root + ".useOutlinerColor", 1) - cmds.setAttr(root + ".outlinerColor", - (float(c[0])/255), - (float(c[1])/255), - (float(c[2])/255) - ) + cmds.setAttr(root + ".outlinerColor", red, green, blue) # Create VR volume_node = cmds.createNode("RedshiftVolumeShape", diff --git a/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_vray.py b/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_vray.py index ca0519900b..0c87162629 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_vray.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_vray.py @@ -5,6 +5,7 @@ from ayon_core.pipeline import ( load, get_representation_path ) +from ayon_core.hosts.maya.api.plugin import get_load_color_for_family from maya import cmds @@ -129,15 +130,11 @@ class LoadVDBtoVRay(load.LoaderPlugin): project_name = context["project"]["name"] settings = get_project_settings(project_name) - colors = settings['maya']['load']['colors'] - - c = colors.get(family) - if c is not None: + color = get_load_color_for_family(family, settings) + if color is not None: + red, green, blue = color cmds.setAttr(root + ".useOutlinerColor", 1) - cmds.setAttr(root + ".outlinerColor", - float(c[0]) / 255, - float(c[1]) / 255, - float(c[2]) / 255) + cmds.setAttr(root + ".outlinerColor", red, green, blue) # Create VRayVolumeGrid grid_node = cmds.createNode("VRayVolumeGrid", diff --git a/client/ayon_core/hosts/maya/plugins/load/load_vrayproxy.py b/client/ayon_core/hosts/maya/plugins/load/load_vrayproxy.py index 9b36303b64..50b63f4f11 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_vrayproxy.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_vrayproxy.py @@ -22,6 +22,7 @@ from ayon_core.hosts.maya.api.lib import ( unique_namespace ) from ayon_core.hosts.maya.api.pipeline import containerise +from ayon_core.hosts.maya.api.plugin import get_load_color_for_family class VRayProxyLoader(load.LoaderPlugin): @@ -80,15 +81,12 @@ class VRayProxyLoader(load.LoaderPlugin): # colour the group node project_name = context["project"]["name"] settings = get_project_settings(project_name) - colors = settings['maya']['load']['colors'] - c = colors.get(family) - if c is not None: + color = get_load_color_for_family(family, settings) + if color is not None: + red, green, blue = color cmds.setAttr("{0}.useOutlinerColor".format(group_node), 1) cmds.setAttr( - "{0}.outlinerColor".format(group_node), - (float(c[0]) / 255), - (float(c[1]) / 255), - (float(c[2]) / 255) + "{0}.outlinerColor".format(group_node), red, green, blue ) return containerise( diff --git a/client/ayon_core/hosts/maya/plugins/load/load_vrayscene.py b/client/ayon_core/hosts/maya/plugins/load/load_vrayscene.py index 92d2b32549..7b4edb0567 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_vrayscene.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_vrayscene.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import os import maya.cmds as cmds # noqa from ayon_core.settings import get_project_settings from ayon_core.pipeline import ( @@ -12,6 +11,7 @@ from ayon_core.hosts.maya.api.lib import ( unique_namespace ) from ayon_core.hosts.maya.api.pipeline import containerise +from ayon_core.hosts.maya.api.plugin import get_load_color_for_family class VRaySceneLoader(load.LoaderPlugin): @@ -58,14 +58,12 @@ class VRaySceneLoader(load.LoaderPlugin): # colour the group node project_name = context["project"]["name"] settings = get_project_settings(project_name) - colors = settings['maya']['load']['colors'] - c = colors.get(family) - if c is not None: + color = get_load_color_for_family(family, settings) + if color is not None: + red, green, blue = color cmds.setAttr("{0}.useOutlinerColor".format(root_node), 1) - cmds.setAttr("{0}.outlinerColor".format(root_node), - (float(c[0])/255), - (float(c[1])/255), - (float(c[2])/255) + cmds.setAttr( + "{0}.outlinerColor".format(root_node), red, green, blue ) return containerise( diff --git a/client/ayon_core/hosts/maya/plugins/load/load_yeti_cache.py b/client/ayon_core/hosts/maya/plugins/load/load_yeti_cache.py index d2fc1c0ab0..afbb632d87 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_yeti_cache.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_yeti_cache.py @@ -13,6 +13,7 @@ from ayon_core.pipeline import ( ) from ayon_core.hosts.maya.api import lib from ayon_core.hosts.maya.api.pipeline import containerise +from ayon_core.hosts.maya.api.plugin import get_load_color_for_family # Do not reset these values on update but only apply on first load @@ -81,16 +82,11 @@ class YetiCacheLoader(load.LoaderPlugin): project_name = context["project"]["name"] settings = get_project_settings(project_name) - colors = settings['maya']['load']['colors'] - - c = colors.get(family) - if c is not None: + color = get_load_color_for_family(family, settings) + if color is not None: + red, green, blue = color cmds.setAttr(group_node + ".useOutlinerColor", 1) - cmds.setAttr(group_node + ".outlinerColor", - (float(c[0])/255), - (float(c[1])/255), - (float(c[2])/255) - ) + cmds.setAttr(group_node + ".outlinerColor", red, green, blue) nodes.append(group_node) diff --git a/client/ayon_core/hosts/maya/plugins/load/load_yeti_rig.py b/client/ayon_core/hosts/maya/plugins/load/load_yeti_rig.py index 2572e550e2..e7178be38b 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_yeti_rig.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_yeti_rig.py @@ -1,11 +1,10 @@ import maya.cmds as cmds -from ayon_core.settings import get_current_project_settings -import ayon_core.hosts.maya.api.plugin +from ayon_core.hosts.maya.api import plugin from ayon_core.hosts.maya.api import lib -class YetiRigLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader): +class YetiRigLoader(plugin.ReferenceLoader): """This loader will load Yeti rig.""" families = ["yetiRig"] @@ -41,14 +40,12 @@ class YetiRigLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader): groupName=group_name ) - settings = get_current_project_settings() - colors = settings["maya"]["load"]["colors"] - c = colors.get("yetiRig") - if c is not None: + color = plugin.get_load_color_for_family("yetiRig") + if color is not None: + red, green, blue = color cmds.setAttr(group_name + ".useOutlinerColor", 1) cmds.setAttr( - group_name + ".outlinerColor", - (float(c[0]) / 255), (float(c[1]) / 255), (float(c[2]) / 255) + group_name + ".outlinerColor", red, green, blue ) self[:] = nodes diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 1a353a5a64..5734ac0707 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -344,13 +344,6 @@ def _convert_maya_project_settings(ayon_settings, output): subitem["subset_name_filters"] = subitem.pop( "product_name_filters") - _convert_host_imageio(ayon_maya) - - ayon_maya_load = ayon_maya["load"] - load_colors = ayon_maya_load["colors"] - for key, color in tuple(load_colors.items()): - load_colors[key] = _convert_color(color) - output["maya"] = ayon_maya diff --git a/server_addon/maya/server/settings/loaders.py b/server_addon/maya/server/settings/loaders.py index 15d4275b80..df1172ae7d 100644 --- a/server_addon/maya/server/settings/loaders.py +++ b/server_addon/maya/server/settings/loaders.py @@ -1,40 +1,136 @@ from ayon_server.settings import BaseSettingsModel, SettingsField -from ayon_server.types import ColorRGBA_uint8 +from ayon_server.types import ColorRGB_float class ColorsSetting(BaseSettingsModel): - model: ColorRGBA_uint8 = SettingsField( - (209, 132, 30, 1.0), title="Model:") - rig: ColorRGBA_uint8 = SettingsField( - (59, 226, 235, 1.0), title="Rig:") - pointcache: ColorRGBA_uint8 = SettingsField( - (94, 209, 30, 1.0), title="Pointcache:") - animation: ColorRGBA_uint8 = SettingsField( - (94, 209, 30, 1.0), title="Animation:") - ass: ColorRGBA_uint8 = SettingsField( - (249, 135, 53, 1.0), title="Arnold StandIn:") - camera: ColorRGBA_uint8 = SettingsField( - (136, 114, 244, 1.0), title="Camera:") - fbx: ColorRGBA_uint8 = SettingsField( - (215, 166, 255, 1.0), title="FBX:") - mayaAscii: ColorRGBA_uint8 = SettingsField( - (67, 174, 255, 1.0), title="Maya Ascii:") - mayaScene: ColorRGBA_uint8 = SettingsField( - (67, 174, 255, 1.0), title="Maya Scene:") - setdress: ColorRGBA_uint8 = SettingsField( - (255, 250, 90, 1.0), title="Set Dress:") - layout: ColorRGBA_uint8 = SettingsField(( - 255, 250, 90, 1.0), title="Layout:") - vdbcache: ColorRGBA_uint8 = SettingsField( - (249, 54, 0, 1.0), title="VDB Cache:") - vrayproxy: ColorRGBA_uint8 = SettingsField( - (255, 150, 12, 1.0), title="VRay Proxy:") - vrayscene_layer: ColorRGBA_uint8 = SettingsField( - (255, 150, 12, 1.0), title="VRay Scene:") - yeticache: ColorRGBA_uint8 = SettingsField( - (99, 206, 220, 1.0), title="Yeti Cache:") - yetiRig: ColorRGBA_uint8 = SettingsField( - (0, 205, 125, 1.0), title="Yeti Rig:") + model: ColorRGB_float = SettingsField( + ( + 0.8196078431372549, + 0.5176470588235295, + 0.11764705882352941 + ), + title="Model:" + ) + rig: ColorRGB_float = SettingsField( + ( + 0.23137254901960785, + 0.8862745098039215, + 0.9215686274509803 + ), + title="Rig:" + ) + pointcache: ColorRGB_float = SettingsField( + ( + 0.3686274509803922, + 0.8196078431372549, + 0.11764705882352941 + ), + title="Pointcache:" + ) + animation: ColorRGB_float = SettingsField( + ( + 0.3686274509803922, + 0.8196078431372549, + 0.11764705882352941 + ), + title="Animation:" + ) + ass: ColorRGB_float = SettingsField( + ( + 0.9764705882352941, + 0.5294117647058824, + 0.20784313725490197 + ), + title="Arnold StandIn:" + ) + camera: ColorRGB_float = SettingsField( + ( + 0.5333333333333333, + 0.4470588235294118, + 0.9568627450980393 + ), + title="Camera:" + ) + fbx: ColorRGB_float = SettingsField( + ( + 0.8431372549019608, + 0.6509803921568628, + 1.0 + ), + title="FBX:" + ) + mayaAscii: ColorRGB_float = SettingsField( + ( + 0.2627450980392157, + 0.6823529411764706, + 1.0 + ), + title="Maya Ascii:" + ) + mayaScene: ColorRGB_float = SettingsField( + ( + 0.2627450980392157, + 0.6823529411764706, + 1.0 + ), + title="Maya Scene:" + ) + setdress: ColorRGB_float = SettingsField( + ( + 1.0, + 0.9803921568627451, + 0.35294117647058826 + ), + title="Set Dress:" + ) + layout: ColorRGB_float = SettingsField( + ( + 1.0, + 0.9803921568627451, + 0.35294117647058826 + ), + title="Layout:" + ) + vdbcache: ColorRGB_float = SettingsField( + ( + 0.9764705882352941, + 0.21176470588235294, + 0.0 + ), + title="VDB Cache:" + ) + vrayproxy: ColorRGB_float = SettingsField( + ( + 1.0, + 0.5882352941176471, + 0.047058823529411764 + ), + title="VRay Proxy:" + ) + vrayscene_layer: ColorRGB_float = SettingsField( + ( + 1.0, + 0.5882352941176471, + 0.047058823529411764 + ), + title="VRay Scene:" + ) + yeticache: ColorRGB_float = SettingsField( + ( + 0.38823529411764707, + 0.807843137254902, + 0.8627450980392157 + ), + title="Yeti Cache:" + ) + yetiRig: ColorRGB_float = SettingsField( + ( + 0.0, + 0.803921568627451, + 0.49019607843137253 + ), + title="Yeti Rig:" + ) class ReferenceLoaderModel(BaseSettingsModel): @@ -68,52 +164,84 @@ class LoadersModel(BaseSettingsModel): DEFAULT_LOADERS_SETTING = { "colors": { "model": [ - 209, 132, 30, 1.0 + 0.8196078431372549, + 0.5176470588235295, + 0.11764705882352941 ], "rig": [ - 59, 226, 235, 1.0 + 0.23137254901960785, + 0.8862745098039215, + 0.9215686274509803 ], "pointcache": [ - 94, 209, 30, 1.0 + 0.3686274509803922, + 0.8196078431372549, + 0.11764705882352941 ], "animation": [ - 94, 209, 30, 1.0 + 0.3686274509803922, + 0.8196078431372549, + 0.11764705882352941 ], "ass": [ - 249, 135, 53, 1.0 + 0.9764705882352941, + 0.5294117647058824, + 0.20784313725490197 ], "camera": [ - 136, 114, 244, 1.0 + 0.5333333333333333, + 0.4470588235294118, + 0.9568627450980393 ], "fbx": [ - 215, 166, 255, 1.0 + 0.8431372549019608, + 0.6509803921568628, + 1.0 ], "mayaAscii": [ - 67, 174, 255, 1.0 + 0.2627450980392157, + 0.6823529411764706, + 1.0 ], "mayaScene": [ - 67, 174, 255, 1.0 + 0.2627450980392157, + 0.6823529411764706, + 1.0 ], "setdress": [ - 255, 250, 90, 1.0 + 1.0, + 0.9803921568627451, + 0.35294117647058826 ], "layout": [ - 255, 250, 90, 1.0 + 1.0, + 0.9803921568627451, + 0.35294117647058826 ], "vdbcache": [ - 249, 54, 0, 1.0 + 0.9764705882352941, + 0.21176470588235294, + 0.0 ], "vrayproxy": [ - 255, 150, 12, 1.0 + 1.0, + 0.5882352941176471, + 0.047058823529411764 ], "vrayscene_layer": [ - 255, 150, 12, 1.0 + 1.0, + 0.5882352941176471, + 0.047058823529411764 ], "yeticache": [ - 99, 206, 220, 1.0 + 0.38823529411764707, + 0.807843137254902, + 0.8627450980392157 ], "yetiRig": [ - 0, 205, 125, 1.0 + 0.0, + 0.803921568627451, + 0.49019607843137253 ] }, "reference_loader": { From c3a8c2ac7f1f7869ef8c7ec09988e571c2a399e4 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 16:55:54 +0100 Subject: [PATCH 064/112] build workfile works with new keys --- client/ayon_core/pipeline/workfile/build_workfile.py | 10 +++++----- client/ayon_core/settings/ayon_settings.py | 11 +---------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/client/ayon_core/pipeline/workfile/build_workfile.py b/client/ayon_core/pipeline/workfile/build_workfile.py index c62facaaa9..8df3830d6e 100644 --- a/client/ayon_core/pipeline/workfile/build_workfile.py +++ b/client/ayon_core/pipeline/workfile/build_workfile.py @@ -321,7 +321,7 @@ class BuildWorkfile: continue # Check families - profile_families = profile.get("families") + profile_families = profile.get("product_types") if not profile_families: self.log.warning(( "Build profile is missing families configuration: {0}" @@ -338,7 +338,7 @@ class BuildWorkfile: continue # Prepare lowered families and representation names - profile["families_lowered"] = [ + profile["product_types_lowered"] = [ fam.lower() for fam in profile_families ] profile["repre_names_lowered"] = [ @@ -375,11 +375,11 @@ class BuildWorkfile: family_low = family.lower() for profile in profiles: # Skip profile if does not contain family - if family_low not in profile["families_lowered"]: + if family_low not in profile["product_types_lowered"]: continue # Precompile name filters as regexes - profile_regexes = profile.get("subset_name_filters") + profile_regexes = profile.get("product_name_filters") if profile_regexes: _profile_regexes = [] for regex in profile_regexes: @@ -538,7 +538,7 @@ class BuildWorkfile: build_presets += self.build_presets.get("linked_assets", []) subset_ids_ordered = [] for preset in build_presets: - for preset_family in preset["families"]: + for preset_family in preset["product_types"]: for id, subset in subsets_by_id.items(): if preset_family not in subset["data"].get("families", []): continue diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 5734ac0707..40d4c775be 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -333,16 +333,7 @@ def _convert_maya_project_settings(ayon_settings, output): ayon_maya = ayon_settings["maya"] - # Workfile build - ayon_workfile_build = ayon_maya["workfile_build"] - for item in ayon_workfile_build["profiles"]: - for key in ("current_context", "linked_assets"): - for subitem in item[key]: - if "families" in subitem: - break - subitem["families"] = subitem.pop("product_types") - subitem["subset_name_filters"] = subitem.pop( - "product_name_filters") + _convert_host_imageio(ayon_maya) output["maya"] = ayon_maya From 85526b41ad8f3dccca1a98fc000367c63e3084fa Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 17:05:14 +0100 Subject: [PATCH 065/112] flame 'ExtractProductResources' uses AYON settings --- .../publish/extract_subset_resources.py | 19 ++++++++++++------- client/ayon_core/settings/ayon_settings.py | 19 ------------------- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/client/ayon_core/hosts/flame/plugins/publish/extract_subset_resources.py b/client/ayon_core/hosts/flame/plugins/publish/extract_subset_resources.py index af699fd03a..9e55dbce96 100644 --- a/client/ayon_core/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/client/ayon_core/hosts/flame/plugins/publish/extract_subset_resources.py @@ -1,6 +1,5 @@ import os import re -import tempfile from copy import deepcopy import pyblish.api @@ -15,12 +14,12 @@ from ayon_core.pipeline.editorial import ( import flame -class ExtractSubsetResources(publish.Extractor): +class ExtractProductResources(publish.Extractor): """ Extractor for transcoding files from Flame clip """ - label = "Extract subset resources" + label = "Extract product resources" order = pyblish.api.ExtractorOrder families = ["clip"] hosts = ["flame"] @@ -47,7 +46,7 @@ class ExtractSubsetResources(publish.Extractor): hide_ui_on_process = True # settings - export_presets_mapping = {} + export_presets_mapping = [] def process(self, instance): if not self.keep_original_representation: @@ -146,15 +145,21 @@ class ExtractSubsetResources(publish.Extractor): # append staging dir for later cleanup instance.context.data["cleanupFullPaths"].append(staging_dir) + export_presets_mapping = {} + for preset_mapping in deepcopy(self.export_presets_mapping): + name = preset_mapping.pop("name") + export_presets_mapping[name] = preset_mapping + # add default preset type for thumbnail and reviewable video # update them with settings and override in case the same # are found in there - _preset_keys = [k.split('_')[0] for k in self.export_presets_mapping] + _preset_keys = [k.split('_')[0] for k in export_presets_mapping] export_presets = { - k: v for k, v in deepcopy(self.default_presets).items() + k: v + for k, v in deepcopy(self.default_presets).items() if k not in _preset_keys } - export_presets.update(self.export_presets_mapping) + export_presets.update(export_presets_mapping) if not instance.data.get("versionData"): instance.data["versionData"] = {} diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 40d4c775be..7de6011916 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -268,25 +268,6 @@ def _convert_flame_project_settings(ayon_settings, output): ayon_flame = ayon_settings["flame"] ayon_publish_flame = ayon_flame["publish"] - # Plugin 'ExtractSubsetResources' renamed to 'ExtractProductResources' - if "ExtractSubsetResources" in ayon_publish_flame: - ayon_product_resources = ayon_publish_flame["ExtractSubsetResources"] - else: - ayon_product_resources = ( - ayon_publish_flame.pop("ExtractProductResources")) - ayon_publish_flame["ExtractSubsetResources"] = ayon_product_resources - - # 'ExtractSubsetResources' changed model of 'export_presets_mapping' - # - some keys were moved under 'other_parameters' - new_subset_resources = {} - for item in ayon_product_resources.pop("export_presets_mapping"): - name = item.pop("name") - if "other_parameters" in item: - other_parameters = item.pop("other_parameters") - item.update(other_parameters) - new_subset_resources[name] = item - - ayon_product_resources["export_presets_mapping"] = new_subset_resources # 'imageio' changed model # - missing subkey 'project' which is in root of 'imageio' model From ab3b62b842092c2066430f1a97b20aeb7b73b4e9 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 9 Feb 2024 17:09:42 +0100 Subject: [PATCH 066/112] OP-8165 - fix AE local render doesnt push thumbnail to Ftrack Without thumbnail review is not clickable from main Versions list. Clone of PR to legacy OP. --- openpype/plugins/publish/extract_thumbnail.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/plugins/publish/extract_thumbnail.py b/openpype/plugins/publish/extract_thumbnail.py index 10eb261482..291345abb1 100644 --- a/openpype/plugins/publish/extract_thumbnail.py +++ b/openpype/plugins/publish/extract_thumbnail.py @@ -35,6 +35,7 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): "traypublisher", "substancepainter", "nuke", + "aftereffects" ] enabled = False From f19d8762df971ac9802c163d2e29d379bbadcf6d Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 17:10:47 +0100 Subject: [PATCH 067/112] flame Loaders can use AYON settings --- .../flame/plugins/load/load_clip_batch.py | 19 ++++++++++--- client/ayon_core/settings/ayon_settings.py | 27 ------------------- 2 files changed, 15 insertions(+), 31 deletions(-) diff --git a/client/ayon_core/hosts/flame/plugins/load/load_clip_batch.py b/client/ayon_core/hosts/flame/plugins/load/load_clip_batch.py index a66bf53622..57797e5a44 100644 --- a/client/ayon_core/hosts/flame/plugins/load/load_clip_batch.py +++ b/client/ayon_core/hosts/flame/plugins/load/load_clip_batch.py @@ -50,17 +50,28 @@ class LoadClipBatch(opfapi.ClipLoader): version_name = version.get("name", None) colorspace = self.get_colorspace(context) + # TODO remove '{folder[name]}' and '{product[name]}' replacement + clip_name_template = ( + self.clip_name_template + .replace("{folder[name]}", "{asset}") + .replace("{product[name]}", "{subset}") + ) + layer_rename_template = ( + self.layer_rename_template + .replace("{folder[name]}", "{asset}") + .replace("{product[name]}", "{subset}") + ) # in case output is not in context replace key to representation if not context["representation"]["context"].get("output"): - self.clip_name_template = self.clip_name_template.replace( + clip_name_template = clip_name_template.replace( "output", "representation") - self.layer_rename_template = self.layer_rename_template.replace( + layer_rename_template = layer_rename_template.replace( "output", "representation") formatting_data = deepcopy(context["representation"]["context"]) formatting_data["batch"] = self.batch.name.get_value() - clip_name = StringTemplate(self.clip_name_template).format( + clip_name = StringTemplate(clip_name_template).format( formatting_data) # convert colorspace with ocio to flame mapping @@ -86,7 +97,7 @@ class LoadClipBatch(opfapi.ClipLoader): "path": path.replace("\\", "/"), "colorspace": colorspace, "version": "v{:0>3}".format(version_name), - "layer_rename_template": self.layer_rename_template, + "layer_rename_template": layer_rename_template, "layer_rename_patterns": self.layer_rename_patterns, "context_data": formatting_data } diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 7de6011916..39e30d4846 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -267,34 +267,7 @@ def _convert_flame_project_settings(ayon_settings, output): ayon_flame = ayon_settings["flame"] - ayon_publish_flame = ayon_flame["publish"] - - # 'imageio' changed model - # - missing subkey 'project' which is in root of 'imageio' model _convert_host_imageio(ayon_flame) - ayon_imageio_flame = ayon_flame["imageio"] - if "project" not in ayon_imageio_flame: - profile_mapping = ayon_imageio_flame.pop("profilesMapping") - ayon_flame["imageio"] = { - "project": ayon_imageio_flame, - "profilesMapping": profile_mapping - } - - ayon_load_flame = ayon_flame["load"] - for plugin_name in ("LoadClip", "LoadClipBatch"): - plugin_settings = ayon_load_flame[plugin_name] - plugin_settings["families"] = plugin_settings.pop("product_types") - plugin_settings["clip_name_template"] = ( - plugin_settings["clip_name_template"] - .replace("{folder[name]}", "{asset}") - .replace("{product[name]}", "{subset}") - ) - plugin_settings["layer_rename_template"] = ( - plugin_settings["layer_rename_template"] - .replace("{folder[name]}", "{asset}") - .replace("{product[name]}", "{subset}") - ) - output["flame"] = ayon_flame From b0dd56326135d4c16214cb347d576bd821a0a84d Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 17:13:52 +0100 Subject: [PATCH 068/112] max PointCloud uses AYON settings --- .../hosts/max/plugins/publish/extract_pointcloud.py | 4 +++- .../hosts/max/plugins/publish/validate_pointcloud.py | 4 +++- client/ayon_core/settings/ayon_settings.py | 7 ------- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/extract_pointcloud.py b/client/ayon_core/hosts/max/plugins/publish/extract_pointcloud.py index 294d63794e..67dde7f0a6 100644 --- a/client/ayon_core/hosts/max/plugins/publish/extract_pointcloud.py +++ b/client/ayon_core/hosts/max/plugins/publish/extract_pointcloud.py @@ -155,7 +155,9 @@ class ExtractPointCloud(publish.Extractor): custom_attr_list = [] attr_settings = self.settings["attribute"] - for key, value in attr_settings.items(): + for attr in attr_settings: + key = attr["name"] + value = attr["value"] custom_attr = "{0}.PRTChannels_{1}=True".format(operator, value) self.log.debug( diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_pointcloud.py b/client/ayon_core/hosts/max/plugins/publish/validate_pointcloud.py index a025ed3992..73b18984ed 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_pointcloud.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_pointcloud.py @@ -59,7 +59,9 @@ class ValidatePointCloud(pyblish.api.InstancePlugin): event_name = sub_anim.name opt = "${0}.{1}.export_particles".format(sel.name, event_name) - for key, value in attr_settings.items(): + for attr in attr_settings: + key = attr["name"] + value = attr["value"] custom_attr = "{0}.PRTChannels_{1}".format(opt, value) try: diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 39e30d4846..5a1fbfb947 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -298,13 +298,6 @@ def _convert_3dsmax_project_settings(ayon_settings, output): ayon_max = ayon_settings["max"] _convert_host_imageio(ayon_max) - if "PointCloud" in ayon_max: - point_cloud_attribute = ayon_max["PointCloud"]["attribute"] - new_point_cloud_attribute = { - item["name"]: item["value"] - for item in point_cloud_attribute - } - ayon_max["PointCloud"]["attribute"] = new_point_cloud_attribute # --- Publish (START) --- ayon_publish = ayon_max["publish"] if "ValidateAttributes" in ayon_publish: From 96cbbeb823809ae68071a883f19b877d0cd7452e Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 17:15:51 +0100 Subject: [PATCH 069/112] max 'ValidateAttributes' can use AYON settings --- .../plugins/publish/validate_attributes.py | 22 ++++++++++++++----- client/ayon_core/settings/ayon_settings.py | 8 ------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_attributes.py b/client/ayon_core/hosts/max/plugins/publish/validate_attributes.py index 444a8f0829..354539871f 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_attributes.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_attributes.py @@ -1,5 +1,7 @@ # -*- coding: utf-8 -*- """Validator for Attributes.""" +import json + from pyblish.api import ContextPlugin, ValidatorOrder from pymxs import runtime as rt @@ -61,9 +63,13 @@ class ValidateAttributes(OptionalPyblishPluginMixin, @classmethod def get_invalid(cls, context): - attributes = ( - context.data["project_settings"]["max"]["publish"] - ["ValidateAttributes"]["attributes"] + attributes = json.loads( + context.data + ["project_settings"] + ["max"] + ["publish"] + ["ValidateAttributes"] + ["attributes"] ) if not attributes: return @@ -112,9 +118,13 @@ class ValidateAttributes(OptionalPyblishPluginMixin, @classmethod def repair(cls, context): - attributes = ( - context.data["project_settings"]["max"]["publish"] - ["ValidateAttributes"]["attributes"] + attributes = json.loads( + context.data + ["project_settings"] + ["max"] + ["publish"] + ["ValidateAttributes"] + ["attributes"] ) invalid_attributes = cls.get_invalid(context) for attrs in invalid_attributes: diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 5a1fbfb947..4d79e922b3 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -300,14 +300,6 @@ def _convert_3dsmax_project_settings(ayon_settings, output): _convert_host_imageio(ayon_max) # --- Publish (START) --- ayon_publish = ayon_max["publish"] - if "ValidateAttributes" in ayon_publish: - try: - attributes = json.loads( - ayon_publish["ValidateAttributes"]["attributes"] - ) - except ValueError: - attributes = {} - ayon_publish["ValidateAttributes"]["attributes"] = attributes if "ValidateLoadedPlugin" in ayon_publish: loaded_plugin = ( From d8c8f7f0ec9687afa782eb3fa225e50186a85fc0 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 17:23:10 +0100 Subject: [PATCH 070/112] max 'ValidateLoadedPlugin' can use AYON settings --- .../max/plugins/publish/validate_loaded_plugin.py | 12 ++++++++++-- client/ayon_core/settings/ayon_settings.py | 10 ---------- server_addon/max/server/settings/publishers.py | 4 ++-- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_loaded_plugin.py b/client/ayon_core/hosts/max/plugins/publish/validate_loaded_plugin.py index fe6e32b27b..bf5ac26fef 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_loaded_plugin.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_loaded_plugin.py @@ -25,7 +25,7 @@ class ValidateLoadedPlugin(OptionalPyblishPluginMixin, optional = True actions = [RepairAction] - family_plugins_mapping = {} + family_plugins_mapping = [] @classmethod def get_invalid(cls, instance): @@ -34,6 +34,12 @@ class ValidateLoadedPlugin(OptionalPyblishPluginMixin, if not family_plugins_mapping: return + # Backward compatibility - settings did have 'product_types' + if "product_types" in family_plugins_mapping: + family_plugins_mapping["families"] = family_plugins_mapping.pop( + "product_types" + ) + invalid = [] # Find all plug-in requirements for current instance instance_families = {instance.data["family"]} @@ -47,7 +53,9 @@ class ValidateLoadedPlugin(OptionalPyblishPluginMixin, if not mapping: return - match_families = {fam.strip() for fam in mapping["families"]} + match_families = { + fam.strip() for fam in mapping["families"] + } has_match = "*" in match_families or match_families.intersection( instance_families) diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 4d79e922b3..02442645bb 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -297,16 +297,6 @@ def _convert_3dsmax_project_settings(ayon_settings, output): return ayon_max = ayon_settings["max"] - _convert_host_imageio(ayon_max) - # --- Publish (START) --- - ayon_publish = ayon_max["publish"] - - if "ValidateLoadedPlugin" in ayon_publish: - loaded_plugin = ( - ayon_publish["ValidateLoadedPlugin"]["family_plugins_mapping"] - ) - for item in loaded_plugin: - item["families"] = item.pop("product_types") output["max"] = ayon_max diff --git a/server_addon/max/server/settings/publishers.py b/server_addon/max/server/settings/publishers.py index da782cb494..e8a48ec3d1 100644 --- a/server_addon/max/server/settings/publishers.py +++ b/server_addon/max/server/settings/publishers.py @@ -28,9 +28,9 @@ class ValidateAttributesModel(BaseSettingsModel): class FamilyMappingItemModel(BaseSettingsModel): - product_types: list[str] = SettingsField( + families: list[str] = SettingsField( default_factory=list, - title="Product Types" + title="Families" ) plugins: list[str] = SettingsField( default_factory=list, From 7e2331467df72d8c8a1a72ffdfba8c940cbcfad1 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 17:35:22 +0100 Subject: [PATCH 071/112] simplify general settings conversion --- client/ayon_core/pipeline/template_data.py | 7 ++-- client/ayon_core/settings/__init__.py | 2 -- client/ayon_core/settings/ayon_settings.py | 40 ++++------------------ client/ayon_core/settings/lib.py | 12 +++---- 4 files changed, 14 insertions(+), 47 deletions(-) diff --git a/client/ayon_core/pipeline/template_data.py b/client/ayon_core/pipeline/template_data.py index a1b944a431..a5ca84c754 100644 --- a/client/ayon_core/pipeline/template_data.py +++ b/client/ayon_core/pipeline/template_data.py @@ -17,12 +17,11 @@ def get_general_template_data(system_settings=None): if not system_settings: system_settings = get_system_settings() - studio_name = system_settings["general"]["studio_name"] - studio_code = system_settings["general"]["studio_code"] + core_settings = system_settings["core"] return { "studio": { - "name": studio_name, - "code": studio_code + "name": core_settings["studio_name"], + "code": core_settings["studio_code"] }, "user": get_ayon_username() } diff --git a/client/ayon_core/settings/__init__.py b/client/ayon_core/settings/__init__.py index 51019ca570..ed3aaef7d4 100644 --- a/client/ayon_core/settings/__init__.py +++ b/client/ayon_core/settings/__init__.py @@ -4,7 +4,6 @@ from .constants import ( ) from .lib import ( get_general_environments, - get_global_settings, get_system_settings, get_project_settings, get_current_project_settings, @@ -17,7 +16,6 @@ __all__ = ( "PROJECT_SETTINGS_KEY", "get_general_environments", - "get_global_settings", "get_system_settings", "get_project_settings", "get_current_project_settings", diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 02442645bb..1aa82995b6 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -73,31 +73,13 @@ def _convert_host_imageio(host_settings): def _convert_general(ayon_settings, output, default_settings): - # TODO get studio name/code - core_settings = ayon_settings["core"] - environments = core_settings["environments"] - if isinstance(environments, six.string_types): - environments = json.loads(environments) - - general = default_settings["general"] - general.update({ - "log_to_server": False, - "studio_name": core_settings["studio_name"], - "studio_code": core_settings["studio_code"], - "environment": environments - }) - output["general"] = general - - -def _convert_kitsu_system_settings( - ayon_settings, output, addon_versions, default_settings -): - enabled = addon_versions.get("kitsu") is not None - kitsu_settings = default_settings["modules"]["kitsu"] - kitsu_settings["enabled"] = enabled - if enabled: - kitsu_settings["server"] = ayon_settings["kitsu"]["server"] - output["modules"]["kitsu"] = kitsu_settings + output["core"] = ayon_settings["core"] + version_check_interval = ( + default_settings["general"]["version_check_interval"] + ) + output["general"] = { + "version_check_interval": version_check_interval + } def _convert_timers_manager_system_settings( @@ -701,14 +683,6 @@ def _convert_global_project_settings(ayon_settings, output, default_settings): ayon_core = ayon_settings["core"] _convert_host_imageio(ayon_core) - - for key in ( - "environments", - "studio_name", - "studio_code", - ): - ayon_core.pop(key, None) - # Publish conversion ayon_publish = ayon_core["publish"] diff --git a/client/ayon_core/settings/lib.py b/client/ayon_core/settings/lib.py index beae376b7c..ee453956d2 100644 --- a/client/ayon_core/settings/lib.py +++ b/client/ayon_core/settings/lib.py @@ -15,7 +15,8 @@ from .constants import ( from .ayon_settings import ( get_ayon_project_settings, - get_ayon_system_settings + get_ayon_system_settings, + get_ayon_settings, ) log = logging.getLogger(__name__) @@ -253,14 +254,9 @@ def get_current_project_settings(): return get_project_settings(project_name) -def get_global_settings(): - default_settings = load_openpype_default_settings() - return default_settings["system_settings"]["general"] - - def get_general_environments(): - value = get_system_settings() - return value["general"]["environment"] + settings = get_ayon_settings() + return json.loads(settings["core"]["environments"]) def get_system_settings(*args, **kwargs): From b0d7e1601165e74cbf7ff50c4a49d5cf729be1c4 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 17:40:13 +0100 Subject: [PATCH 072/112] bump addon versions --- server_addon/max/server/version.py | 2 +- server_addon/maya/server/version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server_addon/max/server/version.py b/server_addon/max/server/version.py index bbab0242f6..1276d0254f 100644 --- a/server_addon/max/server/version.py +++ b/server_addon/max/server/version.py @@ -1 +1 @@ -__version__ = "0.1.4" +__version__ = "0.1.5" diff --git a/server_addon/maya/server/version.py b/server_addon/maya/server/version.py index 684d830189..8202425a2d 100644 --- a/server_addon/maya/server/version.py +++ b/server_addon/maya/server/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring addon version.""" -__version__ = "0.1.8" +__version__ = "0.1.9" From bae63d5e015df8d09f59354899accd58d35d6512 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 17:49:54 +0100 Subject: [PATCH 073/112] fix houdini lib --- client/ayon_core/hosts/houdini/api/lib.py | 1 + 1 file changed, 1 insertion(+) diff --git a/client/ayon_core/hosts/houdini/api/lib.py b/client/ayon_core/hosts/houdini/api/lib.py index 7163aebdec..bf66890285 100644 --- a/client/ayon_core/hosts/houdini/api/lib.py +++ b/client/ayon_core/hosts/houdini/api/lib.py @@ -6,6 +6,7 @@ import re import uuid import logging import json +from contextlib import contextmanager import six From cafbff361bfa4de76fe345d9b7e1839d2d2e13ed Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 17:51:15 +0100 Subject: [PATCH 074/112] use 'SetCurrentProcessExplicitAppUserModelID' only when running from code --- client/ayon_core/tools/traypublisher/window.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/tools/traypublisher/window.py b/client/ayon_core/tools/traypublisher/window.py index dad314e510..4335b9e92b 100644 --- a/client/ayon_core/tools/traypublisher/window.py +++ b/client/ayon_core/tools/traypublisher/window.py @@ -12,7 +12,7 @@ from qtpy import QtWidgets, QtCore import qtawesome import appdirs -from ayon_core.lib import JSONSettingRegistry +from ayon_core.lib import JSONSettingRegistry, is_running_from_build from ayon_core.pipeline import install_host from ayon_core.hosts.traypublisher.api import TrayPublisherHost from ayon_core.tools.publisher.control_qt import QtPublisherController @@ -265,7 +265,7 @@ def main(): app_instance = get_ayon_qt_app() - if platform.system().lower() == "windows": + if not is_running_from_build() and platform.system().lower() == "windows": import ctypes ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID( u"traypublisher" From 7f462c73246bf1390f83c5abc315fda78b200165 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 17:55:01 +0100 Subject: [PATCH 075/112] Use AYON in docstrings and labels --- client/ayon_core/hosts/resolve/startup.py | 6 +++--- client/ayon_core/lib/local_settings.py | 4 ++-- client/ayon_core/modules/job_queue/module.py | 4 ++-- client/ayon_core/modules/timers_manager/widget_user_idle.py | 2 +- client/ayon_core/modules/webserver/webserver_module.py | 2 +- client/ayon_core/style/__init__.py | 4 ++-- client/ayon_core/tools/traypublisher/window.py | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/client/ayon_core/hosts/resolve/startup.py b/client/ayon_core/hosts/resolve/startup.py index 174a2878c5..b3c1a024d9 100644 --- a/client/ayon_core/hosts/resolve/startup.py +++ b/client/ayon_core/hosts/resolve/startup.py @@ -33,7 +33,7 @@ def ensure_installed_host(): def launch_menu(): - print("Launching Resolve OpenPype menu..") + print("Launching Resolve AYON menu..") ensure_installed_host() ayon_core.hosts.resolve.api.launch_pype_menu() @@ -54,7 +54,7 @@ def main(): else: log.info("No last workfile set to open. Skipping..") - # Launch OpenPype menu + # Launch AYON menu from ayon_core.settings import get_project_settings from ayon_core.pipeline.context_tools import get_current_project_name project_name = get_current_project_name() @@ -62,7 +62,7 @@ def main(): settings = get_project_settings(project_name) if settings.get("resolve", {}).get("launch_openpype_menu_on_start", True): - log.info("Launching OpenPype menu..") + log.info("Launching AYON menu..") launch_menu() diff --git a/client/ayon_core/lib/local_settings.py b/client/ayon_core/lib/local_settings.py index 33b3232128..022f63a618 100644 --- a/client/ayon_core/lib/local_settings.py +++ b/client/ayon_core/lib/local_settings.py @@ -38,8 +38,8 @@ class AYONSecureRegistry: Registry should be used for private data that should be available only for user. - All passed registry names will have added prefix `OpenPype/` to easier - identify which data were created by OpenPype. + All passed registry names will have added prefix `AYON/` to easier + identify which data were created by AYON. Args: name(str): Name of registry used as identifier for data. diff --git a/client/ayon_core/modules/job_queue/module.py b/client/ayon_core/modules/job_queue/module.py index 1cecd62de5..f2b022069b 100644 --- a/client/ayon_core/modules/job_queue/module.py +++ b/client/ayon_core/modules/job_queue/module.py @@ -1,4 +1,4 @@ -"""Job queue OpenPype module was created for remote execution of commands. +"""Job queue AYON addon was created for remote execution of commands. ## Why is needed Primarily created for hosts which are not easilly controlled from command line @@ -30,7 +30,7 @@ workstations know where to send or receive jobs. ### start_worker - start worker which will process jobs -- has required possitional argument which is application name from OpenPype +- has required possitional argument which is application name from AYON settings e.g. 'tvpaint/11-5' ('tvpaint' is group '11-5' is variant) - it is possible to specify server url but url from settings is used when not passed (this is added mainly for developing purposes) diff --git a/client/ayon_core/modules/timers_manager/widget_user_idle.py b/client/ayon_core/modules/timers_manager/widget_user_idle.py index 94d7a606ed..c59ab15b38 100644 --- a/client/ayon_core/modules/timers_manager/widget_user_idle.py +++ b/client/ayon_core/modules/timers_manager/widget_user_idle.py @@ -9,7 +9,7 @@ class WidgetUserIdle(QtWidgets.QWidget): def __init__(self, module): super(WidgetUserIdle, self).__init__() - self.setWindowTitle("OpenPype - Stop timers") + self.setWindowTitle("AYON - Stop timers") icon = QtGui.QIcon(resources.get_ayon_icon_filepath()) self.setWindowIcon(icon) diff --git a/client/ayon_core/modules/webserver/webserver_module.py b/client/ayon_core/modules/webserver/webserver_module.py index ec143d0866..c324e0dd18 100644 --- a/client/ayon_core/modules/webserver/webserver_module.py +++ b/client/ayon_core/modules/webserver/webserver_module.py @@ -1,6 +1,6 @@ """WebServerAddon spawns aiohttp server in asyncio loop. -Main usage of the module is in OpenPype tray where make sense to add ability +Main usage of the module is in AYON tray where make sense to add ability of other modules to add theirs routes. Module which would want use that option must have implemented method `webserver_initialization` which must expect `WebServerManager` object where is possible to add routes or paths diff --git a/client/ayon_core/style/__init__.py b/client/ayon_core/style/__init__.py index 8b2dfa1bcb..8d3089ef86 100644 --- a/client/ayon_core/style/__init__.py +++ b/client/ayon_core/style/__init__.py @@ -198,7 +198,7 @@ def _load_font(): def load_stylesheet(): - """Load and return OpenPype Qt stylesheet.""" + """Load and return AYON Qt stylesheet.""" if _Cache.stylesheet is None: _Cache.stylesheet = _load_stylesheet() @@ -207,7 +207,7 @@ def load_stylesheet(): def get_app_icon_path(): - """Path to OpenPype icon.""" + """Path to AYON icon.""" return resources.get_ayon_icon_filepath() diff --git a/client/ayon_core/tools/traypublisher/window.py b/client/ayon_core/tools/traypublisher/window.py index 4335b9e92b..79386d7ea0 100644 --- a/client/ayon_core/tools/traypublisher/window.py +++ b/client/ayon_core/tools/traypublisher/window.py @@ -35,7 +35,7 @@ class TrayPublisherController(QtPublisherController): class TrayPublisherRegistry(JSONSettingRegistry): - """Class handling OpenPype general settings registry. + """Class handling AYON general settings registry. Attributes: vendor (str): Name used for path construction. From 01ac49c8b315e8013ddaf649686751797e5e67ad Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 17:55:21 +0100 Subject: [PATCH 076/112] fix docstring argument name --- client/ayon_core/pipeline/farm/patterning.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/pipeline/farm/patterning.py b/client/ayon_core/pipeline/farm/patterning.py index 1e4b5bf37d..d7b046113b 100644 --- a/client/ayon_core/pipeline/farm/patterning.py +++ b/client/ayon_core/pipeline/farm/patterning.py @@ -11,7 +11,7 @@ def match_aov_pattern(host_name, aov_patterns, render_file_name): that we have grabbed from `exp_files`. Args: - app (str): Host name. + host_name (str): Host name. aov_patterns (dict): AOV patterns from AOV filters. render_file_name (str): Incoming file name to match against. From 3365919d966b7ddfd687d12e53153e9d3a9205fd Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 18:31:54 +0100 Subject: [PATCH 077/112] host addons inherit from AYONAddon --- client/ayon_core/hosts/aftereffects/addon.py | 7 ++----- client/ayon_core/hosts/blender/addon.py | 7 ++----- client/ayon_core/hosts/celaction/addon.py | 7 ++----- client/ayon_core/hosts/flame/addon.py | 7 ++----- client/ayon_core/hosts/fusion/addon.py | 7 ++----- client/ayon_core/hosts/harmony/addon.py | 7 ++----- client/ayon_core/hosts/hiero/addon.py | 7 ++----- client/ayon_core/hosts/houdini/addon.py | 7 ++----- client/ayon_core/hosts/max/addon.py | 7 ++----- client/ayon_core/hosts/maya/addon.py | 7 ++----- client/ayon_core/hosts/nuke/addon.py | 7 ++----- client/ayon_core/hosts/photoshop/addon.py | 7 ++----- client/ayon_core/hosts/resolve/addon.py | 7 ++----- client/ayon_core/hosts/substancepainter/addon.py | 7 ++----- client/ayon_core/hosts/traypublisher/addon.py | 11 +++++------ client/ayon_core/hosts/tvpaint/addon.py | 7 ++----- client/ayon_core/hosts/unreal/addon.py | 7 ++----- 17 files changed, 37 insertions(+), 86 deletions(-) diff --git a/client/ayon_core/hosts/aftereffects/addon.py b/client/ayon_core/hosts/aftereffects/addon.py index 278f836a72..46d0818247 100644 --- a/client/ayon_core/hosts/aftereffects/addon.py +++ b/client/ayon_core/hosts/aftereffects/addon.py @@ -1,13 +1,10 @@ -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon -class AfterEffectsAddon(OpenPypeModule, IHostAddon): +class AfterEffectsAddon(AYONAddon, IHostAddon): name = "aftereffects" host_name = "aftereffects" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): """Modify environments to contain all required for implementation.""" defaults = { diff --git a/client/ayon_core/hosts/blender/addon.py b/client/ayon_core/hosts/blender/addon.py index c3804382e5..b7484de243 100644 --- a/client/ayon_core/hosts/blender/addon.py +++ b/client/ayon_core/hosts/blender/addon.py @@ -1,16 +1,13 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon BLENDER_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -class BlenderAddon(OpenPypeModule, IHostAddon): +class BlenderAddon(AYONAddon, IHostAddon): name = "blender" host_name = "blender" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): """Modify environments to contain all required for implementation.""" # Prepare path to implementation script diff --git a/client/ayon_core/hosts/celaction/addon.py b/client/ayon_core/hosts/celaction/addon.py index 4573ee7e56..d00401a2e0 100644 --- a/client/ayon_core/hosts/celaction/addon.py +++ b/client/ayon_core/hosts/celaction/addon.py @@ -1,16 +1,13 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon CELACTION_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -class CelactionAddon(OpenPypeModule, IHostAddon): +class CelactionAddon(AYONAddon, IHostAddon): name = "celaction" host_name = "celaction" - def initialize(self, module_settings): - self.enabled = True - def get_launch_hook_paths(self, app): if app.host_name != self.host_name: return [] diff --git a/client/ayon_core/hosts/flame/addon.py b/client/ayon_core/hosts/flame/addon.py index e30d7cab08..f5560cde7a 100644 --- a/client/ayon_core/hosts/flame/addon.py +++ b/client/ayon_core/hosts/flame/addon.py @@ -1,16 +1,13 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon HOST_DIR = os.path.dirname(os.path.abspath(__file__)) -class FlameAddon(OpenPypeModule, IHostAddon): +class FlameAddon(AYONAddon, IHostAddon): name = "flame" host_name = "flame" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): # Add requirements to DL_PYTHON_HOOK_PATH env["DL_PYTHON_HOOK_PATH"] = os.path.join(HOST_DIR, "startup") diff --git a/client/ayon_core/hosts/fusion/addon.py b/client/ayon_core/hosts/fusion/addon.py index 7eff2d93c8..391ee770c4 100644 --- a/client/ayon_core/hosts/fusion/addon.py +++ b/client/ayon_core/hosts/fusion/addon.py @@ -1,6 +1,6 @@ import os import re -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon from ayon_core.lib import Logger FUSION_HOST_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -48,13 +48,10 @@ def get_fusion_version(app_name): ) -class FusionAddon(OpenPypeModule, IHostAddon): +class FusionAddon(AYONAddon, IHostAddon): name = "fusion" host_name = "fusion" - def initialize(self, module_settings): - self.enabled = True - def get_launch_hook_paths(self, app): if app.host_name != self.host_name: return [] diff --git a/client/ayon_core/hosts/harmony/addon.py b/client/ayon_core/hosts/harmony/addon.py index 172a1f104f..476d569415 100644 --- a/client/ayon_core/hosts/harmony/addon.py +++ b/client/ayon_core/hosts/harmony/addon.py @@ -1,16 +1,13 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon HARMONY_HOST_DIR = os.path.dirname(os.path.abspath(__file__)) -class HarmonyAddon(OpenPypeModule, IHostAddon): +class HarmonyAddon(AYONAddon, IHostAddon): name = "harmony" host_name = "harmony" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): """Modify environments to contain all required for implementation.""" openharmony_path = os.path.join( diff --git a/client/ayon_core/hosts/hiero/addon.py b/client/ayon_core/hosts/hiero/addon.py index 447700e2e1..f612493ca1 100644 --- a/client/ayon_core/hosts/hiero/addon.py +++ b/client/ayon_core/hosts/hiero/addon.py @@ -1,17 +1,14 @@ import os import platform -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon HIERO_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -class HieroAddon(OpenPypeModule, IHostAddon): +class HieroAddon(AYONAddon, IHostAddon): name = "hiero" host_name = "hiero" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): # Add requirements to HIERO_PLUGIN_PATH new_hiero_paths = [ diff --git a/client/ayon_core/hosts/houdini/addon.py b/client/ayon_core/hosts/houdini/addon.py index 34d140db3c..95d714aea1 100644 --- a/client/ayon_core/hosts/houdini/addon.py +++ b/client/ayon_core/hosts/houdini/addon.py @@ -1,16 +1,13 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon HOUDINI_HOST_DIR = os.path.dirname(os.path.abspath(__file__)) -class HoudiniAddon(OpenPypeModule, IHostAddon): +class HoudiniAddon(AYONAddon, IHostAddon): name = "houdini" host_name = "houdini" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): # Add requirements to HOUDINI_PATH and HOUDINI_MENU_PATH startup_path = os.path.join(HOUDINI_HOST_DIR, "startup") diff --git a/client/ayon_core/hosts/max/addon.py b/client/ayon_core/hosts/max/addon.py index 416014025c..12f5f7eca0 100644 --- a/client/ayon_core/hosts/max/addon.py +++ b/client/ayon_core/hosts/max/addon.py @@ -1,17 +1,14 @@ # -*- coding: utf-8 -*- import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon MAX_HOST_DIR = os.path.dirname(os.path.abspath(__file__)) -class MaxAddon(OpenPypeModule, IHostAddon): +class MaxAddon(AYONAddon, IHostAddon): name = "max" host_name = "max" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): # Remove auto screen scale factor for Qt # - let 3dsmax decide it's value diff --git a/client/ayon_core/hosts/maya/addon.py b/client/ayon_core/hosts/maya/addon.py index 745850f6a8..c68aa4c911 100644 --- a/client/ayon_core/hosts/maya/addon.py +++ b/client/ayon_core/hosts/maya/addon.py @@ -1,16 +1,13 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon MAYA_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -class MayaAddon(OpenPypeModule, IHostAddon): +class MayaAddon(AYONAddon, IHostAddon): name = "maya" host_name = "maya" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): # Add requirements to PYTHONPATH new_python_paths = [ diff --git a/client/ayon_core/hosts/nuke/addon.py b/client/ayon_core/hosts/nuke/addon.py index 4ca4408271..8e640624f0 100644 --- a/client/ayon_core/hosts/nuke/addon.py +++ b/client/ayon_core/hosts/nuke/addon.py @@ -1,17 +1,14 @@ import os import platform -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon NUKE_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -class NukeAddon(OpenPypeModule, IHostAddon): +class NukeAddon(AYONAddon, IHostAddon): name = "nuke" host_name = "nuke" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): # Add requirements to NUKE_PATH new_nuke_paths = [ diff --git a/client/ayon_core/hosts/photoshop/addon.py b/client/ayon_core/hosts/photoshop/addon.py index 0c7efdb317..3016912960 100644 --- a/client/ayon_core/hosts/photoshop/addon.py +++ b/client/ayon_core/hosts/photoshop/addon.py @@ -1,16 +1,13 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon PHOTOSHOP_HOST_DIR = os.path.dirname(os.path.abspath(__file__)) -class PhotoshopAddon(OpenPypeModule, IHostAddon): +class PhotoshopAddon(AYONAddon, IHostAddon): name = "photoshop" host_name = "photoshop" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): """Modify environments to contain all required for implementation.""" defaults = { diff --git a/client/ayon_core/hosts/resolve/addon.py b/client/ayon_core/hosts/resolve/addon.py index 9c9932826b..1354caabb2 100644 --- a/client/ayon_core/hosts/resolve/addon.py +++ b/client/ayon_core/hosts/resolve/addon.py @@ -1,17 +1,14 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon from .utils import RESOLVE_ROOT_DIR -class ResolveAddon(OpenPypeModule, IHostAddon): +class ResolveAddon(AYONAddon, IHostAddon): name = "resolve" host_name = "resolve" - def initialize(self, module_settings): - self.enabled = True - def get_launch_hook_paths(self, app): if app.host_name != self.host_name: return [] diff --git a/client/ayon_core/hosts/substancepainter/addon.py b/client/ayon_core/hosts/substancepainter/addon.py index a7f21c2288..26829d3153 100644 --- a/client/ayon_core/hosts/substancepainter/addon.py +++ b/client/ayon_core/hosts/substancepainter/addon.py @@ -1,16 +1,13 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon SUBSTANCE_HOST_DIR = os.path.dirname(os.path.abspath(__file__)) -class SubstanceAddon(OpenPypeModule, IHostAddon): +class SubstanceAddon(AYONAddon, IHostAddon): name = "substancepainter" host_name = "substancepainter" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): # Add requirements to SUBSTANCE_PAINTER_PLUGINS_PATH plugin_path = os.path.join(SUBSTANCE_HOST_DIR, "deploy") diff --git a/client/ayon_core/hosts/traypublisher/addon.py b/client/ayon_core/hosts/traypublisher/addon.py index d8fc5ed105..70bdfe9a64 100644 --- a/client/ayon_core/hosts/traypublisher/addon.py +++ b/client/ayon_core/hosts/traypublisher/addon.py @@ -2,9 +2,9 @@ import os from ayon_core.lib import get_ayon_launcher_args from ayon_core.lib.execute import run_detached_process -from ayon_core.modules import ( +from ayon_core.addon import ( click_wrap, - OpenPypeModule, + AYONAddon, ITrayAction, IHostAddon, ) @@ -12,13 +12,12 @@ from ayon_core.modules import ( TRAYPUBLISH_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -class TrayPublishAddon(OpenPypeModule, IHostAddon, ITrayAction): +class TrayPublishAddon(AYONAddon, IHostAddon, ITrayAction): label = "Publisher" name = "traypublisher" host_name = "traypublisher" - def initialize(self, modules_settings): - self.enabled = True + def initialize(self, settings): self.publish_paths = [ os.path.join(TRAYPUBLISH_ROOT_DIR, "plugins", "publish") ] @@ -36,7 +35,7 @@ class TrayPublishAddon(OpenPypeModule, IHostAddon, ITrayAction): def run_traypublisher(self): args = get_ayon_launcher_args( - "module", self.name, "launch" + "addon", self.name, "launch" ) run_detached_process(args) diff --git a/client/ayon_core/hosts/tvpaint/addon.py b/client/ayon_core/hosts/tvpaint/addon.py index 375f7266ae..6756b274f9 100644 --- a/client/ayon_core/hosts/tvpaint/addon.py +++ b/client/ayon_core/hosts/tvpaint/addon.py @@ -1,5 +1,5 @@ import os -from ayon_core.modules import OpenPypeModule, IHostAddon +from ayon_core.addon import AYONAddon, IHostAddon TVPAINT_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -12,13 +12,10 @@ def get_launch_script_path(): ) -class TVPaintAddon(OpenPypeModule, IHostAddon): +class TVPaintAddon(AYONAddon, IHostAddon): name = "tvpaint" host_name = "tvpaint" - def initialize(self, module_settings): - self.enabled = True - def add_implementation_envs(self, env, _app): """Modify environments to contain all required for implementation.""" diff --git a/client/ayon_core/hosts/unreal/addon.py b/client/ayon_core/hosts/unreal/addon.py index 745df951c1..c65490bd8c 100644 --- a/client/ayon_core/hosts/unreal/addon.py +++ b/client/ayon_core/hosts/unreal/addon.py @@ -1,17 +1,14 @@ import os import re -from ayon_core.modules import IHostAddon, OpenPypeModule +from ayon_core.addon import AYONAddon, IHostAddon UNREAL_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -class UnrealAddon(OpenPypeModule, IHostAddon): +class UnrealAddon(AYONAddon, IHostAddon): name = "unreal" host_name = "unreal" - def initialize(self, module_settings): - self.enabled = True - def get_global_environments(self): return { "AYON_UNREAL_ROOT": UNREAL_ROOT_DIR, From 4e3fd869875a30347740f405a85efce14447654c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 18:32:27 +0100 Subject: [PATCH 078/112] console interpreter inherits from AYONaddon --- .../modules/python_console_interpreter/__init__.py | 2 +- .../python_console_interpreter/{module.py => addon.py} | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) rename client/ayon_core/modules/python_console_interpreter/{module.py => addon.py} (77%) diff --git a/client/ayon_core/modules/python_console_interpreter/__init__.py b/client/ayon_core/modules/python_console_interpreter/__init__.py index 5f54ac497b..8d5c23bdba 100644 --- a/client/ayon_core/modules/python_console_interpreter/__init__.py +++ b/client/ayon_core/modules/python_console_interpreter/__init__.py @@ -1,4 +1,4 @@ -from .module import ( +from .addon import ( PythonInterpreterAction ) diff --git a/client/ayon_core/modules/python_console_interpreter/module.py b/client/ayon_core/modules/python_console_interpreter/addon.py similarity index 77% rename from client/ayon_core/modules/python_console_interpreter/module.py rename to client/ayon_core/modules/python_console_interpreter/addon.py index 7819c9cbf3..ffad3ce707 100644 --- a/client/ayon_core/modules/python_console_interpreter/module.py +++ b/client/ayon_core/modules/python_console_interpreter/addon.py @@ -1,13 +1,12 @@ -from ayon_core.modules import OpenPypeModule, ITrayAction +from ayon_core.addon import AYONAddon, ITrayAction -class PythonInterpreterAction(OpenPypeModule, ITrayAction): +class PythonInterpreterAction(AYONAddon, ITrayAction): label = "Console" name = "python_interpreter" admin_action = True - def initialize(self, modules_settings): - self.enabled = True + def initialize(self, settings): self._interpreter_window = None def tray_init(self): @@ -22,7 +21,7 @@ class PythonInterpreterAction(OpenPypeModule, ITrayAction): if self._interpreter_window: return - from openpype_modules.python_console_interpreter.window import ( + from ayon_core.modules.python_console_interpreter.window import ( PythonInterpreterWidget ) From 5c294300246b0379e68ed38603fffd7a2e33986b Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 18:32:39 +0100 Subject: [PATCH 079/112] launcher action addon inherits from AYONaddon --- client/ayon_core/modules/launcher_action.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/client/ayon_core/modules/launcher_action.py b/client/ayon_core/modules/launcher_action.py index c0266e3a57..1faf6ef4b1 100644 --- a/client/ayon_core/modules/launcher_action.py +++ b/client/ayon_core/modules/launcher_action.py @@ -1,19 +1,14 @@ import os from ayon_core import AYON_CORE_ROOT -from ayon_core.modules import ( - OpenPypeModule, - ITrayAction, -) +from ayon_core.addon import AYONAddon, ITrayAction -class LauncherAction(OpenPypeModule, ITrayAction): +class LauncherAction(AYONAddon, ITrayAction): label = "Launcher" name = "launcher_tool" - def initialize(self, _modules_settings): - # This module is always enabled - self.enabled = True + def initialize(self, settings): # Tray attributes self._window = None From b7d86bee3fb67ee4321de3ef5807fdbaa5949d12 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 18:34:42 +0100 Subject: [PATCH 080/112] renamed libray loader action to loader action --- .../modules/library_loader_action.py | 67 ------------------- client/ayon_core/modules/loader_action.py | 67 +++++++++++++++++++ 2 files changed, 67 insertions(+), 67 deletions(-) delete mode 100644 client/ayon_core/modules/library_loader_action.py create mode 100644 client/ayon_core/modules/loader_action.py diff --git a/client/ayon_core/modules/library_loader_action.py b/client/ayon_core/modules/library_loader_action.py deleted file mode 100644 index 524c4f7144..0000000000 --- a/client/ayon_core/modules/library_loader_action.py +++ /dev/null @@ -1,67 +0,0 @@ -from ayon_core.modules import AYONAddon, ITrayModule - - -class LibraryLoaderAddon(AYONAddon, ITrayModule): - name = "library_tool" - - def initialize(self, modules_settings): - # Tray attributes - self._library_loader_imported = None - self._library_loader_window = None - - def tray_init(self): - # Add library tool - self._library_loader_imported = False - try: - from ayon_core.tools.loader.ui import LoaderWindow - - self._library_loader_imported = True - except Exception: - self.log.warning( - "Couldn't load Library loader tool for tray.", - exc_info=True - ) - - # Definition of Tray menu - def tray_menu(self, tray_menu): - if not self._library_loader_imported: - return - - from qtpy import QtWidgets - # Actions - action_library_loader = QtWidgets.QAction( - "Loader", tray_menu - ) - - action_library_loader.triggered.connect(self.show_library_loader) - - tray_menu.addAction(action_library_loader) - - def tray_start(self, *_a, **_kw): - return - - def tray_exit(self, *_a, **_kw): - return - - def show_library_loader(self): - if self._library_loader_window is None: - from ayon_core.pipeline import install_ayon_plugins - - self._init_library_loader() - - install_ayon_plugins() - - self._library_loader_window.show() - - # Raise and activate the window - # for MacOS - self._library_loader_window.raise_() - # for Windows - self._library_loader_window.activateWindow() - - def _init_library_loader(self): - from ayon_core.tools.loader.ui import LoaderWindow - - libraryloader = LoaderWindow() - - self._library_loader_window = libraryloader diff --git a/client/ayon_core/modules/loader_action.py b/client/ayon_core/modules/loader_action.py new file mode 100644 index 0000000000..a0cc417b66 --- /dev/null +++ b/client/ayon_core/modules/loader_action.py @@ -0,0 +1,67 @@ +from ayon_core.addon import AYONAddon, ITrayAddon + + +class LoaderAddon(AYONAddon, ITrayAddon): + name = "loader_tool" + + def initialize(self, settings): + # Tray attributes + self._loader_imported = None + self._loader_window = None + + def tray_init(self): + # Add library tool + self._loader_imported = False + try: + from ayon_core.tools.loader.ui import LoaderWindow + + self._loader_imported = True + except Exception: + self.log.warning( + "Couldn't load Loader tool for tray.", + exc_info=True + ) + + # Definition of Tray menu + def tray_menu(self, tray_menu): + if not self._loader_imported: + return + + from qtpy import QtWidgets + # Actions + action_loader = QtWidgets.QAction( + "Loader", tray_menu + ) + + action_loader.triggered.connect(self.show_loader) + + tray_menu.addAction(action_loader) + + def tray_start(self, *_a, **_kw): + return + + def tray_exit(self, *_a, **_kw): + return + + def show_loader(self): + if self._loader_window is None: + from ayon_core.pipeline import install_ayon_plugins + + self._init_loader() + + install_ayon_plugins() + + self._loader_window.show() + + # Raise and activate the window + # for MacOS + self._loader_window.raise_() + # for Windows + self._loader_window.activateWindow() + + def _init_loader(self): + from ayon_core.tools.loader.ui import LoaderWindow + + libraryloader = LoaderWindow() + + self._loader_window = libraryloader From 3484a3d79b2b8966f78fd7c49c2aa4a72d8978d8 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 18:35:49 +0100 Subject: [PATCH 081/112] modified click_wrap examples and readme --- client/ayon_core/addon/README.md | 8 ++++---- client/ayon_core/addon/click_wrap.py | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/client/ayon_core/addon/README.md b/client/ayon_core/addon/README.md index b793b0ffb4..a15e8bdc69 100644 --- a/client/ayon_core/addon/README.md +++ b/client/ayon_core/addon/README.md @@ -31,7 +31,7 @@ AYON addons should contain separated logic of specific kind of implementation, s - addon must implement `get_plugin_paths` which must return dictionary with possible keys `"publish"`, `"load"`, `"create"` or `"actions"` - each key may contain list or string with a path to directory with plugins -## ITrayModule +## ITrayAddon - addon has more logic when used in a tray - it is possible that addon can be used only in the tray - abstract methods @@ -46,7 +46,7 @@ AYON addons should contain separated logic of specific kind of implementation, s - if addon has logic only in tray or for both then should be checking for `tray_initialized` attribute to decide how should handle situations ### ITrayService -- inherits from `ITrayModule` and implements `tray_menu` method for you +- inherits from `ITrayAddon` and implements `tray_menu` method for you - adds action to submenu "Services" in tray widget menu with icon and label - abstract attribute `label` - label shown in menu @@ -57,7 +57,7 @@ AYON addons should contain separated logic of specific kind of implementation, s - these states must be set by addon itself `set_service_running` is default state on initialization ### ITrayAction -- inherits from `ITrayModule` and implements `tray_menu` method for you +- inherits from `ITrayAddon` and implements `tray_menu` method for you - adds action to tray widget menu with label - abstract attribute `label` - label shown in menu @@ -89,4 +89,4 @@ AYON addons should contain separated logic of specific kind of implementation, s ### TrayAddonsManager - inherits from `AddonsManager` -- has specific implementation for Pype Tray tool and handle `ITrayModule` methods +- has specific implementation for Pype Tray tool and handle `ITrayAddon` methods diff --git a/client/ayon_core/addon/click_wrap.py b/client/ayon_core/addon/click_wrap.py index d49188312d..911a5a5707 100644 --- a/client/ayon_core/addon/click_wrap.py +++ b/client/ayon_core/addon/click_wrap.py @@ -15,7 +15,7 @@ method to convert 'click_wrap' object to 'click' object. Before ```python import click -from ayon_core.modules import AYONAddon +from ayon_core.addon import AYONAddon class ExampleAddon(AYONAddon): @@ -40,7 +40,7 @@ def mycommand(arg1, arg2): Now ``` from ayon_core import click_wrap -from ayon_core.modules import AYONAddon +from ayon_core.addon import AYONAddon class ExampleAddon(AYONAddon): @@ -72,7 +72,7 @@ Added small enhancements: Example: ```python from ayon_core import click_wrap - from ayon_core.modules import AYONAddon + from ayon_core.addon import AYONAddon class ExampleAddon(AYONAddon): From df9cb75799ed6ef43ba23ec10b81aa5de03aa422 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 9 Feb 2024 18:43:29 +0100 Subject: [PATCH 082/112] added 'USE_AYON_ENTITIES' for forwards compatibility possibilities --- client/ayon_core/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/ayon_core/__init__.py b/client/ayon_core/__init__.py index c9c0dfc614..5f9eb6cea3 100644 --- a/client/ayon_core/__init__.py +++ b/client/ayon_core/__init__.py @@ -7,3 +7,6 @@ AYON_CORE_ROOT = os.path.dirname(os.path.abspath(__file__)) PACKAGE_DIR = AYON_CORE_ROOT PLUGINS_DIR = os.path.join(AYON_CORE_ROOT, "plugins") AYON_SERVER_ENABLED = True + +# Indicate if AYON entities should be used instead of OpenPype entities +USE_AYON_ENTITIES = False From 2e925ea64b32848097a34abbf9e13f89ec0e805a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 9 Feb 2024 21:50:30 +0100 Subject: [PATCH 083/112] fix variable check --- client/ayon_core/plugins/publish/collect_rendered_files.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/collect_rendered_files.py b/client/ayon_core/plugins/publish/collect_rendered_files.py index 714d790269..1442111a31 100644 --- a/client/ayon_core/plugins/publish/collect_rendered_files.py +++ b/client/ayon_core/plugins/publish/collect_rendered_files.py @@ -144,7 +144,7 @@ class CollectRenderedFiles(pyblish.api.ContextPlugin): os.environ.get("AYON_PUBLISH_DATA") or os.environ.get("OPENPYPE_PUBLISH_DATA") ) - if publish_data_paths: + if not publish_data_paths: raise KnownPublishError("Missing `AYON_PUBLISH_DATA`") # QUESTION From 9d807f28f069ffff23c7306d88c756526246379d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 9 Feb 2024 22:16:43 +0100 Subject: [PATCH 084/112] session is not required key --- client/ayon_core/plugins/publish/collect_rendered_files.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/collect_rendered_files.py b/client/ayon_core/plugins/publish/collect_rendered_files.py index 1442111a31..a7b6064b7a 100644 --- a/client/ayon_core/plugins/publish/collect_rendered_files.py +++ b/client/ayon_core/plugins/publish/collect_rendered_files.py @@ -72,7 +72,7 @@ class CollectRenderedFiles(pyblish.api.ContextPlugin): # validate basic necessary data data_err = "invalid json file - missing data" required = ["asset", "user", "comment", - "job", "instances", "session", "version"] + "job", "instances", "version"] assert all(elem in data.keys() for elem in required), data_err # set context by first json file From a1900487649617447d92133a6219867e5b60d722 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 12 Feb 2024 10:31:56 +0100 Subject: [PATCH 085/112] removed unnecessary changes --- client/ayon_core/plugins/publish/extract_review.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index a6e0196dc7..4e6ece0038 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -1059,10 +1059,8 @@ class ExtractReview(pyblish.api.InstancePlugin): # NOTE: value in "-ac" was hardcoded to 2, changed to audio inputs len. # Need to merge audio if there are more than 1 input. if len(audio_inputs) > 1: - audio_out_args.extend([ - "-filter_complex", "amerge", - "-ac", str(len(audio_inputs)) - ]) + audio_out_args.append("-filter_complex amerge") + audio_out_args.append("-ac {}".format(len(audio_inputs))) return audio_in_args, audio_filters, audio_out_args From 0057e4509f4e476a459e3ffd9f9ed1b9acb095e7 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 12 Feb 2024 15:25:05 +0100 Subject: [PATCH 086/112] removed tests in client codebase --- client/ayon_core/tests/README.md | 4 - client/ayon_core/tests/__init__.py | 0 client/ayon_core/tests/lib.py | 88 ------ client/ayon_core/tests/mongo_performance.py | 288 ------------------ .../tests/test_avalon_plugin_presets.py | 43 --- .../tests/test_lib_restructuralization.py | 25 -- client/ayon_core/tests/test_pyblish_filter.py | 60 ---- 7 files changed, 508 deletions(-) delete mode 100644 client/ayon_core/tests/README.md delete mode 100644 client/ayon_core/tests/__init__.py delete mode 100644 client/ayon_core/tests/lib.py delete mode 100644 client/ayon_core/tests/mongo_performance.py delete mode 100644 client/ayon_core/tests/test_avalon_plugin_presets.py delete mode 100644 client/ayon_core/tests/test_lib_restructuralization.py delete mode 100644 client/ayon_core/tests/test_pyblish_filter.py diff --git a/client/ayon_core/tests/README.md b/client/ayon_core/tests/README.md deleted file mode 100644 index c05166767c..0000000000 --- a/client/ayon_core/tests/README.md +++ /dev/null @@ -1,4 +0,0 @@ -Tests for Pype --------------- -Trigger by: - `pype test --pype` \ No newline at end of file diff --git a/client/ayon_core/tests/__init__.py b/client/ayon_core/tests/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/client/ayon_core/tests/lib.py b/client/ayon_core/tests/lib.py deleted file mode 100644 index c7d4423aba..0000000000 --- a/client/ayon_core/tests/lib.py +++ /dev/null @@ -1,88 +0,0 @@ -import os -import sys -import shutil -import tempfile -import contextlib - -import pyblish -import pyblish.plugin -from pyblish.vendor import six - - -# Setup -HOST = 'python' -FAMILY = 'test.family' - -REGISTERED = pyblish.plugin.registered_paths() -PACKAGEPATH = pyblish.lib.main_package_path() -ENVIRONMENT = os.environ.get("PYBLISHPLUGINPATH", "") -PLUGINPATH = os.path.join(PACKAGEPATH, '..', 'tests', 'plugins') - - -def setup(): - pyblish.plugin.deregister_all_paths() - - -def setup_empty(): - """Disable all plug-ins""" - setup() - pyblish.plugin.deregister_all_plugins() - pyblish.plugin.deregister_all_paths() - pyblish.plugin.deregister_all_hosts() - pyblish.plugin.deregister_all_callbacks() - pyblish.plugin.deregister_all_targets() - pyblish.api.deregister_all_discovery_filters() - - -def teardown(): - """Restore previously REGISTERED paths""" - - pyblish.plugin.deregister_all_paths() - for path in REGISTERED: - pyblish.plugin.register_plugin_path(path) - - os.environ["PYBLISHPLUGINPATH"] = ENVIRONMENT - pyblish.api.deregister_all_plugins() - pyblish.api.deregister_all_hosts() - pyblish.api.deregister_all_discovery_filters() - pyblish.api.deregister_test() - pyblish.api.__init__() - - -@contextlib.contextmanager -def captured_stdout(): - """Temporarily reassign stdout to a local variable""" - try: - sys.stdout = six.StringIO() - yield sys.stdout - finally: - sys.stdout = sys.__stdout__ - - -@contextlib.contextmanager -def captured_stderr(): - """Temporarily reassign stderr to a local variable""" - try: - sys.stderr = six.StringIO() - yield sys.stderr - finally: - sys.stderr = sys.__stderr__ - - -@contextlib.contextmanager -def tempdir(): - """Provide path to temporary directory""" - try: - tempdir = tempfile.mkdtemp() - yield tempdir - finally: - shutil.rmtree(tempdir) - - -def is_in_tests(): - """Returns if process is running in automatic tests mode. - - In tests mode different source DB is used, some plugins might be disabled - etc. - """ - return os.environ.get("IS_TEST") == '1' diff --git a/client/ayon_core/tests/mongo_performance.py b/client/ayon_core/tests/mongo_performance.py deleted file mode 100644 index 2df3363f4b..0000000000 --- a/client/ayon_core/tests/mongo_performance.py +++ /dev/null @@ -1,288 +0,0 @@ -import pymongo -import bson -import random -from datetime import datetime -import os - - -class TestPerformance(): - ''' - Class for testing performance of representation and their 'files' - parts. - Discussion is if embedded array: - 'files' : [ {'_id': '1111', 'path':'....}, - {'_id'...}] - OR documents: - 'files' : { - '1111': {'path':'....'}, - '2222': {'path':'...'} - } - is faster. - - Current results: - without additional partial index documents is 3x faster - With index is array 50x faster then document - - Partial index something like: - db.getCollection('performance_test').createIndex - ({'files._id': 1}, - {partialFilterExpresion: {'files': {'$exists': true}}}) - !DIDNT work for me, had to create manually in Compass - - ''' - - MONGO_URL = 'mongodb://localhost:27017' - MONGO_DB = 'performance_test' - MONGO_COLLECTION = 'performance_test' - - MAX_FILE_SIZE_B = 5000 - MAX_NUMBER_OF_SITES = 50 - ROOT_DIR = "C:/projects" - - inserted_ids = [] - - def __init__(self, version='array'): - ''' - It creates and fills collection, based on value of 'version'. - - :param version: 'array' - files as embedded array, - 'doc' - as document - ''' - self.client = pymongo.MongoClient(self.MONGO_URL) - self.db = self.client[self.MONGO_DB] - self.collection_name = self.MONGO_COLLECTION - - self.version = version - - if self.version != 'array': - self.collection_name = self.MONGO_COLLECTION + '_doc' - - self.collection = self.db[self.collection_name] - - self.ids = [] # for testing - self.inserted_ids = [] - - def prepare(self, no_of_records=100000, create_files=False): - ''' - Produce 'no_of_records' of representations with 'files' segment. - It depends on 'version' value in constructor, 'arrray' or 'doc' - :return: - ''' - print('Purging {} collection'.format(self.collection_name)) - self.collection.delete_many({}) - - id = bson.objectid.ObjectId() - - insert_recs = [] - for i in range(no_of_records): - file_id = bson.objectid.ObjectId() - file_id2 = bson.objectid.ObjectId() - file_id3 = bson.objectid.ObjectId() - - self.inserted_ids.extend([file_id, file_id2, file_id3]) - version_str = "v{:03d}".format(i + 1) - file_name = "test_Cylinder_workfileLookdev_{}.mb".\ - format(version_str) - - document = {"files": self.get_files(self.version, i + 1, - file_id, file_id2, file_id3, - create_files) - , - "context": { - "subset": "workfileLookdev", - "username": "petrk", - "task": "lookdev", - "family": "workfile", - "hierarchy": "Assets", - "project": {"code": "test", "name": "Test"}, - "version": i + 1, - "asset": "Cylinder", - "representation": "mb", - "root": self.ROOT_DIR - }, - "dependencies": [], - "name": "mb", - "parent": {"oid": '{}'.format(id)}, - "data": { - "path": "C:\\projects\\test_performance\\Assets\\Cylinder\\publish\\workfile\\workfileLookdev\\{}\\{}".format(version_str, file_name), # noqa: E501 - "template": "{root[work]}\\{project[name]}\\{hierarchy}\\{asset}\\publish\\{family}\\{subset}\\v{version:0>3}\\{project[code]}_{asset}_{subset}_v{version:0>3}<_{output}><.{frame:0>4}>.{representation}" # noqa: E501 - }, - "type": "representation", - "schema": "openpype:representation-2.0" - } - - insert_recs.append(document) - - print('Prepared {} records in {} collection'. - format(no_of_records, self.collection_name)) - - self.collection.insert_many(insert_recs) - # TODO refactore to produce real array and not needeing ugly regex - self.collection.insert_one({"inserted_id": self.inserted_ids}) - print('-' * 50) - - def run(self, queries=1000, loops=3): - ''' - Run X'queries' that are searching collection Y'loops' times - :param queries: how many times do ..find(...) - :param loops: loop of testing X queries - :return: None - ''' - print('Testing version {} on {}'.format(self.version, - self.collection_name)) - print('Queries rung {} in {} loops'.format(queries, loops)) - - inserted_ids = list(self.collection. - find({"inserted_id": {"$exists": True}})) - import re - self.ids = re.findall("'[0-9a-z]*'", str(inserted_ids)) - - import time - - found_cnt = 0 - for _ in range(loops): - print('Starting loop {}'.format(_)) - start = time.time() - for _ in range(queries): - # val = random.choice(self.ids) - # val = val.replace("'", '') - val = random.randint(0, 50) - print(val) - - if (self.version == 'array'): - # prepared for partial index, without 'files': exists - # wont engage - found = self.collection.\ - find({'files': {"$exists": True}, - 'files.sites.name': "local_{}".format(val)}).\ - count() - else: - key = "files.{}".format(val) - found = self.collection.find_one({key: {"$exists": True}}) - print("found {} records".format(found)) - # if found: - # found_cnt += len(list(found)) - - end = time.time() - print('duration per loop {}'.format(end - start)) - print("found_cnt {}".format(found_cnt)) - - def get_files(self, mode, i, file_id, file_id2, file_id3, - create_files=False): - ''' - Wrapper to decide if 'array' or document version should be used - :param mode: 'array'|'doc' - :param i: step number - :param file_id: ObjectId of first dummy file - :param file_id2: .. - :param file_id3: .. - :return: - ''' - if mode == 'array': - return self.get_files_array(i, file_id, file_id2, file_id3, - create_files) - else: - return self.get_files_doc(i, file_id, file_id2, file_id3) - - def get_files_array(self, i, file_id, file_id2, file_id3, - create_files=False): - ret = [ - { - "path": "{root[work]}" + "{root[work]}/test_performance/Assets/Cylinder/publish/workfile/workfileLookdev/v{:03d}/test_Cylinder_A_workfileLookdev_v{:03d}.dat".format(i, i), # noqa: E501 - "_id": '{}'.format(file_id), - "hash": "temphash", - "sites": self.get_sites(self.MAX_NUMBER_OF_SITES), - "size": random.randint(0, self.MAX_FILE_SIZE_B) - }, - { - "path": "{root[work]}" + "/test_performance/Assets/Cylinder/publish/workfile/workfileLookdev/v{:03d}/test_Cylinder_B_workfileLookdev_v{:03d}.dat".format(i, i), # noqa: E501 - "_id": '{}'.format(file_id2), - "hash": "temphash", - "sites": self.get_sites(self.MAX_NUMBER_OF_SITES), - "size": random.randint(0, self.MAX_FILE_SIZE_B) - }, - { - "path": "{root[work]}" + "/test_performance/Assets/Cylinder/publish/workfile/workfileLookdev/v{:03d}/test_Cylinder_C_workfileLookdev_v{:03d}.dat".format(i, i), # noqa: E501 - "_id": '{}'.format(file_id3), - "hash": "temphash", - "sites": self.get_sites(self.MAX_NUMBER_OF_SITES), - "size": random.randint(0, self.MAX_FILE_SIZE_B) - } - - ] - if create_files: - for f in ret: - path = f.get("path").replace("{root[work]}", self.ROOT_DIR) - os.makedirs(os.path.dirname(path), exist_ok=True) - with open(path, 'wb') as fp: - fp.write(os.urandom(f.get("size"))) - - return ret - - def get_files_doc(self, i, file_id, file_id2, file_id3): - ret = {} - ret['{}'.format(file_id)] = { - "path": "{root[work]}" + - "/test_performance/Assets/Cylinder/publish/workfile/workfileLookdev/" # noqa: E501 - "v{:03d}/test_CylinderA_workfileLookdev_v{:03d}.mb".format(i, i), # noqa: E501 - "hash": "temphash", - "sites": ["studio"], - "size": 87236 - } - - ret['{}'.format(file_id2)] = { - "path": "{root[work]}" + - "/test_performance/Assets/Cylinder/publish/workfile/workfileLookdev/" # noqa: E501 - "v{:03d}/test_CylinderB_workfileLookdev_v{:03d}.mb".format(i, i), # noqa: E501 - "hash": "temphash", - "sites": ["studio"], - "size": 87236 - } - ret['{}'.format(file_id3)] = { - "path": "{root[work]}" + - "/test_performance/Assets/Cylinder/publish/workfile/workfileLookdev/" # noqa: E501 - "v{:03d}/test_CylinderC_workfileLookdev_v{:03d}.mb".format(i, i), # noqa: E501 - "hash": "temphash", - "sites": ["studio"], - "size": 87236 - } - - return ret - - def get_sites(self, number_of_sites=50): - """ - Return array of sites declaration. - Currently on 1st site has "created_dt" fillled, which should - trigger upload to 'gdrive' site. - 'gdrive' site is appended, its destination for syncing for - Sync Server - Args: - number_of_sites: - - Returns: - - """ - sites = [] - for i in range(number_of_sites): - site = {'name': "local_{}".format(i)} - # do not create null 'created_dt' field, Mongo doesnt like it - if i == 0: - site['created_dt'] = datetime.now() - - sites.append(site) - - sites.append({'name': "gdrive"}) - - return sites - - -if __name__ == '__main__': - tp = TestPerformance('array') - tp.prepare(no_of_records=10000, create_files=True) - # tp.run(10, 3) - - # print('-'*50) - # - # tp = TestPerformance('doc') - # tp.prepare() # enable to prepare data - # tp.run(1000, 3) diff --git a/client/ayon_core/tests/test_avalon_plugin_presets.py b/client/ayon_core/tests/test_avalon_plugin_presets.py deleted file mode 100644 index 4926286ca3..0000000000 --- a/client/ayon_core/tests/test_avalon_plugin_presets.py +++ /dev/null @@ -1,43 +0,0 @@ -from ayon_core.pipeline import ( - install_host, - LegacyCreator, - register_creator_plugin, - discover_creator_plugins, -) - - -class MyTestCreator(LegacyCreator): - - my_test_property = "A" - - def __init__(self, name, asset, options=None, data=None): - super(MyTestCreator, self).__init__(self, name, asset, - options=None, data=None) - - -# this is hack like no other - we need to inject our own avalon host -# and bypass all its validation. Avalon hosts are modules that needs -# `ls` callable as attribute. Voila: -class Test: - __name__ = "test" - ls = len - - @staticmethod - def install(): - register_creator_plugin(MyTestCreator) - - -def test_avalon_plugin_presets(monkeypatch, printer): - install_host(Test) - - plugins = discover_creator_plugins() - printer("Test if we got our test plugin") - assert MyTestCreator in plugins - for p in plugins: - if p.__name__ == "MyTestCreator": - printer("Test if we have overridden existing property") - assert p.my_test_property == "B" - printer("Test if we have overridden superclass property") - assert p.active is False - printer("Test if we have added new property") - assert p.new_property == "new" diff --git a/client/ayon_core/tests/test_lib_restructuralization.py b/client/ayon_core/tests/test_lib_restructuralization.py deleted file mode 100644 index ffbd62b045..0000000000 --- a/client/ayon_core/tests/test_lib_restructuralization.py +++ /dev/null @@ -1,25 +0,0 @@ -# Test for backward compatibility of restructure of lib.py into lib library -# Contains simple imports that should still work - - -def test_backward_compatibility(printer): - printer("Test if imports still work") - try: - from ayon_core.lib import execute_hook - from ayon_core.lib import PypeHook - - from ayon_core.lib import ApplicationLaunchFailed - - from ayon_core.lib import get_ffmpeg_tool_path - from ayon_core.lib import get_last_version_from_path - from ayon_core.lib import get_paths_from_environ - from ayon_core.lib import get_version_from_path - from ayon_core.lib import version_up - - from ayon_core.lib import get_ffprobe_streams - - from ayon_core.lib import source_hash - from ayon_core.lib import run_subprocess - - except ImportError as e: - raise diff --git a/client/ayon_core/tests/test_pyblish_filter.py b/client/ayon_core/tests/test_pyblish_filter.py deleted file mode 100644 index bc20f863c9..0000000000 --- a/client/ayon_core/tests/test_pyblish_filter.py +++ /dev/null @@ -1,60 +0,0 @@ -import os -import pyblish.api -import pyblish.util -import pyblish.plugin -from ayon_core.pipeline.publish.lib import filter_pyblish_plugins -from . import lib - - -def test_pyblish_plugin_filter_modifier(printer, monkeypatch): - """ - Test if pyblish filter can filter and modify plugins on-the-fly. - """ - - lib.setup_empty() - monkeypatch.setitem(os.environ, 'PYBLISHPLUGINPATH', '') - plugins = pyblish.api.registered_plugins() - printer("Test if we have no registered plugins") - assert len(plugins) == 0 - paths = pyblish.api.registered_paths() - printer("Test if we have no registered plugin paths") - assert len(paths) == 0 - - class MyTestPlugin(pyblish.api.InstancePlugin): - my_test_property = 1 - label = "Collect Renderable Camera(s)" - hosts = ["test"] - families = ["default"] - - pyblish.api.register_host("test") - pyblish.api.register_plugin(MyTestPlugin) - pyblish.api.register_discovery_filter(filter_pyblish_plugins) - plugins = pyblish.api.discover() - - printer("Test if only one plugin was discovered") - assert len(plugins) == 1 - printer("Test if properties are modified correctly") - assert plugins[0].label == "loaded from preset" - assert plugins[0].families == ["changed", "by", "preset"] - assert plugins[0].optional is True - - lib.teardown() - - -def test_pyblish_plugin_filter_removal(monkeypatch): - """ Test that plugin can be removed by filter """ - lib.setup_empty() - monkeypatch.setitem(os.environ, 'PYBLISHPLUGINPATH', '') - plugins = pyblish.api.registered_plugins() - - class MyTestRemovedPlugin(pyblish.api.InstancePlugin): - my_test_property = 1 - label = "Collect Renderable Camera(s)" - hosts = ["test"] - families = ["default"] - - pyblish.api.register_host("test") - pyblish.api.register_plugin(MyTestRemovedPlugin) - pyblish.api.register_discovery_filter(filter_pyblish_plugins) - plugins = pyblish.api.discover() - assert len(plugins) == 0 From 531ce4e695808b371373ead6b924fa64db904117 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 12 Feb 2024 15:26:14 +0100 Subject: [PATCH 087/112] removed mongo dependencies from client --- client/pyproject.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/pyproject.toml b/client/pyproject.toml index c21ca305a7..7b4329a31a 100644 --- a/client/pyproject.toml +++ b/client/pyproject.toml @@ -10,8 +10,6 @@ wsrpc_aiohttp = "^3.1.1" # websocket server Click = "^8" clique = "1.6.*" jsonschema = "^2.6.0" -pymongo = "^3.11.2" -log4mongo = "^1.7" pyblish-base = "^1.8.11" pynput = "^1.7.2" # Timers manager - TODO remove speedcopy = "^2.1" From 9caab106f782fb2d520da55af995111b77f73496 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 12 Feb 2024 16:26:10 +0100 Subject: [PATCH 088/112] use AYON prefix in harmony env variables --- client/ayon_core/hosts/harmony/api/README.md | 2 +- client/ayon_core/hosts/harmony/api/TB_sceneOpened.js | 2 +- client/ayon_core/hosts/harmony/api/lib.py | 4 ++-- .../settings/defaults/system_settings/applications.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client/ayon_core/hosts/harmony/api/README.md b/client/ayon_core/hosts/harmony/api/README.md index cdc17b2285..680a88c423 100644 --- a/client/ayon_core/hosts/harmony/api/README.md +++ b/client/ayon_core/hosts/harmony/api/README.md @@ -52,7 +52,7 @@ Because Harmony projects are directories, this integration uses `.zip` as work f ### Show Workfiles on launch -You can show the Workfiles app when Harmony launches by setting environment variable `AVALON_HARMONY_WORKFILES_ON_LAUNCH=1`. +You can show the Workfiles app when Harmony launches by setting environment variable `AYON_HARMONY_WORKFILES_ON_LAUNCH=1`. ## Developing diff --git a/client/ayon_core/hosts/harmony/api/TB_sceneOpened.js b/client/ayon_core/hosts/harmony/api/TB_sceneOpened.js index 1fb0d295e7..cdf60c1aa8 100644 --- a/client/ayon_core/hosts/harmony/api/TB_sceneOpened.js +++ b/client/ayon_core/hosts/harmony/api/TB_sceneOpened.js @@ -349,7 +349,7 @@ function start() { /** hostname or ip of server - should be localhost */ var host = '127.0.0.1'; /** port of the server */ - var port = parseInt(System.getenv('AVALON_HARMONY_PORT')); + var port = parseInt(System.getenv('AYON_HARMONY_PORT')); // Attach the client to the QApplication to preserve. var app = QCoreApplication.instance(); diff --git a/client/ayon_core/hosts/harmony/api/lib.py b/client/ayon_core/hosts/harmony/api/lib.py index 782134c343..bc73e19066 100644 --- a/client/ayon_core/hosts/harmony/api/lib.py +++ b/client/ayon_core/hosts/harmony/api/lib.py @@ -189,14 +189,14 @@ def launch(application_path, *args): install_host(harmony) ProcessContext.port = random.randrange(49152, 65535) - os.environ["AVALON_HARMONY_PORT"] = str(ProcessContext.port) + os.environ["AYON_HARMONY_PORT"] = str(ProcessContext.port) ProcessContext.application_path = application_path # Launch Harmony. setup_startup_scripts() check_libs() - if not os.environ.get("AVALON_HARMONY_WORKFILES_ON_LAUNCH", False): + if not os.environ.get("AYON_HARMONY_WORKFILES_ON_LAUNCH", False): open_empty_workfile() return diff --git a/client/ayon_core/settings/defaults/system_settings/applications.json b/client/ayon_core/settings/defaults/system_settings/applications.json index a5283751e9..2610c15315 100644 --- a/client/ayon_core/settings/defaults/system_settings/applications.json +++ b/client/ayon_core/settings/defaults/system_settings/applications.json @@ -1271,7 +1271,7 @@ "icon": "{}/app_icons/harmony.png", "host_name": "harmony", "environment": { - "AVALON_HARMONY_WORKFILES_ON_LAUNCH": "1" + "AYON_HARMONY_WORKFILES_ON_LAUNCH": "1" }, "variants": { "21": { From f1c70af6ef090e34e9538984deb58014074a4a79 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 12 Feb 2024 15:42:27 +0000 Subject: [PATCH 089/112] Add submodule --- client/ayon_core/hosts/unreal/integration | 1 + 1 file changed, 1 insertion(+) create mode 160000 client/ayon_core/hosts/unreal/integration diff --git a/client/ayon_core/hosts/unreal/integration b/client/ayon_core/hosts/unreal/integration new file mode 160000 index 0000000000..6d2793170e --- /dev/null +++ b/client/ayon_core/hosts/unreal/integration @@ -0,0 +1 @@ +Subproject commit 6d2793170ed57187842f683a943593973abcc337 From 28ae27f5b034e782a1532298a5d85656f1fc1f6d Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 12 Feb 2024 16:47:07 +0100 Subject: [PATCH 090/112] fix kitsu conversion --- client/ayon_core/settings/ayon_settings.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 1aa82995b6..35652d5c3c 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -82,6 +82,20 @@ def _convert_general(ayon_settings, output, default_settings): } +def _convert_kitsu_system_settings( + ayon_settings, output, addon_versions, default_settings +): + if "kitsu" in ayon_settings: + output["kitsu"] = ayon_settings["kitsu"] + + enabled = addon_versions.get("kitsu") is not None + kitsu_settings = default_settings["modules"]["kitsu"] + kitsu_settings["enabled"] = enabled + if enabled: + kitsu_settings["server"] = ayon_settings["kitsu"]["server"] + output["modules"]["kitsu"] = kitsu_settings + + def _convert_timers_manager_system_settings( ayon_settings, output, addon_versions, default_settings ): From f22358e78fcdf93d545774cbc78b7c75a43e4c16 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 12 Feb 2024 17:42:13 +0100 Subject: [PATCH 091/112] fix default value in 'filter_output_defs' --- client/ayon_core/plugins/publish/extract_review.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 4e6ece0038..7af0da386b 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -1513,11 +1513,11 @@ class ExtractReview(pyblish.api.InstancePlugin): Returns: list: Containg all output definitions matching entered families. """ + filtered_outputs = {} outputs = profile.get("outputs") if not outputs: - return [] + return filtered_outputs - filtered_outputs = {} for output_def in outputs: filename_suffix = output_def["name"] output_filters = output_def.get("filter") From daf8228e9a2db00cbe8cb03b05078850e7cdde8e Mon Sep 17 00:00:00 2001 From: Braden Jennings Date: Tue, 13 Feb 2024 10:00:12 +1300 Subject: [PATCH 092/112] enhancement/OP-7723_hidden_joints_validator --- .../hosts/maya/plugins/publish/validate_rig_joints_hidden.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_rig_joints_hidden.py b/client/ayon_core/hosts/maya/plugins/publish/validate_rig_joints_hidden.py index c6b9d23574..bb5ec8353e 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_rig_joints_hidden.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_rig_joints_hidden.py @@ -7,6 +7,7 @@ from ayon_core.hosts.maya.api import lib from ayon_core.pipeline.publish import ( RepairAction, ValidateContentsOrder, + PublishValidationError ) @@ -38,7 +39,8 @@ class ValidateRigJointsHidden(pyblish.api.InstancePlugin): invalid = self.get_invalid(instance) if invalid: - raise ValueError("Visible joints found: {0}".format(invalid)) + raise PublishValidationError( + "Visible joints found: {0}".format(invalid)) @classmethod def repair(cls, instance): From bf82de09d09e1a8704c7a47884d919c16d8000ef Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 12 Feb 2024 22:38:51 +0100 Subject: [PATCH 093/112] add version that is printed in GlobalJobPreLoad plugin --- .../deadline/repository/custom/plugins/GlobalJobPreLoad.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py b/client/ayon_core/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py index 81aab00b93..459153c957 100644 --- a/client/ayon_core/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py +++ b/client/ayon_core/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py @@ -14,7 +14,7 @@ from Deadline.Scripting import ( DirectoryUtils, ProcessUtils, ) - +__version__ = "1.0.0" VERSION_REGEX = re.compile( r"(?P0|[1-9]\d*)" r"\.(?P0|[1-9]\d*)" @@ -593,7 +593,7 @@ def inject_render_job_id(deadlinePlugin): def __main__(deadlinePlugin): - print("*** GlobalJobPreload start ...") + print("*** GlobalJobPreload {} start ...".format(__version__)) print(">>> Getting job ...") job = deadlinePlugin.GetJob() From 2c93caebbff89ce5ae7d9a40a286e972ff733c7c Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 12 Feb 2024 23:02:52 +0100 Subject: [PATCH 094/112] adding workflow pr-labeler missing config --- .github/pr-glob-labeler.yml | 102 ++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 .github/pr-glob-labeler.yml diff --git a/.github/pr-glob-labeler.yml b/.github/pr-glob-labeler.yml new file mode 100644 index 0000000000..286e7768b5 --- /dev/null +++ b/.github/pr-glob-labeler.yml @@ -0,0 +1,102 @@ +# Add type: unittest label if any changes in tests folders +'type: unittest': +- '*/*tests*/**/*' + +# any changes in documentation structure +'type: documentation': +- '*/**/*website*/**/*' +- '*/**/*docs*/**/*' + +# hosts triage +'host: Nuke': +- '*/**/*nuke*' +- '*/**/*nuke*/**/*' + +'host: Photoshop': +- '*/**/*photoshop*' +- '*/**/*photoshop*/**/*' + +'host: Harmony': +- '*/**/*harmony*' +- '*/**/*harmony*/**/*' + +'host: UE': +- '*/**/*unreal*' +- '*/**/*unreal*/**/*' + +'host: Houdini': +- '*/**/*houdini*' +- '*/**/*houdini*/**/*' + +'host: Maya': +- '*/**/*maya*' +- '*/**/*maya*/**/*' + +'host: Resolve': +- '*/**/*resolve*' +- '*/**/*resolve*/**/*' + +'host: Blender': +- '*/**/*blender*' +- '*/**/*blender*/**/*' + +'host: Hiero': +- '*/**/*hiero*' +- '*/**/*hiero*/**/*' + +'host: Fusion': +- '*/**/*fusion*' +- '*/**/*fusion*/**/*' + +'host: Flame': +- '*/**/*flame*' +- '*/**/*flame*/**/*' + +'host: TrayPublisher': +- '*/**/*traypublisher*' +- '*/**/*traypublisher*/**/*' + +'host: 3dsmax': +- '*/**/*max*' +- '*/**/*max*/**/*' + +'host: TV Paint': +- '*/**/*tvpaint*' +- '*/**/*tvpaint*/**/*' + +'host: CelAction': +- '*/**/*celaction*' +- '*/**/*celaction*/**/*' + +'host: After Effects': +- '*/**/*aftereffects*' +- '*/**/*aftereffects*/**/*' + +'host: Substance Painter': +- '*/**/*substancepainter*' +- '*/**/*substancepainter*/**/*' + +# modules triage +'module: Deadline': +- '*/**/*deadline*' +- '*/**/*deadline*/**/*' + +'module: RoyalRender': +- '*/**/*royalrender*' +- '*/**/*royalrender*/**/*' + +'module: Sitesync': +- '*/**/*sync_server*' +- '*/**/*sync_server*/**/*' + +'module: Ftrack': +- '*/**/*ftrack*' +- '*/**/*ftrack*/**/*' + +'module: Shotgrid': +- '*/**/*shotgrid*' +- '*/**/*shotgrid*/**/*' + +'module: Kitsu': +- '*/**/*kitsu*' +- '*/**/*kitsu*/**/*' From 87d5b3baeced304c02ffdd8c4d44d18907c32e94 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 12 Feb 2024 23:06:14 +0100 Subject: [PATCH 095/112] fix overscan_color default value --- server/settings/publish_plugins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/settings/publish_plugins.py b/server/settings/publish_plugins.py index c684ddda40..c01fb92b9c 100644 --- a/server/settings/publish_plugins.py +++ b/server/settings/publish_plugins.py @@ -946,7 +946,7 @@ DEFAULT_PUBLISH_VALUES = { "single_frame_filter": "multi_frame" }, "overscan_crop": "", - "overscan_color": [0, 0, 0, 1.0], + "overscan_color": [0, 0, 0], "width": 0, "height": 0, "scale_pixel_aspect": True, From 1d85cec34c86e771b1339d6c5fd41fe5f877457c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 13 Feb 2024 10:08:29 +0100 Subject: [PATCH 096/112] fix return type hint --- client/ayon_core/plugins/publish/extract_review.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 7af0da386b..2ab70038c6 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -1511,7 +1511,8 @@ class ExtractReview(pyblish.api.InstancePlugin): subset_name (str): name of subset Returns: - list: Containg all output definitions matching entered families. + dict[str, Any]: Containg all output definitions matching entered + families. """ filtered_outputs = {} outputs = profile.get("outputs") From 646a40635def59c2c7512ab8ca59c8ab949ed579 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 13 Feb 2024 10:29:19 +0100 Subject: [PATCH 097/112] add version to AYON plugin --- .../modules/deadline/repository/custom/plugins/Ayon/Ayon.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/ayon_core/modules/deadline/repository/custom/plugins/Ayon/Ayon.py b/client/ayon_core/modules/deadline/repository/custom/plugins/Ayon/Ayon.py index a1f752605d..de0a2c6d7a 100644 --- a/client/ayon_core/modules/deadline/repository/custom/plugins/Ayon/Ayon.py +++ b/client/ayon_core/modules/deadline/repository/custom/plugins/Ayon/Ayon.py @@ -15,6 +15,7 @@ import re import os import platform +__version__ = "1.0.0" ###################################################################### # This is the function that Deadline calls to get an instance of the @@ -52,6 +53,9 @@ class AyonDeadlinePlugin(DeadlinePlugin): del self.RenderArgumentCallback def InitializeProcess(self): + self.LogInfo( + "Initializing process with AYON plugin {}".format(__version__) + ) self.PluginType = PluginType.Simple self.StdoutHandling = True From f221dfa4252df76e52a9906887693a43fff6fd9a Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 13 Feb 2024 10:53:11 +0100 Subject: [PATCH 098/112] Change label back --- .../ayon_core/hosts/photoshop/plugins/publish/collect_review.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/photoshop/plugins/publish/collect_review.py b/client/ayon_core/hosts/photoshop/plugins/publish/collect_review.py index 3a4b7b5828..1ffbadf022 100644 --- a/client/ayon_core/hosts/photoshop/plugins/publish/collect_review.py +++ b/client/ayon_core/hosts/photoshop/plugins/publish/collect_review.py @@ -13,7 +13,7 @@ class CollectReview(pyblish.api.ContextPlugin): """Adds review to families for instances marked to be reviewable. """ - label = "Collect Review Family" + label = "Collect Review" hosts = ["photoshop"] order = pyblish.api.CollectorOrder + 0.1 From d751fdd798255ca971a2f9ed912f8dbb0ce24b41 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 13 Feb 2024 11:00:45 +0100 Subject: [PATCH 099/112] fix return docstring Co-authored-by: Roy Nieterau --- client/ayon_core/plugins/publish/extract_review.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 2ab70038c6..b0bc94c317 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -1511,7 +1511,7 @@ class ExtractReview(pyblish.api.InstancePlugin): subset_name (str): name of subset Returns: - dict[str, Any]: Containg all output definitions matching entered + dict[str, Any]: Containing all output definitions matching entered families. """ filtered_outputs = {} From b5b4ec2e80ffe2eeafc910bb1c956376de787f56 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 13 Feb 2024 11:17:48 +0100 Subject: [PATCH 100/112] round loader colors --- server_addon/maya/server/settings/loaders.py | 192 ++++--------------- 1 file changed, 32 insertions(+), 160 deletions(-) diff --git a/server_addon/maya/server/settings/loaders.py b/server_addon/maya/server/settings/loaders.py index df1172ae7d..b8264a56ef 100644 --- a/server_addon/maya/server/settings/loaders.py +++ b/server_addon/maya/server/settings/loaders.py @@ -4,131 +4,67 @@ from ayon_server.types import ColorRGB_float class ColorsSetting(BaseSettingsModel): model: ColorRGB_float = SettingsField( - ( - 0.8196078431372549, - 0.5176470588235295, - 0.11764705882352941 - ), + (0.82, 0.52, 0.12), title="Model:" ) rig: ColorRGB_float = SettingsField( - ( - 0.23137254901960785, - 0.8862745098039215, - 0.9215686274509803 - ), + (0.23, 0.89, 0.92), title="Rig:" ) pointcache: ColorRGB_float = SettingsField( - ( - 0.3686274509803922, - 0.8196078431372549, - 0.11764705882352941 - ), + (0.37, 0.82, 0.12), title="Pointcache:" ) animation: ColorRGB_float = SettingsField( - ( - 0.3686274509803922, - 0.8196078431372549, - 0.11764705882352941 - ), + (0.37, 0.82, 0.12), title="Animation:" ) ass: ColorRGB_float = SettingsField( - ( - 0.9764705882352941, - 0.5294117647058824, - 0.20784313725490197 - ), + (0.98, 0.53, 0.21), title="Arnold StandIn:" ) camera: ColorRGB_float = SettingsField( - ( - 0.5333333333333333, - 0.4470588235294118, - 0.9568627450980393 - ), + (0.53, 0.45, 0.96), title="Camera:" ) fbx: ColorRGB_float = SettingsField( - ( - 0.8431372549019608, - 0.6509803921568628, - 1.0 - ), + (0.84, 0.65, 1.0), title="FBX:" ) mayaAscii: ColorRGB_float = SettingsField( - ( - 0.2627450980392157, - 0.6823529411764706, - 1.0 - ), + (0.26, 0.68, 1.0), title="Maya Ascii:" ) mayaScene: ColorRGB_float = SettingsField( - ( - 0.2627450980392157, - 0.6823529411764706, - 1.0 - ), + (0.26, 0.68, 1.0), title="Maya Scene:" ) setdress: ColorRGB_float = SettingsField( - ( - 1.0, - 0.9803921568627451, - 0.35294117647058826 - ), + (1.0, 0.98, 0.35), title="Set Dress:" ) layout: ColorRGB_float = SettingsField( - ( - 1.0, - 0.9803921568627451, - 0.35294117647058826 - ), + (1.0, 0.98, 0.35), title="Layout:" ) vdbcache: ColorRGB_float = SettingsField( - ( - 0.9764705882352941, - 0.21176470588235294, - 0.0 - ), + (0.98, 0.21, 0.0), title="VDB Cache:" ) vrayproxy: ColorRGB_float = SettingsField( - ( - 1.0, - 0.5882352941176471, - 0.047058823529411764 - ), + (1.0, 0.59, 0.05), title="VRay Proxy:" ) vrayscene_layer: ColorRGB_float = SettingsField( - ( - 1.0, - 0.5882352941176471, - 0.047058823529411764 - ), + (1.0, 0.59, 0.05), title="VRay Scene:" ) yeticache: ColorRGB_float = SettingsField( - ( - 0.38823529411764707, - 0.807843137254902, - 0.8627450980392157 - ), + (0.39, 0.81, 0.86), title="Yeti Cache:" ) yetiRig: ColorRGB_float = SettingsField( - ( - 0.0, - 0.803921568627451, - 0.49019607843137253 - ), + (0.0, 0.80, 0.49), title="Yeti Rig:" ) @@ -163,86 +99,22 @@ class LoadersModel(BaseSettingsModel): DEFAULT_LOADERS_SETTING = { "colors": { - "model": [ - 0.8196078431372549, - 0.5176470588235295, - 0.11764705882352941 - ], - "rig": [ - 0.23137254901960785, - 0.8862745098039215, - 0.9215686274509803 - ], - "pointcache": [ - 0.3686274509803922, - 0.8196078431372549, - 0.11764705882352941 - ], - "animation": [ - 0.3686274509803922, - 0.8196078431372549, - 0.11764705882352941 - ], - "ass": [ - 0.9764705882352941, - 0.5294117647058824, - 0.20784313725490197 - ], - "camera": [ - 0.5333333333333333, - 0.4470588235294118, - 0.9568627450980393 - ], - "fbx": [ - 0.8431372549019608, - 0.6509803921568628, - 1.0 - ], - "mayaAscii": [ - 0.2627450980392157, - 0.6823529411764706, - 1.0 - ], - "mayaScene": [ - 0.2627450980392157, - 0.6823529411764706, - 1.0 - ], - "setdress": [ - 1.0, - 0.9803921568627451, - 0.35294117647058826 - ], - "layout": [ - 1.0, - 0.9803921568627451, - 0.35294117647058826 - ], - "vdbcache": [ - 0.9764705882352941, - 0.21176470588235294, - 0.0 - ], - "vrayproxy": [ - 1.0, - 0.5882352941176471, - 0.047058823529411764 - ], - "vrayscene_layer": [ - 1.0, - 0.5882352941176471, - 0.047058823529411764 - ], - "yeticache": [ - 0.38823529411764707, - 0.807843137254902, - 0.8627450980392157 - ], - "yetiRig": [ - 0.0, - 0.803921568627451, - 0.49019607843137253 - ] + "model": [0.82, 0.52, 0.12], + "rig": [0.23, 0.89, 0.92], + "pointcache": [0.37, 0.82, 0.12], + "animation": [0.37, 0.82, 0.12], + "ass": [0.98, 0.53, 0.21], + "camera":[0.53, 0.45, 0.96], + "fbx": [0.84, 0.65, 1.0], + "mayaAscii": [0.26, 0.68, 1.0], + "mayaScene": [0.26, 0.68, 1.0], + "setdress": [1.0, 0.98, 0.35], + "layout": [1.0, 0.98, 0.35], + "vdbcache": [0.98, 0.21, 0.0], + "vrayproxy": [1.0, 0.59, 0.05], + "vrayscene_layer": [1.0, 0.59, 0.05], + "yeticache": [0.39, 0.81, 0.86], + "yetiRig": [0.0, 0.80, 0.49], }, "reference_loader": { "namespace": "{folder[name]}_{product[name]}_##_", From 0fb5c68ee8940f4ebb6d7dc4e54ea30b103cc8f8 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 13 Feb 2024 11:31:41 +0100 Subject: [PATCH 101/112] do not force asset and task during publishing --- .../ayon_core/plugins/publish/collect_from_create_context.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/collect_from_create_context.py b/client/ayon_core/plugins/publish/collect_from_create_context.py index d8e803a43c..7adacbc463 100644 --- a/client/ayon_core/plugins/publish/collect_from_create_context.py +++ b/client/ayon_core/plugins/publish/collect_from_create_context.py @@ -61,7 +61,10 @@ class CollectFromCreateContext(pyblish.api.ContextPlugin): ("AVALON_ASSET", asset_name), ("AVALON_TASK", task_name) ): - os.environ[key] = value + if value is None: + os.environ.pop(key, None) + else: + os.environ[key] = value def create_instance( self, From 9ce795dcedbff897f27816f6a63f10bfb4e3fbaf Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 13 Feb 2024 11:45:02 +0100 Subject: [PATCH 102/112] implement 'is_in_tests' in lib --- client/ayon_core/lib/__init__.py | 2 ++ client/ayon_core/lib/ayon_info.py | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/client/ayon_core/lib/__init__.py b/client/ayon_core/lib/__init__.py index 12a5535a1c..e917467e7c 100644 --- a/client/ayon_core/lib/__init__.py +++ b/client/ayon_core/lib/__init__.py @@ -158,6 +158,7 @@ from .ayon_info import ( is_running_from_build, is_staging_enabled, is_dev_mode_enabled, + is_in_tests, ) @@ -278,6 +279,7 @@ __all__ = [ "is_running_from_build", "is_staging_enabled", "is_dev_mode_enabled", + "is_in_tests", "requests_get", "requests_post" diff --git a/client/ayon_core/lib/ayon_info.py b/client/ayon_core/lib/ayon_info.py index 725e10fa0e..97a35adcc6 100644 --- a/client/ayon_core/lib/ayon_info.py +++ b/client/ayon_core/lib/ayon_info.py @@ -38,6 +38,16 @@ def is_staging_enabled(): return os.getenv("AYON_USE_STAGING") == "1" +def is_in_tests(): + """Process is running in automatic tests mode. + + Returns: + bool: True if running in tests. + + """ + return os.environ.get("AYON_IN_TESTS") == "1" + + def is_dev_mode_enabled(): """Dev mode is enabled in AYON. From 742a39ea9e0034c0397761843c058f0e7901f3c5 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 13 Feb 2024 11:45:33 +0100 Subject: [PATCH 103/112] use new location of 'is_in_tests' --- client/ayon_core/hosts/aftereffects/api/launch_logic.py | 3 +-- client/ayon_core/hosts/photoshop/api/lib.py | 3 +-- .../hosts/photoshop/plugins/publish/collect_batch_data.py | 2 +- .../plugins/publish/collect_color_coded_instances.py | 3 +-- .../plugins/publish/submit_aftereffects_deadline.py | 2 +- .../deadline/plugins/publish/submit_blender_deadline.py | 2 +- .../deadline/plugins/publish/submit_harmony_deadline.py | 2 +- .../plugins/publish/submit_houdini_cache_deadline.py | 2 +- .../plugins/publish/submit_houdini_render_deadline.py | 2 +- .../deadline/plugins/publish/submit_maya_deadline.py | 4 ++-- .../publish/submit_maya_remote_publish_deadline.py | 2 +- .../deadline/plugins/publish/submit_nuke_deadline.py | 2 +- .../deadline/plugins/publish/submit_publish_cache_job.py | 3 +-- .../deadline/plugins/publish/submit_publish_job.py | 3 +-- client/ayon_core/modules/royalrender/lib.py | 8 ++++++-- client/ayon_core/pipeline/context_tools.py | 2 +- client/ayon_core/plugins/publish/cleanup.py | 2 +- client/ayon_core/plugins/publish/collect_scene_version.py | 3 +-- 18 files changed, 24 insertions(+), 26 deletions(-) diff --git a/client/ayon_core/hosts/aftereffects/api/launch_logic.py b/client/ayon_core/hosts/aftereffects/api/launch_logic.py index 3d09f4d53c..4ffed8cecf 100644 --- a/client/ayon_core/hosts/aftereffects/api/launch_logic.py +++ b/client/ayon_core/hosts/aftereffects/api/launch_logic.py @@ -15,8 +15,7 @@ from wsrpc_aiohttp import ( from qtpy import QtCore -from ayon_core.lib import Logger -from ayon_core.tests.lib import is_in_tests +from ayon_core.lib import Logger, is_in_tests from ayon_core.pipeline import install_host from ayon_core.addon import AddonsManager from ayon_core.tools.utils import host_tools, get_ayon_qt_app diff --git a/client/ayon_core/hosts/photoshop/api/lib.py b/client/ayon_core/hosts/photoshop/api/lib.py index 3111503e40..af14e6d02f 100644 --- a/client/ayon_core/hosts/photoshop/api/lib.py +++ b/client/ayon_core/hosts/photoshop/api/lib.py @@ -3,12 +3,11 @@ import sys import contextlib import traceback -from ayon_core.lib import env_value_to_bool, Logger +from ayon_core.lib import env_value_to_bool, Logger, is_in_tests from ayon_core.addon import AddonsManager from ayon_core.pipeline import install_host from ayon_core.tools.utils import host_tools from ayon_core.tools.utils import get_ayon_qt_app -from ayon_core.tests.lib import is_in_tests from .launch_logic import ProcessLauncher, stub diff --git a/client/ayon_core/hosts/photoshop/plugins/publish/collect_batch_data.py b/client/ayon_core/hosts/photoshop/plugins/publish/collect_batch_data.py index 6639040bd7..2912dbf23d 100644 --- a/client/ayon_core/hosts/photoshop/plugins/publish/collect_batch_data.py +++ b/client/ayon_core/hosts/photoshop/plugins/publish/collect_batch_data.py @@ -21,7 +21,7 @@ from openpype_modules.webpublisher.lib import ( get_batch_asset_task_info, parse_json ) -from ayon_core.tests.lib import is_in_tests +from ayon_core.lib import is_in_tests class CollectBatchData(pyblish.api.ContextPlugin): diff --git a/client/ayon_core/hosts/photoshop/plugins/publish/collect_color_coded_instances.py b/client/ayon_core/hosts/photoshop/plugins/publish/collect_color_coded_instances.py index e309da62ba..d486136f78 100644 --- a/client/ayon_core/hosts/photoshop/plugins/publish/collect_color_coded_instances.py +++ b/client/ayon_core/hosts/photoshop/plugins/publish/collect_color_coded_instances.py @@ -3,10 +3,9 @@ import re import pyblish.api -from ayon_core.lib import prepare_template_data +from ayon_core.lib import prepare_template_data, is_in_tests from ayon_core.hosts.photoshop import api as photoshop from ayon_core.settings import get_project_settings -from ayon_core.tests.lib import is_in_tests class CollectColorCodedInstances(pyblish.api.ContextPlugin): diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_aftereffects_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_aftereffects_deadline.py index 618b71bbaf..fb75f3a917 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_aftereffects_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_aftereffects_deadline.py @@ -7,10 +7,10 @@ from datetime import datetime from ayon_core.lib import ( env_value_to_bool, collect_frames, + is_in_tests, ) from openpype_modules.deadline import abstract_submit_deadline from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo -from ayon_core.tests.lib import is_in_tests @attr.s diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_blender_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_blender_deadline.py index af864ace5b..07b9f6e819 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_blender_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_blender_deadline.py @@ -10,10 +10,10 @@ from ayon_core.lib import ( BoolDef, NumberDef, TextDef, + is_in_tests, ) from ayon_core.pipeline.publish import AYONPyblishPluginMixin from ayon_core.pipeline.farm.tools import iter_expected_files -from ayon_core.tests.lib import is_in_tests from openpype_modules.deadline import abstract_submit_deadline from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_harmony_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_harmony_deadline.py index 4d375299fa..c7047edd67 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_harmony_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_harmony_deadline.py @@ -12,7 +12,7 @@ import pyblish.api from openpype_modules.deadline import abstract_submit_deadline from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo -from ayon_core.tests.lib import is_in_tests +from ayon_core.lib import is_in_tests class _ZipFile(ZipFile): diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_cache_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_cache_deadline.py index 96ee80c4d7..a864e15c76 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_cache_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_cache_deadline.py @@ -7,11 +7,11 @@ import pyblish.api from ayon_core.lib import ( TextDef, NumberDef, + is_in_tests, ) from ayon_core.pipeline import ( AYONPyblishPluginMixin ) -from ayon_core.tests.lib import is_in_tests from openpype_modules.deadline import abstract_submit_deadline from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_render_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_render_deadline.py index d7a062c9a6..dbc000a163 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_render_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_houdini_render_deadline.py @@ -6,10 +6,10 @@ from datetime import datetime import pyblish.api from ayon_core.pipeline import AYONPyblishPluginMixin -from ayon_core.tests.lib import is_in_tests from openpype_modules.deadline import abstract_submit_deadline from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo from ayon_core.lib import ( + is_in_tests, BoolDef, NumberDef ) diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py index 2b7a7cf698..79c5c364e0 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -35,14 +35,14 @@ from ayon_core.lib import ( BoolDef, NumberDef, TextDef, - EnumDef + EnumDef, + is_in_tests, ) from ayon_core.hosts.maya.api.lib_rendersettings import RenderSettings from ayon_core.hosts.maya.api.lib import get_attr_in_layer from openpype_modules.deadline import abstract_submit_deadline from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo -from ayon_core.tests.lib import is_in_tests from ayon_core.pipeline.farm.tools import iter_expected_files diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py index ed360d84ae..c4a7a43ce0 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py @@ -3,7 +3,7 @@ import attr from datetime import datetime from ayon_core.pipeline import PublishXmlValidationError -from ayon_core.tests.lib import is_in_tests +from ayon_core.lib import is_in_tests from openpype_modules.deadline import abstract_submit_deadline from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_nuke_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_nuke_deadline.py index 61a334e184..f6fcca4480 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_nuke_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_nuke_deadline.py @@ -10,8 +10,8 @@ import pyblish.api from ayon_core.pipeline.publish import ( AYONPyblishPluginMixin ) -from ayon_core.tests.lib import is_in_tests from ayon_core.lib import ( + is_in_tests, BoolDef, NumberDef ) diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_publish_cache_job.py b/client/ayon_core/modules/deadline/plugins/publish/submit_publish_cache_job.py index 38ea31ab7b..e6b49d4e58 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_publish_cache_job.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_publish_cache_job.py @@ -12,8 +12,7 @@ from ayon_core.client import ( get_last_version_by_subset_name, ) from ayon_core.pipeline import publish -from ayon_core.lib import EnumDef -from ayon_core.tests.lib import is_in_tests +from ayon_core.lib import EnumDef, is_in_tests from ayon_core.pipeline.version_start import get_versioning_start from ayon_core.pipeline.farm.pyblish_functions import ( diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_publish_job.py b/client/ayon_core/modules/deadline/plugins/publish/submit_publish_job.py index c4ab6a2932..89a50700ba 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_publish_job.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_publish_job.py @@ -13,8 +13,7 @@ from ayon_core.client import ( get_last_version_by_subset_name, ) from ayon_core.pipeline import publish -from ayon_core.lib import EnumDef -from ayon_core.tests.lib import is_in_tests +from ayon_core.lib import EnumDef, is_in_tests from ayon_core.pipeline.version_start import get_versioning_start from ayon_core.pipeline.farm.pyblish_functions import ( diff --git a/client/ayon_core/modules/royalrender/lib.py b/client/ayon_core/modules/royalrender/lib.py index d985a39d24..b53c5e6186 100644 --- a/client/ayon_core/modules/royalrender/lib.py +++ b/client/ayon_core/modules/royalrender/lib.py @@ -10,7 +10,12 @@ from datetime import datetime import pyblish.api -from ayon_core.lib import BoolDef, NumberDef, is_running_from_build +from ayon_core.lib import ( + BoolDef, + NumberDef, + is_running_from_build, + is_in_tests, +) from ayon_core.lib.execute import run_ayon_launcher_process from ayon_core.modules.royalrender.api import Api as rrApi from ayon_core.modules.royalrender.rr_job import ( @@ -22,7 +27,6 @@ from ayon_core.modules.royalrender.rr_job import ( from ayon_core.pipeline import AYONPyblishPluginMixin from ayon_core.pipeline.publish import KnownPublishError from ayon_core.pipeline.publish.lib import get_published_workfile_instance -from ayon_core.tests.lib import is_in_tests class BaseCreateRoyalRenderJob(pyblish.api.InstancePlugin, diff --git a/client/ayon_core/pipeline/context_tools.py b/client/ayon_core/pipeline/context_tools.py index 339ef9187f..445e27604d 100644 --- a/client/ayon_core/pipeline/context_tools.py +++ b/client/ayon_core/pipeline/context_tools.py @@ -19,10 +19,10 @@ from ayon_core.client import ( get_asset_name_identifier, get_ayon_server_api_connection, ) +from ayon_core.lib import is_in_tests from ayon_core.lib.events import emit_event from ayon_core.addon import load_addons, AddonsManager from ayon_core.settings import get_project_settings -from ayon_core.tests.lib import is_in_tests from .publish.lib import filter_pyblish_plugins from .anatomy import Anatomy diff --git a/client/ayon_core/plugins/publish/cleanup.py b/client/ayon_core/plugins/publish/cleanup.py index 7bed3269c2..df68af7e57 100644 --- a/client/ayon_core/plugins/publish/cleanup.py +++ b/client/ayon_core/plugins/publish/cleanup.py @@ -5,7 +5,7 @@ import shutil import pyblish.api import re -from ayon_core.tests.lib import is_in_tests +from ayon_core.lib import is_in_tests class CleanUp(pyblish.api.InstancePlugin): diff --git a/client/ayon_core/plugins/publish/collect_scene_version.py b/client/ayon_core/plugins/publish/collect_scene_version.py index 254d3c913d..b04900c74e 100644 --- a/client/ayon_core/plugins/publish/collect_scene_version.py +++ b/client/ayon_core/plugins/publish/collect_scene_version.py @@ -1,8 +1,7 @@ import os import pyblish.api -from ayon_core.lib import get_version_from_path -from ayon_core.tests.lib import is_in_tests +from ayon_core.lib import get_version_from_path, is_in_tests from ayon_core.pipeline import KnownPublishError From 62d76f7b110afa4d931a1cc23ba8119c87dc70cf Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 13 Feb 2024 11:45:46 +0100 Subject: [PATCH 104/112] add missing items to '__all__' --- client/ayon_core/lib/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/ayon_core/lib/__init__.py b/client/ayon_core/lib/__init__.py index e917467e7c..ab6a604adc 100644 --- a/client/ayon_core/lib/__init__.py +++ b/client/ayon_core/lib/__init__.py @@ -230,6 +230,8 @@ __all__ = [ "IniSettingRegistry", "JSONSettingRegistry", + "AYONSecureRegistry", + "AYONSettingsRegistry", "OpenPypeSecureRegistry", "OpenPypeSettingsRegistry", "get_local_site_id", @@ -272,6 +274,7 @@ __all__ = [ "terminal", "get_datetime_data", + "get_timestamp", "get_formatted_current_time", "Logger", From 20487204ba7c89f7310ef52f7af9b879978a1372 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 13 Feb 2024 11:57:39 +0100 Subject: [PATCH 105/112] added 3dsmax imageio conversion back --- client/ayon_core/settings/ayon_settings.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index 35652d5c3c..cea0158159 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -294,6 +294,8 @@ def _convert_3dsmax_project_settings(ayon_settings, output): ayon_max = ayon_settings["max"] + _convert_host_imageio(ayon_max) + output["max"] = ayon_max From 6bb04dfe08c63aa67d4f115f207c8cc8d1aaa428 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 13 Feb 2024 13:06:48 +0100 Subject: [PATCH 106/112] fix 'RenderSettings' key usage --- .../plugins/publish/validate_render_image_rule.py | 11 +++++++---- .../maya/plugins/publish/validate_rendersettings.py | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_render_image_rule.py b/client/ayon_core/hosts/maya/plugins/publish/validate_render_image_rule.py index efc622c416..384d99df1a 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_render_image_rule.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_render_image_rule.py @@ -60,7 +60,10 @@ class ValidateRenderImageRule(pyblish.api.InstancePlugin): ) return staging_dir - return instance.context.data.get('project_settings')\ - .get('maya') \ - .get('RenderSettings') \ - .get('default_render_image_folder') + return ( + instance.context.data + ["project_settings"] + ["maya"] + ["render_settings"] + ["default_render_image_folder"] + ) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_rendersettings.py b/client/ayon_core/hosts/maya/plugins/publish/validate_rendersettings.py index 7f6c0bab1d..78a247b3f2 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_rendersettings.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_rendersettings.py @@ -265,7 +265,7 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin): # load validation definitions from settings settings_lights_flag = instance.context.data["project_settings"].get( "maya", {}).get( - "RenderSettings", {}).get( + "render_settings", {}).get( "enable_all_lights", False) instance_lights_flag = instance.data.get("renderSetupIncludeLights") From 4529a5988950bc3cfa5035f0f397c80edda4adbe Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 13 Feb 2024 14:25:41 +0100 Subject: [PATCH 107/112] fix 'RenderSettings' to 'render_settings' in deadline --- .../modules/deadline/plugins/publish/submit_maya_deadline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py b/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py index b9c858a6a7..a4a5391ce1 100644 --- a/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/client/ayon_core/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -259,7 +259,7 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, default_rs_include_lights = ( instance.context.data['project_settings'] ['maya'] - ['RenderSettings'] + ['render_settings'] ['enable_all_lights'] ) From 40dc41a7a98572d0e3b2ba3dcdb90df85f4ea78c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 13 Feb 2024 16:52:51 +0100 Subject: [PATCH 108/112] remove conversion of traypublisher settings --- client/ayon_core/settings/ayon_settings.py | 52 ---------------------- 1 file changed, 52 deletions(-) diff --git a/client/ayon_core/settings/ayon_settings.py b/client/ayon_core/settings/ayon_settings.py index cea0158159..fe54714f75 100644 --- a/client/ayon_core/settings/ayon_settings.py +++ b/client/ayon_core/settings/ayon_settings.py @@ -551,58 +551,6 @@ def _convert_traypublisher_project_settings(ayon_settings, output): _convert_host_imageio(ayon_traypublisher) - ayon_editorial_simple = ( - ayon_traypublisher["editorial_creators"]["editorial_simple"] - ) - # Subset -> Product type conversion - if "product_type_presets" in ayon_editorial_simple: - family_presets = ayon_editorial_simple.pop("product_type_presets") - for item in family_presets: - item["family"] = item.pop("product_type") - ayon_editorial_simple["family_presets"] = family_presets - - if "shot_metadata_creator" in ayon_editorial_simple: - shot_metadata_creator = ayon_editorial_simple.pop( - "shot_metadata_creator" - ) - if isinstance(shot_metadata_creator["clip_name_tokenizer"], dict): - shot_metadata_creator["clip_name_tokenizer"] = [ - {"name": "_sequence_", "regex": "(sc\\d{3})"}, - {"name": "_shot_", "regex": "(sh\\d{3})"}, - ] - ayon_editorial_simple.update(shot_metadata_creator) - - ayon_editorial_simple["clip_name_tokenizer"] = { - item["name"]: item["regex"] - for item in ayon_editorial_simple["clip_name_tokenizer"] - } - - if "shot_subset_creator" in ayon_editorial_simple: - ayon_editorial_simple.update( - ayon_editorial_simple.pop("shot_subset_creator")) - for item in ayon_editorial_simple["shot_hierarchy"]["parents"]: - item["type"] = item.pop("parent_type") - - # Simple creators - ayon_simple_creators = ayon_traypublisher["simple_creators"] - for item in ayon_simple_creators: - if "product_type" not in item: - break - item["family"] = item.pop("product_type") - - shot_add_tasks = ayon_editorial_simple["shot_add_tasks"] - - # TODO: backward compatibility and remove in future - if isinstance(shot_add_tasks, dict): - shot_add_tasks = [] - - # aggregate shot_add_tasks items - new_shot_add_tasks = { - item["name"]: {"type": item["task_type"]} - for item in shot_add_tasks - } - ayon_editorial_simple["shot_add_tasks"] = new_shot_add_tasks - output["traypublisher"] = ayon_traypublisher From 6c158157cc533f386d1255ebb035cee05612ff04 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 13 Feb 2024 16:53:14 +0100 Subject: [PATCH 109/112] modify SettingsCreator to match new settings --- client/ayon_core/hosts/traypublisher/api/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/traypublisher/api/plugin.py b/client/ayon_core/hosts/traypublisher/api/plugin.py index 77a8f23d2e..d3d7f80e89 100644 --- a/client/ayon_core/hosts/traypublisher/api/plugin.py +++ b/client/ayon_core/hosts/traypublisher/api/plugin.py @@ -311,7 +311,7 @@ class SettingsCreator(TrayPublishCreator): @classmethod def from_settings(cls, item_data): identifier = item_data["identifier"] - family = item_data["family"] + family = item_data["product_type"] if not identifier: identifier = "settings_{}".format(family) return type( From 197d3d6786a320289e9765c3ac4152bc36648325 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 13 Feb 2024 16:55:45 +0100 Subject: [PATCH 110/112] change how setting are applied in editorial creator --- .../hosts/traypublisher/api/editorial.py | 24 +++++++----- .../plugins/create/create_editorial.py | 39 ++++++++----------- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/client/ayon_core/hosts/traypublisher/api/editorial.py b/client/ayon_core/hosts/traypublisher/api/editorial.py index d84a7200c8..2c77a66ac7 100644 --- a/client/ayon_core/hosts/traypublisher/api/editorial.py +++ b/client/ayon_core/hosts/traypublisher/api/editorial.py @@ -16,25 +16,31 @@ class ShotMetadataSolver: NO_DECOR_PATERN = re.compile(r"\{([a-z]*?)\}") - # presets - clip_name_tokenizer = None - shot_rename = True - shot_hierarchy = None - shot_add_tasks = None + def __init__(self, logger): + self.clip_name_tokenizer = [] + self.shot_rename = { + "enabled": False, + "shot_rename_template": "", + } + self.shot_hierarchy = { + "enabled": False, + "parents": [], + "parents_path": "", + } + self.shot_add_tasks = [] + self.log = logger - def __init__( + def update_data( self, clip_name_tokenizer, shot_rename, shot_hierarchy, - shot_add_tasks, - logger + shot_add_tasks ): self.clip_name_tokenizer = clip_name_tokenizer self.shot_rename = shot_rename self.shot_hierarchy = shot_hierarchy self.shot_add_tasks = shot_add_tasks - self.log = logger def _rename_template(self, data): """Shot renaming function diff --git a/client/ayon_core/hosts/traypublisher/plugins/create/create_editorial.py b/client/ayon_core/hosts/traypublisher/plugins/create/create_editorial.py index 51a67a871e..791d989070 100644 --- a/client/ayon_core/hosts/traypublisher/plugins/create/create_editorial.py +++ b/client/ayon_core/hosts/traypublisher/plugins/create/create_editorial.py @@ -174,35 +174,28 @@ Supporting publishing new shots to project or updating already created. Publishing will create OTIO file. """ icon = "fa.file" + product_type_presets = [] - def __init__( - self, project_settings, *args, **kwargs - ): - super(EditorialSimpleCreator, self).__init__( - project_settings, *args, **kwargs - ) + def __init__(self, *args, **kwargs): + self._shot_metadata_solver = ShotMetadataSolver(self.log) + super(EditorialSimpleCreator, self).__init__(*args, **kwargs) + + def apply_settings(self, project_settings): editorial_creators = deepcopy( project_settings["traypublisher"]["editorial_creators"] ) - # get this creator settings by identifier - self._creator_settings = editorial_creators.get(self.identifier) + creator_settings = editorial_creators.get(self.identifier) - clip_name_tokenizer = self._creator_settings["clip_name_tokenizer"] - shot_rename = self._creator_settings["shot_rename"] - shot_hierarchy = self._creator_settings["shot_hierarchy"] - shot_add_tasks = self._creator_settings["shot_add_tasks"] - - self._shot_metadata_solver = ShotMetadataSolver( - clip_name_tokenizer, - shot_rename, - shot_hierarchy, - shot_add_tasks, - self.log + self._shot_metadata_solver.update_data( + creator_settings["clip_name_tokenizer"], + creator_settings["shot_rename"], + creator_settings["shot_hierarchy"], + creator_settings["shot_add_tasks"] ) - - # try to set main attributes from settings - if self._creator_settings.get("default_variants"): - self.default_variants = self._creator_settings["default_variants"] + self.product_type_presets = creator_settings["product_type_presets"] + default_variants = creator_settings.get("default_variants") + if default_variants: + self.default_variants = default_variants def create(self, subset_name, instance_data, pre_create_data): allowed_family_presets = self._get_allowed_family_presets( From 0669ef30c8560a6d19a03376cf8f443e3d33db92 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 13 Feb 2024 16:56:03 +0100 Subject: [PATCH 111/112] use new settings structure in ShotMetadataSolver --- .../hosts/traypublisher/api/editorial.py | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/client/ayon_core/hosts/traypublisher/api/editorial.py b/client/ayon_core/hosts/traypublisher/api/editorial.py index 2c77a66ac7..6153bc5752 100644 --- a/client/ayon_core/hosts/traypublisher/api/editorial.py +++ b/client/ayon_core/hosts/traypublisher/api/editorial.py @@ -92,7 +92,9 @@ class ShotMetadataSolver: search_text = parent_name + clip_name - for token_key, pattern in self.clip_name_tokenizer.items(): + for clip_name_item in self.clip_name_tokenizer: + token_key = clip_name_item["name"] + pattern = clip_name_item["regex"] p = re.compile(pattern) match = p.findall(search_text) if not match: @@ -143,11 +145,11 @@ class ShotMetadataSolver: )) _parent_tokens_type = { - parent_token["name"]: parent_token["type"] + parent_token["name"]: parent_token["parent_type"] for parent_token in hierarchy_parents } for _index, _parent in enumerate( - shot_hierarchy["parents_path"].split("/") + shot_hierarchy["parents_path"].split("/") ): # format parent token with value which is formatted try: @@ -268,22 +270,22 @@ class ShotMetadataSolver: """ tasks_to_add = {} - project_tasks = project_doc["config"]["tasks"] - for task_name, task_data in self.shot_add_tasks.items(): - _task_data = deepcopy(task_data) + project_task_types = project_doc["config"]["tasks"] + for task_item in self.shot_add_tasks: + task_name = task_item["name"] + task_type = task_item["task_type"] # check if task type in project task types - if _task_data["type"] in project_tasks.keys(): - tasks_to_add[task_name] = _task_data - else: + if task_type not in project_task_types.keys(): raise KeyError( "Missing task type `{}` for `{}` is not" " existing in `{}``".format( - _task_data["type"], + task_type, task_name, - list(project_tasks.keys()) + list(project_task_types.keys()) ) ) + tasks_to_add[task_name] = {"type": task_type} return tasks_to_add From 551184e3c23662b2b9197b0ebd8f8da528675c12 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 13 Feb 2024 16:56:18 +0100 Subject: [PATCH 112/112] change variables used during create editorial --- .../plugins/create/create_editorial.py | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/client/ayon_core/hosts/traypublisher/plugins/create/create_editorial.py b/client/ayon_core/hosts/traypublisher/plugins/create/create_editorial.py index 791d989070..d6501e65a2 100644 --- a/client/ayon_core/hosts/traypublisher/plugins/create/create_editorial.py +++ b/client/ayon_core/hosts/traypublisher/plugins/create/create_editorial.py @@ -198,15 +198,18 @@ or updating already created. Publishing will create OTIO file. self.default_variants = default_variants def create(self, subset_name, instance_data, pre_create_data): - allowed_family_presets = self._get_allowed_family_presets( + allowed_product_type_presets = self._get_allowed_product_type_presets( pre_create_data) + product_types = { + item["product_type"] + for item in self.product_type_presets + } clip_instance_properties = { - k: v for k, v in pre_create_data.items() + k: v + for k, v in pre_create_data.items() if k != "sequence_filepath_data" - if k not in [ - i["family"] for i in self._creator_settings["family_presets"] - ] + if k not in product_types } asset_name = instance_data["folderPath"] @@ -248,7 +251,7 @@ or updating already created. Publishing will create OTIO file. otio_timeline, media_path, clip_instance_properties, - allowed_family_presets, + allowed_product_type_presets, os.path.basename(seq_path), first_otio_timeline ) @@ -348,7 +351,7 @@ or updating already created. Publishing will create OTIO file. otio_timeline, media_path, instance_data, - family_presets, + product_type_presets, sequence_file_name, first_otio_timeline=None ): @@ -358,7 +361,7 @@ or updating already created. Publishing will create OTIO file. otio_timeline (otio.Timeline): otio timeline object media_path (str): media file path string instance_data (dict): clip instance data - family_presets (list): list of dict settings subset presets + product_type_presets (list): list of dict settings subset presets """ tracks = [ @@ -404,17 +407,17 @@ or updating already created. Publishing will create OTIO file. "instance_id": None } - for _fpreset in family_presets: + for product_type_preset in product_type_presets: # exclude audio family if no audio stream if ( - _fpreset["family"] == "audio" + product_type_preset["product_type"] == "audio" and not media_data.get("audio") ): continue instance = self._make_subset_instance( otio_clip, - _fpreset, + product_type_preset, deepcopy(base_instance_data), parenting_data ) @@ -526,7 +529,7 @@ or updating already created. Publishing will create OTIO file. def _make_subset_instance( self, otio_clip, - preset, + product_type_preset, instance_data, parenting_data ): @@ -534,16 +537,16 @@ or updating already created. Publishing will create OTIO file. Args: otio_clip (otio.Clip): otio clip object - preset (dict): single family preset + product_type_preset (dict): single family preset instance_data (dict): instance data parenting_data (dict): shot instance parent data Returns: CreatedInstance: creator instance object """ - family = preset["family"] + family = product_type_preset["product_type"] label = self._make_subset_naming( - preset, + product_type_preset, instance_data ) instance_data["label"] = label @@ -562,11 +565,11 @@ or updating already created. Publishing will create OTIO file. else: # add review family if defined instance_data.update({ - "outputFileType": preset["output_file_type"], + "outputFileType": product_type_preset["output_file_type"], "parent_instance_id": parenting_data["instance_id"], "creator_attributes": { "parent_instance": parenting_data["instance_label"], - "add_review_family": preset.get("review") + "add_review_family": product_type_preset.get("review") } }) @@ -578,15 +581,11 @@ or updating already created. Publishing will create OTIO file. return c_instance - def _make_subset_naming( - self, - preset, - instance_data - ): + def _make_subset_naming(self, product_type_preset, instance_data): """ Subset name maker Args: - preset (dict): single preset item + product_type_preset (dict): single preset item instance_data (dict): instance data Returns: @@ -595,10 +594,10 @@ or updating already created. Publishing will create OTIO file. asset_name = instance_data["creator_attributes"]["folderPath"] variant_name = instance_data["variant"] - family = preset["family"] + family = product_type_preset["product_type"] # get variant name from preset or from inheritance - _variant_name = preset.get("variant") or variant_name + _variant_name = product_type_preset.get("variant") or variant_name # subset name subset_name = "{}{}".format( @@ -756,7 +755,7 @@ or updating already created. Publishing will create OTIO file. "sourceOut": int(source_out) } - def _get_allowed_family_presets(self, pre_create_data): + def _get_allowed_product_type_presets(self, pre_create_data): """ Filter out allowed family presets. Args: @@ -766,10 +765,11 @@ or updating already created. Publishing will create OTIO file. list: lit of dict with preset items """ return [ - {"family": "shot"}, + {"product_type": "shot"}, *[ - preset for preset in self._creator_settings["family_presets"] - if pre_create_data[preset["family"]] + preset + for preset in self.product_type_presets + if pre_create_data[preset["product_type"]] ] ] @@ -846,8 +846,8 @@ or updating already created. Publishing will create OTIO file. ] # add variants swithers attr_defs.extend( - BoolDef(_var["family"], label=_var["family"]) - for _var in self._creator_settings["family_presets"] + BoolDef(item["product_type"], label=item["product_type"]) + for item in self.product_type_presets ) attr_defs.append(UISeparatorDef())