From 361d21eff6afb403781e92fa32fc6588af0a9257 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Sun, 31 Dec 2023 14:20:37 +0200 Subject: [PATCH 001/111] =?UTF-8?q?=F0=9F=93=B8=20allow=20taking=20snapsho?= =?UTF-8?q?ots=20from=20houdini?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openpype/hosts/houdini/api/lib.py | 70 +++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/openpype/hosts/houdini/api/lib.py b/openpype/hosts/houdini/api/lib.py index edd50f10c1..7b09d2baf2 100644 --- a/openpype/hosts/houdini/api/lib.py +++ b/openpype/hosts/houdini/api/lib.py @@ -1054,3 +1054,73 @@ def add_self_publish_button(node): template = node.parmTemplateGroup() template.insertBefore((0,), button_parm) node.setParmTemplateGroup(template) + + +def getSceneViewer(): + """ + return an instance of a visible viewport. + There may be many, some could be closed, any visible are current + """ + panes = hou.ui.paneTabs() + panes = [x for x in panes if x.type() == hou.paneTabType.SceneViewer] + panes = sorted(panes, key=lambda x: x.isCurrentTab()) + if panes: + return panes[-1] + else: + return None + + +def sceneview_snapshoot( + filename="$HIP/thumbnails/$HIPNAME.$F4.jpg", + fstart=None, + fend=None + ): + """ + It takes snapshoot of your scene view fot the given frame range. + So, it's capable of generating snapshoots image sequence. + It works in different Houdini context e.g. Objects, Solaris + + Example: + from openpype.hosts.houdini.api import lib + lib.sceneview_snapshoot() + + Notes: + .png output will render poorly, so use .jpg. + + How it works: + Get the current sceneviewer (may be more than one or hidden) + and screengrab the perspective viewport to a file in the + publish location to be picked up with the publish. + + Credits: + https://www.sidefx.com/forum/topic/42808/?page=1#post-354796 + + Args: + filename (str): filename with the desired full path. + fstart (int): the frame at which snapshooting starts + fend (int): the frame at which snapshooting ends + """ + + try: + + if fstart is None: + fstart = hou.frame() + if fend is None: + fend = fstart = hou.frame() + + sceneview = getSceneViewer() + if not sceneview: + log.debug("No SceneViewers detected.") + return + viewport = sceneview.curViewport() + + # this will open an mplay window to show the result + flip_settings = sceneview.flipbookSettings().stash() + flip_settings.frameRange( (fstart, fend) ) + flip_settings.output(filename) + flip_settings.outputToMPlay(False) + sceneview.flipbook(viewport, flip_settings) + log.debug("A snap of sceneview has been saved to: {}".format(filename)) + + except Exception as e: + log.debug(e) From 5658b109259a55a93edbb30f2e0c7f35c64a6201 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Sun, 31 Dec 2023 14:31:31 +0200 Subject: [PATCH 002/111] =?UTF-8?q?=F0=9F=90=BE=20Resolve=20Hound?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openpype/hosts/houdini/api/lib.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/houdini/api/lib.py b/openpype/hosts/houdini/api/lib.py index 7b09d2baf2..1b172595c8 100644 --- a/openpype/hosts/houdini/api/lib.py +++ b/openpype/hosts/houdini/api/lib.py @@ -1073,8 +1073,7 @@ def getSceneViewer(): def sceneview_snapshoot( filename="$HIP/thumbnails/$HIPNAME.$F4.jpg", fstart=None, - fend=None - ): + fend=None): """ It takes snapshoot of your scene view fot the given frame range. So, it's capable of generating snapshoots image sequence. @@ -1116,7 +1115,7 @@ def sceneview_snapshoot( # this will open an mplay window to show the result flip_settings = sceneview.flipbookSettings().stash() - flip_settings.frameRange( (fstart, fend) ) + flip_settings.frameRange((fstart, fend)) flip_settings.output(filename) flip_settings.outputToMPlay(False) sceneview.flipbook(viewport, flip_settings) From ab61e755e99773d3f4997c4fcbf27250e47d8262 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Wed, 3 Jan 2024 17:22:52 +0200 Subject: [PATCH 003/111] =?UTF-8?q?=F0=9F=93=9D=20Kuba's=20and=20Big=20Roy?= =?UTF-8?q?'s=20comments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openpype/hosts/houdini/api/lib.py | 59 +++++++++++++++---------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/openpype/hosts/houdini/api/lib.py b/openpype/hosts/houdini/api/lib.py index 1b172595c8..db9955694d 100644 --- a/openpype/hosts/houdini/api/lib.py +++ b/openpype/hosts/houdini/api/lib.py @@ -1056,7 +1056,7 @@ def add_self_publish_button(node): node.setParmTemplateGroup(template) -def getSceneViewer(): +def get_scene_viewer(): """ return an instance of a visible viewport. There may be many, some could be closed, any visible are current @@ -1066,12 +1066,13 @@ def getSceneViewer(): panes = sorted(panes, key=lambda x: x.isCurrentTab()) if panes: return panes[-1] - else: - return None + + return None -def sceneview_snapshoot( - filename="$HIP/thumbnails/$HIPNAME.$F4.jpg", +def sceneview_snapshot( + sceneview, + filepath="$HIP/thumbnails/$HIPNAME.$F4.jpg", fstart=None, fend=None): """ @@ -1081,7 +1082,8 @@ def sceneview_snapshoot( Example: from openpype.hosts.houdini.api import lib - lib.sceneview_snapshoot() + sceneview = hou.ui.paneTabOfType(hou.paneTabType.SceneViewer) + lib.sceneview_snapshot(sceneview) Notes: .png output will render poorly, so use .jpg. @@ -1095,31 +1097,28 @@ def sceneview_snapshoot( https://www.sidefx.com/forum/topic/42808/?page=1#post-354796 Args: - filename (str): filename with the desired full path. - fstart (int): the frame at which snapshooting starts - fend (int): the frame at which snapshooting ends + sceneview (hou.SceneViewer): The scene view pane from which you want + to take a snapshot. + filepath (str): thumbnail filepath. + fstart (int): the frame at which snapshot starts + fend (int): the frame at which snapshot ends """ - try: + if fstart is None: + fstart = hou.frame() + if fend is None: + fend = fstart - if fstart is None: - fstart = hou.frame() - if fend is None: - fend = fstart = hou.frame() + if not isinstance(sceneview, hou.SceneViewer): + log.debug("Wrong Input. {} is not of type hou.SceneViewer." + .format(sceneview)) + return + viewport = sceneview.curViewport() - sceneview = getSceneViewer() - if not sceneview: - log.debug("No SceneViewers detected.") - return - viewport = sceneview.curViewport() - - # this will open an mplay window to show the result - flip_settings = sceneview.flipbookSettings().stash() - flip_settings.frameRange((fstart, fend)) - flip_settings.output(filename) - flip_settings.outputToMPlay(False) - sceneview.flipbook(viewport, flip_settings) - log.debug("A snap of sceneview has been saved to: {}".format(filename)) - - except Exception as e: - log.debug(e) + # this will open an mplay window to show the result + flip_settings = sceneview.flipbookSettings().stash() + flip_settings.frameRange((fstart, fend)) + flip_settings.output(filepath) + flip_settings.outputToMPlay(False) + sceneview.flipbook(viewport, flip_settings) + log.debug("A snap of sceneview has been saved to: {}".format(filepath)) From a27c7bf8fd99effd8374075b07e1f036467964a4 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Wed, 3 Jan 2024 17:40:49 +0200 Subject: [PATCH 004/111] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20=20fix=20typo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openpype/hosts/houdini/api/lib.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/houdini/api/lib.py b/openpype/hosts/houdini/api/lib.py index db9955694d..7e07bce2d1 100644 --- a/openpype/hosts/houdini/api/lib.py +++ b/openpype/hosts/houdini/api/lib.py @@ -1076,8 +1076,8 @@ def sceneview_snapshot( fstart=None, fend=None): """ - It takes snapshoot of your scene view fot the given frame range. - So, it's capable of generating snapshoots image sequence. + It takes snapshot of your scene view fot the given frame range. + So, it's capable of generating snapshots image sequence. It works in different Houdini context e.g. Objects, Solaris Example: @@ -1121,4 +1121,4 @@ def sceneview_snapshot( flip_settings.output(filepath) flip_settings.outputToMPlay(False) sceneview.flipbook(viewport, flip_settings) - log.debug("A snap of sceneview has been saved to: {}".format(filepath)) + log.debug("A snapshot of sceneview has been saved to: {}".format(filepath)) From b6a432d39363e00894ecb0f3fc4a95586d6d14c8 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Wed, 3 Jan 2024 21:50:48 +0200 Subject: [PATCH 005/111] =?UTF-8?q?=F0=9F=96=BC=EF=B8=8F=20=20Extract=20ac?= =?UTF-8?q?tive=20view=20as=20thumbnail?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../publish/extract_active_view_thumbnail.py | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 openpype/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py diff --git a/openpype/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py b/openpype/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py new file mode 100644 index 0000000000..40b0dac02e --- /dev/null +++ b/openpype/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py @@ -0,0 +1,58 @@ +import os + +import pyblish.api + +from openpype.pipeline import publish, registered_host +from openpype.hosts.houdini.api import lib +from openpype.hosts.houdini.api.pipeline import IS_HEADLESS + +import hou + + +class ExtractActiveViewThumbnail(publish.Extractor): + """Set instance thumbnail to a screengrab of current active viewport. + + This makes it so that if an instance does not have a thumbnail set yet that + it will get a thumbnail of the currently active view at the time of + publishing as a fallback. + + """ + order = pyblish.api.ExtractorOrder + 0.49 + label = "Extract Active View Thumbnail" + families = ["workfile"] + hosts = ["houdini"] + + def process(self, instance): + if IS_HEADLESS: + self.log.debug( + "Skip extraction of active view thumbnail, due to being in" + "headless mode." + ) + return + + thumbnail = instance.data.get("thumbnailPath") + self.log.debug(thumbnail) + if not thumbnail: + view_thumbnail = self.get_view_thumbnail(instance) + if not view_thumbnail: + return + + self.log.debug("Setting instance thumbnail path to: {}".format( + view_thumbnail + )) + instance.data["thumbnailPath"] = view_thumbnail + + def get_view_thumbnail(self, instance): + + host = registered_host() + current_filepath = host.get_current_workfile() + if not current_filepath: + self.log.error("No current workfile path. Thumbnail generation skipped") + return + + thumbnail_path = "{}_thumbnail.jpg".format( + current_filepath.rsplit('.', 1)[0]) + sceneview = lib.get_scene_viewer() + lib.sceneview_snapshot(sceneview, thumbnail_path) + + return thumbnail_path From 08ccdfcea8593776f6898b659bf5c3d606b89770 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Wed, 3 Jan 2024 21:52:33 +0200 Subject: [PATCH 006/111] =?UTF-8?q?=F0=9F=A6=B4=20Resolve=20Hound?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugins/publish/extract_active_view_thumbnail.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py b/openpype/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py index 40b0dac02e..b326f6918d 100644 --- a/openpype/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py +++ b/openpype/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py @@ -1,13 +1,9 @@ -import os - import pyblish.api from openpype.pipeline import publish, registered_host from openpype.hosts.houdini.api import lib from openpype.hosts.houdini.api.pipeline import IS_HEADLESS -import hou - class ExtractActiveViewThumbnail(publish.Extractor): """Set instance thumbnail to a screengrab of current active viewport. @@ -47,7 +43,8 @@ class ExtractActiveViewThumbnail(publish.Extractor): host = registered_host() current_filepath = host.get_current_workfile() if not current_filepath: - self.log.error("No current workfile path. Thumbnail generation skipped") + self.log.error("No current workfile path. " + "Thumbnail generation skipped") return thumbnail_path = "{}_thumbnail.jpg".format( From 0e7efc5da979d3cfdaa12cdfa31b926569ff2ea0 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Thu, 4 Jan 2024 18:56:59 +0200 Subject: [PATCH 007/111] Kuba's comments - Better Code --- openpype/hosts/houdini/api/lib.py | 18 +++++++++--------- .../publish/extract_active_view_thumbnail.py | 17 ++++++----------- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/openpype/hosts/houdini/api/lib.py b/openpype/hosts/houdini/api/lib.py index 7e07bce2d1..318de5f538 100644 --- a/openpype/hosts/houdini/api/lib.py +++ b/openpype/hosts/houdini/api/lib.py @@ -1073,8 +1073,8 @@ def get_scene_viewer(): def sceneview_snapshot( sceneview, filepath="$HIP/thumbnails/$HIPNAME.$F4.jpg", - fstart=None, - fend=None): + frame_start=None, + frame_end=None): """ It takes snapshot of your scene view fot the given frame range. So, it's capable of generating snapshots image sequence. @@ -1100,14 +1100,14 @@ def sceneview_snapshot( sceneview (hou.SceneViewer): The scene view pane from which you want to take a snapshot. filepath (str): thumbnail filepath. - fstart (int): the frame at which snapshot starts - fend (int): the frame at which snapshot ends + frame_start (int): the frame at which snapshot starts + frame_end (int): the frame at which snapshot ends """ - if fstart is None: - fstart = hou.frame() - if fend is None: - fend = fstart + if frame_start is None: + frame_start = hou.frame() + if frame_end is None: + frame_end = frame_start if not isinstance(sceneview, hou.SceneViewer): log.debug("Wrong Input. {} is not of type hou.SceneViewer." @@ -1117,7 +1117,7 @@ def sceneview_snapshot( # this will open an mplay window to show the result flip_settings = sceneview.flipbookSettings().stash() - flip_settings.frameRange((fstart, fend)) + flip_settings.frameRange((frame_start, frame_end)) flip_settings.output(filepath) flip_settings.outputToMPlay(False) sceneview.flipbook(viewport, flip_settings) diff --git a/openpype/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py b/openpype/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py index b326f6918d..82976bdf83 100644 --- a/openpype/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py +++ b/openpype/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py @@ -1,6 +1,6 @@ import pyblish.api - -from openpype.pipeline import publish, registered_host +import tempfile +from openpype.pipeline import publish from openpype.hosts.houdini.api import lib from openpype.hosts.houdini.api.pipeline import IS_HEADLESS @@ -27,7 +27,6 @@ class ExtractActiveViewThumbnail(publish.Extractor): return thumbnail = instance.data.get("thumbnailPath") - self.log.debug(thumbnail) if not thumbnail: view_thumbnail = self.get_view_thumbnail(instance) if not view_thumbnail: @@ -40,15 +39,11 @@ class ExtractActiveViewThumbnail(publish.Extractor): def get_view_thumbnail(self, instance): - host = registered_host() - current_filepath = host.get_current_workfile() - if not current_filepath: - self.log.error("No current workfile path. " - "Thumbnail generation skipped") - return + with tempfile.NamedTemporaryFile("w", suffix=".jpg") as tmp: + thumbnail_path = tmp.name + + instance.context.data["cleanupFullPaths"].append(thumbnail_path) - thumbnail_path = "{}_thumbnail.jpg".format( - current_filepath.rsplit('.', 1)[0]) sceneview = lib.get_scene_viewer() lib.sceneview_snapshot(sceneview, thumbnail_path) From 435cd9cce1e6a95fd5074aef1282866b8c126ef8 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Fri, 5 Jan 2024 17:04:36 +0200 Subject: [PATCH 008/111] =?UTF-8?q?=E2=9E=96=20Remove=20unnecessary=20comm?= =?UTF-8?q?ent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openpype/hosts/houdini/api/lib.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/houdini/api/lib.py b/openpype/hosts/houdini/api/lib.py index 318de5f538..bd15b8b83d 100644 --- a/openpype/hosts/houdini/api/lib.py +++ b/openpype/hosts/houdini/api/lib.py @@ -1115,7 +1115,6 @@ def sceneview_snapshot( return viewport = sceneview.curViewport() - # this will open an mplay window to show the result flip_settings = sceneview.flipbookSettings().stash() flip_settings.frameRange((frame_start, frame_end)) flip_settings.output(filepath) From 3ffb6db49fe161e1790c039142bc2236b492265a Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Tue, 9 Jan 2024 10:01:38 +0200 Subject: [PATCH 009/111] =?UTF-8?q?=F0=9F=93=9D=20Stick=20to=20Google=20do?= =?UTF-8?q?c=20string=20style?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openpype/hosts/houdini/api/lib.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/houdini/api/lib.py b/openpype/hosts/houdini/api/lib.py index bd15b8b83d..33b74ca6b9 100644 --- a/openpype/hosts/houdini/api/lib.py +++ b/openpype/hosts/houdini/api/lib.py @@ -1058,7 +1058,8 @@ def add_self_publish_button(node): def get_scene_viewer(): """ - return an instance of a visible viewport. + Return an instance of a visible viewport. + There may be many, some could be closed, any visible are current """ panes = hou.ui.paneTabs() @@ -1075,8 +1076,9 @@ def sceneview_snapshot( filepath="$HIP/thumbnails/$HIPNAME.$F4.jpg", frame_start=None, frame_end=None): - """ - It takes snapshot of your scene view fot the given frame range. + """Take a snapshot of your scene view. + + It takes snapshot of your scene view for the given frame range. So, it's capable of generating snapshots image sequence. It works in different Houdini context e.g. Objects, Solaris From 62020ca29d2ec75b7e545fbf3d1a0b835dd86e98 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Mon, 4 Mar 2024 15:46:28 +0200 Subject: [PATCH 010/111] update 'sceneview_snapshot' docstring --- client/ayon_core/hosts/houdini/api/lib.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/hosts/houdini/api/lib.py b/client/ayon_core/hosts/houdini/api/lib.py index b9a92fab0c..3cab61ff26 100644 --- a/client/ayon_core/hosts/houdini/api/lib.py +++ b/client/ayon_core/hosts/houdini/api/lib.py @@ -1083,9 +1083,11 @@ def sceneview_snapshot( It works in different Houdini context e.g. Objects, Solaris Example: - from openpype.hosts.houdini.api import lib - sceneview = hou.ui.paneTabOfType(hou.paneTabType.SceneViewer) - lib.sceneview_snapshot(sceneview) + This is how the function can be used:: + + from ayon_core.hosts.houdini.api import lib + sceneview = hou.ui.paneTabOfType(hou.paneTabType.SceneViewer) + lib.sceneview_snapshot(sceneview) Notes: .png output will render poorly, so use .jpg. From ab6d89c8c29c0dd883cbece387f8a9f872a3aaa3 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Mon, 4 Mar 2024 16:01:08 +0200 Subject: [PATCH 011/111] wrap lib.sceneview_snapshot() into tempfile.NamedTemporaryFile --- .../plugins/publish/extract_active_view_thumbnail.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/client/ayon_core/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py b/client/ayon_core/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py index 27c4493f44..392201e865 100644 --- a/client/ayon_core/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py +++ b/client/ayon_core/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py @@ -39,12 +39,10 @@ class ExtractActiveViewThumbnail(publish.Extractor): def get_view_thumbnail(self, instance): - with tempfile.NamedTemporaryFile("w", suffix=".jpg") as tmp: + sceneview = lib.get_scene_viewer() + with tempfile.NamedTemporaryFile("w", suffix=".jpg", delete=False) as tmp: + lib.sceneview_snapshot(sceneview, tmp.name) thumbnail_path = tmp.name instance.context.data["cleanupFullPaths"].append(thumbnail_path) - - sceneview = lib.get_scene_viewer() - lib.sceneview_snapshot(sceneview, thumbnail_path) - return thumbnail_path From 8320ab7b5138fdc57f352e708738cbce0f40c424 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Mon, 4 Mar 2024 16:46:34 +0200 Subject: [PATCH 012/111] Houdini: add a warning if no sceneview was found --- .../houdini/plugins/publish/extract_active_view_thumbnail.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/ayon_core/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py b/client/ayon_core/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py index 392201e865..1be8cb7440 100644 --- a/client/ayon_core/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py +++ b/client/ayon_core/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py @@ -40,6 +40,11 @@ class ExtractActiveViewThumbnail(publish.Extractor): def get_view_thumbnail(self, instance): sceneview = lib.get_scene_viewer() + if sceneview is None: + self.log.warning("Skipping Extract Active View Thumbnail" + " because no scene view was detected.") + return + with tempfile.NamedTemporaryFile("w", suffix=".jpg", delete=False) as tmp: lib.sceneview_snapshot(sceneview, tmp.name) thumbnail_path = tmp.name From d1364d2c15de6b66dcd985f5f514c669352c2179 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 13 Mar 2024 20:31:14 +0800 Subject: [PATCH 013/111] bug fix on getting aov expected files when global aov mode disabled --- .../hosts/maya/api/lib_renderproducts.py | 112 +++++++++--------- 1 file changed, 58 insertions(+), 54 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/lib_renderproducts.py b/client/ayon_core/hosts/maya/api/lib_renderproducts.py index 7f26145e1d..63071c0053 100644 --- a/client/ayon_core/hosts/maya/api/lib_renderproducts.py +++ b/client/ayon_core/hosts/maya/api/lib_renderproducts.py @@ -1136,68 +1136,72 @@ class RenderProductsRedshift(ARenderProducts): light_groups_enabled = False has_beauty_aov = False colorspace = lib.get_color_management_output_transform() - for aov in aovs: - enabled = self._get_attr(aov, "enabled") - if not enabled: - continue + global_aov_enabled = bool( + self._get_attr("redshiftOptions.aovGlobalEnableMode") + ) + if global_aov_enabled: + for aov in aovs: + enabled = self._get_attr(aov, "enabled") + if not enabled: + continue - aov_type = self._get_attr(aov, "aovType") - if self.multipart and aov_type not in self.unmerged_aovs: - continue + aov_type = self._get_attr(aov, "aovType") + if self.multipart and aov_type not in self.unmerged_aovs: + continue - # Any AOVs that still get processed, like Cryptomatte - # by themselves are not multipart files. + # Any AOVs that still get processed, like Cryptomatte + # by themselves are not multipart files. - # Redshift skips rendering of masterlayer without AOV suffix - # when a Beauty AOV is rendered. It overrides the main layer. - if aov_type == "Beauty": - has_beauty_aov = True + # Redshift skips rendering of masterlayer without AOV suffix + # when a Beauty AOV is rendered. It overrides the main layer. + if aov_type == "Beauty": + has_beauty_aov = True - aov_name = self._get_attr(aov, "name") + aov_name = self._get_attr(aov, "name") - # Support light Groups - light_groups = [] - if self._get_attr(aov, "supportsLightGroups"): - all_light_groups = self._get_attr(aov, "allLightGroups") - if all_light_groups: - # All light groups is enabled - light_groups = self._get_redshift_light_groups() - else: - value = self._get_attr(aov, "lightGroupList") - # note: string value can return None when never set - if value: - selected_light_groups = value.strip().split() - light_groups = selected_light_groups + # Support light Groups + light_groups = [] + if self._get_attr(aov, "supportsLightGroups"): + all_light_groups = self._get_attr(aov, "allLightGroups") + if all_light_groups: + # All light groups is enabled + light_groups = self._get_redshift_light_groups() + else: + value = self._get_attr(aov, "lightGroupList") + # note: string value can return None when never set + if value: + selected_light_groups = value.strip().split() + light_groups = selected_light_groups - for light_group in light_groups: - aov_light_group_name = "{}_{}".format(aov_name, - light_group) - for camera in cameras: - product = RenderProduct( - productName=aov_light_group_name, - aov=aov_name, - ext=ext, - multipart=False, - camera=camera, - driver=aov, - colorspace=colorspace) - products.append(product) + for light_group in light_groups: + aov_light_group_name = "{}_{}".format(aov_name, + light_group) + for camera in cameras: + product = RenderProduct( + productName=aov_light_group_name, + aov=aov_name, + ext=ext, + multipart=False, + camera=camera, + driver=aov, + colorspace=colorspace) + products.append(product) - if light_groups: - light_groups_enabled = True + if light_groups: + light_groups_enabled = True - # Redshift AOV Light Select always renders the global AOV - # even when light groups are present so we don't need to - # exclude it when light groups are active - for camera in cameras: - product = RenderProduct(productName=aov_name, - aov=aov_name, - ext=ext, - multipart=False, - camera=camera, - driver=aov, - colorspace=colorspace) - products.append(product) + # Redshift AOV Light Select always renders the global AOV + # even when light groups are present so we don't need to + # exclude it when light groups are active + for camera in cameras: + product = RenderProduct(productName=aov_name, + aov=aov_name, + ext=ext, + multipart=False, + camera=camera, + driver=aov, + colorspace=colorspace) + products.append(product) # When a Beauty AOV is added manually, it will be rendered as # 'Beauty_other' in file name and "standard" beauty will have From 024f6f5163a72722f7bed1d2062c45cf02332d80 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 13 Mar 2024 21:22:23 +0800 Subject: [PATCH 014/111] return products instead if global aov mode is disabled --- .../hosts/maya/api/lib_renderproducts.py | 112 +++++++++--------- 1 file changed, 57 insertions(+), 55 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/lib_renderproducts.py b/client/ayon_core/hosts/maya/api/lib_renderproducts.py index 63071c0053..28981e1187 100644 --- a/client/ayon_core/hosts/maya/api/lib_renderproducts.py +++ b/client/ayon_core/hosts/maya/api/lib_renderproducts.py @@ -1139,69 +1139,71 @@ class RenderProductsRedshift(ARenderProducts): global_aov_enabled = bool( self._get_attr("redshiftOptions.aovGlobalEnableMode") ) - if global_aov_enabled: - for aov in aovs: - enabled = self._get_attr(aov, "enabled") - if not enabled: - continue + if not global_aov_enabled: + return products - aov_type = self._get_attr(aov, "aovType") - if self.multipart and aov_type not in self.unmerged_aovs: - continue + for aov in aovs: + enabled = self._get_attr(aov, "enabled") + if not enabled: + continue - # Any AOVs that still get processed, like Cryptomatte - # by themselves are not multipart files. + aov_type = self._get_attr(aov, "aovType") + if self.multipart and aov_type not in self.unmerged_aovs: + continue - # Redshift skips rendering of masterlayer without AOV suffix - # when a Beauty AOV is rendered. It overrides the main layer. - if aov_type == "Beauty": - has_beauty_aov = True + # Any AOVs that still get processed, like Cryptomatte + # by themselves are not multipart files. - aov_name = self._get_attr(aov, "name") + # Redshift skips rendering of masterlayer without AOV suffix + # when a Beauty AOV is rendered. It overrides the main layer. + if aov_type == "Beauty": + has_beauty_aov = True - # Support light Groups - light_groups = [] - if self._get_attr(aov, "supportsLightGroups"): - all_light_groups = self._get_attr(aov, "allLightGroups") - if all_light_groups: - # All light groups is enabled - light_groups = self._get_redshift_light_groups() - else: - value = self._get_attr(aov, "lightGroupList") - # note: string value can return None when never set - if value: - selected_light_groups = value.strip().split() - light_groups = selected_light_groups + aov_name = self._get_attr(aov, "name") - for light_group in light_groups: - aov_light_group_name = "{}_{}".format(aov_name, - light_group) - for camera in cameras: - product = RenderProduct( - productName=aov_light_group_name, - aov=aov_name, - ext=ext, - multipart=False, - camera=camera, - driver=aov, - colorspace=colorspace) - products.append(product) + # Support light Groups + light_groups = [] + if self._get_attr(aov, "supportsLightGroups"): + all_light_groups = self._get_attr(aov, "allLightGroups") + if all_light_groups: + # All light groups is enabled + light_groups = self._get_redshift_light_groups() + else: + value = self._get_attr(aov, "lightGroupList") + # note: string value can return None when never set + if value: + selected_light_groups = value.strip().split() + light_groups = selected_light_groups - if light_groups: - light_groups_enabled = True + for light_group in light_groups: + aov_light_group_name = "{}_{}".format(aov_name, + light_group) + for camera in cameras: + product = RenderProduct( + productName=aov_light_group_name, + aov=aov_name, + ext=ext, + multipart=False, + camera=camera, + driver=aov, + colorspace=colorspace) + products.append(product) - # Redshift AOV Light Select always renders the global AOV - # even when light groups are present so we don't need to - # exclude it when light groups are active - for camera in cameras: - product = RenderProduct(productName=aov_name, - aov=aov_name, - ext=ext, - multipart=False, - camera=camera, - driver=aov, - colorspace=colorspace) - products.append(product) + if light_groups: + light_groups_enabled = True + + # Redshift AOV Light Select always renders the global AOV + # even when light groups are present so we don't need to + # exclude it when light groups are active + for camera in cameras: + product = RenderProduct(productName=aov_name, + aov=aov_name, + ext=ext, + multipart=False, + camera=camera, + driver=aov, + colorspace=colorspace) + products.append(product) # When a Beauty AOV is added manually, it will be rendered as # 'Beauty_other' in file name and "standard" beauty will have From b729bf4f30432a5a86ab7670e73b3e2b4514cc87 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 13 Mar 2024 23:56:31 +0800 Subject: [PATCH 015/111] make sure beauty still being added as render product --- client/ayon_core/hosts/maya/api/lib_renderproducts.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/client/ayon_core/hosts/maya/api/lib_renderproducts.py b/client/ayon_core/hosts/maya/api/lib_renderproducts.py index 28981e1187..3bba25ee12 100644 --- a/client/ayon_core/hosts/maya/api/lib_renderproducts.py +++ b/client/ayon_core/hosts/maya/api/lib_renderproducts.py @@ -1140,6 +1140,15 @@ class RenderProductsRedshift(ARenderProducts): self._get_attr("redshiftOptions.aovGlobalEnableMode") ) if not global_aov_enabled: + beauty_name = "BeautyAux" if has_beauty_aov else "" + for camera in cameras: + products.insert(0, + RenderProduct(productName=beauty_name, + ext=ext, + multipart=self.multipart, + camera=camera, + colorspace=colorspace)) + return products for aov in aovs: From ffa395af64b066808cdffce100ad8593bf36fbd1 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 14 Mar 2024 15:10:03 +0800 Subject: [PATCH 016/111] add only beauty output when global aov disabled --- .../hosts/maya/api/lib_renderproducts.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/lib_renderproducts.py b/client/ayon_core/hosts/maya/api/lib_renderproducts.py index 3bba25ee12..5f3917f642 100644 --- a/client/ayon_core/hosts/maya/api/lib_renderproducts.py +++ b/client/ayon_core/hosts/maya/api/lib_renderproducts.py @@ -1133,24 +1133,24 @@ class RenderProductsRedshift(ARenderProducts): aovs = list(set(aovs) - set(ref_aovs)) products = [] - light_groups_enabled = False - has_beauty_aov = False - colorspace = lib.get_color_management_output_transform() global_aov_enabled = bool( self._get_attr("redshiftOptions.aovGlobalEnableMode") ) + colorspace = lib.get_color_management_output_transform() if not global_aov_enabled: - beauty_name = "BeautyAux" if has_beauty_aov else "" + # only beauty output for camera in cameras: products.insert(0, - RenderProduct(productName=beauty_name, - ext=ext, - multipart=self.multipart, - camera=camera, - colorspace=colorspace)) - + RenderProduct(productName="", + ext=ext, + multipart=self.multipart, + camera=camera, + colorspace=colorspace)) return products + light_groups_enabled = False + has_beauty_aov = False + for aov in aovs: enabled = self._get_attr(aov, "enabled") if not enabled: From 85dc52a2c1b9c63d29c9dd1755c2fe316cf5e2cd Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 20 Mar 2024 17:30:34 +0100 Subject: [PATCH 017/111] Fusion: Add Launch Hook to start "AYON menu" on Fusion start --- .../hooks/pre_fusion_launch_menu_hook.py | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 client/ayon_core/hosts/fusion/hooks/pre_fusion_launch_menu_hook.py diff --git a/client/ayon_core/hosts/fusion/hooks/pre_fusion_launch_menu_hook.py b/client/ayon_core/hosts/fusion/hooks/pre_fusion_launch_menu_hook.py new file mode 100644 index 0000000000..825d432a3e --- /dev/null +++ b/client/ayon_core/hosts/fusion/hooks/pre_fusion_launch_menu_hook.py @@ -0,0 +1,34 @@ +import os +from ayon_core.lib import PreLaunchHook +from ayon_core.hosts.fusion import FUSION_HOST_DIR + + +class FusionLaunchMenuHook(PreLaunchHook): + """Launch OpenPype menu on start of Fusion""" + app_groups = ["fusion"] + order = 9 + + def execute(self): + + # TODO: Make this optional via project settings + + variant = self.application.name + if variant.isnumeric(): + version = int(variant) + if version < 18: + print("Skipping launch of OpenPype menu on Fusion start " + "because Fusion version below 18.0 does not support " + "/execute argument on launch. " + f"Version detected: {version}") + return + else: + print(f"Application variant is not numeric: {variant}. " + "Validation for Fusion version 18+ for /execute " + "prelaunch argument skipped.") + + path = os.path.join(FUSION_HOST_DIR, + "deploy", + "MenuScripts", + "launch_menu.py").replace("\\", "/") + script = f"fusion:RunScript('{path}')" + self.launch_context.launch_args.extend(["/execute", script]) From 39399b1b269d63e4f0cf1cc9390a193c7e87cdc3 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 21 Mar 2024 16:32:37 +0000 Subject: [PATCH 018/111] Publish and load slate frame explicitly --- .../hosts/nuke/plugins/load/load_clip.py | 34 +++++++++++-------- .../plugins/publish/extract_slate_data.py | 22 ++++++++++++ 2 files changed, 41 insertions(+), 15 deletions(-) create mode 100644 client/ayon_core/plugins/publish/extract_slate_data.py diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_clip.py b/client/ayon_core/hosts/nuke/plugins/load/load_clip.py index 8a41d854d9..b2044901a3 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_clip.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_clip.py @@ -130,6 +130,11 @@ class LoadClip(plugin.NukeLoader): first = 1 last = first + duration + # If a slate is present, the frame range is 1 frame longer. + slate_frame = repre_entity["data"].get("slateFrame", False) + if slate_frame: + last += 1 + # Fallback to folder name when namespace is None if namespace is None: namespace = context["folder"]["name"] @@ -167,7 +172,9 @@ class LoadClip(plugin.NukeLoader): repre_entity ) - self._set_range_to_node(read_node, first, last, start_at_workfile) + self._set_range_to_node( + read_node, first, last, start_at_workfile, slate_frame + ) version_name = version_entity["version"] if version_name < 0: @@ -402,14 +409,23 @@ class LoadClip(plugin.NukeLoader): for member in members: nuke.delete(member) - def _set_range_to_node(self, read_node, first, last, start_at_workfile): + def _set_range_to_node( + self, read_node, first, last, start_at_workfile, slate_frame=False + ): read_node['origfirst'].setValue(int(first)) read_node['first'].setValue(int(first)) read_node['origlast'].setValue(int(last)) read_node['last'].setValue(int(last)) # set start frame depending on workfile or version - self._loader_shift(read_node, start_at_workfile) + if start_at_workfile: + read_node['frame_mode'].setValue("start at") + + start_frame = self.script_start + if slate_frame: + start_frame -= 1 + + read_node['frame'].setValue(str(start_frame)) def _make_retimes(self, parent_node, version_data): ''' Create all retime and timewarping nodes with copied animation ''' @@ -466,18 +482,6 @@ class LoadClip(plugin.NukeLoader): for i, n in enumerate(dependent_nodes): last_node.setInput(i, n) - def _loader_shift(self, read_node, workfile_start=False): - """ Set start frame of read node to a workfile start - - Args: - read_node (nuke.Node): The nuke's read node - workfile_start (bool): set workfile start frame if true - - """ - if workfile_start: - read_node['frame_mode'].setValue("start at") - read_node['frame'].setValue(str(self.script_start)) - def _get_node_name(self, context): folder_entity = context["folder"] product_name = context["product"]["name"] diff --git a/client/ayon_core/plugins/publish/extract_slate_data.py b/client/ayon_core/plugins/publish/extract_slate_data.py new file mode 100644 index 0000000000..0a28083f1e --- /dev/null +++ b/client/ayon_core/plugins/publish/extract_slate_data.py @@ -0,0 +1,22 @@ +import pyblish.api + +from ayon_core.pipeline import publish + + +class ExtractSlateData(publish.Extractor): + """Add slate data for integration.""" + + label = "Slate Data" + # Offset from ExtractReviewSlate and ExtractGenerateSlate. + order = pyblish.api.ExtractorOrder + 0.49 + families = ["slate", "review"] + hosts = ["nuke", "shell"] + + def process(self, instance): + for representation in instance.data.get("representations", []): + if "slate-frame" not in representation.get("tags", []): + continue + + data = representation.get("data", {}) + data["slateFrame"] = True + representation["data"] = data From d1e1f3942a7ed9cd88628b774f7421f14b07dd33 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 21 Mar 2024 17:38:43 +0000 Subject: [PATCH 019/111] Fix file sequences --- .../ayon_core/hosts/nuke/plugins/load/load_clip.py | 12 ++++++++++-- .../nuke/plugins/publish/extract_slate_frame.py | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_clip.py b/client/ayon_core/hosts/nuke/plugins/load/load_clip.py index b2044901a3..86a6d359c3 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_clip.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_clip.py @@ -130,10 +130,18 @@ class LoadClip(plugin.NukeLoader): first = 1 last = first + duration - # If a slate is present, the frame range is 1 frame longer. + # If a slate is present, the frame range is 1 frame longer for movies, + # but file sequences its the first frame that is 1 frame lower. slate_frame = repre_entity["data"].get("slateFrame", False) if slate_frame: - last += 1 + extension = "." + repre_entity["context"]["ext"] + + if extension in VIDEO_EXTENSIONS: + last += 1 + + files_count = len(repre_entity["files"]) + if extension in IMAGE_EXTENSIONS and files_count != 1: + first -= 1 # Fallback to folder name when namespace is None if namespace is None: diff --git a/client/ayon_core/hosts/nuke/plugins/publish/extract_slate_frame.py b/client/ayon_core/hosts/nuke/plugins/publish/extract_slate_frame.py index c013da84d2..67d2bd272c 100644 --- a/client/ayon_core/hosts/nuke/plugins/publish/extract_slate_frame.py +++ b/client/ayon_core/hosts/nuke/plugins/publish/extract_slate_frame.py @@ -300,6 +300,10 @@ class ExtractSlateFrame(publish.Extractor): self.log.debug( "__ matching_repre: {}".format(pformat(matching_repre))) + data = matching_repre.get("data", {}) + data["slateFrame"] = True + matching_repre["data"] = data + self.log.info("Added slate frame to representation files") def add_comment_slate_node(self, instance, node): From 943b4d7b087b9d0e257013b5be2e65d4c70d7da7 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 25 Mar 2024 13:35:25 +0100 Subject: [PATCH 020/111] Also update tool on only task or asset change --- client/ayon_core/hosts/fusion/api/plugin.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/ayon_core/hosts/fusion/api/plugin.py b/client/ayon_core/hosts/fusion/api/plugin.py index f63b5eaec3..1af3467bf1 100644 --- a/client/ayon_core/hosts/fusion/api/plugin.py +++ b/client/ayon_core/hosts/fusion/api/plugin.py @@ -125,6 +125,8 @@ class GenericCreateSaver(Creator): product_name = data["productName"] if ( original_product_name != product_name + or tool.GetData("openpype.task") != data["task"] + or tool.GetData("openpype.asset") != data["asset"] or original_format != data["creator_attributes"]["image_format"] ): self._configure_saver_tool(data, tool, product_name) From 55b389b7a7707dd1464bb819a440f2484c52a46b Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 25 Mar 2024 21:36:53 +0100 Subject: [PATCH 021/111] Only launch when enabled in settings --- .../hosts/fusion/hooks/pre_fusion_launch_menu_hook.py | 6 ++++-- server_addon/fusion/server/settings.py | 9 +++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/hosts/fusion/hooks/pre_fusion_launch_menu_hook.py b/client/ayon_core/hosts/fusion/hooks/pre_fusion_launch_menu_hook.py index 825d432a3e..f5a1c75a50 100644 --- a/client/ayon_core/hosts/fusion/hooks/pre_fusion_launch_menu_hook.py +++ b/client/ayon_core/hosts/fusion/hooks/pre_fusion_launch_menu_hook.py @@ -9,8 +9,10 @@ class FusionLaunchMenuHook(PreLaunchHook): order = 9 def execute(self): - - # TODO: Make this optional via project settings + # Prelaunch hook is optional + settings = self.data["project_settings"][self.host_name] + if not settings["hooks"]["FusionLaunchMenuHook"]["enabled"]: + return variant = self.application.name if variant.isnumeric(): diff --git a/server_addon/fusion/server/settings.py b/server_addon/fusion/server/settings.py index a913db16da..b44feb1f03 100644 --- a/server_addon/fusion/server/settings.py +++ b/server_addon/fusion/server/settings.py @@ -75,6 +75,12 @@ class HooksModel(BaseSettingsModel): default_factory=HookOptionalModel, title="Install PySide2" ) + FusionLaunchMenuHook: HookOptionalModel = SettingsField( + default_factory=HookOptionalModel, + title="Launch AYON Menu on Fusion Start", + description="Launch the AYON menu on Fusion application startup. " + "This is only supported for Fusion 18+" + ) class CreateSaverModel(CreateSaverPluginModel): @@ -143,6 +149,9 @@ DEFAULT_VALUES = { "hooks": { "InstallPySideToFusion": { "enabled": True + }, + "FusionLaunchMenuHook": { + "enabled": True } }, "create": { From 38c32c55af7b882cb75b161cbf581bc7c6cc2881 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 25 Mar 2024 21:37:22 +0100 Subject: [PATCH 022/111] Bump fusion server addon version --- server_addon/fusion/server/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server_addon/fusion/server/version.py b/server_addon/fusion/server/version.py index bbab0242f6..1276d0254f 100644 --- a/server_addon/fusion/server/version.py +++ b/server_addon/fusion/server/version.py @@ -1 +1 @@ -__version__ = "0.1.4" +__version__ = "0.1.5" From 2ae618d2cbef243e3ea9ab57197ceda813410aca Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 25 Mar 2024 21:51:12 +0100 Subject: [PATCH 023/111] Update client/ayon_core/hosts/fusion/hooks/pre_fusion_launch_menu_hook.py --- .../ayon_core/hosts/fusion/hooks/pre_fusion_launch_menu_hook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/fusion/hooks/pre_fusion_launch_menu_hook.py b/client/ayon_core/hosts/fusion/hooks/pre_fusion_launch_menu_hook.py index f5a1c75a50..e70d4b844e 100644 --- a/client/ayon_core/hosts/fusion/hooks/pre_fusion_launch_menu_hook.py +++ b/client/ayon_core/hosts/fusion/hooks/pre_fusion_launch_menu_hook.py @@ -4,7 +4,7 @@ from ayon_core.hosts.fusion import FUSION_HOST_DIR class FusionLaunchMenuHook(PreLaunchHook): - """Launch OpenPype menu on start of Fusion""" + """Launch AYON menu on start of Fusion""" app_groups = ["fusion"] order = 9 From b17df02e418b2061ec6631d028e3039ce55105f5 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 26 Mar 2024 23:04:58 +0100 Subject: [PATCH 024/111] Maya: Validate Model Content improve validation message - Also fix `get_invalid` actually returning the instance node. --- .../plugins/publish/validate_model_content.py | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_model_content.py b/client/ayon_core/hosts/maya/plugins/publish/validate_model_content.py index 37c78a72ee..97d602a9ad 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_model_content.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_model_content.py @@ -28,13 +28,15 @@ class ValidateModelContent(pyblish.api.InstancePlugin, validate_top_group = True optional = False + allowed = ('mesh', 'transform', 'nurbsCurve', 'nurbsSurface', 'locator') + @classmethod def get_invalid(cls, instance): content_instance = instance.data.get("setMembers", None) if not content_instance: cls.log.error("Instance has no nodes!") - return [instance.data["name"]] + return [instance.data["instance_node"]] # All children will be included in the extracted export so we also # validate *all* descendents of the set members and we skip any @@ -46,30 +48,39 @@ class ValidateModelContent(pyblish.api.InstancePlugin, content_instance = list(set(content_instance + descendants)) # Ensure only valid node types - allowed = ('mesh', 'transform', 'nurbsCurve', 'nurbsSurface', 'locator') nodes = cmds.ls(content_instance, long=True) - valid = cmds.ls(content_instance, long=True, type=allowed) + valid = cmds.ls(content_instance, long=True, type=cls.allowed) invalid = set(nodes) - set(valid) if invalid: - cls.log.error("These nodes are not allowed: %s" % invalid) + cls.log.error( + "These nodes are not allowed: {}.\n" + "The valid node types are: {}".format(", ".join(invalid), + ", ".join(cls.allowed)) + ) return list(invalid) if not valid: - cls.log.error("No valid nodes in the instance") - return True + cls.log.error( + "No valid nodes in the model instance.\n" + "The valid node types are: {}".format(", ".join(cls.allowed)) + ) + return [instance.data["instance_node"]] # Ensure it has shapes shapes = cmds.ls(valid, long=True, shapes=True) if not shapes: cls.log.error("No shapes in the model instance") - return True + return [instance.data["instance_node"]] - # Top group - top_parents = set([x.split("|")[1] for x in content_instance]) + # Ensure single top group + top_parents = {x.split("|", 2)[1] for x in content_instance} if cls.validate_top_group and len(top_parents) != 1: - cls.log.error("Must have exactly one top group") - return top_parents + cls.log.error( + "A model instance must have exactly one top group. " + "Found top groups: {}".format(", ".join(top_parents)) + ) + return list(top_parents) def _is_visible(node): """Return whether node is visible""" @@ -101,5 +112,11 @@ class ValidateModelContent(pyblish.api.InstancePlugin, if invalid: raise PublishValidationError( title="Model content is invalid", - message="See log for more details" + message="Model content is invalid. See log for more details.", + description=( + "## Model content is invalid\n" + "Your model instance does not adhere to the rules of a " + "model.\n\n" + "See log for more details." + ) ) From cb6f4dd79857ffbe62e8a99cb91d3db83f8712d5 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 27 Mar 2024 09:56:44 +0100 Subject: [PATCH 025/111] Turn off by default --- server_addon/fusion/server/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server_addon/fusion/server/settings.py b/server_addon/fusion/server/settings.py index b44feb1f03..f16ae6e3e7 100644 --- a/server_addon/fusion/server/settings.py +++ b/server_addon/fusion/server/settings.py @@ -151,7 +151,7 @@ DEFAULT_VALUES = { "enabled": True }, "FusionLaunchMenuHook": { - "enabled": True + "enabled": False } }, "create": { From 4dd44b08b78f3a803c0e738841067096a5cea943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Wed, 27 Mar 2024 17:19:52 +0100 Subject: [PATCH 026/111] :art: add support for Maya 2025 some changes to support PySide6 there --- client/ayon_core/hosts/maya/addon.py | 8 ++++---- .../maya/vendor/python}/capture.py | 6 +----- pyproject.toml | 2 +- .../applications/server/applications.json | 20 +++++++++++++++++++ server_addon/applications/server/version.py | 2 +- 5 files changed, 27 insertions(+), 11 deletions(-) rename client/ayon_core/{vendor/python/common => hosts/maya/vendor/python}/capture.py (99%) diff --git a/client/ayon_core/hosts/maya/addon.py b/client/ayon_core/hosts/maya/addon.py index c68aa4c911..1ad0fcf4cf 100644 --- a/client/ayon_core/hosts/maya/addon.py +++ b/client/ayon_core/hosts/maya/addon.py @@ -22,15 +22,15 @@ class MayaAddon(AYONAddon, IHostAddon): if norm_path not in new_python_paths: new_python_paths.append(norm_path) + # add vendor path + new_python_paths.append( + os.path.join(MAYA_ROOT_DIR, "vendor", "python") + ) env["PYTHONPATH"] = os.pathsep.join(new_python_paths) # Set default environments envs = { "AYON_LOG_NO_COLORS": "1", - # For python module 'qtpy' - "QT_API": "PySide2", - # For python module 'Qt' - "QT_PREFERRED_BINDING": "PySide2" } for key, value in envs.items(): env[key] = value diff --git a/client/ayon_core/vendor/python/common/capture.py b/client/ayon_core/hosts/maya/vendor/python/capture.py similarity index 99% rename from client/ayon_core/vendor/python/common/capture.py rename to client/ayon_core/hosts/maya/vendor/python/capture.py index 224699f916..7a3be38f56 100644 --- a/client/ayon_core/vendor/python/common/capture.py +++ b/client/ayon_core/hosts/maya/vendor/python/capture.py @@ -12,11 +12,7 @@ import logging from maya import cmds from maya import mel -try: - from PySide2 import QtGui, QtWidgets -except ImportError: - from PySide import QtGui - QtWidgets = QtGui +from qtpy import QtGui, QtWidgets version_info = (2, 3, 0) diff --git a/pyproject.toml b/pyproject.toml index ee124ddc2d..ec38b746dd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -92,7 +92,7 @@ line-ending = "auto" [tool.codespell] # Ignore words that are not in the dictionary. -ignore-words-list = "ayon,ynput" +ignore-words-list = "ayon,ynput,developpement" skip = "./.*,./package/*,*/vendor/*,*/unreal/integration/*,*/aftereffects/api/extension/js/libs/*" count = true quiet-level = 3 diff --git a/server_addon/applications/server/applications.json b/server_addon/applications/server/applications.json index 85bf6f1dda..e4b72fdff9 100644 --- a/server_addon/applications/server/applications.json +++ b/server_addon/applications/server/applications.json @@ -7,6 +7,26 @@ "host_name": "maya", "environment": "{\n \"MAYA_DISABLE_CLIC_IPM\": \"Yes\",\n \"MAYA_DISABLE_CIP\": \"Yes\",\n \"MAYA_DISABLE_CER\": \"Yes\",\n \"PYMEL_SKIP_MEL_INIT\": \"Yes\",\n \"LC_ALL\": \"C\"\n}\n", "variants": [ + { + "name": "2025", + "label": "2025", + "executables": { + "windows": [ + "C:\\Program Files\\Autodesk\\Maya2025\\bin\\maya.exe" + ], + "darwin": ["/Applications/Autodesk/maya2025/Maya.app"], + "linux": [ + "/usr/autodesk/maya2025/bin/maya" + ] + }, + "arguments": { + "windows": [], + "darwin": [], + "linux": [] + }, + "environment": "{\n \"MAYA_VERSION\": \"2025\"\n}", + "use_python_2": false + }, { "name": "2024", "label": "2024", diff --git a/server_addon/applications/server/version.py b/server_addon/applications/server/version.py index 9cb17e7976..c11f861afb 100644 --- a/server_addon/applications/server/version.py +++ b/server_addon/applications/server/version.py @@ -1 +1 @@ -__version__ = "0.1.8" +__version__ = "0.1.9" From 149c83e136d342b53bc667b114df43ede22915f3 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 28 Mar 2024 13:57:37 +0100 Subject: [PATCH 027/111] Raise PublishValidationError --- .../publish/validate_current_renderlayer_renderable.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_current_renderlayer_renderable.py b/client/ayon_core/hosts/maya/plugins/publish/validate_current_renderlayer_renderable.py index 4590c53931..332c5aff02 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_current_renderlayer_renderable.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_current_renderlayer_renderable.py @@ -3,9 +3,11 @@ import pyblish.api from maya import cmds from ayon_core.pipeline.publish import ( context_plugin_should_run, + PublishValidationError, OptionalPyblishPluginMixin ) + class ValidateCurrentRenderLayerIsRenderable(pyblish.api.ContextPlugin, OptionalPyblishPluginMixin): """Validate if current render layer has a renderable camera @@ -35,5 +37,9 @@ class ValidateCurrentRenderLayerIsRenderable(pyblish.api.ContextPlugin, layer = cmds.editRenderLayerGlobals(query=True, currentRenderLayer=True) cameras = cmds.ls(type="camera", long=True) renderable = any(c for c in cameras if cmds.getAttr(c + ".renderable")) - assert renderable, ("Current render layer '%s' has no renderable " - "camera" % layer) + if not renderable: + raise PublishValidationError( + "Current render layer '{}' has no renderable camera".format( + layer + ) + ) From 4a69d68a40c845180baa36e6c665d608d1fe1b6c Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 28 Mar 2024 14:00:05 +0100 Subject: [PATCH 028/111] Add description to report --- .../publish/validate_current_renderlayer_renderable.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_current_renderlayer_renderable.py b/client/ayon_core/hosts/maya/plugins/publish/validate_current_renderlayer_renderable.py index 332c5aff02..f02c401bf9 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_current_renderlayer_renderable.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_current_renderlayer_renderable.py @@ -1,3 +1,5 @@ +import inspect + import pyblish.api from maya import cmds @@ -10,7 +12,7 @@ from ayon_core.pipeline.publish import ( class ValidateCurrentRenderLayerIsRenderable(pyblish.api.ContextPlugin, OptionalPyblishPluginMixin): - """Validate if current render layer has a renderable camera + """Validate if current render layer has a renderable camera. There is a bug in Redshift which occurs when the current render layer at file open has no renderable camera. The error raised is as follows: @@ -41,5 +43,6 @@ class ValidateCurrentRenderLayerIsRenderable(pyblish.api.ContextPlugin, raise PublishValidationError( "Current render layer '{}' has no renderable camera".format( layer - ) + ), + description=inspect.getdoc(self) ) From 03ee91cf2c2826e0ff865b2d0949c71d8ca7ee46 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 28 Mar 2024 14:01:51 +0100 Subject: [PATCH 029/111] Only query current renderlayer if there is no renderable camera --- .../plugins/publish/validate_current_renderlayer_renderable.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_current_renderlayer_renderable.py b/client/ayon_core/hosts/maya/plugins/publish/validate_current_renderlayer_renderable.py index f02c401bf9..da8468c1b6 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_current_renderlayer_renderable.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_current_renderlayer_renderable.py @@ -36,10 +36,11 @@ class ValidateCurrentRenderLayerIsRenderable(pyblish.api.ContextPlugin, if not context_plugin_should_run(self, context): return - layer = cmds.editRenderLayerGlobals(query=True, currentRenderLayer=True) cameras = cmds.ls(type="camera", long=True) renderable = any(c for c in cameras if cmds.getAttr(c + ".renderable")) if not renderable: + layer = cmds.editRenderLayerGlobals(query=True, + currentRenderLayer=True) raise PublishValidationError( "Current render layer '{}' has no renderable camera".format( layer From 312fd21b23f680c9f2032497ae9b857b38c52f99 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 28 Mar 2024 19:37:25 +0100 Subject: [PATCH 030/111] Expose `timecode` for formatting ffmpeg args --- .../plugins/publish/extract_review.py | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 905158c851..ac213b8669 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -32,6 +32,35 @@ from ayon_core.pipeline.publish import ( from ayon_core.pipeline.publish.lib import add_repre_files_for_cleanup +def frame_to_timecode(frame: int, fps: float) -> str: + """Convert a frame number and FPS to editorial timecode (HH:MM:SS:FF). + + Unlike `ayon_core.pipeline.editorial.frames_to_timecode` this does not + rely on the `opentimelineio` package, so it can be used across hosts that + do not have it available. + + Args: + frame (int): The frame number to be converted. + fps (float): The frames per second of the video. + + Returns: + str: The timecode in HH:MM:SS:FF format. + """ + # Calculate total seconds + total_seconds = frame / fps + + # Extract hours, minutes, and seconds + hours = int(total_seconds // 3600) + minutes = int((total_seconds % 3600) // 60) + seconds = int(total_seconds % 60) + + # Adjust for non-integer FPS by rounding the remaining frames appropriately + remaining_frames = round((total_seconds - int(total_seconds)) * fps) + + # Format and return the timecode + return f"{hours:02d}:{minutes:02d}:{seconds:02d}:{remaining_frames:02d}" + + class ExtractReview(pyblish.api.InstancePlugin): """Extracting Review mov file for Ftrack @@ -390,7 +419,16 @@ class ExtractReview(pyblish.api.InstancePlugin): # add outputName to anatomy format fill_data fill_data.update({ "output": output_name, - "ext": output_ext + "ext": output_ext, + + # By adding `timecode` as data we can use it + # in the ffmpeg arguments for `--timecode` so that editorial + # like Resolve or Premiere can detect the start frame for e.g. + # review output files + "timecode": frame_to_timecode( + frame=temp_data["frame_start_handle"], + fps=float(instance.data["fps"]) + ) }) try: # temporary until oiiotool is supported cross platform From 33fd95dd009d65097cc68f7f4f10251eff4ea874 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Fri, 29 Mar 2024 10:57:27 +0100 Subject: [PATCH 031/111] Add `usd` to product type enum for Loader Product Type Filter Used in `ayon+settings://core/tools/loader/product_type_filter_profiles` --- server/settings/tools.py | 1 + 1 file changed, 1 insertion(+) diff --git a/server/settings/tools.py b/server/settings/tools.py index 488d27e8f1..fb8430a71c 100644 --- a/server/settings/tools.py +++ b/server/settings/tools.py @@ -173,6 +173,7 @@ def _product_types_enum(): "rig", "setdress", "take", + "usd", "usdShade", "vdbcache", "vrayproxy", From a4b0dbc4936da61f167912167959916138b8e2b4 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Fri, 29 Mar 2024 13:17:49 +0100 Subject: [PATCH 032/111] Optimize `cbId` logic for large scenes --- client/ayon_core/hosts/maya/api/lib.py | 191 +++++++++++++----- client/ayon_core/hosts/maya/api/pipeline.py | 3 +- .../maya/plugins/publish/validate_node_ids.py | 9 +- .../publish/validate_node_ids_in_database.py | 11 +- 4 files changed, 153 insertions(+), 61 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/lib.py b/client/ayon_core/hosts/maya/api/lib.py index b18d3a0c33..4b9b80f0e7 100644 --- a/client/ayon_core/hosts/maya/api/lib.py +++ b/client/ayon_core/hosts/maya/api/lib.py @@ -1519,24 +1519,30 @@ def extract_alembic(file, # region ID -def get_id_required_nodes(referenced_nodes=False, nodes=None): - """Filter out any node which are locked (reference) or readOnly +def get_id_required_nodes(referenced_nodes=False, + nodes=None, + existing_ids=True): + """Return nodes that should receive a `cbId` attribute. + + This includes only mesh and curve nodes, parent transforms of the shape + nodes, file texture nodes and object sets (including shading engines). + + This filters out any node which is locked, referenced, read-only, + intermediate object. Args: - referenced_nodes (bool): set True to filter out reference nodes + referenced_nodes (bool): set True to include referenced nodes nodes (list, Optional): nodes to consider + existing_ids (bool): set True to include nodes with `cbId` attribute + Returns: nodes (set): list of filtered nodes """ - lookup = None - if nodes is None: - # Consider all nodes - nodes = cmds.ls() - else: - # Build a lookup for the only allowed nodes in output based - # on `nodes` input of the function (+ ensure long names) - lookup = set(cmds.ls(nodes, long=True)) + if nodes is not None and not nodes: + # User supplied an empty `nodes` list to check so all we can + # do is return the empty result + return set() def _node_type_exists(node_type): try: @@ -1545,63 +1551,142 @@ def get_id_required_nodes(referenced_nodes=False, nodes=None): except RuntimeError: return False + def iterate(maya_iterator): + while not maya_iterator.isDone(): + yield maya_iterator.thisNode() + maya_iterator.next() + # `readOnly` flag is obsolete as of Maya 2016 therefore we explicitly # remove default nodes and reference nodes - camera_shapes = ["frontShape", "sideShape", "topShape", "perspShape"] + default_camera_shapes = { + "frontShape", "sideShape", "topShape", "perspShape" + } - ignore = set() - if not referenced_nodes: - ignore |= set(cmds.ls(long=True, referencedNodes=True)) - - # list all defaultNodes to filter out from the rest - ignore |= set(cmds.ls(long=True, defaultNodes=True)) - ignore |= set(cmds.ls(camera_shapes, long=True)) - - # Remove Turtle from the result of `cmds.ls` if Turtle is loaded - # TODO: This should be a less specific check for a single plug-in. - if _node_type_exists("ilrBakeLayer"): - ignore |= set(cmds.ls(type="ilrBakeLayer", long=True)) - - # Establish set of nodes types to include - types = ["objectSet", "file", "mesh", "nurbsCurve", "nurbsSurface"] + # The filtered types do not include transforms because we only want the + # parent transforms that have a child shape that we filtered to, so we + # include the parents here + types = ["mesh", "nurbsCurve", "nurbsSurface", "file", "objectSet"] # Check if plugin nodes are available for Maya by checking if the plugin # is loaded if cmds.pluginInfo("pgYetiMaya", query=True, loaded=True): types.append("pgYetiMaya") - # We *always* ignore intermediate shapes, so we filter them out directly - nodes = cmds.ls(nodes, type=types, long=True, noIntermediate=True) + iterator_type = OpenMaya.MIteratorType() + # This tries to be closest matching API equivalents of `types` variable + iterator_type.filterList = [ + OpenMaya.MFn.kMesh, # mesh + OpenMaya.MFn.kNurbsSurface, # nurbsSurface + OpenMaya.MFn.kNurbsCurve, # nurbsCurve + OpenMaya.MFn.kFileTexture, # file + OpenMaya.MFn.kSet, # objectSet + OpenMaya.MFn.kPluginShape # pgYetiMaya + ] + it = OpenMaya.MItDependencyNodes(iterator_type) - # The items which need to pass the id to their parent - # Add the collected transform to the nodes - dag = cmds.ls(nodes, type="dagNode", long=True) # query only dag nodes - transforms = cmds.listRelatives(dag, - parent=True, - fullPath=True) or [] + fn_dep = OpenMaya.MFnDependencyNode() + fn_dag = OpenMaya.MFnDagNode() + result = set() - nodes = set(nodes) - nodes |= set(transforms) + def _should_include_parents(obj): + """Whether to include parents of obj in output""" + if not obj.hasFn(OpenMaya.MFn.kShape): + return False - nodes -= ignore # Remove the ignored nodes - if not nodes: - return nodes + fn_dag.setObject(obj) + if fn_dag.isIntermediateObject: + return False - # Ensure only nodes from the input `nodes` are returned when a - # filter was applied on function call because we also iterated - # to parents and alike - if lookup is not None: - nodes &= lookup + # Skip default cameras + if ( + obj.hasFn(OpenMaya.MFn.kCamera) and + fn_dag.name() in default_camera_shapes + ): + return False - # Avoid locked nodes - nodes_list = list(nodes) - locked = cmds.lockNode(nodes_list, query=True, lock=True) - for node, lock in zip(nodes_list, locked): - if lock: - log.warning("Skipping locked node: %s" % node) - nodes.remove(node) + return True - return nodes + def _add_to_result_if_valid(obj): + """Add to `result` if the object should be included""" + fn_dep.setObject(obj) + if not existing_ids and fn_dep.hasAttribute("cbId"): + return + + if not referenced_nodes and fn_dep.isFromReferencedFile: + return + + if fn_dep.isDefaultNode: + return + + if fn_dep.isLocked: + return + + # Skip default cameras + if ( + obj.hasFn(OpenMaya.MFn.kCamera) and + fn_dep.name() in default_camera_shapes + ): + return + + if obj.hasFn(OpenMaya.MFn.kDagNode): + # DAG nodes + fn_dag.setObject(obj) + + # Skip intermediate objects + if fn_dag.isIntermediateObject: + return + + # DAG nodes can be instanced and thus may have multiple paths. + # We need to identify each path + paths = OpenMaya.MDagPath.getAllPathsTo(obj) + for dag in paths: + path = dag.fullPathName() + result.add(path) + else: + # Dependency node + path = fn_dep.name() + result.add(path) + + for obj in iterate(it): + # For any non-intermediate shape node always include the parent + # even if we exclude the shape itself (e.g. when locked, default) + if _should_include_parents(obj): + fn_dag.setObject(obj) + parents = [ + fn_dag.parent(index) for index in range(fn_dag.parentCount()) + ] + for parent_obj in parents: + _add_to_result_if_valid(parent_obj) + + _add_to_result_if_valid(obj) + + if not result: + return result + + # Exclude some additional types + exclude_types = [] + if _node_type_exists("ilrBakeLayer"): + # Remove Turtle from the result if Turtle is loaded + exclude_types.append("ilrBakeLayer") + + if exclude_types: + exclude_nodes = set(cmds.ls(nodes, long=True, type=exclude_types)) + if exclude_nodes: + result -= exclude_nodes + + # Filter to explicit input nodes if provided + if nodes is not None: + # The amount of input nodes to filter to can be large and querying + # many nodes can be slow in Maya. As such we want to try and reduce + # it as much as possible, so we include the type filter to try and + # reduce the result of `maya.cmds.ls` here. + nodes = set(cmds.ls(nodes, long=True, type=types + ["dagNode"])) + if nodes: + result &= nodes + else: + return set() + + return result def get_id(node): diff --git a/client/ayon_core/hosts/maya/api/pipeline.py b/client/ayon_core/hosts/maya/api/pipeline.py index 2be452a22a..464e87814c 100644 --- a/client/ayon_core/hosts/maya/api/pipeline.py +++ b/client/ayon_core/hosts/maya/api/pipeline.py @@ -580,7 +580,8 @@ def on_save(): _remove_workfile_lock() # Generate ids of the current context on nodes in the scene - nodes = lib.get_id_required_nodes(referenced_nodes=False) + nodes = lib.get_id_required_nodes(referenced_nodes=False, + existing_ids=False) for node, new_id in lib.generate_ids(nodes): lib.set_id(node, new_id, overwrite=False) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids.py b/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids.py index ba748a4fc4..2d6f231cb5 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids.py @@ -60,7 +60,8 @@ class ValidateNodeIDs(pyblish.api.InstancePlugin): # We do want to check the referenced nodes as it might be # part of the end product. id_nodes = lib.get_id_required_nodes(referenced_nodes=True, - nodes=instance[:]) - invalid = [n for n in id_nodes if not lib.get_id(n)] - - return invalid + nodes=instance[:], + # Exclude those with already + # existing ids + existing_ids=False) + return id_nodes 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 5ca9690fd7..58978fb538 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 @@ -43,11 +43,15 @@ class ValidateNodeIdsInDatabase(pyblish.api.InstancePlugin): @classmethod def get_invalid(cls, instance): - invalid = [] + nodes = instance[:] + if not nodes: + return # Get all id required nodes - id_required_nodes = lib.get_id_required_nodes(referenced_nodes=True, - nodes=instance[:]) + id_required_nodes = lib.get_id_required_nodes(referenced_nodes=False, + nodes=nodes) + if not id_required_nodes: + return # check ids against database ids project_name = instance.context.data["projectName"] @@ -58,6 +62,7 @@ class ValidateNodeIdsInDatabase(pyblish.api.InstancePlugin): } # Get all asset IDs + invalid = [] for node in id_required_nodes: cb_id = lib.get_id(node) From e73a4ef4bf11f65a20b1303ec0c2bb41535e102a Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Fri, 29 Mar 2024 20:16:35 +0100 Subject: [PATCH 033/111] Only collect file dependencies if enabled in settings and only collect if renderlayer family is present --- .../publish/collect_file_dependencies.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/collect_file_dependencies.py b/client/ayon_core/hosts/maya/plugins/publish/collect_file_dependencies.py index 94fcc834e1..93b46c511b 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/collect_file_dependencies.py +++ b/client/ayon_core/hosts/maya/plugins/publish/collect_file_dependencies.py @@ -1,5 +1,3 @@ -import json - from maya import cmds import pyblish.api @@ -11,18 +9,24 @@ class CollectFileDependencies(pyblish.api.ContextPlugin): label = "Collect File Dependencies" order = pyblish.api.CollectorOrder - 0.49 hosts = ["maya"] + families = ["renderlayer"] + + @classmethod + def apply_settings(cls, project_settings, system_settings): + # Disable plug-in if not used for deadline submission anyway + settings = project_settings["deadline"]["publish"]["MayaSubmitDeadline"] # noqa + cls.enabled = settings.get("asset_dependencies", True) def process(self, context): - dependencies = [] + dependencies = set() for node in cmds.ls(type="file"): path = cmds.getAttr("{}.{}".format(node, "fileTextureName")) if path not in dependencies: - dependencies.append(path) + dependencies.add(path) for node in cmds.ls(type="AlembicNode"): path = cmds.getAttr("{}.{}".format(node, "abc_File")) if path not in dependencies: - dependencies.append(path) + dependencies.add(path) - context.data["fileDependencies"] = dependencies - self.log.debug(json.dumps(dependencies, indent=4)) + context.data["fileDependencies"] = list(dependencies) From 2bf1ca2a2df2fc5009cdd4d4d704e4a4c791b8d9 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 2 Apr 2024 10:03:59 +0200 Subject: [PATCH 034/111] Validate only when redshift renderer is used --- ...validate_current_renderlayer_renderable.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_current_renderlayer_renderable.py b/client/ayon_core/hosts/maya/plugins/publish/validate_current_renderlayer_renderable.py index da8468c1b6..045e22545c 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_current_renderlayer_renderable.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_current_renderlayer_renderable.py @@ -36,6 +36,12 @@ class ValidateCurrentRenderLayerIsRenderable(pyblish.api.ContextPlugin, if not context_plugin_should_run(self, context): return + # This validator only makes sense when publishing renderlayer instances + # with Redshift. We skip validation if there isn't any. + if not any(self.is_active_redshift_render_instance(instance) + for instance in context): + return + cameras = cmds.ls(type="camera", long=True) renderable = any(c for c in cameras if cmds.getAttr(c + ".renderable")) if not renderable: @@ -47,3 +53,22 @@ class ValidateCurrentRenderLayerIsRenderable(pyblish.api.ContextPlugin, ), description=inspect.getdoc(self) ) + + @staticmethod + def is_active_redshift_render_instance(instance) -> bool: + """Return whether instance is an active renderlayer instance set to + render with Redshift renderer.""" + if not instance.data.get("active", True): + return False + + # Check this before families just because it's a faster check + if not instance.data.get("renderer") == "redshift": + return False + + families = set() + families.add(instance.data.get("family")) + families.update(instance.data.get("families", [])) + if "renderlayer" not in families: + return False + + return True From ec34bc463fe9e529c6affb8ba2bb95026cad3544 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 2 Apr 2024 16:13:04 +0800 Subject: [PATCH 035/111] support to fix the task in validate context in maya --- .../publish/validate_instance_in_context.py | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_instance_in_context.py b/client/ayon_core/hosts/maya/plugins/publish/validate_instance_in_context.py index c5a3b1659d..ec80eb6e06 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_instance_in_context.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_instance_in_context.py @@ -38,17 +38,20 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, return folder_path = instance.data.get("folderPath") - context_folder_path = self.get_context_folder_path(instance) - if folder_path != context_folder_path: + task = instance.data.get("task") + context = self.get_context(instance) + if (folder_path, task) != context: + context_label = "{} > {}".format(*context) + instance_label = "{} > {}".format(folder_path, task) raise PublishValidationError( message=( - "Instance '{}' publishes to different folder than current" + "Instance '{}' publishes to different context than current" " context: {}. Current context: {}".format( - instance.name, folder_path, context_folder_path + instance.name, instance_label, context_label ) ), description=( - "## Publishing to a different folder\n" + "## Publishing to a different context data\n" "There are publish instances present which are publishing " "into a different folder than your current context.\n\n" "Usually this is not what you want but there can be cases " @@ -64,14 +67,22 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, @classmethod def repair(cls, instance): - context_folder_path = cls.get_context_folder_path(instance) + context_folder_path, context_task = cls.get_context( + instance) instance_node = instance.data["instance_node"] cmds.setAttr( "{}.folderPath".format(instance_node), context_folder_path, type="string" ) + cmds.setAttr( + "{}.task".format(instance_node), + context_task, + type="string" + ) @staticmethod - def get_context_folder_path(instance): - return instance.context.data["folderPath"] + def get_context(instance): + """Return asset, task from publishing context data""" + context = instance.context + return context.data["folderPath"], context.data["task"] From 39d6ffa1c126f2492277591271318cde35778f59 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 2 Apr 2024 16:37:35 +0800 Subject: [PATCH 036/111] update reset scene reoslution with ayon_api related function --- client/ayon_core/hosts/maya/api/lib.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/lib.py b/client/ayon_core/hosts/maya/api/lib.py index b18d3a0c33..23120f465f 100644 --- a/client/ayon_core/hosts/maya/api/lib.py +++ b/client/ayon_core/hosts/maya/api/lib.py @@ -2640,13 +2640,14 @@ def reset_scene_resolution(): Returns: None """ - - folder_attributes = get_current_project_folder()["attrib"] + project_name = get_current_project_name() + project_entity = ayon_api.get_project(project_name) + project_attribs = project_entity["attrib"] # Set resolution - width = folder_attributes.get("resolutionWidth", 1920) - height = folder_attributes.get("resolutionHeight", 1080) - pixelAspect = folder_attributes.get("pixelAspect", 1) + width = project_attribs.get("resolutionWidth", 1920) + height = project_attribs.get("resolutionHeight", 1080) + pixelAspect = project_attribs.get("pixelAspect", 1) set_scene_resolution(width, height, pixelAspect) From 3d98c1ae0a3fafab4b47af27a659c4d5df13ea5a Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 2 Apr 2024 17:11:11 +0800 Subject: [PATCH 037/111] use taskEntity instead --- client/ayon_core/hosts/maya/api/lib.py | 21 +++++++++++++------ .../plugins/publish/validate_resolution.py | 14 ++++++------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/lib.py b/client/ayon_core/hosts/maya/api/lib.py index 23120f465f..4c25daffc7 100644 --- a/client/ayon_core/hosts/maya/api/lib.py +++ b/client/ayon_core/hosts/maya/api/lib.py @@ -2640,18 +2640,27 @@ def reset_scene_resolution(): Returns: None """ - project_name = get_current_project_name() - project_entity = ayon_api.get_project(project_name) - project_attribs = project_entity["attrib"] + # Set frame start/end + project_name = get_current_project_name() + folder_path = get_current_folder_path() + task_name = get_current_task_name() + + folder_entity = ayon_api.get_folder_by_path( + project_name, folder_path, fields={"id"}) + task_entity = ayon_api.get_task_by_name( + project_name, folder_entity["id"], task_name + ) + task_attributes = task_entity["attrib"] # Set resolution - width = project_attribs.get("resolutionWidth", 1920) - height = project_attribs.get("resolutionHeight", 1080) - pixelAspect = project_attribs.get("pixelAspect", 1) + width = task_attributes.get("resolutionWidth", 1920) + height = task_attributes.get("resolutionHeight", 1080) + pixelAspect = task_attributes.get("pixelAspect", 1) set_scene_resolution(width, height, pixelAspect) + def set_context_settings( fps=True, resolution=True, diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_resolution.py b/client/ayon_core/hosts/maya/plugins/publish/validate_resolution.py index 1e5a9a944c..1398907f6c 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_resolution.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_resolution.py @@ -84,15 +84,15 @@ class ValidateResolution(pyblish.api.InstancePlugin, @classmethod def get_folder_resolution(cls, instance): - folder_attributes = instance.data["folderEntity"]["attrib"] + task_attributes = instance.data["taskEntity"]["attrib"] if ( - "resolutionWidth" in folder_attributes - and "resolutionHeight" in folder_attributes - and "pixelAspect" in folder_attributes + "resolutionWidth" in task_attributes + and "resolutionHeight" in task_attributes + and "pixelAspect" in task_attributes ): - width = folder_attributes["resolutionWidth"] - height = folder_attributes["resolutionHeight"] - pixelAspect = folder_attributes["pixelAspect"] + width = task_attributes["resolutionWidth"] + height = task_attributes["resolutionHeight"] + pixelAspect = task_attributes["pixelAspect"] return int(width), int(height), float(pixelAspect) # Defaults if not found in asset document or project document From 27e8d8d03c2789a69818aa9425df1d5e559f439b Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 2 Apr 2024 17:53:50 +0800 Subject: [PATCH 038/111] update the code with field with 'attrib' --- client/ayon_core/hosts/maya/api/lib.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/lib.py b/client/ayon_core/hosts/maya/api/lib.py index 4c25daffc7..6e15c54d12 100644 --- a/client/ayon_core/hosts/maya/api/lib.py +++ b/client/ayon_core/hosts/maya/api/lib.py @@ -2649,8 +2649,11 @@ def reset_scene_resolution(): folder_entity = ayon_api.get_folder_by_path( project_name, folder_path, fields={"id"}) task_entity = ayon_api.get_task_by_name( - project_name, folder_entity["id"], task_name - ) + project_name, + folder_entity["id"], + task_name, + fields={"attrib"} + ) task_attributes = task_entity["attrib"] # Set resolution width = task_attributes.get("resolutionWidth", 1920) @@ -2660,7 +2663,6 @@ def reset_scene_resolution(): set_scene_resolution(width, height, pixelAspect) - def set_context_settings( fps=True, resolution=True, From 71bb5552f38ea72e1bab07f41281cc3e595070ae Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Tue, 2 Apr 2024 12:30:33 +0200 Subject: [PATCH 039/111] BigRoy's comments - Better doc strings --- client/ayon_core/hosts/houdini/api/lib.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/houdini/api/lib.py b/client/ayon_core/hosts/houdini/api/lib.py index dfdca62b61..111b230252 100644 --- a/client/ayon_core/hosts/houdini/api/lib.py +++ b/client/ayon_core/hosts/houdini/api/lib.py @@ -1003,6 +1003,9 @@ def get_scene_viewer(): Return an instance of a visible viewport. There may be many, some could be closed, any visible are current + + Returns: + Optional[hou.SceneViewer]: A scene viewer, if any. """ panes = hou.ui.paneTabs() panes = [x for x in panes if x.type() == hou.paneTabType.SceneViewer] @@ -1045,7 +1048,9 @@ def sceneview_snapshot( Args: sceneview (hou.SceneViewer): The scene view pane from which you want to take a snapshot. - filepath (str): thumbnail filepath. + filepath (str): thumbnail filepath. it expects `$F4` token + when frame_end is bigger than frame_star other wise + each frame will override its predecessor. frame_start (int): the frame at which snapshot starts frame_end (int): the frame at which snapshot ends """ From f543e560011a6bae6346e9a611ec1cc102fbb690 Mon Sep 17 00:00:00 2001 From: MustafaJafar Date: Tue, 2 Apr 2024 12:36:22 +0200 Subject: [PATCH 040/111] BigRoy's comment - Better logic --- .../publish/extract_active_view_thumbnail.py | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/client/ayon_core/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py b/client/ayon_core/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py index 1be8cb7440..aedcb1da02 100644 --- a/client/ayon_core/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py +++ b/client/ayon_core/hosts/houdini/plugins/publish/extract_active_view_thumbnail.py @@ -27,22 +27,24 @@ class ExtractActiveViewThumbnail(publish.Extractor): return thumbnail = instance.data.get("thumbnailPath") - if not thumbnail: - view_thumbnail = self.get_view_thumbnail(instance) - if not view_thumbnail: - return + if thumbnail: + # A thumbnail was already set for this instance + return - self.log.debug("Setting instance thumbnail path to: {}".format( - view_thumbnail - )) - instance.data["thumbnailPath"] = view_thumbnail + view_thumbnail = self.get_view_thumbnail(instance) + if not view_thumbnail: + return + self.log.debug("Setting instance thumbnail path to: {}" + .format(view_thumbnail) + ) + instance.data["thumbnailPath"] = view_thumbnail def get_view_thumbnail(self, instance): sceneview = lib.get_scene_viewer() if sceneview is None: - self.log.warning("Skipping Extract Active View Thumbnail" - " because no scene view was detected.") + self.log.debug("Skipping Extract Active View Thumbnail" + " because no scene view was detected.") return with tempfile.NamedTemporaryFile("w", suffix=".jpg", delete=False) as tmp: From d68664b20b22dbf9051d78ec19ac4653e3f97b0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Tue, 2 Apr 2024 14:21:12 +0200 Subject: [PATCH 041/111] :bug: fix compatibility with Qt6 --- client/ayon_core/hosts/maya/vendor/python/capture.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/maya/vendor/python/capture.py b/client/ayon_core/hosts/maya/vendor/python/capture.py index 7a3be38f56..4ccfdb35f3 100644 --- a/client/ayon_core/hosts/maya/vendor/python/capture.py +++ b/client/ayon_core/hosts/maya/vendor/python/capture.py @@ -869,7 +869,11 @@ def _get_screen_size(): if _in_standalone(): return [0, 0] - rect = QtWidgets.QDesktopWidget().screenGeometry(-1) + try: + rect = QtWidgets.QDesktopWidget().screenGeometry(-1) + except AttributeError: + # in Qt6 it is a different call + rect = QtWidgets.QApplication.primaryScreen().availableGeometry() return [rect.width(), rect.height()] From 059191c8d47ac321f8804b55cabad9425968ddce Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 2 Apr 2024 22:03:04 +0800 Subject: [PATCH 042/111] tweak on validation error message --- .../max/plugins/publish/validate_instance_in_context.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py index 963a601009..5107665235 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py @@ -38,15 +38,15 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, context_label = "{} > {}".format(*context) instance_label = "{} > {}".format(folderPath, task) message = ( - "Instance '{}' publishes to different context than current " - "context: {}. Current context: {}".format( + "Instance '{}' publishes to different context(folder or task) " + "than current context: {}. Current context: {}".format( instance.name, instance_label, context_label ) ) raise PublishValidationError( message=message, description=( - "## Publishing to a different context data\n" + "## Publishing to a different context data(folder or task)\n" "There are publish instances present which are publishing " "into a different folder path or task than your current context.\n\n" "Usually this is not what you want but there can be cases " From 98bed9f5c610deb2f947d643573ce18bd85054da Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 2 Apr 2024 18:10:03 +0200 Subject: [PATCH 043/111] Update to latest avalon core --- client/ayon_core/hosts/fusion/api/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/fusion/api/plugin.py b/client/ayon_core/hosts/fusion/api/plugin.py index c2ecea93fc..80167189a5 100644 --- a/client/ayon_core/hosts/fusion/api/plugin.py +++ b/client/ayon_core/hosts/fusion/api/plugin.py @@ -126,7 +126,7 @@ class GenericCreateSaver(Creator): if ( original_product_name != product_name or tool.GetData("openpype.task") != data["task"] - or tool.GetData("openpype.asset") != data["asset"] + or tool.GetData("openpype.folderPath") != data["folderPath"] or original_format != data["creator_attributes"]["image_format"] ): self._configure_saver_tool(data, tool, product_name) From dd77f243ddd2eaf3ed26ca8ec66d50af6e914451 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 11:42:10 +0200 Subject: [PATCH 044/111] Allow specifying raw JSON custom tools menu for Maya. --- client/ayon_core/hosts/maya/api/menu.py | 12 +++++- .../maya/server/settings/scriptsmenu.py | 41 ++++++++++++++++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/menu.py b/client/ayon_core/hosts/maya/api/menu.py index 0cb7edd40d..bc01b8b42c 100644 --- a/client/ayon_core/hosts/maya/api/menu.py +++ b/client/ayon_core/hosts/maya/api/menu.py @@ -1,4 +1,5 @@ import os +import json import logging from functools import partial @@ -214,9 +215,18 @@ def install(project_settings): ) return - config = project_settings["maya"]["scriptsmenu"]["definition"] _menu = project_settings["maya"]["scriptsmenu"]["name"] + config = project_settings["maya"]["scriptsmenu"]["definition"] + if project_settings["maya"]["scriptsmenu"].get("use_json_definition"): + data = project_settings["maya"]["scriptsmenu"]["definition_json"] + try: + config = json.loads(data) + except json.JSONDecodeError as exc: + print("Skipping studio menu, error decoding JSON definition.") + log.error(exc) + return + if not config: log.warning("Skipping studio menu, no definition found.") return diff --git a/server_addon/maya/server/settings/scriptsmenu.py b/server_addon/maya/server/settings/scriptsmenu.py index d01dff1621..fe80d816df 100644 --- a/server_addon/maya/server/settings/scriptsmenu.py +++ b/server_addon/maya/server/settings/scriptsmenu.py @@ -1,3 +1,7 @@ +import json + +from pydantic import validator +from ayon_server.exceptions import BadRequestException from ayon_server.settings import BaseSettingsModel, SettingsField @@ -15,18 +19,52 @@ class ScriptsmenuSubmodel(BaseSettingsModel): class ScriptsmenuModel(BaseSettingsModel): + """Add a custom scripts menu to Maya""" _isGroup = True name: str = SettingsField(title="Menu Name") + use_json_definition: bool = SettingsField( + title="Use Raw JSON Definition", + description="When enabled, the definition field will be ignored. " + "Instead the menu will be build from the raw JSON " + "definition below it." + ) definition: list[ScriptsmenuSubmodel] = SettingsField( default_factory=list, title="Menu Definition", description="Scriptmenu Items Definition" ) + definition_json: str = SettingsField( + "[]", title="Definition JSON", widget="textarea", + description=( + "When Use Raw JSON definition is enabled this field will be used " + "to put the direct JSON content instead of using the definition " + "menu builder UI above. For more details on the JSON format, see " + "[here](https://github.com/Colorbleed/scriptsmenu?tab=readme-ov-file#configuration)." # noqa: E501 + ) + ) + + @validator("definition_json") + def validate_json(cls, value): + if not value.strip(): + return "[]" + try: + converted_value = json.loads(value) + success = isinstance(converted_value, list) + except json.JSONDecodeError: + success = False + + if not success: + raise BadRequestException( + "The definition can't be parsed as json list object" + ) + return value + DEFAULT_SCRIPTSMENU_SETTINGS = { "name": "Custom Tools", + "use_json_definition": False, "definition": [ { "type": "action", @@ -39,5 +77,6 @@ DEFAULT_SCRIPTSMENU_SETTINGS = { "shader" ] } - ] + ], + "definition_raw": "" } From 6109803c1d48a0a302e158e81724aff96821f070 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 16:08:09 +0200 Subject: [PATCH 045/111] Update instances using `CreateContext` to correctly update product names if needed - Also rely on task attributes for resolution and frame ranges instead of folder attributes --- client/ayon_core/hosts/maya/api/lib.py | 71 +++++++++++++++----------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/lib.py b/client/ayon_core/hosts/maya/api/lib.py index 8d418813cd..52ac67f3e2 100644 --- a/client/ayon_core/hosts/maya/api/lib.py +++ b/client/ayon_core/hosts/maya/api/lib.py @@ -37,7 +37,7 @@ from ayon_core.pipeline import ( AYON_CONTAINER_ID, ) from ayon_core.lib import NumberDef -from ayon_core.pipeline.context_tools import get_current_folder_entity +from ayon_core.pipeline.context_tools import get_current_task_entity from ayon_core.pipeline.create import CreateContext from ayon_core.lib.profiles_filtering import filter_profiles @@ -2636,7 +2636,7 @@ def reset_scene_resolution(): None """ - folder_attributes = get_current_folder_entity()["attrib"] + folder_attributes = get_current_task_entity(fields={"attrib"})["attrib"] # Set resolution width = folder_attributes.get("resolutionWidth", 1920) @@ -3244,33 +3244,46 @@ def update_content_on_context_change(): """ This will update scene content to match new folder on context change """ - scene_sets = cmds.listSets(allSets=True) - folder_entity = get_current_folder_entity() - folder_attributes = folder_entity["attrib"] - new_folder_path = folder_entity["path"] - for s in scene_sets: - try: - if cmds.getAttr("{}.id".format(s)) in { - AYON_INSTANCE_ID, AVALON_INSTANCE_ID - }: - attr = cmds.listAttr(s) - print(s) - if "folderPath" in attr: - print( - " - setting folder to: [ {} ]".format(new_folder_path) - ) - cmds.setAttr( - "{}.folderPath".format(s), - new_folder_path, type="string" - ) - if "frameStart" in attr: - cmds.setAttr("{}.frameStart".format(s), - folder_attributes["frameStart"]) - if "frameEnd" in attr: - cmds.setAttr("{}.frameEnd".format(s), - folder_attributes["frameEnd"],) - except ValueError: - pass + + host = registered_host() + create_context = CreateContext(host) + folder_entity = get_current_task_entity(fields={"attrib"}) + + instance_values = { + "folderPath": create_context.get_current_folder_path(), + "task": create_context.get_current_task_name(), + } + creator_attribute_values = { + "frameStart": folder_entity["attrib"]["frameStart"], + "frameEnd": folder_entity["attrib"]["frameEnd"], + } + + has_changes = False + for instance in create_context.instances: + for key, value in instance_values.items(): + if key not in instance or instance[key] == value: + continue + + # Update instance value + print(f"Updating {instance.product_name} {key} to: {value}") + instance[key] = value + has_changes = True + + creator_attributes = instance.creator_attributes + for key, value in creator_attribute_values.items(): + if ( + key not in creator_attributes + or creator_attributes[key] == value + ): + continue + + # Update instance creator attribute value + print(f"Updating {instance.product_name} {key} to: {value}") + instance[key] = value + has_changes = True + + if has_changes: + create_context.save_changes() def show_message(title, msg): From 5acf6f3b08fc3423c4af9a7bea4fc442a50b80a8 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 16:12:51 +0200 Subject: [PATCH 046/111] Update variable name --- client/ayon_core/hosts/maya/api/lib.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/lib.py b/client/ayon_core/hosts/maya/api/lib.py index 52ac67f3e2..8bf753693f 100644 --- a/client/ayon_core/hosts/maya/api/lib.py +++ b/client/ayon_core/hosts/maya/api/lib.py @@ -2636,12 +2636,12 @@ def reset_scene_resolution(): None """ - folder_attributes = get_current_task_entity(fields={"attrib"})["attrib"] + task_attributes = get_current_task_entity(fields={"attrib"})["attrib"] # Set resolution - width = folder_attributes.get("resolutionWidth", 1920) - height = folder_attributes.get("resolutionHeight", 1080) - pixelAspect = folder_attributes.get("pixelAspect", 1) + width = task_attributes.get("resolutionWidth", 1920) + height = task_attributes.get("resolutionHeight", 1080) + pixelAspect = task_attributes.get("pixelAspect", 1) set_scene_resolution(width, height, pixelAspect) From ef0cc38d7f7b3cb959444673c9f28d36ce861338 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 16:13:02 +0200 Subject: [PATCH 047/111] Cosmetics --- client/ayon_core/hosts/maya/api/lib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/lib.py b/client/ayon_core/hosts/maya/api/lib.py index 8bf753693f..07ae65748e 100644 --- a/client/ayon_core/hosts/maya/api/lib.py +++ b/client/ayon_core/hosts/maya/api/lib.py @@ -2641,9 +2641,9 @@ def reset_scene_resolution(): # Set resolution width = task_attributes.get("resolutionWidth", 1920) height = task_attributes.get("resolutionHeight", 1080) - pixelAspect = task_attributes.get("pixelAspect", 1) + pixel_aspect = task_attributes.get("pixelAspect", 1) - set_scene_resolution(width, height, pixelAspect) + set_scene_resolution(width, height, pixel_aspect) def set_context_settings( From c48364cd0546e50d8497a3fc6e163f13d25931a7 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 16:13:32 +0200 Subject: [PATCH 048/111] Update docstring --- client/ayon_core/hosts/maya/api/lib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/lib.py b/client/ayon_core/hosts/maya/api/lib.py index 07ae65748e..72f680943f 100644 --- a/client/ayon_core/hosts/maya/api/lib.py +++ b/client/ayon_core/hosts/maya/api/lib.py @@ -2629,8 +2629,8 @@ def reset_frame_range(playback=True, render=True, fps=True): def reset_scene_resolution(): """Apply the scene resolution from the project definition - scene resolution can be overwritten by an folder if the folder.attrib - contains any information regarding scene resolution . + The scene resolution will be retrieved from the current task entity's + attributes. Returns: None From 2803b8521f701291547325053df8de9ff987f8e0 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 16:29:52 +0200 Subject: [PATCH 049/111] Remove enforced updating of context settings (this is replaced by the "update on context change" dialog) --- client/ayon_core/hosts/maya/api/pipeline.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/pipeline.py b/client/ayon_core/hosts/maya/api/pipeline.py index 8e6e2ccd8a..eb46088ecd 100644 --- a/client/ayon_core/hosts/maya/api/pipeline.py +++ b/client/ayon_core/hosts/maya/api/pipeline.py @@ -653,10 +653,6 @@ def on_task_changed(): "Can't set project for new context because path does not exist: {}" ).format(workdir)) - with lib.suspended_refresh(): - lib.set_context_settings() - lib.update_content_on_context_change() - global _about_to_save if not lib.IS_HEADLESS and _about_to_save: # Let's prompt the user to update the context settings or not From 44e89240f199478ce7dc7e2404220e2e1b7d46d1 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 17:05:17 +0200 Subject: [PATCH 050/111] Maya: Expose loaders enabled state to settings --- .../hosts/maya/plugins/load/actions.py | 5 + server_addon/maya/server/settings/loaders.py | 111 +++++++++++++++++- 2 files changed, 115 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/maya/plugins/load/actions.py b/client/ayon_core/hosts/maya/plugins/load/actions.py index a98fe97692..982f007251 100644 --- a/client/ayon_core/hosts/maya/plugins/load/actions.py +++ b/client/ayon_core/hosts/maya/plugins/load/actions.py @@ -125,6 +125,11 @@ class ImportMayaLoader(ayon_core.hosts.maya.api.plugin.Loader): ) ] + @classmethod + def apply_settings(cls, project_settings): + super(ImportMayaLoader, cls).apply_settings(project_settings) + cls.enabled = cls.load_settings["import_loader"].get("enabled", True) + def load(self, context, name=None, namespace=None, data=None): import maya.cmds as cmds diff --git a/server_addon/maya/server/settings/loaders.py b/server_addon/maya/server/settings/loaders.py index 418a7046ae..4e949f616a 100644 --- a/server_addon/maya/server/settings/loaders.py +++ b/server_addon/maya/server/settings/loaders.py @@ -2,6 +2,10 @@ from ayon_server.settings import BaseSettingsModel, SettingsField from ayon_server.types import ColorRGB_float, ColorRGBA_uint8 +class LoaderEnabledModel(BaseSettingsModel): + enabled: bool = SettingsField(title="Enabled") + + class ColorsSetting(BaseSettingsModel): model: ColorRGBA_uint8 = SettingsField( (209, 132, 30, 1.0), title="Model:") @@ -94,6 +98,7 @@ class ReferenceLoaderModel(BaseSettingsModel): class ImportLoaderModel(BaseSettingsModel): + enabled: bool = SettingsField(title="Enabled") namespace: str = SettingsField(title="Namespace") group_name: str = SettingsField(title="Group name") @@ -113,6 +118,89 @@ class LoadersModel(BaseSettingsModel): title="Import Loader" ) + # Enable/disable loaders + ArnoldStandinLoader: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="Arnold Standin Loader" + ) + AssemblyLoader: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="Assembly Loader" + ) + AudioLoader: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="Audio Loader" + ) + GpuCacheLoader: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="GPU Cache Loader" + ) + FileNodeLoader: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="File Node (Image) Loader" + ) + ImagePlaneLoader: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="Image Plane Loader" + ) + LookLoader: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="Look Loader" + ) + MatchmoveLoader: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="Matchmove Loader" + ) + MultiverseUsdLoader: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="Multiverse USD Loader" + ) + MultiverseUsdOverLoader: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="Multiverse USD Override Loader" + ) + RedshiftProxyLoader: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="Redshift Proxy Loader" + ) + RenderSetupLoader: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="Render Setup Loader" + ) + LoadVDBtoArnold: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="VDB to Arnold Loader" + ) + LoadVDBtoRedShift: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="VDB to Redshift Loader" + ) + LoadVDBtoVRay: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="VDB to V-Ray Loader" + ) + VRayProxyLoader: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="Vray Proxy Loader" + ) + VRaySceneLoader: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="VrayScene Loader" + ) + XgenLoader: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="Xgen Loader" + ) + YetiCacheLoader: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="Yeti Cache Loader" + ) + YetiRigLoader: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="Yeti Rig Loader" + ) + + DEFAULT_LOADERS_SETTING = { "colors": { "model": [209, 132, 30, 1.0], @@ -154,8 +242,29 @@ DEFAULT_LOADERS_SETTING = { "display_handle": True }, "import_loader": { + "enabled": True, "namespace": "{folder[name]}_{product[name]}_##_", "group_name": "_GRP", "display_handle": True - } + }, + "ArnoldStandinLoader": {"enabled": True}, + "AssemblyLoader": {"enabled": True}, + "AudioLoader": {"enabled": True}, + "FileNodeLoader": {"enabled": True}, + "GpuCacheLoader": {"enabled": True}, + "ImagePlaneLoader": {"enabled": True}, + "LookLoader": {"enabled": True}, + "MatchmoveLoader": {"enabled": True}, + "MultiverseUsdLoader": {"enabled": True}, + "MultiverseUsdOverLoader": {"enabled": True}, + "RedshiftProxyLoader": {"enabled": True}, + "RenderSetupLoader": {"enabled": True}, + "LoadVDBtoArnold": {"enabled": True}, + "LoadVDBtoRedShift": {"enabled": True}, + "LoadVDBtoVRay": {"enabled": True}, + "VRayProxyLoader": {"enabled": True}, + "VRaySceneLoader": {"enabled": True}, + "XgenLoader": {"enabled": True}, + "YetiCacheLoader": {"enabled": True}, + "YetiRigLoader": {"enabled": True}, } From fdd3da9b0093fe94e23dca690d85659618b09919 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 17:08:19 +0200 Subject: [PATCH 051/111] Bump maya server addon version --- server_addon/maya/server/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server_addon/maya/server/version.py b/server_addon/maya/server/version.py index 1a4f79a972..e332ce4b6e 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.13" +__version__ = "0.1.14" From 0f77c170cf64dd9cbaa1e16a806c5055acae5ea9 Mon Sep 17 00:00:00 2001 From: Kayla Man <64118225+moonyuet@users.noreply.github.com> Date: Wed, 3 Apr 2024 23:43:11 +0800 Subject: [PATCH 052/111] Update client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py --- .../hosts/max/plugins/publish/validate_instance_in_context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py index 5107665235..001c8d35be 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py @@ -46,7 +46,7 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, raise PublishValidationError( message=message, description=( - "## Publishing to a different context data(folder or task)\n" + "## Publishing to a different context folder or task\n" "There are publish instances present which are publishing " "into a different folder path or task than your current context.\n\n" "Usually this is not what you want but there can be cases " From 8ebb52603aa6dcf109a6fad31bc6cf7648afba10 Mon Sep 17 00:00:00 2001 From: Kayla Man <64118225+moonyuet@users.noreply.github.com> Date: Wed, 3 Apr 2024 23:43:19 +0800 Subject: [PATCH 053/111] Update client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py Co-authored-by: Roy Nieterau --- .../hosts/max/plugins/publish/validate_instance_in_context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py index 001c8d35be..cecfd5fd12 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py @@ -38,7 +38,7 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, context_label = "{} > {}".format(*context) instance_label = "{} > {}".format(folderPath, task) message = ( - "Instance '{}' publishes to different context(folder or task) " + "Instance '{}' publishes to different folder or task " "than current context: {}. Current context: {}".format( instance.name, instance_label, context_label ) From 42e7e32264e034fc35af8b4c75e4b1bd8c12634d Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 19:47:38 +0200 Subject: [PATCH 054/111] Cache the result of the folder ids query so we don't query per instance --- .../publish/validate_node_ids_in_database.py | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) 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 5ca9690fd7..85850d413b 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 @@ -50,12 +50,7 @@ class ValidateNodeIdsInDatabase(pyblish.api.InstancePlugin): nodes=instance[:]) # check ids against database ids - project_name = instance.context.data["projectName"] - folder_entities = ayon_api.get_folders(project_name, fields={"id"}) - folder_ids = { - folder_entity["id"] - for folder_entity in folder_entities - } + folder_ids = cls.get_project_folder_ids(context=instance.context) # Get all asset IDs for node in id_required_nodes: @@ -71,3 +66,22 @@ class ValidateNodeIdsInDatabase(pyblish.api.InstancePlugin): invalid.append(node) return invalid + + @classmethod + def get_project_folder_ids(cls, context): + # We query the database only for the first instance instead of + # per instance by storing a cache in the context + key = "__cache_project_folders_ids" + if key in context.data: + return context.data[key] + + # check ids against database + project_name = context.data["projectName"] + folder_entities = ayon_api.get_folders(project_name, fields={"id"}) + folder_ids = { + folder_entity["id"] + for folder_entity in folder_entities + } + + context.data[key] = folder_ids + return folder_ids From 8daf9d1d39b4779f82b97c2f5e7b12791642f820 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 19:50:02 +0200 Subject: [PATCH 055/111] Opt-out early if there's nothing to validate anyway --- .../maya/plugins/publish/validate_node_ids_in_database.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 85850d413b..a26a4b6843 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 @@ -43,16 +43,17 @@ class ValidateNodeIdsInDatabase(pyblish.api.InstancePlugin): @classmethod def get_invalid(cls, instance): - invalid = [] - # Get all id required nodes id_required_nodes = lib.get_id_required_nodes(referenced_nodes=True, nodes=instance[:]) + if not id_required_nodes: + return [] # check ids against database ids folder_ids = cls.get_project_folder_ids(context=instance.context) # Get all asset IDs + invalid = [] for node in id_required_nodes: cb_id = lib.get_id(node) From ed99521224f1278974d556b9fbb7a253848f2215 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 19:50:09 +0200 Subject: [PATCH 056/111] Add docstring --- .../plugins/publish/validate_node_ids_in_database.py | 9 +++++++++ 1 file changed, 9 insertions(+) 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 a26a4b6843..814202c66c 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 @@ -70,6 +70,15 @@ class ValidateNodeIdsInDatabase(pyblish.api.InstancePlugin): @classmethod def get_project_folder_ids(cls, context): + """Return all folder ids in the current project. + + Arguments: + context (pyblish.api.Context): The publish context. + + Returns: + set[str]: All folder ids in the current project. + + """ # We query the database only for the first instance instead of # per instance by storing a cache in the context key = "__cache_project_folders_ids" From 322615906d7115ca1962f97f9deb9ac96c381ed1 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 19:50:31 +0200 Subject: [PATCH 057/111] Cosmetics --- .../maya/plugins/publish/validate_node_ids_in_database.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 814202c66c..94f3aad8aa 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 @@ -37,8 +37,8 @@ class ValidateNodeIdsInDatabase(pyblish.api.InstancePlugin): invalid = self.get_invalid(instance) if invalid: raise PublishValidationError( - ("Found folder ids which are not related to " - "current project in instance: `{}`").format(instance.name)) + "Found folder ids which are not related to " + "current project in instance: `{}`".format(instance.name)) @classmethod def get_invalid(cls, instance): From a5c19963d5f54ac0007b60e531c67eb534cc7d5a Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 19:56:12 +0200 Subject: [PATCH 058/111] Improve key --- .../hosts/maya/plugins/publish/validate_node_ids_in_database.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 94f3aad8aa..8e29edc0ce 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 @@ -81,7 +81,7 @@ class ValidateNodeIdsInDatabase(pyblish.api.InstancePlugin): """ # We query the database only for the first instance instead of # per instance by storing a cache in the context - key = "__cache_project_folders_ids" + key = "__cache_project_folder_ids" if key in context.data: return context.data[key] From eb0e1c9cf7b1f40a1642a63344dd8354632c21ea Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 19:59:23 +0200 Subject: [PATCH 059/111] Opt-out even earlier if instance has no members/nodes. --- .../maya/plugins/publish/validate_node_ids_in_database.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 8e29edc0ce..bb6b590f5c 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 @@ -43,9 +43,13 @@ class ValidateNodeIdsInDatabase(pyblish.api.InstancePlugin): @classmethod def get_invalid(cls, instance): + nodes = instance[:] + if not nodes: + return + # Get all id required nodes id_required_nodes = lib.get_id_required_nodes(referenced_nodes=True, - nodes=instance[:]) + nodes=nodes) if not id_required_nodes: return [] From daa07a8a7495ac7c1c7961a6100b9fad35d6909d Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 20:09:59 +0200 Subject: [PATCH 060/111] Improve report --- .../maya/plugins/publish/validate_node_ids_unique.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_unique.py b/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_unique.py index f4994922ce..735441a921 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_unique.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_unique.py @@ -41,7 +41,7 @@ class ValidateNodeIdsUnique(pyblish.api.InstancePlugin): if invalid: label = "Nodes found with non-unique folder ids" raise PublishValidationError( - message="{}: {}".format(label, invalid), + message="{}, see log".format(label), title="Non-unique folder ids on nodes", description="{}\n- {}".format(label, "\n- ".join(sorted(invalid))) @@ -70,7 +70,12 @@ class ValidateNodeIdsUnique(pyblish.api.InstancePlugin): _iteritems = getattr(ids, "iteritems", ids.items) for _ids, members in _iteritems(): if len(members) > 1: - cls.log.error("ID found on multiple nodes: '%s'" % members) + members_text = "\n".join( + "- {}".format(member) for member in sorted(members) + ) + cls.log.error( + "ID found on multiple nodes:\n{}".format(members_text) + ) invalid.extend(members) return invalid From be9c8a531b47e1775220cafd7d7cef06c626ba33 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 20:10:19 +0200 Subject: [PATCH 061/111] Move import to top --- .../hosts/maya/plugins/publish/validate_node_ids_unique.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_unique.py b/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_unique.py index 735441a921..6c838d2b86 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_unique.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_unique.py @@ -8,6 +8,8 @@ from ayon_core.pipeline.publish import ( import ayon_core.hosts.maya.api.action from ayon_core.hosts.maya.api import lib +from maya import cmds + class ValidateNodeIdsUnique(pyblish.api.InstancePlugin): """Validate the nodes in the instance have a unique Colorbleed Id @@ -54,7 +56,6 @@ class ValidateNodeIdsUnique(pyblish.api.InstancePlugin): # Check only non intermediate shapes # todo: must the instance itself ensure to have no intermediates? # todo: how come there are intermediates? - from maya import cmds instance_members = cmds.ls(instance, noIntermediate=True, long=True) # Collect each id with their members From b4139cb10ea8523e107993f409dbfa1cb0086ed6 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 20:11:19 +0200 Subject: [PATCH 062/111] Remove Python 2 optimization --- .../hosts/maya/plugins/publish/validate_node_ids_unique.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_unique.py b/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_unique.py index 6c838d2b86..6b44a307d2 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_unique.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_node_ids_unique.py @@ -68,8 +68,7 @@ class ValidateNodeIdsUnique(pyblish.api.InstancePlugin): # Take only the ids with more than one member invalid = list() - _iteritems = getattr(ids, "iteritems", ids.items) - for _ids, members in _iteritems(): + for members in ids.values(): if len(members) > 1: members_text = "\n".join( "- {}".format(member) for member in sorted(members) From 630f03ac946fd7eb7a1b5fb74ac0f15fe5ea06f4 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 21:09:31 +0200 Subject: [PATCH 063/111] Fix: remove from list while iterating over a copy --- client/ayon_core/hosts/maya/plugins/publish/collect_look.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/collect_look.py b/client/ayon_core/hosts/maya/plugins/publish/collect_look.py index 00e1855b19..3df83276e9 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/collect_look.py +++ b/client/ayon_core/hosts/maya/plugins/publish/collect_look.py @@ -59,7 +59,7 @@ for node_type in list(FILE_NODES.keys()): if node_type not in all_node_types: FILE_NODES.pop(node_type) -for node_type in RENDER_SET_TYPES: +for node_type in list(RENDER_SET_TYPES): if node_type not in all_node_types: RENDER_SET_TYPES.remove(node_type) del all_node_types From c873416b6a01032304973f8570a60f06c3d64686 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 21:10:36 +0200 Subject: [PATCH 064/111] Use list comprehension instead (faster than `.remove`) --- client/ayon_core/hosts/maya/plugins/publish/collect_look.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/collect_look.py b/client/ayon_core/hosts/maya/plugins/publish/collect_look.py index 3df83276e9..314f0dc01f 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/collect_look.py +++ b/client/ayon_core/hosts/maya/plugins/publish/collect_look.py @@ -59,9 +59,8 @@ for node_type in list(FILE_NODES.keys()): if node_type not in all_node_types: FILE_NODES.pop(node_type) -for node_type in list(RENDER_SET_TYPES): - if node_type not in all_node_types: - RENDER_SET_TYPES.remove(node_type) +RENDER_SET_TYPES = [node_type for node_type in RENDER_SET_TYPES + if node_type in all_node_types] del all_node_types # Cache pixar dependency node types so we can perform a type lookup against it From adf5b24bab6f75ef3d737142b7215dfc260dd8f0 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 21:11:58 +0200 Subject: [PATCH 065/111] Report num materials with textures --- client/ayon_core/hosts/maya/plugins/publish/collect_look.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/ayon_core/hosts/maya/plugins/publish/collect_look.py b/client/ayon_core/hosts/maya/plugins/publish/collect_look.py index 314f0dc01f..31d3e7a2f7 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/collect_look.py +++ b/client/ayon_core/hosts/maya/plugins/publish/collect_look.py @@ -359,6 +359,7 @@ class CollectLook(pyblish.api.InstancePlugin): "rman__surface", "rman__displacement" ] + materials = [] if look_sets: self.log.debug("Found look sets: {}".format(look_sets)) @@ -437,6 +438,8 @@ class CollectLook(pyblish.api.InstancePlugin): not in instance_lookup) self.log.debug("Collected look for %s" % instance) + self.log.info("Collected {} materials with {} " + "textures.".format(len(materials), len(resources))) def collect_sets(self, instance): """Collect all objectSets which are of importance for publishing From 912b22817a1a789c7c0499d0c553d33b10459de8 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 21:34:29 +0200 Subject: [PATCH 066/111] Restructure / optimize logic + improve docstrings --- .../maya/plugins/publish/collect_look.py | 166 +++++++++--------- 1 file changed, 85 insertions(+), 81 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/collect_look.py b/client/ayon_core/hosts/maya/plugins/publish/collect_look.py index 31d3e7a2f7..0c8280ea1b 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/collect_look.py +++ b/client/ayon_core/hosts/maya/plugins/publish/collect_look.py @@ -8,7 +8,7 @@ from maya import cmds # noqa import pyblish.api from ayon_core.hosts.maya.api import lib -SHAPE_ATTRS = ["castsShadows", +SHAPE_ATTRS = {"castsShadows", "receiveShadows", "motionBlur", "primaryVisibility", @@ -16,8 +16,7 @@ SHAPE_ATTRS = ["castsShadows", "visibleInReflections", "visibleInRefractions", "doubleSided", - "opposite"] -SHAPE_ATTRS = set(SHAPE_ATTRS) + "opposite"} def get_pxr_multitexture_file_attrs(node): @@ -108,8 +107,7 @@ def get_look_attrs(node): if cmds.objectType(node, isAType="shape"): attrs = cmds.listAttr(node, changedSinceFileOpen=True) or [] for attr in attrs: - if attr in SHAPE_ATTRS or \ - attr not in SHAPE_ATTRS and attr.startswith('ai'): + if attr in SHAPE_ATTRS or attr.startswith('ai'): result.append(attr) return result @@ -289,7 +287,6 @@ class CollectLook(pyblish.api.InstancePlugin): families = ["look"] label = "Collect Look" hosts = ["maya"] - maketx = True def process(self, instance): """Collect the Look in the instance with the correct layer settings""" @@ -301,15 +298,12 @@ class CollectLook(pyblish.api.InstancePlugin): """Collect looks. Args: - instance: Instance to collect. + instance (pyblish.api.Instance): Instance to collect. """ self.log.debug("Looking for look associations " "for %s" % instance.data['name']) - # Lookup set (optimization) - instance_lookup = set(cmds.ls(instance, long=True)) - # Discover related object sets self.log.debug("Gathering sets ...") sets = self.collect_sets(instance) @@ -350,76 +344,15 @@ class CollectLook(pyblish.api.InstancePlugin): # Collect file nodes used by shading engines (if we have any) files = [] look_sets = list(sets.keys()) - shader_attrs = [ - "surfaceShader", - "volumeShader", - "displacementShader", - "aiSurfaceShader", - "aiVolumeShader", - "rman__surface", - "rman__displacement" - ] - materials = [] if look_sets: self.log.debug("Found look sets: {}".format(look_sets)) - - # Get all material attrs for all look sets to retrieve their inputs - existing_attrs = [] - for look in look_sets: - for attr in shader_attrs: - if cmds.attributeQuery(attr, node=look, exists=True): - existing_attrs.append("{}.{}".format(look, attr)) - - materials = cmds.listConnections(existing_attrs, - source=True, - destination=False) or [] - - self.log.debug("Found materials:\n{}".format(materials)) - - self.log.debug("Found the following sets:\n{}".format(look_sets)) - # Get the entire node chain of the look sets - # history = cmds.listHistory(look_sets, allConnections=True) - # if materials list is empty, listHistory() will crash with - # RuntimeError - history = set() - if materials: - history = set( - cmds.listHistory(materials, allConnections=True)) - - # Since we retrieved history only of the connected materials - # connected to the look sets above we now add direct history - # for some of the look sets directly - # handling render attribute sets - - # Maya (at least 2024) crashes with Warning when render set type - # isn't available. cmds.ls() will return empty list - if RENDER_SET_TYPES: - render_sets = cmds.ls(look_sets, type=RENDER_SET_TYPES) - if render_sets: - history.update( - cmds.listHistory(render_sets, - future=False, - pruneDagObjects=True) - or [] - ) - - # Ensure unique entries only - history = list(history) - - files = cmds.ls(history, - # It's important only node types are passed that - # exist (e.g. for loaded plugins) because otherwise - # the result will turn back empty - type=list(FILE_NODES.keys()), - long=True) - - # Sort for log readability - files.sort() + files = self.collect_file_nodes(look_sets) self.log.debug("Collected file nodes:\n{}".format(files)) - # Collect textures if any file nodes are found + + # Collect texture resources if any file nodes are found resources = [] - for node in files: # sort for log readability + for node in files: resources.extend(self.collect_resources(node)) instance.data["resources"] = resources self.log.debug("Collected resources: {}".format(resources)) @@ -438,8 +371,78 @@ class CollectLook(pyblish.api.InstancePlugin): not in instance_lookup) self.log.debug("Collected look for %s" % instance) - self.log.info("Collected {} materials with {} " - "textures.".format(len(materials), len(resources))) + + def collect_file_nodes(self, look_sets): + """Get the entire node chain of the look sets and return file nodes + + Arguments: + look_sets (List[str]): List of sets and shading engines relevant + to the look. + + Returns: + List[str]: List of file node names. + + """ + + shader_attrs = [ + "surfaceShader", + "volumeShader", + "displacementShader", + "aiSurfaceShader", + "aiVolumeShader", + "rman__surface", + "rman__displacement" + ] + + # Get all material attrs for all look sets to retrieve their inputs + existing_attrs = [] + for look_set in look_sets: + for attr in shader_attrs: + if cmds.attributeQuery(attr, node=look_set, exists=True): + existing_attrs.append("{}.{}".format(look_set, attr)) + + materials = cmds.listConnections(existing_attrs, + source=True, + destination=False) or [] + + self.log.debug("Found materials:\n{}".format(materials)) + + # Get the entire node chain of the look sets + # history = cmds.listHistory(look_sets, allConnections=True) + # if materials list is empty, listHistory() will crash with + # RuntimeError + history = set() + if materials: + history = set(cmds.listHistory(materials, allConnections=True)) + + # Since we retrieved history only of the connected materials connected + # to the look sets above we now add direct history for some of the + # look sets directly handling render attribute sets + + # Maya (at least 2024) crashes with Warning when render set type + # isn't available. cmds.ls() will return empty list + if RENDER_SET_TYPES: + render_sets = cmds.ls(look_sets, type=RENDER_SET_TYPES) + if render_sets: + history.update( + cmds.listHistory(render_sets, + future=False, + pruneDagObjects=True) + or [] + ) + + # Get file nodes in the material history + files = cmds.ls(list(history), + # It's important only node types are passed that + # exist (e.g. for loaded plugins) because otherwise + # the result will turn back empty + type=list(FILE_NODES.keys()), + long=True) + + # Sort for log readability + files.sort() + + return files def collect_sets(self, instance): """Collect all objectSets which are of importance for publishing @@ -448,7 +451,8 @@ class CollectLook(pyblish.api.InstancePlugin): which need to be Args: - instance (list): all nodes to be published + instance (pyblish.api.Instance): publish instance containing all + nodes to be published. Returns: dict @@ -626,7 +630,7 @@ class CollectLook(pyblish.api.InstancePlugin): "source": source, # required for resources "files": files, "color_space": color_space - } # required for resources + } class CollectModelRenderSets(CollectLook): @@ -641,13 +645,13 @@ class CollectModelRenderSets(CollectLook): families = ["model"] label = "Collect Model Render Sets" hosts = ["maya"] - maketx = True def collect_sets(self, instance): """Collect all related objectSets except shadingEngines Args: - instance (list): all nodes to be published + instance (pyblish.api.Instance): publish instance containing all + nodes to be published. Returns: dict From 939794700c704ac7a5f75d7acadec008d40a121d Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 21:35:58 +0200 Subject: [PATCH 067/111] Optimize query --- client/ayon_core/hosts/maya/plugins/publish/collect_look.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/collect_look.py b/client/ayon_core/hosts/maya/plugins/publish/collect_look.py index 0c8280ea1b..9d8bfd270d 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/collect_look.py +++ b/client/ayon_core/hosts/maya/plugins/publish/collect_look.py @@ -667,7 +667,7 @@ class CollectModelRenderSets(CollectLook): if objset in sets: continue - if "shadingEngine" in cmds.nodeType(objset, inherited=True): + if cmds.objectType(objset, isAType="shadingEngine"): continue sets[objset] = {"uuid": lib.get_id(objset), "members": list()} From 0b16bfc42ccaea7014e2dba0f806577d1bb2a3e9 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 3 Apr 2024 22:55:44 +0200 Subject: [PATCH 068/111] Use enum in settings to toggle between the two menu build options --- client/ayon_core/hosts/maya/api/menu.py | 13 ++++---- .../maya/server/settings/scriptsmenu.py | 31 ++++++++++++------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/menu.py b/client/ayon_core/hosts/maya/api/menu.py index bc01b8b42c..e3ef50cdc0 100644 --- a/client/ayon_core/hosts/maya/api/menu.py +++ b/client/ayon_core/hosts/maya/api/menu.py @@ -215,11 +215,12 @@ def install(project_settings): ) return - _menu = project_settings["maya"]["scriptsmenu"]["name"] + menu_settings = project_settings["maya"]["scriptsmenu"] + menu_name = menu_settings["name"] + config = menu_settings["definition"] - config = project_settings["maya"]["scriptsmenu"]["definition"] - if project_settings["maya"]["scriptsmenu"].get("use_json_definition"): - data = project_settings["maya"]["scriptsmenu"]["definition_json"] + if menu_settings.get("definition_type") == "definition_json": + data = menu_settings["definition_json"] try: config = json.loads(data) except json.JSONDecodeError as exc: @@ -233,8 +234,8 @@ def install(project_settings): # run the launcher for Maya menu studio_menu = launchformaya.main( - title=_menu.title(), - objectName=_menu.title().lower().replace(" ", "_") + title=menu_name.title(), + objectName=menu_name.title().lower().replace(" ", "_") ) # apply configuration diff --git a/server_addon/maya/server/settings/scriptsmenu.py b/server_addon/maya/server/settings/scriptsmenu.py index fe80d816df..7b0ba7d831 100644 --- a/server_addon/maya/server/settings/scriptsmenu.py +++ b/server_addon/maya/server/settings/scriptsmenu.py @@ -18,29 +18,36 @@ class ScriptsmenuSubmodel(BaseSettingsModel): ) +_definition_mode_type = [ + {"value": "definition", "label": "Menu Builder"}, + {"value": "definition_json", "label": "Raw JSON (advanced)"} +] + + class ScriptsmenuModel(BaseSettingsModel): """Add a custom scripts menu to Maya""" _isGroup = True name: str = SettingsField(title="Menu Name") - use_json_definition: bool = SettingsField( - title="Use Raw JSON Definition", - description="When enabled, the definition field will be ignored. " - "Instead the menu will be build from the raw JSON " - "definition below it." + + definition_type: str = SettingsField( + title="Define menu using", + description="Choose the way to define the custom scripts menu " + "via settings", + enum_resolver=lambda: _definition_mode_type, + conditionalEnum=True, + default="definition" ) definition: list[ScriptsmenuSubmodel] = SettingsField( default_factory=list, title="Menu Definition", description="Scriptmenu Items Definition" ) - definition_json: str = SettingsField( - "[]", title="Definition JSON", widget="textarea", + "[]", title="Menu Definition JSON", widget="textarea", description=( - "When Use Raw JSON definition is enabled this field will be used " - "to put the direct JSON content instead of using the definition " - "menu builder UI above. For more details on the JSON format, see " + "Define the custom tools menu using a JSON list. " + "For more details on the JSON format, see " "[here](https://github.com/Colorbleed/scriptsmenu?tab=readme-ov-file#configuration)." # noqa: E501 ) ) @@ -64,7 +71,7 @@ class ScriptsmenuModel(BaseSettingsModel): DEFAULT_SCRIPTSMENU_SETTINGS = { "name": "Custom Tools", - "use_json_definition": False, + "definition_type": "definition", "definition": [ { "type": "action", @@ -78,5 +85,5 @@ DEFAULT_SCRIPTSMENU_SETTINGS = { ] } ], - "definition_raw": "" + "definition_json": "[]" } From ca04b809c3e12614497739dd39818b4a4a4b8a00 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 4 Apr 2024 01:43:19 +0200 Subject: [PATCH 069/111] Compute workdir based on instance folder path and task data if it does not match current context --- client/ayon_core/hosts/fusion/api/plugin.py | 31 ++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/fusion/api/plugin.py b/client/ayon_core/hosts/fusion/api/plugin.py index 80167189a5..efe8269120 100644 --- a/client/ayon_core/hosts/fusion/api/plugin.py +++ b/client/ayon_core/hosts/fusion/api/plugin.py @@ -16,6 +16,12 @@ from ayon_core.pipeline import ( AVALON_INSTANCE_ID, AYON_INSTANCE_ID, ) +from ayon_core.pipeline.workfile import get_workdir +from ayon_api import ( + get_project, + get_folder_by_path, + get_task_by_name +) class GenericCreateSaver(Creator): @@ -147,7 +153,30 @@ class GenericCreateSaver(Creator): folder_path = formatting_data["folderPath"] folder_name = folder_path.rsplit("/", 1)[-1] - workdir = os.path.normpath(os.getenv("AYON_WORKDIR")) + # If the folder path and task do not match the current context then the + # workdir is not just the `AYON_WORKDIR`. Hence, we need to actually + # compute the resulting workdir + if ( + data["folderPath"] == self.create_context.get_current_folder_path() + and data["task"] == self.create_context.get_current_task_name() + ): + workdir = os.path.normpath(os.getenv("AYON_WORKDIR")) + else: + # TODO: Optimize this logic + project_name = self.create_context.get_current_project_name() + project_entity = get_project(project_name) + folder_entity = get_folder_by_path(project_name, + data["folderPath"]) + task_entity = get_task_by_name(project_name, + folder_id=folder_entity["id"], + task_name=data["task"]) + workdir = get_workdir( + project_entity=project_entity, + folder_entity=folder_entity, + task_entity=task_entity, + host_name=self.create_context.host_name, + ) + formatting_data.update({ "workdir": workdir, "frame": "0" * frame_padding, From 8e107744eb31d770e34e192b2f78d7090d5bc86b Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 4 Apr 2024 10:30:43 +0100 Subject: [PATCH 070/111] Account for no nodes in container --- client/ayon_core/hosts/maya/api/workfile_template_builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/maya/api/workfile_template_builder.py b/client/ayon_core/hosts/maya/api/workfile_template_builder.py index cb25a722f0..75386d7e64 100644 --- a/client/ayon_core/hosts/maya/api/workfile_template_builder.py +++ b/client/ayon_core/hosts/maya/api/workfile_template_builder.py @@ -286,7 +286,7 @@ class MayaPlaceholderLoadPlugin(PlaceholderPlugin, PlaceholderLoadMixin): if not container: return - roots = cmds.sets(container, q=True) + roots = cmds.sets(container, q=True) or [] ref_node = None try: ref_node = get_reference_node(roots) From 905587a00f88fc5e6038059b2fb6fe3d2c6ea67e Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 4 Apr 2024 12:32:39 +0200 Subject: [PATCH 071/111] remove start.py or ayon executable instead of script --- client/ayon_core/cli.py | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/client/ayon_core/cli.py b/client/ayon_core/cli.py index ab8e9f47f4..2f01f71a98 100644 --- a/client/ayon_core/cli.py +++ b/client/ayon_core/cli.py @@ -11,7 +11,7 @@ import acre from ayon_core import AYON_CORE_ROOT from ayon_core.addon import AddonsManager from ayon_core.settings import get_general_environments -from ayon_core.lib import initialize_ayon_connection +from ayon_core.lib import initialize_ayon_connection, is_running_from_build from .cli_commands import Commands @@ -167,16 +167,29 @@ def run(script): if not script: print("Error: missing path to script file.") + return + + # Remove first argument if it is the same as AYON executable + # - Forwards compatibility with future AYON versions. + # - Current AYON launcher keep the arguments with first argument but + # future versions might remove it. + first_arg = sys.argv[0] + if is_running_from_build(): + comp_path = os.path.join(os.environ["AYON_ROOT"], "start.py") else: + comp_path = os.getenv("AYON_EXECUTABLE") + # Normalize paths for comparison + first_arg = os.path.normpath(first_arg).lower() + comp_path = os.path.normpath(comp_path).lower() + if first_arg == comp_path: + sys.argv.pop(0) - args = sys.argv - args.remove("run") - args.remove(script) - sys.argv = args + # Remove 'run' command from sys.argv + sys.argv.remove("run") - args_string = " ".join(args[1:]) - print(f"... running: {script} {args_string}") - runpy.run_path(script, run_name="__main__", ) + args_string = " ".join(sys.argv[1:]) + print(f"... running: {script} {args_string}") + runpy.run_path(script, run_name="__main__", ) @main_cli.command() From f7ea2cc525924794e2e12f4e6b039fc606808b8c Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 4 Apr 2024 12:42:37 +0200 Subject: [PATCH 072/111] typos and cosmetics Co-authored-by: Roy Nieterau --- client/ayon_core/cli.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/cli.py b/client/ayon_core/cli.py index 2f01f71a98..40227b63b8 100644 --- a/client/ayon_core/cli.py +++ b/client/ayon_core/cli.py @@ -170,8 +170,8 @@ def run(script): return # Remove first argument if it is the same as AYON executable - # - Forwards compatibility with future AYON versions. - # - Current AYON launcher keep the arguments with first argument but + # - Forward compatibility with future AYON versions. + # - Current AYON launcher keeps the arguments with first argument but # future versions might remove it. first_arg = sys.argv[0] if is_running_from_build(): @@ -189,7 +189,7 @@ def run(script): args_string = " ".join(sys.argv[1:]) print(f"... running: {script} {args_string}") - runpy.run_path(script, run_name="__main__", ) + runpy.run_path(script, run_name="__main__") @main_cli.command() From 041933e96bba36f001de2194b160b311d1da4110 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 4 Apr 2024 12:49:52 +0200 Subject: [PATCH 073/111] use pathlib instead --- client/ayon_core/cli.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/client/ayon_core/cli.py b/client/ayon_core/cli.py index 40227b63b8..80fbb57340 100644 --- a/client/ayon_core/cli.py +++ b/client/ayon_core/cli.py @@ -4,6 +4,7 @@ import os import sys import code import traceback +from pathlib import Path import click import acre @@ -178,10 +179,8 @@ def run(script): comp_path = os.path.join(os.environ["AYON_ROOT"], "start.py") else: comp_path = os.getenv("AYON_EXECUTABLE") - # Normalize paths for comparison - first_arg = os.path.normpath(first_arg).lower() - comp_path = os.path.normpath(comp_path).lower() - if first_arg == comp_path: + # Compare paths and remove first argument if it is the same as AYON + if Path(first_arg).resolve() == Path(comp_path).resolve(): sys.argv.pop(0) # Remove 'run' command from sys.argv From a4758f501c11cc3d1e8bfc2d8ea41e129d877713 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 4 Apr 2024 14:19:16 +0200 Subject: [PATCH 074/111] bump version to '0.3.0' --- client/ayon_core/version.py | 2 +- package.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/version.py b/client/ayon_core/version.py index f3ad9713d5..7061e3c126 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.3.0-dev.1" +__version__ = "0.3.0" diff --git a/package.py b/package.py index 470bbf256b..4b511da60d 100644 --- a/package.py +++ b/package.py @@ -1,6 +1,6 @@ name = "core" title = "Core" -version = "0.3.0-dev.1" +version = "0.3.0" client_dir = "ayon_core" From f42ee6049006ca803f90f54db613c9a5dc24b132 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 4 Apr 2024 14:40:00 +0200 Subject: [PATCH 075/111] bump version to '0.3.1-dev.1' --- client/ayon_core/version.py | 2 +- package.py | 2 +- pyproject.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/version.py b/client/ayon_core/version.py index 7061e3c126..a60de0493a 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.3.0" +__version__ = "0.3.1-dev.1" diff --git a/package.py b/package.py index 4b511da60d..79450d029f 100644 --- a/package.py +++ b/package.py @@ -1,6 +1,6 @@ name = "core" title = "Core" -version = "0.3.0" +version = "0.3.1-dev.1" client_dir = "ayon_core" diff --git a/pyproject.toml b/pyproject.toml index bfdc3cca8c..3c9ff4ea0a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ [tool.poetry] name = "ayon-core" -version = "0.3.0" +version = "0.3.1" description = "" authors = ["Ynput Team "] readme = "README.md" From 368444a7f25c2d9a6d044f605a860677f268d2d8 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 4 Apr 2024 22:21:11 +0800 Subject: [PATCH 076/111] use cmds.setattr instead of self._get_attr() --- client/ayon_core/hosts/maya/api/lib_renderproducts.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/lib_renderproducts.py b/client/ayon_core/hosts/maya/api/lib_renderproducts.py index 5f3917f642..6b73639040 100644 --- a/client/ayon_core/hosts/maya/api/lib_renderproducts.py +++ b/client/ayon_core/hosts/maya/api/lib_renderproducts.py @@ -1133,9 +1133,11 @@ class RenderProductsRedshift(ARenderProducts): aovs = list(set(aovs) - set(ref_aovs)) products = [] + # global_aov_enabled = bool( + # self._get_attr("redshiftOptions.aovGlobalEnableMode") + # ) global_aov_enabled = bool( - self._get_attr("redshiftOptions.aovGlobalEnableMode") - ) + cmds.getAttr("redshiftOptions.aovGlobalEnableMode")) colorspace = lib.get_color_management_output_transform() if not global_aov_enabled: # only beauty output From 4a04bd1397a9a5e564c6b5d7e7f7262b53588ccc Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 4 Apr 2024 16:35:49 +0200 Subject: [PATCH 077/111] fix update of context change --- client/ayon_core/tools/workfiles/control.py | 38 ++++++++++----------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/client/ayon_core/tools/workfiles/control.py b/client/ayon_core/tools/workfiles/control.py index 7fa7af1662..2cdcd37d53 100644 --- a/client/ayon_core/tools/workfiles/control.py +++ b/client/ayon_core/tools/workfiles/control.py @@ -659,16 +659,7 @@ class BaseWorkfileController( folder_id != self.get_current_folder_id() or task_name != self.get_current_task_name() ): - folder_entity = ayon_api.get_folder_by_id( - event_data["project_name"], - event_data["folder_id"], - ) - task_entity = ayon_api.get_task_by_name( - event_data["project_name"], - event_data["folder_id"], - event_data["task_name"] - ) - change_current_context(folder_entity, task_entity) + self._change_current_context(project_name, folder_id, task_id) self._host_open_workfile(filepath) @@ -710,16 +701,8 @@ class BaseWorkfileController( folder_id != self.get_current_folder_id() or task_name != self.get_current_task_name() ): - folder_entity = ayon_api.get_folder_by_id( - project_name, folder["id"] - ) - task_entity = ayon_api.get_task_by_name( - project_name, folder["id"], task_name - ) - change_current_context( - folder_entity, - task_entity, - template_key=template_key + self._change_current_context( + project_name, folder_id, task_id, template_key ) # Save workfile @@ -745,3 +728,18 @@ class BaseWorkfileController( # Trigger after save events emit_event("workfile.save.after", event_data, source="workfiles.tool") self.reset() + + def _change_current_context( + self, project_name, folder_id, task_id, template_key=None + ): + # Change current context + folder_entity = self.get_folder_entity(project_name, folder_id) + task_entity = self.get_task_entity(project_name, task_id) + change_current_context( + folder_entity, + task_entity, + template_key=template_key + ) + self._current_folder_id = folder_entity["id"] + self._current_folder_path = folder_entity["path"] + self._current_task_name = task_entity["name"] From 1e0c115a5ad52375b63060250e32fd8a95037f82 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 4 Apr 2024 16:38:00 +0200 Subject: [PATCH 078/111] Improve artist-facing report --- .../plugins/publish/validate_model_content.py | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_model_content.py b/client/ayon_core/hosts/maya/plugins/publish/validate_model_content.py index 97d602a9ad..015f4c11ed 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_model_content.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_model_content.py @@ -1,3 +1,5 @@ +import inspect + from maya import cmds import pyblish.api @@ -14,8 +16,7 @@ class ValidateModelContent(pyblish.api.InstancePlugin, OptionalPyblishPluginMixin): """Adheres to the content of 'model' product type - - Must have one top group. (configurable) - - Must only contain: transforms, meshes and groups + See `get_description` for more details. """ @@ -35,7 +36,8 @@ class ValidateModelContent(pyblish.api.InstancePlugin, content_instance = instance.data.get("setMembers", None) if not content_instance: - cls.log.error("Instance has no nodes!") + cls.log.error("Model instance has no nodes. " + "It is not allowed to be empty") return [instance.data["instance_node"]] # All children will be included in the extracted export so we also @@ -53,10 +55,13 @@ class ValidateModelContent(pyblish.api.InstancePlugin, invalid = set(nodes) - set(valid) if invalid: + # List as bullet points + invalid_bullets = "\n".join(f"- {node}" for node in invalid) + cls.log.error( - "These nodes are not allowed: {}.\n" - "The valid node types are: {}".format(", ".join(invalid), - ", ".join(cls.allowed)) + "These nodes are not allowed:\n{}\n" + "The valid node types are: {}".format( + invalid_bullets, ", ".join(cls.allowed)) ) return list(invalid) @@ -113,10 +118,20 @@ class ValidateModelContent(pyblish.api.InstancePlugin, raise PublishValidationError( title="Model content is invalid", message="Model content is invalid. See log for more details.", - description=( - "## Model content is invalid\n" - "Your model instance does not adhere to the rules of a " - "model.\n\n" - "See log for more details." - ) + description=self.get_description() ) + + @classmethod + def get_description(cls): + return inspect.cleandoc(f""" + ### Model content is invalid + + Your model instance does not adhere to the rules of a + model product type: + + - Must have at least one visible shape in it, like a mesh. + - Must have one root node. When exporting multiple meshes they + must be inside a group. + - May only contain the following node types: + {", ".join(cls.allowed)} + """) From 2701d4bf8aeddb4da0841b49d7d06451ee5f06d8 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 4 Apr 2024 16:46:15 +0200 Subject: [PATCH 079/111] removed unnecessary `reset` call --- client/ayon_core/tools/workfiles/control.py | 1 - 1 file changed, 1 deletion(-) diff --git a/client/ayon_core/tools/workfiles/control.py b/client/ayon_core/tools/workfiles/control.py index 2cdcd37d53..3048e6be94 100644 --- a/client/ayon_core/tools/workfiles/control.py +++ b/client/ayon_core/tools/workfiles/control.py @@ -727,7 +727,6 @@ class BaseWorkfileController( # Trigger after save events emit_event("workfile.save.after", event_data, source="workfiles.tool") - self.reset() def _change_current_context( self, project_name, folder_id, task_id, template_key=None From fca484dd01cb84f1b14f23d1d50690955eeae57a Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 4 Apr 2024 17:11:26 +0200 Subject: [PATCH 080/111] Improve log readability --- .../hosts/maya/plugins/publish/validate_model_content.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_model_content.py b/client/ayon_core/hosts/maya/plugins/publish/validate_model_content.py index 015f4c11ed..1001bee91f 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_model_content.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_model_content.py @@ -59,7 +59,7 @@ class ValidateModelContent(pyblish.api.InstancePlugin, invalid_bullets = "\n".join(f"- {node}" for node in invalid) cls.log.error( - "These nodes are not allowed:\n{}\n" + "These nodes are not allowed:\n{}\n\n" "The valid node types are: {}".format( invalid_bullets, ", ".join(cls.allowed)) ) From dc21231c291ebffb532151806e2e696ac3510fdc Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 4 Apr 2024 23:16:12 +0800 Subject: [PATCH 081/111] exposes asString as arguments for getting attributes for renderlayer & renderlayersetup --- client/ayon_core/hosts/maya/api/lib.py | 9 +++++---- client/ayon_core/hosts/maya/api/lib_renderproducts.py | 10 ++++------ client/ayon_core/hosts/maya/api/lib_rendersetup.py | 6 +++--- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/lib.py b/client/ayon_core/hosts/maya/api/lib.py index 060c16056c..89582bac8b 100644 --- a/client/ayon_core/hosts/maya/api/lib.py +++ b/client/ayon_core/hosts/maya/api/lib.py @@ -3129,7 +3129,7 @@ def load_capture_preset(data): return options -def get_attr_in_layer(attr, layer): +def get_attr_in_layer(attr, layer, as_string=True): """Return attribute value in specified renderlayer. Same as cmds.getAttr but this gets the attribute's value in a @@ -3156,7 +3156,8 @@ def get_attr_in_layer(attr, layer): try: if cmds.mayaHasRenderSetup(): from . import lib_rendersetup - return lib_rendersetup.get_attr_in_layer(attr, layer) + return lib_rendersetup.get_attr_in_layer( + attr, layer, as_string=as_string) except AttributeError: pass @@ -3173,7 +3174,7 @@ def get_attr_in_layer(attr, layer): type="renderLayer") or [] connections = filter(lambda x: x.endswith(".plug"), connections) if not connections: - return cmds.getAttr(attr) + return cmds.getAttr(attr, asString=as_string) # Some value types perform a conversion when assigning # TODO: See if there's a maya method to allow this conversion @@ -3215,7 +3216,7 @@ def get_attr_in_layer(attr, layer): value *= conversion return value - return cmds.getAttr(attr) + return cmds.getAttr(attr, asString=as_string) def fix_incompatible_containers(): diff --git a/client/ayon_core/hosts/maya/api/lib_renderproducts.py b/client/ayon_core/hosts/maya/api/lib_renderproducts.py index 6b73639040..832d1c21c2 100644 --- a/client/ayon_core/hosts/maya/api/lib_renderproducts.py +++ b/client/ayon_core/hosts/maya/api/lib_renderproducts.py @@ -297,7 +297,7 @@ class ARenderProducts: """ return self._get_attr("defaultRenderGlobals", attribute) - def _get_attr(self, node_attr, attribute=None): + def _get_attr(self, node_attr, attribute=None, as_string=True): """Return the value of the attribute in the renderlayer For readability this allows passing in the attribute in two ways. @@ -317,7 +317,7 @@ class ARenderProducts: else: plug = "{}.{}".format(node_attr, attribute) - return lib.get_attr_in_layer(plug, layer=self.layer) + return lib.get_attr_in_layer(plug, layer=self.layer, as_string=as_string) @staticmethod def extract_separator(file_prefix): @@ -1133,11 +1133,9 @@ class RenderProductsRedshift(ARenderProducts): aovs = list(set(aovs) - set(ref_aovs)) products = [] - # global_aov_enabled = bool( - # self._get_attr("redshiftOptions.aovGlobalEnableMode") - # ) global_aov_enabled = bool( - cmds.getAttr("redshiftOptions.aovGlobalEnableMode")) + self._get_attr("redshiftOptions.aovGlobalEnableMode", as_string=False) + ) colorspace = lib.get_color_management_output_transform() if not global_aov_enabled: # only beauty output diff --git a/client/ayon_core/hosts/maya/api/lib_rendersetup.py b/client/ayon_core/hosts/maya/api/lib_rendersetup.py index c2b5ec843c..6dca8eb6dd 100644 --- a/client/ayon_core/hosts/maya/api/lib_rendersetup.py +++ b/client/ayon_core/hosts/maya/api/lib_rendersetup.py @@ -77,7 +77,7 @@ def get_rendersetup_layer(layer): if conn.endswith(".legacyRenderLayer")), None) -def get_attr_in_layer(node_attr, layer): +def get_attr_in_layer(node_attr, layer, as_string=True): """Return attribute value in Render Setup layer. This will only work for attributes which can be @@ -124,7 +124,7 @@ def get_attr_in_layer(node_attr, layer): node = history_overrides[-1] if history_overrides else override node_attr_ = node + ".original" - return get_attribute(node_attr_, asString=True) + return get_attribute(node_attr_, asString=as_string) layer = get_rendersetup_layer(layer) rs = renderSetup.instance() @@ -144,7 +144,7 @@ def get_attr_in_layer(node_attr, layer): # we will let it error out. rs.switchToLayer(current_layer) - return get_attribute(node_attr, asString=True) + return get_attribute(node_attr, asString=as_string) overrides = get_attr_overrides(node_attr, layer) default_layer_value = get_default_layer_value(node_attr) From 8573a0f6cf63103284466d84c1c48ea6067e9fb0 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 4 Apr 2024 17:51:00 +0200 Subject: [PATCH 082/111] Improve Creator error for new users --- .../hosts/maya/plugins/create/create_render.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) 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 213d5b543e..e5a8d4dbd8 100644 --- a/client/ayon_core/hosts/maya/plugins/create/create_render.py +++ b/client/ayon_core/hosts/maya/plugins/create/create_render.py @@ -40,8 +40,15 @@ class CreateRenderlayer(plugin.RenderlayerCreator): def create(self, product_name, instance_data, pre_create_data): # Only allow a single render instance to exist if self._get_singleton_node(): - raise CreatorError("A Render instance already exists - only " - "one can be configured.") + raise CreatorError( + "A Render instance already exists - only one can be " + "configured.\n\n" + "To render multiple render layers, create extra Render Setup " + "Layers via Maya's Render Setup UI.\n" + "Then refresh the publisher to detect the new layers for " + "rendering.\n\n" + "With a render instance present all Render Setup layers in " + "your workfile are renderable instances.") # Apply default project render settings on create if self.render_settings.get("apply_render_settings"): From 55070d9528fd693ee6353d113d7b8e4ed3bc3838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabi=C3=A0=20Serra=20Arrizabalaga?= Date: Thu, 4 Apr 2024 23:54:57 +0200 Subject: [PATCH 083/111] Fix typos --- .../ayon_core/hosts/hiero/plugins/create/create_shot_clip.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/hosts/hiero/plugins/create/create_shot_clip.py b/client/ayon_core/hosts/hiero/plugins/create/create_shot_clip.py index 2985a81317..1fc808fdd1 100644 --- a/client/ayon_core/hosts/hiero/plugins/create/create_shot_clip.py +++ b/client/ayon_core/hosts/hiero/plugins/create/create_shot_clip.py @@ -137,7 +137,7 @@ class CreateShotClip(phiero.Creator): "value": ["", "main", "bg", "fg", "bg", "animatic"], "type": "QComboBox", - "label": "pRODUCT Name", + "label": "Product Name", "target": "ui", "toolTip": "chose product name pattern, if is selected, name of track layer will be used", # noqa "order": 0}, @@ -159,7 +159,7 @@ class CreateShotClip(phiero.Creator): "type": "QCheckBox", "label": "Include audio", "target": "tag", - "toolTip": "Process productS with corresponding audio", # noqa + "toolTip": "Process products with corresponding audio", # noqa "order": 3}, "sourceResolution": { "value": False, From 26b7a53656062625fed2c62f1573ad0166a6dbc3 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 5 Apr 2024 15:10:36 +0800 Subject: [PATCH 084/111] add docstring and make sure the backward compatible is converting to string value as before --- client/ayon_core/hosts/maya/api/lib.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/lib.py b/client/ayon_core/hosts/maya/api/lib.py index 89582bac8b..91f60824b6 100644 --- a/client/ayon_core/hosts/maya/api/lib.py +++ b/client/ayon_core/hosts/maya/api/lib.py @@ -3147,6 +3147,7 @@ def get_attr_in_layer(attr, layer, as_string=True): Args: attr (str): attribute name, ex. "node.attribute" layer (str): layer name + as_string (bool): whether attribute should convert to a string value Returns: The return value from `maya.cmds.getAttr` @@ -3165,7 +3166,7 @@ def get_attr_in_layer(attr, layer, as_string=True): current_layer = cmds.editRenderLayerGlobals(query=True, currentRenderLayer=True) if layer == current_layer: - return cmds.getAttr(attr) + return cmds.getAttr(attr, asString=as_string) connections = cmds.listConnections(attr, plugs=True, @@ -3174,7 +3175,7 @@ def get_attr_in_layer(attr, layer, as_string=True): type="renderLayer") or [] connections = filter(lambda x: x.endswith(".plug"), connections) if not connections: - return cmds.getAttr(attr, asString=as_string) + return cmds.getAttr(attr) # Some value types perform a conversion when assigning # TODO: See if there's a maya method to allow this conversion From 1d286e7341c48e71715246f9603eb67a80fc61b3 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 5 Apr 2024 20:08:51 +0800 Subject: [PATCH 085/111] refactor repair action --- .../publish/validate_instance_in_context.py | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_instance_in_context.py b/client/ayon_core/hosts/maya/plugins/publish/validate_instance_in_context.py index ec80eb6e06..4e43e8811f 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_instance_in_context.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_instance_in_context.py @@ -4,16 +4,19 @@ from __future__ import absolute_import import pyblish.api import ayon_core.hosts.maya.api.action +from ayon_core.pipeline import registered_host from ayon_core.pipeline.publish import ( RepairAction, ValidateContentsOrder, PublishValidationError, OptionalPyblishPluginMixin ) +from ayon_core.pipeline.create import CreateContext from maya import cmds + class ValidateInstanceInContext(pyblish.api.InstancePlugin, OptionalPyblishPluginMixin): """Validator to check if instance asset match context asset. @@ -70,16 +73,20 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, context_folder_path, context_task = cls.get_context( instance) instance_node = instance.data["instance_node"] - cmds.setAttr( - "{}.folderPath".format(instance_node), - context_folder_path, - type="string" - ) - cmds.setAttr( - "{}.task".format(instance_node), - context_task, - type="string" - ) + host = registered_host() + create_context = CreateContext(host) + + instance_values = { + "folderPath": context_folder_path, + "task": context_task + } + + for instance in create_context.instances: + if instance["productName"] == instance_node: + for key, value in instance_values.items(): + instance[key] = value + + create_context.save_changes() @staticmethod def get_context(instance): From 287e5753f33410b892895510c5f566b7d1e31033 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 5 Apr 2024 21:30:12 +0800 Subject: [PATCH 086/111] use the instance data for getting create-context data instead --- .../publish/validate_instance_in_context.py | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_instance_in_context.py b/client/ayon_core/hosts/maya/plugins/publish/validate_instance_in_context.py index 4e43e8811f..e6f4b908bb 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_instance_in_context.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_instance_in_context.py @@ -4,17 +4,12 @@ from __future__ import absolute_import import pyblish.api import ayon_core.hosts.maya.api.action -from ayon_core.pipeline import registered_host from ayon_core.pipeline.publish import ( RepairAction, ValidateContentsOrder, PublishValidationError, OptionalPyblishPluginMixin ) -from ayon_core.pipeline.create import CreateContext - -from maya import cmds - class ValidateInstanceInContext(pyblish.api.InstancePlugin, @@ -72,20 +67,14 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, def repair(cls, instance): context_folder_path, context_task = cls.get_context( instance) - instance_node = instance.data["instance_node"] - host = registered_host() - create_context = CreateContext(host) - - instance_values = { - "folderPath": context_folder_path, - "task": context_task - } - - for instance in create_context.instances: - if instance["productName"] == instance_node: - for key, value in instance_values.items(): - instance[key] = value + create_context = instance.context.data["create_context"] + instance_id = instance.data["instance_id"] + created_instance = create_context.get_instance_by_id( + instance_id + ) + created_instance["folderPath"] = context_folder_path + created_instance["task"] = context_task create_context.save_changes() @staticmethod From 51569b17dbe3dc1113b316e148a45cbd9d3ee841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabi=C3=A0=20Serra=20Arrizabalaga?= Date: Fri, 5 Apr 2024 22:38:23 +0200 Subject: [PATCH 087/111] Pass env var used to login to ayon-shotgrid addon --- .../deadline/plugins/publish/submit_publish_cache_job.py | 2 +- .../modules/deadline/plugins/publish/submit_publish_job.py | 2 +- .../plugins/publish/create_publish_royalrender_job.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 910b2e46db..4e4657d886 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 @@ -67,7 +67,7 @@ class ProcessSubmittedCacheJobOnFarm(pyblish.api.InstancePlugin, "FTRACK_SERVER", "AYON_APP_NAME", "AYON_USERNAME", - "OPENPYPE_SG_USER", + "AYON_SG_USERNAME", "KITSU_LOGIN", "KITSU_PWD" ] 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 af5839d0cf..8def9cc63c 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 @@ -130,7 +130,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin, "FTRACK_SERVER", "AYON_APP_NAME", "AYON_USERNAME", - "OPENPYPE_SG_USER", + "AYON_SG_USERNAME", "KITSU_LOGIN", "KITSU_PWD" ] 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 662913cadf..f3287b7638 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 @@ -65,7 +65,7 @@ class CreatePublishRoyalRenderJob(pyblish.api.InstancePlugin, "FTRACK_SERVER", "AYON_APP_NAME", "AYON_USERNAME", - "OPENPYPE_SG_USER", + "AYON_SG_USERNAME", ] priority = 50 From 78074e4d16324041d40091fe3412de6198e2959d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabi=C3=A0=20Serra=20Arrizabalaga?= Date: Fri, 5 Apr 2024 22:38:29 +0200 Subject: [PATCH 088/111] Fix typo --- .../hosts/hiero/plugins/publish/extract_thumbnail.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/ayon_core/hosts/hiero/plugins/publish/extract_thumbnail.py b/client/ayon_core/hosts/hiero/plugins/publish/extract_thumbnail.py index bcaf5308d9..3599a830d2 100644 --- a/client/ayon_core/hosts/hiero/plugins/publish/extract_thumbnail.py +++ b/client/ayon_core/hosts/hiero/plugins/publish/extract_thumbnail.py @@ -4,12 +4,12 @@ import pyblish.api from ayon_core.pipeline import publish -class ExtractThumnail(publish.Extractor): +class ExtractThumbnail(publish.Extractor): """ - Extractor for track item's tumnails + Extractor for track item's tumbnails """ - label = "Extract Thumnail" + label = "Extract Thumbnail" order = pyblish.api.ExtractorOrder families = ["plate", "take"] hosts = ["hiero"] @@ -48,7 +48,7 @@ class ExtractThumnail(publish.Extractor): self.log.debug( "__ thumb_path: `{}`, frame: `{}`".format(thumbnail, thumb_frame)) - self.log.info("Thumnail was generated to: {}".format(thumb_path)) + self.log.info("Thumbnail was generated to: {}".format(thumb_path)) thumb_representation = { 'files': thumb_file, 'stagingDir': staging_dir, From a08b1786b0891a3cd4e6bb5d8d557f3bf749b7c4 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 8 Apr 2024 08:47:50 +0100 Subject: [PATCH 089/111] Account for multiple slate frames. --- .../hosts/nuke/plugins/load/load_clip.py | 23 ++++++++----------- .../plugins/publish/extract_slate_frame.py | 2 +- .../plugins/publish/extract_slate_data.py | 2 +- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_clip.py b/client/ayon_core/hosts/nuke/plugins/load/load_clip.py index 86a6d359c3..062a5295ed 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_clip.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_clip.py @@ -132,16 +132,15 @@ class LoadClip(plugin.NukeLoader): # If a slate is present, the frame range is 1 frame longer for movies, # but file sequences its the first frame that is 1 frame lower. - slate_frame = repre_entity["data"].get("slateFrame", False) - if slate_frame: - extension = "." + repre_entity["context"]["ext"] + slate_frames = repre_entity["data"].get("slateFrames", 0) + extension = "." + repre_entity["context"]["ext"] - if extension in VIDEO_EXTENSIONS: - last += 1 + if extension in VIDEO_EXTENSIONS: + last += slate_frames - files_count = len(repre_entity["files"]) - if extension in IMAGE_EXTENSIONS and files_count != 1: - first -= 1 + files_count = len(repre_entity["files"]) + if extension in IMAGE_EXTENSIONS and files_count != 1: + first -= slate_frames # Fallback to folder name when namespace is None if namespace is None: @@ -181,7 +180,7 @@ class LoadClip(plugin.NukeLoader): ) self._set_range_to_node( - read_node, first, last, start_at_workfile, slate_frame + read_node, first, last, start_at_workfile, slate_frames ) version_name = version_entity["version"] @@ -418,7 +417,7 @@ class LoadClip(plugin.NukeLoader): nuke.delete(member) def _set_range_to_node( - self, read_node, first, last, start_at_workfile, slate_frame=False + self, read_node, first, last, start_at_workfile, slate_frames=0 ): read_node['origfirst'].setValue(int(first)) read_node['first'].setValue(int(first)) @@ -429,9 +428,7 @@ class LoadClip(plugin.NukeLoader): if start_at_workfile: read_node['frame_mode'].setValue("start at") - start_frame = self.script_start - if slate_frame: - start_frame -= 1 + start_frame = self.script_start - slate_frames read_node['frame'].setValue(str(start_frame)) diff --git a/client/ayon_core/hosts/nuke/plugins/publish/extract_slate_frame.py b/client/ayon_core/hosts/nuke/plugins/publish/extract_slate_frame.py index 67d2bd272c..627888ac92 100644 --- a/client/ayon_core/hosts/nuke/plugins/publish/extract_slate_frame.py +++ b/client/ayon_core/hosts/nuke/plugins/publish/extract_slate_frame.py @@ -301,7 +301,7 @@ class ExtractSlateFrame(publish.Extractor): "__ matching_repre: {}".format(pformat(matching_repre))) data = matching_repre.get("data", {}) - data["slateFrame"] = True + data["slateFrames"] = 1 matching_repre["data"] = data self.log.info("Added slate frame to representation files") diff --git a/client/ayon_core/plugins/publish/extract_slate_data.py b/client/ayon_core/plugins/publish/extract_slate_data.py index 0a28083f1e..750fb5d60a 100644 --- a/client/ayon_core/plugins/publish/extract_slate_data.py +++ b/client/ayon_core/plugins/publish/extract_slate_data.py @@ -18,5 +18,5 @@ class ExtractSlateData(publish.Extractor): continue data = representation.get("data", {}) - data["slateFrame"] = True + data["slateFrames"] = 1 representation["data"] = data From 825add6c2cf51be99b8a1454e357f1ca7acfa891 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 9 Apr 2024 10:26:40 +0200 Subject: [PATCH 090/111] Fix support for non-unique top group names --- .../hosts/maya/plugins/publish/validate_model_content.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/validate_model_content.py b/client/ayon_core/hosts/maya/plugins/publish/validate_model_content.py index 1001bee91f..bbc644c3db 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/validate_model_content.py +++ b/client/ayon_core/hosts/maya/plugins/publish/validate_model_content.py @@ -79,7 +79,7 @@ class ValidateModelContent(pyblish.api.InstancePlugin, return [instance.data["instance_node"]] # Ensure single top group - top_parents = {x.split("|", 2)[1] for x in content_instance} + top_parents = {"|" + x.split("|", 2)[1] for x in content_instance} if cls.validate_top_group and len(top_parents) != 1: cls.log.error( "A model instance must have exactly one top group. " From 738f0924b5a92d3346f18ddae2e7959df8172423 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Tue, 9 Apr 2024 12:27:56 +0200 Subject: [PATCH 091/111] Update client/ayon_core/hosts/maya/plugins/publish/collect_look.py Co-authored-by: Kayla Man <64118225+moonyuet@users.noreply.github.com> --- client/ayon_core/hosts/maya/plugins/publish/collect_look.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/maya/plugins/publish/collect_look.py b/client/ayon_core/hosts/maya/plugins/publish/collect_look.py index 9d8bfd270d..a3a32bc0cb 100644 --- a/client/ayon_core/hosts/maya/plugins/publish/collect_look.py +++ b/client/ayon_core/hosts/maya/plugins/publish/collect_look.py @@ -413,7 +413,7 @@ class CollectLook(pyblish.api.InstancePlugin): # RuntimeError history = set() if materials: - history = set(cmds.listHistory(materials, allConnections=True)) + history.update(cmds.listHistory(materials, allConnections=True)) # Since we retrieved history only of the connected materials connected # to the look sets above we now add direct history for some of the From c193e2e6144c259ee7dbcefaebfe9800c2a0bd3b Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 9 Apr 2024 13:19:12 +0200 Subject: [PATCH 092/111] Fix delivery - fixes #351 --- client/ayon_core/plugins/load/delivery.py | 27 +++++++++++++++-------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/client/ayon_core/plugins/load/delivery.py b/client/ayon_core/plugins/load/delivery.py index f8184c8567..5fadf7ea3c 100644 --- a/client/ayon_core/plugins/load/delivery.py +++ b/client/ayon_core/plugins/load/delivery.py @@ -91,9 +91,15 @@ class DeliveryOptionsDialog(QtWidgets.QDialog): longest_key = max(self.templates.keys(), key=len) dropdown.setMinimumContentsLength(len(longest_key)) - template_label = QtWidgets.QLabel() - template_label.setCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor)) - template_label.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse) + template_dir_label = QtWidgets.QLabel() + template_dir_label.setCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor)) + template_dir_label.setTextInteractionFlags( + QtCore.Qt.TextSelectableByMouse) + + template_file_label = QtWidgets.QLabel() + template_file_label.setCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor)) + template_file_label.setTextInteractionFlags( + QtCore.Qt.TextSelectableByMouse) renumber_frame = QtWidgets.QCheckBox() @@ -123,7 +129,8 @@ class DeliveryOptionsDialog(QtWidgets.QDialog): input_layout.addRow("Selected representations", selected_label) input_layout.addRow("Delivery template", dropdown) - input_layout.addRow("Template value", template_label) + input_layout.addRow("Template directory", template_dir_label) + input_layout.addRow("Template file", template_file_label) input_layout.addRow("Renumber Frame", renumber_frame) input_layout.addRow("Renumber start frame", first_frame_start) input_layout.addRow("Root", root_line_edit) @@ -151,7 +158,8 @@ class DeliveryOptionsDialog(QtWidgets.QDialog): layout.addWidget(text_area) self.selected_label = selected_label - self.template_label = template_label + self.template_dir_label = template_dir_label + self.template_file_label = template_file_label self.dropdown = dropdown self.first_frame_start = first_frame_start self.renumber_frame = renumber_frame @@ -282,10 +290,10 @@ class DeliveryOptionsDialog(QtWidgets.QDialog): """Adds list of delivery templates from Anatomy to dropdown.""" templates = {} for template_name, value in anatomy.templates["delivery"].items(): - path_template = value["path"] + directory_template = value["directory"] if ( - not isinstance(path_template, str) - or not path_template.startswith('{root') + not isinstance(directory_template, str) + or not directory_template.startswith('{root') ): continue @@ -350,7 +358,8 @@ class DeliveryOptionsDialog(QtWidgets.QDialog): name = self.dropdown.currentText() template_value = self.templates.get(name) if template_value: - self.template_label.setText(template_value) + self.template_dir_label.setText(template_value["directory"]) + self.template_file_label.setText(template_value["file"]) self.btn_delivery.setEnabled(bool(self._get_selected_repres())) def _update_progress(self, uploaded): From 010655007e1a71a92c783ec6d6c7e1c66c215ec6 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 9 Apr 2024 13:56:17 +0200 Subject: [PATCH 093/111] Update client/ayon_core/plugins/load/delivery.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/plugins/load/delivery.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/plugins/load/delivery.py b/client/ayon_core/plugins/load/delivery.py index 5fadf7ea3c..d685649496 100644 --- a/client/ayon_core/plugins/load/delivery.py +++ b/client/ayon_core/plugins/load/delivery.py @@ -129,8 +129,8 @@ class DeliveryOptionsDialog(QtWidgets.QDialog): input_layout.addRow("Selected representations", selected_label) input_layout.addRow("Delivery template", dropdown) - input_layout.addRow("Template directory", template_dir_label) - input_layout.addRow("Template file", template_file_label) + input_layout.addRow("Directory template", template_dir_label) + input_layout.addRow("File template", template_file_label) input_layout.addRow("Renumber Frame", renumber_frame) input_layout.addRow("Renumber start frame", first_frame_start) input_layout.addRow("Root", root_line_edit) From e70651bd3f94742a588883cd20fa98db74bff0f0 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 9 Apr 2024 13:57:38 +0200 Subject: [PATCH 094/111] Skip string check --- client/ayon_core/plugins/load/delivery.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/client/ayon_core/plugins/load/delivery.py b/client/ayon_core/plugins/load/delivery.py index d685649496..f363c6418f 100644 --- a/client/ayon_core/plugins/load/delivery.py +++ b/client/ayon_core/plugins/load/delivery.py @@ -291,10 +291,7 @@ class DeliveryOptionsDialog(QtWidgets.QDialog): templates = {} for template_name, value in anatomy.templates["delivery"].items(): directory_template = value["directory"] - if ( - not isinstance(directory_template, str) - or not directory_template.startswith('{root') - ): + if not directory_template.startswith('{root'): continue templates[template_name] = value From 30460440539306de5f1d2ba6f5b26260feec9b99 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 9 Apr 2024 13:57:49 +0200 Subject: [PATCH 095/111] Cosmetics --- client/ayon_core/plugins/load/delivery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/load/delivery.py b/client/ayon_core/plugins/load/delivery.py index f363c6418f..7ad054b6b9 100644 --- a/client/ayon_core/plugins/load/delivery.py +++ b/client/ayon_core/plugins/load/delivery.py @@ -291,7 +291,7 @@ class DeliveryOptionsDialog(QtWidgets.QDialog): templates = {} for template_name, value in anatomy.templates["delivery"].items(): directory_template = value["directory"] - if not directory_template.startswith('{root'): + if not directory_template.startswith("{root"): continue templates[template_name] = value From ecfb972332fe628dc822d6513344705c50f7e121 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 9 Apr 2024 14:13:10 +0200 Subject: [PATCH 096/111] Log a warning --- client/ayon_core/plugins/load/delivery.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/ayon_core/plugins/load/delivery.py b/client/ayon_core/plugins/load/delivery.py index 7ad054b6b9..e2a283a516 100644 --- a/client/ayon_core/plugins/load/delivery.py +++ b/client/ayon_core/plugins/load/delivery.py @@ -292,6 +292,10 @@ class DeliveryOptionsDialog(QtWidgets.QDialog): for template_name, value in anatomy.templates["delivery"].items(): directory_template = value["directory"] if not directory_template.startswith("{root"): + self.log.warning( + "Skipping template '%s' because directory template does " + "not start with `{root`", template_name + ) continue templates[template_name] = value From 8ec3c80c5fe59f0fa65b0e1aaa80bd2843c628a4 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 9 Apr 2024 14:13:49 +0200 Subject: [PATCH 097/111] Log the directory template for better log message --- client/ayon_core/plugins/load/delivery.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/load/delivery.py b/client/ayon_core/plugins/load/delivery.py index e2a283a516..cd358846ea 100644 --- a/client/ayon_core/plugins/load/delivery.py +++ b/client/ayon_core/plugins/load/delivery.py @@ -294,7 +294,8 @@ class DeliveryOptionsDialog(QtWidgets.QDialog): if not directory_template.startswith("{root"): self.log.warning( "Skipping template '%s' because directory template does " - "not start with `{root`", template_name + "not start with `{root` in value: %s", + template_name, directory_template ) continue From 17e7c9ff00aebb94f5198a9dcf30407f41a5f301 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 9 Apr 2024 17:23:45 +0200 Subject: [PATCH 098/111] change 'representations' attribute on loader plugin to 'set' --- client/ayon_core/pipeline/load/plugins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/pipeline/load/plugins.py b/client/ayon_core/pipeline/load/plugins.py index 064af4ddc1..3f47ec421e 100644 --- a/client/ayon_core/pipeline/load/plugins.py +++ b/client/ayon_core/pipeline/load/plugins.py @@ -24,7 +24,7 @@ class LoaderPlugin(list): """ product_types = set() - representations = [] + representations = set() extensions = {"*"} order = 0 is_multiple_contexts_compatible = False From 43b4be851ede5043729446de171d30b0fd717640 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 9 Apr 2024 17:26:28 +0200 Subject: [PATCH 099/111] use 'set' for 'representations' attribute --- .../hosts/aftereffects/plugins/load/load_background.py | 2 +- .../ayon_core/hosts/aftereffects/plugins/load/load_file.py | 2 +- .../ayon_core/hosts/blender/plugins/load/import_workfile.py | 4 ++-- client/ayon_core/hosts/blender/plugins/load/load_abc.py | 2 +- client/ayon_core/hosts/blender/plugins/load/load_action.py | 2 +- .../ayon_core/hosts/blender/plugins/load/load_animation.py | 2 +- client/ayon_core/hosts/blender/plugins/load/load_audio.py | 2 +- client/ayon_core/hosts/blender/plugins/load/load_blend.py | 2 +- .../ayon_core/hosts/blender/plugins/load/load_blendscene.py | 2 +- .../ayon_core/hosts/blender/plugins/load/load_camera_abc.py | 2 +- .../ayon_core/hosts/blender/plugins/load/load_camera_fbx.py | 2 +- client/ayon_core/hosts/blender/plugins/load/load_fbx.py | 2 +- .../hosts/blender/plugins/load/load_layout_json.py | 2 +- client/ayon_core/hosts/blender/plugins/load/load_look.py | 2 +- client/ayon_core/hosts/flame/plugins/load/load_clip.py | 2 +- .../ayon_core/hosts/flame/plugins/load/load_clip_batch.py | 2 +- client/ayon_core/hosts/fusion/plugins/load/actions.py | 4 ++-- client/ayon_core/hosts/fusion/plugins/load/load_alembic.py | 2 +- client/ayon_core/hosts/fusion/plugins/load/load_fbx.py | 2 +- client/ayon_core/hosts/fusion/plugins/load/load_sequence.py | 2 +- client/ayon_core/hosts/fusion/plugins/load/load_usd.py | 2 +- client/ayon_core/hosts/fusion/plugins/load/load_workfile.py | 2 +- client/ayon_core/hosts/harmony/api/README.md | 2 +- client/ayon_core/hosts/harmony/plugins/load/load_audio.py | 2 +- .../ayon_core/hosts/harmony/plugins/load/load_background.py | 2 +- .../hosts/harmony/plugins/load/load_imagesequence.py | 2 +- client/ayon_core/hosts/harmony/plugins/load/load_palette.py | 2 +- .../ayon_core/hosts/harmony/plugins/load/load_template.py | 2 +- .../hosts/harmony/plugins/load/load_template_workfile.py | 4 ++-- client/ayon_core/hosts/hiero/plugins/load/load_clip.py | 2 +- client/ayon_core/hosts/hiero/plugins/load/load_effects.py | 2 +- client/ayon_core/hosts/houdini/plugins/load/actions.py | 4 ++-- client/ayon_core/hosts/houdini/plugins/load/load_alembic.py | 2 +- .../hosts/houdini/plugins/load/load_alembic_archive.py | 2 +- client/ayon_core/hosts/houdini/plugins/load/load_ass.py | 2 +- client/ayon_core/hosts/houdini/plugins/load/load_bgeo.py | 4 ++-- client/ayon_core/hosts/houdini/plugins/load/load_camera.py | 2 +- client/ayon_core/hosts/houdini/plugins/load/load_fbx.py | 2 +- .../ayon_core/hosts/houdini/plugins/load/load_filepath.py | 2 +- client/ayon_core/hosts/houdini/plugins/load/load_hda.py | 2 +- client/ayon_core/hosts/houdini/plugins/load/load_image.py | 2 +- .../hosts/houdini/plugins/load/load_redshift_proxy.py | 2 +- .../ayon_core/hosts/houdini/plugins/load/load_usd_layer.py | 2 +- .../hosts/houdini/plugins/load/load_usd_reference.py | 2 +- client/ayon_core/hosts/houdini/plugins/load/load_usd_sop.py | 2 +- client/ayon_core/hosts/houdini/plugins/load/load_vdb.py | 2 +- client/ayon_core/hosts/houdini/plugins/load/show_usdview.py | 2 +- client/ayon_core/hosts/max/plugins/load/load_camera_fbx.py | 2 +- client/ayon_core/hosts/max/plugins/load/load_max_scene.py | 2 +- client/ayon_core/hosts/max/plugins/load/load_model.py | 2 +- client/ayon_core/hosts/max/plugins/load/load_model_fbx.py | 2 +- client/ayon_core/hosts/max/plugins/load/load_model_obj.py | 2 +- client/ayon_core/hosts/max/plugins/load/load_model_usd.py | 2 +- client/ayon_core/hosts/max/plugins/load/load_pointcache.py | 2 +- .../hosts/max/plugins/load/load_pointcache_ornatrix.py | 2 +- client/ayon_core/hosts/max/plugins/load/load_pointcloud.py | 2 +- .../ayon_core/hosts/max/plugins/load/load_redshift_proxy.py | 2 +- client/ayon_core/hosts/max/plugins/load/load_tycache.py | 2 +- client/ayon_core/hosts/maya/plugins/load/_load_animation.py | 4 ++-- client/ayon_core/hosts/maya/plugins/load/actions.py | 6 +++--- .../hosts/maya/plugins/load/load_arnold_standin.py | 2 +- client/ayon_core/hosts/maya/plugins/load/load_assembly.py | 2 +- client/ayon_core/hosts/maya/plugins/load/load_audio.py | 2 +- client/ayon_core/hosts/maya/plugins/load/load_gpucache.py | 2 +- client/ayon_core/hosts/maya/plugins/load/load_image.py | 2 +- .../ayon_core/hosts/maya/plugins/load/load_image_plane.py | 4 ++-- client/ayon_core/hosts/maya/plugins/load/load_look.py | 2 +- client/ayon_core/hosts/maya/plugins/load/load_matchmove.py | 2 +- client/ayon_core/hosts/maya/plugins/load/load_maya_usd.py | 2 +- .../hosts/maya/plugins/load/load_multiverse_usd.py | 2 +- .../hosts/maya/plugins/load/load_multiverse_usd_over.py | 2 +- .../hosts/maya/plugins/load/load_redshift_proxy.py | 2 +- client/ayon_core/hosts/maya/plugins/load/load_reference.py | 4 ++-- .../ayon_core/hosts/maya/plugins/load/load_rendersetup.py | 2 +- .../ayon_core/hosts/maya/plugins/load/load_vdb_to_arnold.py | 2 +- .../hosts/maya/plugins/load/load_vdb_to_redshift.py | 2 +- .../ayon_core/hosts/maya/plugins/load/load_vdb_to_vray.py | 2 +- client/ayon_core/hosts/maya/plugins/load/load_vrayproxy.py | 2 +- client/ayon_core/hosts/maya/plugins/load/load_vrayscene.py | 2 +- client/ayon_core/hosts/maya/plugins/load/load_xgen.py | 2 +- client/ayon_core/hosts/maya/plugins/load/load_yeti_cache.py | 2 +- client/ayon_core/hosts/maya/plugins/load/load_yeti_rig.py | 2 +- client/ayon_core/hosts/nuke/plugins/load/actions.py | 4 ++-- client/ayon_core/hosts/nuke/plugins/load/load_backdrop.py | 2 +- client/ayon_core/hosts/nuke/plugins/load/load_camera_abc.py | 2 +- client/ayon_core/hosts/nuke/plugins/load/load_clip.py | 2 +- client/ayon_core/hosts/nuke/plugins/load/load_effects.py | 2 +- client/ayon_core/hosts/nuke/plugins/load/load_effects_ip.py | 2 +- client/ayon_core/hosts/nuke/plugins/load/load_gizmo.py | 2 +- client/ayon_core/hosts/nuke/plugins/load/load_gizmo_ip.py | 2 +- client/ayon_core/hosts/nuke/plugins/load/load_image.py | 2 +- client/ayon_core/hosts/nuke/plugins/load/load_matchmove.py | 2 +- client/ayon_core/hosts/nuke/plugins/load/load_model.py | 2 +- client/ayon_core/hosts/nuke/plugins/load/load_ociolook.py | 2 +- .../hosts/nuke/plugins/load/load_script_precomp.py | 2 +- client/ayon_core/hosts/photoshop/api/README.md | 2 +- client/ayon_core/hosts/photoshop/plugins/load/load_image.py | 2 +- .../photoshop/plugins/load/load_image_from_sequence.py | 2 +- .../hosts/photoshop/plugins/load/load_reference.py | 2 +- client/ayon_core/hosts/resolve/plugins/load/load_clip.py | 2 +- .../hosts/substancepainter/plugins/load/load_mesh.py | 2 +- client/ayon_core/hosts/tvpaint/plugins/load/load_image.py | 2 +- .../hosts/tvpaint/plugins/load/load_reference_image.py | 2 +- client/ayon_core/hosts/tvpaint/plugins/load/load_sound.py | 2 +- .../ayon_core/hosts/tvpaint/plugins/load/load_workfile.py | 2 +- .../hosts/unreal/plugins/load/load_alembic_animation.py | 2 +- .../ayon_core/hosts/unreal/plugins/load/load_animation.py | 2 +- client/ayon_core/hosts/unreal/plugins/load/load_camera.py | 2 +- .../hosts/unreal/plugins/load/load_geometrycache_abc.py | 2 +- client/ayon_core/hosts/unreal/plugins/load/load_layout.py | 2 +- .../hosts/unreal/plugins/load/load_layout_existing.py | 2 +- .../hosts/unreal/plugins/load/load_skeletalmesh_abc.py | 2 +- .../hosts/unreal/plugins/load/load_skeletalmesh_fbx.py | 2 +- .../hosts/unreal/plugins/load/load_staticmesh_abc.py | 2 +- .../hosts/unreal/plugins/load/load_staticmesh_fbx.py | 2 +- client/ayon_core/hosts/unreal/plugins/load/load_uasset.py | 4 ++-- .../ayon_core/hosts/unreal/plugins/load/load_yeticache.py | 2 +- client/ayon_core/plugins/load/copy_file.py | 2 +- client/ayon_core/plugins/load/copy_file_path.py | 2 +- client/ayon_core/plugins/load/delete_old_versions.py | 2 +- client/ayon_core/plugins/load/delivery.py | 2 +- client/ayon_core/plugins/load/open_file.py | 2 +- client/ayon_core/plugins/load/push_to_library.py | 2 +- 123 files changed, 135 insertions(+), 135 deletions(-) diff --git a/client/ayon_core/hosts/aftereffects/plugins/load/load_background.py b/client/ayon_core/hosts/aftereffects/plugins/load/load_background.py index 7c9bd2fcfd..5685011d5f 100644 --- a/client/ayon_core/hosts/aftereffects/plugins/load/load_background.py +++ b/client/ayon_core/hosts/aftereffects/plugins/load/load_background.py @@ -21,7 +21,7 @@ class BackgroundLoader(api.AfterEffectsLoader): """ label = "Load JSON Background" product_types = {"background"} - representations = ["json"] + representations = {"json"} def load(self, context, name=None, namespace=None, data=None): stub = self.get_stub() diff --git a/client/ayon_core/hosts/aftereffects/plugins/load/load_file.py b/client/ayon_core/hosts/aftereffects/plugins/load/load_file.py index 79e791af7b..4b81201722 100644 --- a/client/ayon_core/hosts/aftereffects/plugins/load/load_file.py +++ b/client/ayon_core/hosts/aftereffects/plugins/load/load_file.py @@ -20,7 +20,7 @@ class FileLoader(api.AfterEffectsLoader): "review", "audio", } - representations = ["*"] + representations = {"*"} def load(self, context, name=None, namespace=None, data=None): stub = self.get_stub() diff --git a/client/ayon_core/hosts/blender/plugins/load/import_workfile.py b/client/ayon_core/hosts/blender/plugins/load/import_workfile.py index 3aa73a5143..d2e58c7752 100644 --- a/client/ayon_core/hosts/blender/plugins/load/import_workfile.py +++ b/client/ayon_core/hosts/blender/plugins/load/import_workfile.py @@ -43,7 +43,7 @@ class AppendBlendLoader(plugin.AssetLoader): so you could also use it as a new base. """ - representations = ["blend"] + representations = {"blend"} product_types = {"workfile"} label = "Append Workfile" @@ -68,7 +68,7 @@ class ImportBlendLoader(plugin.AssetLoader): so you could also use it as a new base. """ - representations = ["blend"] + representations = {"blend"} product_types = {"workfile"} label = "Import Workfile" diff --git a/client/ayon_core/hosts/blender/plugins/load/load_abc.py b/client/ayon_core/hosts/blender/plugins/load/load_abc.py index 938ae6106b..c074b5ed13 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_abc.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_abc.py @@ -27,7 +27,7 @@ class CacheModelLoader(plugin.AssetLoader): At least for now it only supports Alembic files. """ product_types = {"model", "pointcache", "animation"} - representations = ["abc"] + representations = {"abc"} label = "Load Alembic" icon = "code-fork" diff --git a/client/ayon_core/hosts/blender/plugins/load/load_action.py b/client/ayon_core/hosts/blender/plugins/load/load_action.py index 4161f8bff3..8135df042a 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_action.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_action.py @@ -25,7 +25,7 @@ class BlendActionLoader(plugin.AssetLoader): """ product_types = {"action"} - representations = ["blend"] + representations = {"blend"} label = "Link Action" icon = "code-fork" diff --git a/client/ayon_core/hosts/blender/plugins/load/load_animation.py b/client/ayon_core/hosts/blender/plugins/load/load_animation.py index effb91c48c..c9f3b33a6f 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_animation.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_animation.py @@ -17,7 +17,7 @@ class BlendAnimationLoader(plugin.AssetLoader): """ product_types = {"animation"} - representations = ["blend"] + representations = {"blend"} label = "Link Animation" icon = "code-fork" diff --git a/client/ayon_core/hosts/blender/plugins/load/load_audio.py b/client/ayon_core/hosts/blender/plugins/load/load_audio.py index db83c4bca2..3d2f412e2b 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_audio.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_audio.py @@ -21,7 +21,7 @@ class AudioLoader(plugin.AssetLoader): """Load audio in Blender.""" product_types = {"audio"} - representations = ["wav"] + representations = {"wav"} label = "Load Audio" icon = "volume-up" diff --git a/client/ayon_core/hosts/blender/plugins/load/load_blend.py b/client/ayon_core/hosts/blender/plugins/load/load_blend.py index 1984193a30..f9377d615c 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_blend.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_blend.py @@ -21,7 +21,7 @@ class BlendLoader(plugin.AssetLoader): """Load assets from a .blend file.""" product_types = {"model", "rig", "layout", "camera"} - representations = ["blend"] + representations = {"blend"} label = "Append Blend" icon = "code-fork" diff --git a/client/ayon_core/hosts/blender/plugins/load/load_blendscene.py b/client/ayon_core/hosts/blender/plugins/load/load_blendscene.py index 627941752f..f91d828d83 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_blendscene.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_blendscene.py @@ -19,7 +19,7 @@ class BlendSceneLoader(plugin.AssetLoader): """Load assets from a .blend file.""" product_types = {"blendScene"} - representations = ["blend"] + representations = {"blend"} label = "Append Blend" icon = "code-fork" diff --git a/client/ayon_core/hosts/blender/plugins/load/load_camera_abc.py b/client/ayon_core/hosts/blender/plugins/load/load_camera_abc.py index e677fc3e58..6178578081 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_camera_abc.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_camera_abc.py @@ -24,7 +24,7 @@ class AbcCameraLoader(plugin.AssetLoader): """ product_types = {"camera"} - representations = ["abc"] + representations = {"abc"} label = "Load Camera (ABC)" icon = "code-fork" diff --git a/client/ayon_core/hosts/blender/plugins/load/load_camera_fbx.py b/client/ayon_core/hosts/blender/plugins/load/load_camera_fbx.py index 14d61a6395..a510d42850 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_camera_fbx.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_camera_fbx.py @@ -24,7 +24,7 @@ class FbxCameraLoader(plugin.AssetLoader): """ product_types = {"camera"} - representations = ["fbx"] + representations = {"fbx"} label = "Load Camera (FBX)" icon = "code-fork" diff --git a/client/ayon_core/hosts/blender/plugins/load/load_fbx.py b/client/ayon_core/hosts/blender/plugins/load/load_fbx.py index 0042482284..e323d49dea 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_fbx.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_fbx.py @@ -24,7 +24,7 @@ class FbxModelLoader(plugin.AssetLoader): """ product_types = {"model", "rig"} - representations = ["fbx"] + representations = {"fbx"} label = "Load FBX" icon = "code-fork" diff --git a/client/ayon_core/hosts/blender/plugins/load/load_layout_json.py b/client/ayon_core/hosts/blender/plugins/load/load_layout_json.py index 7a3da1882e..bea997108b 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_layout_json.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_layout_json.py @@ -27,7 +27,7 @@ class JsonLayoutLoader(plugin.AssetLoader): """Load layout published from Unreal.""" product_types = {"layout"} - representations = ["json"] + representations = {"json"} label = "Load Layout" icon = "code-fork" diff --git a/client/ayon_core/hosts/blender/plugins/load/load_look.py b/client/ayon_core/hosts/blender/plugins/load/load_look.py index ce677a8471..75401f94ec 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_look.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_look.py @@ -24,7 +24,7 @@ class BlendLookLoader(plugin.AssetLoader): """ product_types = {"look"} - representations = ["json"] + representations = {"json"} label = "Load Look" icon = "code-fork" diff --git a/client/ayon_core/hosts/flame/plugins/load/load_clip.py b/client/ayon_core/hosts/flame/plugins/load/load_clip.py index f528caeb29..40ab9c038b 100644 --- a/client/ayon_core/hosts/flame/plugins/load/load_clip.py +++ b/client/ayon_core/hosts/flame/plugins/load/load_clip.py @@ -18,7 +18,7 @@ class LoadClip(opfapi.ClipLoader): """ product_types = {"render2d", "source", "plate", "render", "review"} - representations = ["*"] + representations = {"*"} extensions = set( ext.lstrip(".") for ext in IMAGE_EXTENSIONS.union(VIDEO_EXTENSIONS) ) 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 9bdd467d63..1b23a8b465 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 @@ -17,7 +17,7 @@ class LoadClipBatch(opfapi.ClipLoader): """ product_types = {"render2d", "source", "plate", "render", "review"} - representations = ["*"] + representations = {"*"} extensions = set( ext.lstrip(".") for ext in IMAGE_EXTENSIONS.union(VIDEO_EXTENSIONS) ) diff --git a/client/ayon_core/hosts/fusion/plugins/load/actions.py b/client/ayon_core/hosts/fusion/plugins/load/actions.py index 9600479680..95400ea41c 100644 --- a/client/ayon_core/hosts/fusion/plugins/load/actions.py +++ b/client/ayon_core/hosts/fusion/plugins/load/actions.py @@ -17,7 +17,7 @@ class FusionSetFrameRangeLoader(load.LoaderPlugin): "pointcache", "render", } - representations = ["*"] + representations = {"*"} extensions = {"*"} label = "Set frame range" @@ -54,7 +54,7 @@ class FusionSetFrameRangeWithHandlesLoader(load.LoaderPlugin): "pointcache", "render", } - representations = ["*"] + representations = {"*"} label = "Set frame range (with handles)" order = 12 diff --git a/client/ayon_core/hosts/fusion/plugins/load/load_alembic.py b/client/ayon_core/hosts/fusion/plugins/load/load_alembic.py index ae2175964d..312362caca 100644 --- a/client/ayon_core/hosts/fusion/plugins/load/load_alembic.py +++ b/client/ayon_core/hosts/fusion/plugins/load/load_alembic.py @@ -13,7 +13,7 @@ class FusionLoadAlembicMesh(load.LoaderPlugin): """Load Alembic mesh into Fusion""" product_types = {"pointcache", "model"} - representations = ["*"] + representations = {"*"} extensions = {"abc"} label = "Load alembic mesh" diff --git a/client/ayon_core/hosts/fusion/plugins/load/load_fbx.py b/client/ayon_core/hosts/fusion/plugins/load/load_fbx.py index 68b7cdacd1..a84e7e0914 100644 --- a/client/ayon_core/hosts/fusion/plugins/load/load_fbx.py +++ b/client/ayon_core/hosts/fusion/plugins/load/load_fbx.py @@ -13,7 +13,7 @@ class FusionLoadFBXMesh(load.LoaderPlugin): """Load FBX mesh into Fusion""" product_types = {"*"} - representations = ["*"] + representations = {"*"} extensions = { "3ds", "amc", diff --git a/client/ayon_core/hosts/fusion/plugins/load/load_sequence.py b/client/ayon_core/hosts/fusion/plugins/load/load_sequence.py index f0a8233377..7c70b54e48 100644 --- a/client/ayon_core/hosts/fusion/plugins/load/load_sequence.py +++ b/client/ayon_core/hosts/fusion/plugins/load/load_sequence.py @@ -137,7 +137,7 @@ class FusionLoadSequence(load.LoaderPlugin): "image", "online", } - representations = ["*"] + representations = {"*"} extensions = set( ext.lstrip(".") for ext in IMAGE_EXTENSIONS.union(VIDEO_EXTENSIONS) ) diff --git a/client/ayon_core/hosts/fusion/plugins/load/load_usd.py b/client/ayon_core/hosts/fusion/plugins/load/load_usd.py index 2f8eeb4c66..309b0c094c 100644 --- a/client/ayon_core/hosts/fusion/plugins/load/load_usd.py +++ b/client/ayon_core/hosts/fusion/plugins/load/load_usd.py @@ -17,7 +17,7 @@ class FusionLoadUSD(load.LoaderPlugin): """ product_types = {"*"} - representations = ["*"] + representations = {"*"} extensions = {"usd", "usda", "usdz"} label = "Load USD" diff --git a/client/ayon_core/hosts/fusion/plugins/load/load_workfile.py b/client/ayon_core/hosts/fusion/plugins/load/load_workfile.py index fd2fa7c08b..818fbcb187 100644 --- a/client/ayon_core/hosts/fusion/plugins/load/load_workfile.py +++ b/client/ayon_core/hosts/fusion/plugins/load/load_workfile.py @@ -15,7 +15,7 @@ class FusionLoadWorkfile(load.LoaderPlugin): """Load the content of a workfile into Fusion""" product_types = {"workfile"} - representations = ["*"] + representations = {"*"} extensions = {"comp"} label = "Load Workfile" diff --git a/client/ayon_core/hosts/harmony/api/README.md b/client/ayon_core/hosts/harmony/api/README.md index 7ac185638a..b8d1dbc100 100644 --- a/client/ayon_core/hosts/harmony/api/README.md +++ b/client/ayon_core/hosts/harmony/api/README.md @@ -590,7 +590,7 @@ class ImageSequenceLoader(load.LoaderPlugin): "reference", "review", } - representations = ["*"] + representations = {"*"} extensions = {"jpeg", "png", "jpg"} def load(self, context, name=None, namespace=None, data=None): diff --git a/client/ayon_core/hosts/harmony/plugins/load/load_audio.py b/client/ayon_core/hosts/harmony/plugins/load/load_audio.py index 00f3ac77ec..d23f3ed034 100644 --- a/client/ayon_core/hosts/harmony/plugins/load/load_audio.py +++ b/client/ayon_core/hosts/harmony/plugins/load/load_audio.py @@ -36,7 +36,7 @@ class ImportAudioLoader(load.LoaderPlugin): """Import audio.""" product_types = {"shot", "audio"} - representations = ["wav"] + representations = {"wav"} label = "Import Audio" def load(self, context, name=None, namespace=None, data=None): diff --git a/client/ayon_core/hosts/harmony/plugins/load/load_background.py b/client/ayon_core/hosts/harmony/plugins/load/load_background.py index 74bc5a4fd8..dad6ac2f22 100644 --- a/client/ayon_core/hosts/harmony/plugins/load/load_background.py +++ b/client/ayon_core/hosts/harmony/plugins/load/load_background.py @@ -234,7 +234,7 @@ class BackgroundLoader(load.LoaderPlugin): Stores the imported asset in a container named after the asset. """ product_types = {"background"} - representations = ["json"] + representations = {"json"} def load(self, context, name=None, namespace=None, data=None): diff --git a/client/ayon_core/hosts/harmony/plugins/load/load_imagesequence.py b/client/ayon_core/hosts/harmony/plugins/load/load_imagesequence.py index bf4b87a03e..f81ebca9af 100644 --- a/client/ayon_core/hosts/harmony/plugins/load/load_imagesequence.py +++ b/client/ayon_core/hosts/harmony/plugins/load/load_imagesequence.py @@ -28,7 +28,7 @@ class ImageSequenceLoader(load.LoaderPlugin): "reference", "review", } - representations = ["*"] + representations = {"*"} extensions = {"jpeg", "png", "jpg"} def load(self, context, name=None, namespace=None, data=None): diff --git a/client/ayon_core/hosts/harmony/plugins/load/load_palette.py b/client/ayon_core/hosts/harmony/plugins/load/load_palette.py index d5fbeb323b..24f4b4e8d4 100644 --- a/client/ayon_core/hosts/harmony/plugins/load/load_palette.py +++ b/client/ayon_core/hosts/harmony/plugins/load/load_palette.py @@ -12,7 +12,7 @@ class ImportPaletteLoader(load.LoaderPlugin): """Import palettes.""" product_types = {"palette", "harmony.palette"} - representations = ["plt"] + representations = {"plt"} label = "Import Palette" def load(self, context, name=None, namespace=None, data=None): diff --git a/client/ayon_core/hosts/harmony/plugins/load/load_template.py b/client/ayon_core/hosts/harmony/plugins/load/load_template.py index 48064f2b75..96dadb0375 100644 --- a/client/ayon_core/hosts/harmony/plugins/load/load_template.py +++ b/client/ayon_core/hosts/harmony/plugins/load/load_template.py @@ -24,7 +24,7 @@ class TemplateLoader(load.LoaderPlugin): """ product_types = {"template", "workfile"} - representations = ["*"] + representations = {"*"} label = "Load Template" icon = "gift" diff --git a/client/ayon_core/hosts/harmony/plugins/load/load_template_workfile.py b/client/ayon_core/hosts/harmony/plugins/load/load_template_workfile.py index c7132ce373..fa5ffe5105 100644 --- a/client/ayon_core/hosts/harmony/plugins/load/load_template_workfile.py +++ b/client/ayon_core/hosts/harmony/plugins/load/load_template_workfile.py @@ -14,7 +14,7 @@ class ImportTemplateLoader(load.LoaderPlugin): """Import templates.""" product_types = {"harmony.template", "workfile"} - representations = ["*"] + representations = {"*"} label = "Import Template" def load(self, context, name=None, namespace=None, data=None): @@ -61,5 +61,5 @@ class ImportWorkfileLoader(ImportTemplateLoader): """Import workfiles.""" product_types = {"workfile"} - representations = ["zip"] + representations = {"zip"} label = "Import Workfile" diff --git a/client/ayon_core/hosts/hiero/plugins/load/load_clip.py b/client/ayon_core/hosts/hiero/plugins/load/load_clip.py index 72d7e03a9a..715e8c508e 100644 --- a/client/ayon_core/hosts/hiero/plugins/load/load_clip.py +++ b/client/ayon_core/hosts/hiero/plugins/load/load_clip.py @@ -16,7 +16,7 @@ class LoadClip(phiero.SequenceLoader): """ product_types = {"render2d", "source", "plate", "render", "review"} - representations = ["*"] + representations = {"*"} extensions = set( ext.lstrip(".") for ext in IMAGE_EXTENSIONS.union(VIDEO_EXTENSIONS) ) diff --git a/client/ayon_core/hosts/hiero/plugins/load/load_effects.py b/client/ayon_core/hosts/hiero/plugins/load/load_effects.py index fd6b8ed694..92aa2de325 100644 --- a/client/ayon_core/hosts/hiero/plugins/load/load_effects.py +++ b/client/ayon_core/hosts/hiero/plugins/load/load_effects.py @@ -15,7 +15,7 @@ class LoadEffects(load.LoaderPlugin): """Loading colorspace soft effect exported from nukestudio""" product_types = {"effect"} - representations = ["*"] + representations = {"*"} extension = {"json"} label = "Load Effects" diff --git a/client/ayon_core/hosts/houdini/plugins/load/actions.py b/client/ayon_core/hosts/houdini/plugins/load/actions.py index fbd89ab9c2..3e9cc35504 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/actions.py +++ b/client/ayon_core/hosts/houdini/plugins/load/actions.py @@ -15,7 +15,7 @@ class SetFrameRangeLoader(load.LoaderPlugin): "vdbcache", "usd", } - representations = ["abc", "vdb", "usd"] + representations = {"abc", "vdb", "usd"} label = "Set frame range" order = 11 @@ -52,7 +52,7 @@ class SetFrameRangeWithHandlesLoader(load.LoaderPlugin): "vdbcache", "usd", } - representations = ["abc", "vdb", "usd"] + representations = {"abc", "vdb", "usd"} label = "Set frame range (with handles)" order = 12 diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_alembic.py b/client/ayon_core/hosts/houdini/plugins/load/load_alembic.py index 37657cbdff..1bb9043cd0 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_alembic.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_alembic.py @@ -11,7 +11,7 @@ class AbcLoader(load.LoaderPlugin): product_types = {"model", "animation", "pointcache", "gpuCache"} label = "Load Alembic" - representations = ["*"] + representations = {"*"} extensions = {"abc"} order = -10 icon = "code-fork" diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_alembic_archive.py b/client/ayon_core/hosts/houdini/plugins/load/load_alembic_archive.py index 39928fd952..a231bd9993 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_alembic_archive.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_alembic_archive.py @@ -11,7 +11,7 @@ class AbcArchiveLoader(load.LoaderPlugin): product_types = {"model", "animation", "pointcache", "gpuCache"} label = "Load Alembic as Archive" - representations = ["*"] + representations = {"*"} extensions = {"abc"} order = -5 icon = "code-fork" diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_ass.py b/client/ayon_core/hosts/houdini/plugins/load/load_ass.py index fd0e8f4604..6e0922e305 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_ass.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_ass.py @@ -13,7 +13,7 @@ class AssLoader(load.LoaderPlugin): product_types = {"ass"} label = "Load Arnold Procedural" - representations = ["ass"] + representations = {"ass"} order = -10 icon = "code-fork" color = "orange" diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_bgeo.py b/client/ayon_core/hosts/houdini/plugins/load/load_bgeo.py index fd8071c0de..a318b71963 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_bgeo.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_bgeo.py @@ -14,9 +14,9 @@ class BgeoLoader(load.LoaderPlugin): label = "Load bgeo" product_types = {"model", "pointcache", "bgeo"} - representations = [ + representations = { "bgeo", "bgeosc", "bgeogz", - "bgeo.sc", "bgeo.gz", "bgeo.lzma", "bgeo.bz2"] + "bgeo.sc", "bgeo.gz", "bgeo.lzma", "bgeo.bz2"} order = -10 icon = "code-fork" color = "orange" diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_camera.py b/client/ayon_core/hosts/houdini/plugins/load/load_camera.py index 7cb4542d0c..b7912f88f1 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_camera.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_camera.py @@ -89,7 +89,7 @@ class CameraLoader(load.LoaderPlugin): product_types = {"camera"} label = "Load Camera (abc)" - representations = ["abc"] + representations = {"abc"} order = -10 icon = "code-fork" diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_fbx.py b/client/ayon_core/hosts/houdini/plugins/load/load_fbx.py index a0c5e0c934..398019a3bd 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_fbx.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_fbx.py @@ -17,7 +17,7 @@ class FbxLoader(load.LoaderPlugin): order = -10 product_types = {"*"} - representations = ["*"] + representations = {"*"} extensions = {"fbx"} def load(self, context, name=None, namespace=None, data=None): diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_filepath.py b/client/ayon_core/hosts/houdini/plugins/load/load_filepath.py index f107190f96..d189a027fd 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_filepath.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_filepath.py @@ -22,7 +22,7 @@ class FilePathLoader(load.LoaderPlugin): icon = "link" color = "white" product_types = {"*"} - representations = ["*"] + representations = {"*"} def load(self, context, name=None, namespace=None, data=None): diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_hda.py b/client/ayon_core/hosts/houdini/plugins/load/load_hda.py index df77783a34..10fc03be03 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_hda.py @@ -12,7 +12,7 @@ class HdaLoader(load.LoaderPlugin): product_types = {"hda"} label = "Load Hda" - representations = ["hda"] + representations = {"hda"} order = -10 icon = "code-fork" color = "orange" diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_image.py b/client/ayon_core/hosts/houdini/plugins/load/load_image.py index 0429b1c3fe..dfbd3c11eb 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_image.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_image.py @@ -54,7 +54,7 @@ class ImageLoader(load.LoaderPlugin): "online", } label = "Load Image (COP2)" - representations = ["*"] + representations = {"*"} order = -10 icon = "code-fork" diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_redshift_proxy.py b/client/ayon_core/hosts/houdini/plugins/load/load_redshift_proxy.py index a6556619fc..f09856a970 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_redshift_proxy.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_redshift_proxy.py @@ -15,7 +15,7 @@ class RedshiftProxyLoader(load.LoaderPlugin): product_types = {"redshiftproxy"} label = "Load Redshift Proxy" - representations = ["rs"] + representations = {"rs"} order = -10 icon = "code-fork" color = "orange" diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_usd_layer.py b/client/ayon_core/hosts/houdini/plugins/load/load_usd_layer.py index 19950e2c98..4e6954c531 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_usd_layer.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_usd_layer.py @@ -14,7 +14,7 @@ class USDSublayerLoader(load.LoaderPlugin): "usdCamera", } label = "Sublayer USD" - representations = ["usd", "usda", "usdlc", "usdnc", "abc"] + representations = {"usd", "usda", "usdlc", "usdnc", "abc"} order = 1 icon = "code-fork" diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_usd_reference.py b/client/ayon_core/hosts/houdini/plugins/load/load_usd_reference.py index 25f98c7c7c..7e82a6abd0 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_usd_reference.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_usd_reference.py @@ -14,7 +14,7 @@ class USDReferenceLoader(load.LoaderPlugin): "usdCamera", } label = "Reference USD" - representations = ["usd", "usda", "usdlc", "usdnc", "abc"] + representations = {"usd", "usda", "usdlc", "usdnc", "abc"} order = -8 icon = "code-fork" diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_usd_sop.py b/client/ayon_core/hosts/houdini/plugins/load/load_usd_sop.py index 5b7e022e73..506f6140bf 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_usd_sop.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_usd_sop.py @@ -9,7 +9,7 @@ class SopUsdImportLoader(load.LoaderPlugin): label = "Load USD to SOPs" product_types = {"*"} - representations = ["usd"] + representations = {"usd"} order = -6 icon = "code-fork" color = "orange" diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_vdb.py b/client/ayon_core/hosts/houdini/plugins/load/load_vdb.py index d9808020d7..0008f0d5f8 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_vdb.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_vdb.py @@ -13,7 +13,7 @@ class VdbLoader(load.LoaderPlugin): product_types = {"vdbcache"} label = "Load VDB" - representations = ["vdb"] + representations = {"vdb"} order = -10 icon = "code-fork" color = "orange" diff --git a/client/ayon_core/hosts/houdini/plugins/load/show_usdview.py b/client/ayon_core/hosts/houdini/plugins/load/show_usdview.py index 9506d9dd0c..0158a6b963 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/show_usdview.py +++ b/client/ayon_core/hosts/houdini/plugins/load/show_usdview.py @@ -10,7 +10,7 @@ class ShowInUsdview(load.LoaderPlugin): """Open USD file in usdview""" label = "Show in usdview" - representations = ["*"] + representations = {"*"} product_types = {"*"} extensions = {"usd", "usda", "usdlc", "usdnc", "abc"} order = 15 diff --git a/client/ayon_core/hosts/max/plugins/load/load_camera_fbx.py b/client/ayon_core/hosts/max/plugins/load/load_camera_fbx.py index e1de6b98f9..6f1e9988c5 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_camera_fbx.py +++ b/client/ayon_core/hosts/max/plugins/load/load_camera_fbx.py @@ -19,7 +19,7 @@ class FbxLoader(load.LoaderPlugin): """Fbx Loader.""" product_types = {"camera"} - representations = ["fbx"] + representations = {"fbx"} order = -9 icon = "code-fork" color = "white" diff --git a/client/ayon_core/hosts/max/plugins/load/load_max_scene.py b/client/ayon_core/hosts/max/plugins/load/load_max_scene.py index 1c2c5317cc..4f982dd5ba 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_max_scene.py +++ b/client/ayon_core/hosts/max/plugins/load/load_max_scene.py @@ -78,7 +78,7 @@ class MaxSceneLoader(load.LoaderPlugin): "model", } - representations = ["max"] + representations = {"max"} order = -8 icon = "code-fork" color = "green" diff --git a/client/ayon_core/hosts/max/plugins/load/load_model.py b/client/ayon_core/hosts/max/plugins/load/load_model.py index 00e675d69c..1070fce2bd 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_model.py +++ b/client/ayon_core/hosts/max/plugins/load/load_model.py @@ -16,7 +16,7 @@ class ModelAbcLoader(load.LoaderPlugin): product_types = {"model"} label = "Load Model with Alembic" - representations = ["abc"] + representations = {"abc"} order = -10 icon = "code-fork" color = "orange" diff --git a/client/ayon_core/hosts/max/plugins/load/load_model_fbx.py b/client/ayon_core/hosts/max/plugins/load/load_model_fbx.py index 4b87c60de0..82cad71c3e 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_model_fbx.py +++ b/client/ayon_core/hosts/max/plugins/load/load_model_fbx.py @@ -18,7 +18,7 @@ class FbxModelLoader(load.LoaderPlugin): """Fbx Model Loader.""" product_types = {"model"} - representations = ["fbx"] + representations = {"fbx"} order = -9 icon = "code-fork" color = "white" diff --git a/client/ayon_core/hosts/max/plugins/load/load_model_obj.py b/client/ayon_core/hosts/max/plugins/load/load_model_obj.py index 2330dbfc24..38f2cdf43c 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_model_obj.py +++ b/client/ayon_core/hosts/max/plugins/load/load_model_obj.py @@ -20,7 +20,7 @@ class ObjLoader(load.LoaderPlugin): """Obj Loader.""" product_types = {"model"} - representations = ["obj"] + representations = {"obj"} order = -9 icon = "code-fork" color = "white" diff --git a/client/ayon_core/hosts/max/plugins/load/load_model_usd.py b/client/ayon_core/hosts/max/plugins/load/load_model_usd.py index bde23e119e..2b946eb2aa 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_model_usd.py +++ b/client/ayon_core/hosts/max/plugins/load/load_model_usd.py @@ -24,7 +24,7 @@ class ModelUSDLoader(load.LoaderPlugin): product_types = {"model"} label = "Load Model(USD)" - representations = ["usda"] + representations = {"usda"} order = -10 icon = "code-fork" color = "orange" diff --git a/client/ayon_core/hosts/max/plugins/load/load_pointcache.py b/client/ayon_core/hosts/max/plugins/load/load_pointcache.py index 7f515ac6a5..0743b3bb34 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_pointcache.py +++ b/client/ayon_core/hosts/max/plugins/load/load_pointcache.py @@ -20,7 +20,7 @@ class AbcLoader(load.LoaderPlugin): product_types = {"camera", "animation", "pointcache"} label = "Load Alembic" - representations = ["abc"] + representations = {"abc"} order = -10 icon = "code-fork" color = "orange" diff --git a/client/ayon_core/hosts/max/plugins/load/load_pointcache_ornatrix.py b/client/ayon_core/hosts/max/plugins/load/load_pointcache_ornatrix.py index 31d3f02ec0..2efb7c7f62 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_pointcache_ornatrix.py +++ b/client/ayon_core/hosts/max/plugins/load/load_pointcache_ornatrix.py @@ -23,7 +23,7 @@ class OxAbcLoader(load.LoaderPlugin): product_types = {"camera", "animation", "pointcache"} label = "Load Alembic with Ornatrix" - representations = ["abc"] + representations = {"abc"} order = -10 icon = "code-fork" color = "orange" diff --git a/client/ayon_core/hosts/max/plugins/load/load_pointcloud.py b/client/ayon_core/hosts/max/plugins/load/load_pointcloud.py index c0000c7a79..0e79882fc5 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_pointcloud.py +++ b/client/ayon_core/hosts/max/plugins/load/load_pointcloud.py @@ -18,7 +18,7 @@ class PointCloudLoader(load.LoaderPlugin): """Point Cloud Loader.""" product_types = {"pointcloud"} - representations = ["prt"] + representations = {"prt"} order = -8 icon = "code-fork" color = "green" diff --git a/client/ayon_core/hosts/max/plugins/load/load_redshift_proxy.py b/client/ayon_core/hosts/max/plugins/load/load_redshift_proxy.py index ff6811bd1b..22d42390d9 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_redshift_proxy.py +++ b/client/ayon_core/hosts/max/plugins/load/load_redshift_proxy.py @@ -24,7 +24,7 @@ class RedshiftProxyLoader(load.LoaderPlugin): label = "Load Redshift Proxy" product_types = {"redshiftproxy"} - representations = ["rs"] + representations = {"rs"} order = -9 icon = "code-fork" color = "white" diff --git a/client/ayon_core/hosts/max/plugins/load/load_tycache.py b/client/ayon_core/hosts/max/plugins/load/load_tycache.py index 0244e4e6fc..7a5296d933 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_tycache.py +++ b/client/ayon_core/hosts/max/plugins/load/load_tycache.py @@ -17,7 +17,7 @@ class TyCacheLoader(load.LoaderPlugin): """TyCache Loader.""" product_types = {"tycache"} - representations = ["tyc"] + representations = {"tyc"} order = -8 icon = "code-fork" color = "green" diff --git a/client/ayon_core/hosts/maya/plugins/load/_load_animation.py b/client/ayon_core/hosts/maya/plugins/load/_load_animation.py index 884bdd7538..393f6b0115 100644 --- a/client/ayon_core/hosts/maya/plugins/load/_load_animation.py +++ b/client/ayon_core/hosts/maya/plugins/load/_load_animation.py @@ -51,7 +51,7 @@ class AbcLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader): "camera", "pointcache", } - representations = ["abc"] + representations = {"abc"} label = "Reference animation" order = -10 @@ -81,7 +81,7 @@ class FbxLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader): "animation", "camera", } - representations = ["fbx"] + representations = {"fbx"} label = "Reference animation" order = -10 diff --git a/client/ayon_core/hosts/maya/plugins/load/actions.py b/client/ayon_core/hosts/maya/plugins/load/actions.py index a98fe97692..3e21d600ac 100644 --- a/client/ayon_core/hosts/maya/plugins/load/actions.py +++ b/client/ayon_core/hosts/maya/plugins/load/actions.py @@ -19,7 +19,7 @@ class SetFrameRangeLoader(load.LoaderPlugin): "proxyAbc", "pointcache", } - representations = ["abc"] + representations = {"abc"} label = "Set frame range" order = 11 @@ -54,7 +54,7 @@ class SetFrameRangeWithHandlesLoader(load.LoaderPlugin): "proxyAbc", "pointcache", } - representations = ["abc"] + representations = {"abc"} label = "Set frame range (with handles)" order = 12 @@ -94,7 +94,7 @@ class ImportMayaLoader(ayon_core.hosts.maya.api.plugin.Loader): so you could also use it as a new base. """ - representations = ["ma", "mb", "obj"] + representations = {"ma", "mb", "obj"} product_types = { "model", "pointcache", 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 7170c30422..4b7d2f42ab 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 @@ -31,7 +31,7 @@ class ArnoldStandinLoader(load.LoaderPlugin): product_types = { "ass", "animation", "model", "proxyAbc", "pointcache", "usd" } - representations = ["ass", "abc", "usda", "usdc", "usd"] + representations = {"ass", "abc", "usda", "usdc", "usd"} label = "Load as Arnold standin" order = -5 diff --git a/client/ayon_core/hosts/maya/plugins/load/load_assembly.py b/client/ayon_core/hosts/maya/plugins/load/load_assembly.py index a0cbf91905..0fcbc6bd07 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_assembly.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_assembly.py @@ -13,7 +13,7 @@ from ayon_core.hosts.maya.api import setdress class AssemblyLoader(load.LoaderPlugin): product_types = {"assembly"} - representations = ["json"] + representations = {"json"} label = "Load Set Dress" order = -9 diff --git a/client/ayon_core/hosts/maya/plugins/load/load_audio.py b/client/ayon_core/hosts/maya/plugins/load/load_audio.py index 0a40993fcd..228189f1a1 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_audio.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_audio.py @@ -13,7 +13,7 @@ class AudioLoader(load.LoaderPlugin): product_types = {"audio"} label = "Load audio" - representations = ["wav"] + representations = {"wav"} icon = "volume-up" color = "orange" 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 9689282ae9..9832d2d657 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_gpucache.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_gpucache.py @@ -14,7 +14,7 @@ class GpuCacheLoader(load.LoaderPlugin): """Load Alembic as gpuCache""" product_types = {"model", "animation", "proxyAbc", "pointcache"} - representations = ["abc", "gpu_cache"] + representations = {"abc", "gpu_cache"} label = "Load Gpu Cache" order = -5 diff --git a/client/ayon_core/hosts/maya/plugins/load/load_image.py b/client/ayon_core/hosts/maya/plugins/load/load_image.py index 3641655d49..5b0858ce70 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_image.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_image.py @@ -93,7 +93,7 @@ class FileNodeLoader(load.LoaderPlugin): product_types = {"image", "plate", "render"} label = "Load file node" - representations = ["exr", "tif", "png", "jpg"] + representations = {"exr", "tif", "png", "jpg"} icon = "image" color = "orange" order = 2 diff --git a/client/ayon_core/hosts/maya/plugins/load/load_image_plane.py b/client/ayon_core/hosts/maya/plugins/load/load_image_plane.py index b298d5b892..15c7654c52 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_image_plane.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_image_plane.py @@ -89,7 +89,7 @@ class ImagePlaneLoader(load.LoaderPlugin): product_types = {"image", "plate", "render"} label = "Load imagePlane" - representations = ["mov", "exr", "preview", "png", "jpg"] + representations = {"mov", "exr", "preview", "png", "jpg"} icon = "image" color = "orange" @@ -171,7 +171,7 @@ class ImagePlaneLoader(load.LoaderPlugin): plug = "{}.{}".format(image_plane_shape, attr) cmds.setAttr(plug, value) - movie_representations = ["mov", "preview"] + movie_representations = {"mov", "preview"} if context["representation"]["name"] in movie_representations: cmds.setAttr(image_plane_shape + ".type", 2) diff --git a/client/ayon_core/hosts/maya/plugins/load/load_look.py b/client/ayon_core/hosts/maya/plugins/load/load_look.py index f126a1df26..af0e000dd2 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_look.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_look.py @@ -18,7 +18,7 @@ class LookLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader): """Specific loader for lookdev""" product_types = {"look"} - representations = ["ma"] + representations = {"ma"} label = "Reference look" order = -10 diff --git a/client/ayon_core/hosts/maya/plugins/load/load_matchmove.py b/client/ayon_core/hosts/maya/plugins/load/load_matchmove.py index 05da173bb7..b19b14b1aa 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_matchmove.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_matchmove.py @@ -9,7 +9,7 @@ class MatchmoveLoader(load.LoaderPlugin): """ product_types = {"matchmove"} - representations = ["py", "mel"] + representations = {"py", "mel"} defaults = ["Camera", "Object", "Mocap"] label = "Run matchmove script" diff --git a/client/ayon_core/hosts/maya/plugins/load/load_maya_usd.py b/client/ayon_core/hosts/maya/plugins/load/load_maya_usd.py index cd73c26de1..628a25e574 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_maya_usd.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_maya_usd.py @@ -17,7 +17,7 @@ class MayaUsdLoader(load.LoaderPlugin): """Read USD data in a Maya USD Proxy""" product_types = {"model", "usd", "pointcache", "animation"} - representations = ["usd", "usda", "usdc", "usdz", "abc"] + representations = {"usd", "usda", "usdc", "usdz", "abc"} label = "Load USD to Maya Proxy" order = -1 diff --git a/client/ayon_core/hosts/maya/plugins/load/load_multiverse_usd.py b/client/ayon_core/hosts/maya/plugins/load/load_multiverse_usd.py index 984d14dff3..f32c76481d 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_multiverse_usd.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_multiverse_usd.py @@ -28,7 +28,7 @@ class MultiverseUsdLoader(load.LoaderPlugin): "pointcache", "animation", } - representations = ["usd", "usda", "usdc", "usdz", "abc"] + representations = {"usd", "usda", "usdc", "usdz", "abc"} label = "Load USD to Multiverse" order = -10 diff --git a/client/ayon_core/hosts/maya/plugins/load/load_multiverse_usd_over.py b/client/ayon_core/hosts/maya/plugins/load/load_multiverse_usd_over.py index dc5bc6ec1c..b23fa48f07 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_multiverse_usd_over.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_multiverse_usd_over.py @@ -20,7 +20,7 @@ class MultiverseUsdOverLoader(load.LoaderPlugin): """Reference file""" product_types = {"mvUsdOverride"} - representations = ["usda", "usd", "udsz"] + representations = {"usda", "usd", "udsz"} label = "Load Usd Override into Compound" order = -10 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 0f91d9048a..7760d4081c 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 @@ -23,7 +23,7 @@ class RedshiftProxyLoader(load.LoaderPlugin): """Load Redshift proxy""" product_types = {"redshiftproxy"} - representations = ["rs"] + representations = {"rs"} label = "Import Redshift Proxy" order = -10 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 de18b2b0ec..847591bd11 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_reference.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_reference.py @@ -107,7 +107,7 @@ class ReferenceLoader(plugin.ReferenceLoader): "matchmove", } - representations = ["ma", "abc", "fbx", "mb"] + representations = {"ma", "abc", "fbx", "mb"} label = "Reference" order = -10 @@ -269,7 +269,7 @@ class MayaUSDReferenceLoader(ReferenceLoader): label = "Reference Maya USD" product_types = {"usd"} - representations = ["usd"] + representations = {"usd"} extensions = {"usd", "usda", "usdc"} options = ReferenceLoader.options + [ diff --git a/client/ayon_core/hosts/maya/plugins/load/load_rendersetup.py b/client/ayon_core/hosts/maya/plugins/load/load_rendersetup.py index 7096f86e35..d5685b2c4c 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_rendersetup.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_rendersetup.py @@ -52,7 +52,7 @@ class RenderSetupLoader(load.LoaderPlugin): """Load json preset for RenderSetup overwriting current one.""" product_types = {"rendersetup"} - representations = ["json"] + representations = {"json"} defaults = ['Main'] label = "Load RenderSetup template" 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 0780a7b3e7..5b0c78fd6f 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 @@ -13,7 +13,7 @@ class LoadVDBtoArnold(load.LoaderPlugin): """Load OpenVDB for Arnold in aiVolume""" product_types = {"vdbcache"} - representations = ["vdb"] + representations = {"vdb"} label = "Load VDB to Arnold" icon = "cloud" 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 3fa490f405..e345a7bf6f 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 @@ -19,7 +19,7 @@ class LoadVDBtoRedShift(load.LoaderPlugin): """ product_types = {"vdbcache"} - representations = ["vdb"] + representations = {"vdb"} label = "Load VDB to RedShift" icon = "cloud" 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 7b87c21f38..d6d1c948b0 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 @@ -78,7 +78,7 @@ class LoadVDBtoVRay(load.LoaderPlugin): """Load OpenVDB in a V-Ray Volume Grid""" product_types = {"vdbcache"} - representations = ["vdb"] + representations = {"vdb"} label = "Load VDB to VRay" icon = "cloud" 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 895a4a4127..14d645021c 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_vrayproxy.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_vrayproxy.py @@ -28,7 +28,7 @@ class VRayProxyLoader(load.LoaderPlugin): """Load VRay Proxy with Alembic or VrayMesh.""" product_types = {"vrayproxy", "model", "pointcache", "animation"} - representations = ["vrmesh", "abc"] + representations = {"vrmesh", "abc"} label = "Import VRay Proxy" order = -10 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 36a25e2af1..ea3215da97 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_vrayscene.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_vrayscene.py @@ -18,7 +18,7 @@ class VRaySceneLoader(load.LoaderPlugin): """Load Vray scene""" product_types = {"vrayscene_layer"} - representations = ["vrscene"] + representations = {"vrscene"} label = "Import VRay Scene" order = -10 diff --git a/client/ayon_core/hosts/maya/plugins/load/load_xgen.py b/client/ayon_core/hosts/maya/plugins/load/load_xgen.py index 880efd82e1..e2664439b0 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_xgen.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_xgen.py @@ -21,7 +21,7 @@ class XgenLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader): """Load Xgen as reference""" product_types = {"xgen"} - representations = ["ma", "mb"] + representations = {"ma", "mb"} label = "Reference Xgen" icon = "code-fork" 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 a5cd04b0f4..caea6b7a72 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 @@ -37,7 +37,7 @@ class YetiCacheLoader(load.LoaderPlugin): """Load Yeti Cache with one or more Yeti nodes""" product_types = {"yeticache", "yetiRig"} - representations = ["fur"] + representations = {"fur"} label = "Load Yeti Cache" order = -9 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 74e33c5866..bf9525bae3 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 @@ -8,7 +8,7 @@ class YetiRigLoader(plugin.ReferenceLoader): """This loader will load Yeti rig.""" product_types = {"yetiRig"} - representations = ["ma"] + representations = {"ma"} label = "Load Yeti Rig" order = -9 diff --git a/client/ayon_core/hosts/nuke/plugins/load/actions.py b/client/ayon_core/hosts/nuke/plugins/load/actions.py index a1b3697ef1..53cb03087b 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/actions.py +++ b/client/ayon_core/hosts/nuke/plugins/load/actions.py @@ -19,7 +19,7 @@ class SetFrameRangeLoader(load.LoaderPlugin): "yeticache", "pointcache", } - representations = ["*"] + representations = {"*"} extensions = {"*"} label = "Set frame range" @@ -53,7 +53,7 @@ class SetFrameRangeWithHandlesLoader(load.LoaderPlugin): "yeticache", "pointcache", } - representations = ["*"] + representations = {"*"} label = "Set frame range (with handles)" order = 12 diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_backdrop.py b/client/ayon_core/hosts/nuke/plugins/load/load_backdrop.py index e48dbf5e2f..7d823919dc 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_backdrop.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_backdrop.py @@ -22,7 +22,7 @@ class LoadBackdropNodes(load.LoaderPlugin): """Loading Published Backdrop nodes (workfile, nukenodes)""" product_types = {"workfile", "nukenodes"} - representations = ["*"] + representations = {"*"} extensions = {"nk"} label = "Import Nuke Nodes" diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_camera_abc.py b/client/ayon_core/hosts/nuke/plugins/load/load_camera_abc.py index 70b736b1c8..14c54c3adc 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_camera_abc.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_camera_abc.py @@ -21,7 +21,7 @@ class AlembicCameraLoader(load.LoaderPlugin): """ product_types = {"camera"} - representations = ["*"] + representations = {"*"} extensions = {"abc"} label = "Load Alembic Camera" diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_clip.py b/client/ayon_core/hosts/nuke/plugins/load/load_clip.py index 062a5295ed..df8f2ab018 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_clip.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_clip.py @@ -42,7 +42,7 @@ class LoadClip(plugin.NukeLoader): "prerender", "review", } - representations = ["*"] + representations = {"*"} extensions = set( ext.lstrip(".") for ext in IMAGE_EXTENSIONS.union(VIDEO_EXTENSIONS) ) diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_effects.py b/client/ayon_core/hosts/nuke/plugins/load/load_effects.py index f17b179d1b..a87c81295a 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_effects.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_effects.py @@ -19,7 +19,7 @@ class LoadEffects(load.LoaderPlugin): """Loading colorspace soft effect exported from nukestudio""" product_types = {"effect"} - representations = ["*"] + representations = {"*"} extensions = {"json"} label = "Load Effects - nodes" diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_effects_ip.py b/client/ayon_core/hosts/nuke/plugins/load/load_effects_ip.py index 6b58977a95..8fa1347598 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_effects_ip.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_effects_ip.py @@ -20,7 +20,7 @@ class LoadEffectsInputProcess(load.LoaderPlugin): """Loading colorspace soft effect exported from nukestudio""" product_types = {"effect"} - representations = ["*"] + representations = {"*"} extensions = {"json"} label = "Load Effects - Input Process" diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_gizmo.py b/client/ayon_core/hosts/nuke/plugins/load/load_gizmo.py index 6709648ffb..95f85bacfc 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_gizmo.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_gizmo.py @@ -22,7 +22,7 @@ class LoadGizmo(load.LoaderPlugin): """Loading nuke Gizmo""" product_types = {"gizmo"} - representations = ["*"] + representations = {"*"} extensions = {"nk"} label = "Load Gizmo" diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_gizmo_ip.py b/client/ayon_core/hosts/nuke/plugins/load/load_gizmo_ip.py index 3017fa5fc9..3112e27811 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_gizmo_ip.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_gizmo_ip.py @@ -24,7 +24,7 @@ class LoadGizmoInputProcess(load.LoaderPlugin): """Loading colorspace soft effect exported from nukestudio""" product_types = {"gizmo"} - representations = ["*"] + representations = {"*"} extensions = {"nk"} label = "Load Gizmo - Input Process" diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_image.py b/client/ayon_core/hosts/nuke/plugins/load/load_image.py index 9d3f9ceea0..d825b621fc 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_image.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_image.py @@ -32,7 +32,7 @@ class LoadImage(load.LoaderPlugin): "review", "image", } - representations = ["*"] + representations = {"*"} extensions = set( ext.lstrip(".") for ext in IMAGE_EXTENSIONS ) diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_matchmove.py b/client/ayon_core/hosts/nuke/plugins/load/load_matchmove.py index 73c21376b4..beebd0458f 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_matchmove.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_matchmove.py @@ -8,7 +8,7 @@ class MatchmoveLoader(load.LoaderPlugin): """ product_types = {"matchmove"} - representations = ["*"] + representations = {"*"} extensions = {"py"} defaults = ["Camera", "Object"] diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_model.py b/client/ayon_core/hosts/nuke/plugins/load/load_model.py index 971c36b6cf..0326e0a4fc 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_model.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_model.py @@ -19,7 +19,7 @@ class AlembicModelLoader(load.LoaderPlugin): """ product_types = {"model", "pointcache", "animation"} - representations = ["*"] + representations = {"*"} extensions = {"abc"} label = "Load Alembic" diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_ociolook.py b/client/ayon_core/hosts/nuke/plugins/load/load_ociolook.py index 82addcdfc0..c369030b65 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_ociolook.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_ociolook.py @@ -21,7 +21,7 @@ class LoadOcioLookNodes(load.LoaderPlugin): """Loading Ocio look to the nuke.Node graph""" product_types = {"ociolook"} - representations = ["*"] + representations = {"*"} extensions = {"json"} label = "Load OcioLook [nodes]" diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_script_precomp.py b/client/ayon_core/hosts/nuke/plugins/load/load_script_precomp.py index ccc4164355..3e554f9d3b 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_script_precomp.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_script_precomp.py @@ -17,7 +17,7 @@ class LinkAsGroup(load.LoaderPlugin): """Copy the published file to be pasted at the desired location""" product_types = {"workfile", "nukenodes"} - representations = ["*"] + representations = {"*"} extensions = {"nk"} label = "Load Precomp" diff --git a/client/ayon_core/hosts/photoshop/api/README.md b/client/ayon_core/hosts/photoshop/api/README.md index c936c1ec1f..b391131a42 100644 --- a/client/ayon_core/hosts/photoshop/api/README.md +++ b/client/ayon_core/hosts/photoshop/api/README.md @@ -207,7 +207,7 @@ class ImageLoader(load.LoaderPlugin): """ families = ["image"] - representations = ["*"] + representations = {"*"} def load(self, context, name=None, namespace=None, data=None): path = self.filepath_from_context(context) diff --git a/client/ayon_core/hosts/photoshop/plugins/load/load_image.py b/client/ayon_core/hosts/photoshop/plugins/load/load_image.py index 72df2706b5..d71067615e 100644 --- a/client/ayon_core/hosts/photoshop/plugins/load/load_image.py +++ b/client/ayon_core/hosts/photoshop/plugins/load/load_image.py @@ -12,7 +12,7 @@ class ImageLoader(photoshop.PhotoshopLoader): """ product_types = {"image", "render"} - representations = ["*"] + representations = {"*"} def load(self, context, name=None, namespace=None, data=None): stub = self.get_stub() diff --git a/client/ayon_core/hosts/photoshop/plugins/load/load_image_from_sequence.py b/client/ayon_core/hosts/photoshop/plugins/load/load_image_from_sequence.py index 73e8c3683c..dd14543f3e 100644 --- a/client/ayon_core/hosts/photoshop/plugins/load/load_image_from_sequence.py +++ b/client/ayon_core/hosts/photoshop/plugins/load/load_image_from_sequence.py @@ -25,7 +25,7 @@ class ImageFromSequenceLoader(photoshop.PhotoshopLoader): """ product_types = {"render"} - representations = ["*"] + representations = {"*"} options = [] def load(self, context, name=None, namespace=None, data=None): diff --git a/client/ayon_core/hosts/photoshop/plugins/load/load_reference.py b/client/ayon_core/hosts/photoshop/plugins/load/load_reference.py index 7cd34690f7..b563faff82 100644 --- a/client/ayon_core/hosts/photoshop/plugins/load/load_reference.py +++ b/client/ayon_core/hosts/photoshop/plugins/load/load_reference.py @@ -15,7 +15,7 @@ class ReferenceLoader(photoshop.PhotoshopLoader): """ product_types = {"image", "render"} - representations = ["*"] + representations = {"*"} def load(self, context, name=None, namespace=None, data=None): stub = self.get_stub() diff --git a/client/ayon_core/hosts/resolve/plugins/load/load_clip.py b/client/ayon_core/hosts/resolve/plugins/load/load_clip.py index c7bced5e8e..2ce1c43957 100644 --- a/client/ayon_core/hosts/resolve/plugins/load/load_clip.py +++ b/client/ayon_core/hosts/resolve/plugins/load/load_clip.py @@ -20,7 +20,7 @@ class LoadClip(plugin.TimelineItemLoader): product_types = {"render2d", "source", "plate", "render", "review"} - representations = ["*"] + representations = {"*"} extensions = set( ext.lstrip(".") for ext in IMAGE_EXTENSIONS.union(VIDEO_EXTENSIONS) ) diff --git a/client/ayon_core/hosts/substancepainter/plugins/load/load_mesh.py b/client/ayon_core/hosts/substancepainter/plugins/load/load_mesh.py index d940d7b05c..01cb65dd5c 100644 --- a/client/ayon_core/hosts/substancepainter/plugins/load/load_mesh.py +++ b/client/ayon_core/hosts/substancepainter/plugins/load/load_mesh.py @@ -18,7 +18,7 @@ class SubstanceLoadProjectMesh(load.LoaderPlugin): """Load mesh for project""" product_types = {"*"} - representations = ["abc", "fbx", "obj", "gltf", "usd", "usda", "usdc"] + representations = {"abc", "fbx", "obj", "gltf", "usd", "usda", "usdc"} label = "Load mesh" order = -10 diff --git a/client/ayon_core/hosts/tvpaint/plugins/load/load_image.py b/client/ayon_core/hosts/tvpaint/plugins/load/load_image.py index e954b72f12..aad8f92d26 100644 --- a/client/ayon_core/hosts/tvpaint/plugins/load/load_image.py +++ b/client/ayon_core/hosts/tvpaint/plugins/load/load_image.py @@ -7,7 +7,7 @@ class ImportImage(plugin.Loader): """Load image or image sequence to TVPaint as new layer.""" product_types = {"render", "image", "background", "plate", "review"} - representations = ["*"] + representations = {"*"} label = "Import Image" order = 1 diff --git a/client/ayon_core/hosts/tvpaint/plugins/load/load_reference_image.py b/client/ayon_core/hosts/tvpaint/plugins/load/load_reference_image.py index ec671b0cb1..a7fcb9f4a4 100644 --- a/client/ayon_core/hosts/tvpaint/plugins/load/load_reference_image.py +++ b/client/ayon_core/hosts/tvpaint/plugins/load/load_reference_image.py @@ -18,7 +18,7 @@ class LoadImage(plugin.Loader): """Load image or image sequence to TVPaint as new layer.""" product_types = {"render", "image", "background", "plate", "review"} - representations = ["*"] + representations = {"*"} label = "Load Image" order = 1 diff --git a/client/ayon_core/hosts/tvpaint/plugins/load/load_sound.py b/client/ayon_core/hosts/tvpaint/plugins/load/load_sound.py index d8c6a7a430..7e8c8022d6 100644 --- a/client/ayon_core/hosts/tvpaint/plugins/load/load_sound.py +++ b/client/ayon_core/hosts/tvpaint/plugins/load/load_sound.py @@ -23,7 +23,7 @@ class ImportSound(plugin.Loader): """ product_types = {"audio", "review", "plate"} - representations = ["*"] + representations = {"*"} label = "Import Sound" order = 1 diff --git a/client/ayon_core/hosts/tvpaint/plugins/load/load_workfile.py b/client/ayon_core/hosts/tvpaint/plugins/load/load_workfile.py index 8663dac997..407671e14d 100644 --- a/client/ayon_core/hosts/tvpaint/plugins/load/load_workfile.py +++ b/client/ayon_core/hosts/tvpaint/plugins/load/load_workfile.py @@ -25,7 +25,7 @@ class LoadWorkfile(plugin.Loader): """Load workfile.""" product_types = {"workfile"} - representations = ["tvpp"] + representations = {"tvpp"} label = "Load Workfile" diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_alembic_animation.py b/client/ayon_core/hosts/unreal/plugins/load/load_alembic_animation.py index 64d684939c..a12f4f41b4 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_alembic_animation.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_alembic_animation.py @@ -16,7 +16,7 @@ class AnimationAlembicLoader(plugin.Loader): product_types = {"animation"} label = "Import Alembic Animation" - representations = ["abc"] + representations = {"abc"} icon = "cube" color = "orange" diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_animation.py b/client/ayon_core/hosts/unreal/plugins/load/load_animation.py index 59b9f66b78..f6a612ce53 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_animation.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_animation.py @@ -22,7 +22,7 @@ class AnimationFBXLoader(plugin.Loader): product_types = {"animation"} label = "Import FBX Animation" - representations = ["fbx"] + representations = {"fbx"} icon = "cube" color = "orange" diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_camera.py b/client/ayon_core/hosts/unreal/plugins/load/load_camera.py index 285834c911..681c83c6a1 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_camera.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_camera.py @@ -30,7 +30,7 @@ class CameraLoader(plugin.Loader): product_types = {"camera"} label = "Load Camera" - representations = ["fbx"] + representations = {"fbx"} icon = "cube" color = "orange" diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_geometrycache_abc.py b/client/ayon_core/hosts/unreal/plugins/load/load_geometrycache_abc.py index 44c308069b..ae7d41192a 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_geometrycache_abc.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_geometrycache_abc.py @@ -21,7 +21,7 @@ class PointCacheAlembicLoader(plugin.Loader): product_types = {"model", "pointcache"} label = "Import Alembic Point Cache" - representations = ["abc"] + representations = {"abc"} icon = "cube" color = "orange" diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_layout.py b/client/ayon_core/hosts/unreal/plugins/load/load_layout.py index b0f09ee8b0..49d95c6459 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_layout.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_layout.py @@ -41,7 +41,7 @@ class LayoutLoader(plugin.Loader): """Load Layout from a JSON file""" product_types = {"layout"} - representations = ["json"] + representations = {"json"} label = "Load Layout" icon = "code-fork" diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_layout_existing.py b/client/ayon_core/hosts/unreal/plugins/load/load_layout_existing.py index 56e36f6185..f9d438367b 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_layout_existing.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_layout_existing.py @@ -22,7 +22,7 @@ class ExistingLayoutLoader(plugin.Loader): """ product_types = {"layout"} - representations = ["json"] + representations = {"json"} label = "Load Layout on Existing Scene" icon = "code-fork" diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_skeletalmesh_abc.py b/client/ayon_core/hosts/unreal/plugins/load/load_skeletalmesh_abc.py index 64b1810080..dfc5d58708 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_skeletalmesh_abc.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_skeletalmesh_abc.py @@ -20,7 +20,7 @@ class SkeletalMeshAlembicLoader(plugin.Loader): product_types = {"pointcache", "skeletalMesh"} label = "Import Alembic Skeletal Mesh" - representations = ["abc"] + representations = {"abc"} icon = "cube" color = "orange" diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_skeletalmesh_fbx.py b/client/ayon_core/hosts/unreal/plugins/load/load_skeletalmesh_fbx.py index f61f0dbc3f..513404ab98 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_skeletalmesh_fbx.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_skeletalmesh_fbx.py @@ -20,7 +20,7 @@ class SkeletalMeshFBXLoader(plugin.Loader): product_types = {"rig", "skeletalMesh"} label = "Import FBX Skeletal Mesh" - representations = ["fbx"] + representations = {"fbx"} icon = "cube" color = "orange" diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_staticmesh_abc.py b/client/ayon_core/hosts/unreal/plugins/load/load_staticmesh_abc.py index 256cb9e8bc..0bf6ce9eaa 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_staticmesh_abc.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_staticmesh_abc.py @@ -20,7 +20,7 @@ class StaticMeshAlembicLoader(plugin.Loader): product_types = {"model", "staticMesh"} label = "Import Alembic Static Mesh" - representations = ["abc"] + representations = {"abc"} icon = "cube" color = "orange" diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_staticmesh_fbx.py b/client/ayon_core/hosts/unreal/plugins/load/load_staticmesh_fbx.py index 0ec4b1b4f8..b7bb57ac23 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_staticmesh_fbx.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_staticmesh_fbx.py @@ -20,7 +20,7 @@ class StaticMeshFBXLoader(plugin.Loader): product_types = {"model", "staticMesh"} label = "Import FBX Static Mesh" - representations = ["fbx"] + representations = {"fbx"} icon = "cube" color = "orange" diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_uasset.py b/client/ayon_core/hosts/unreal/plugins/load/load_uasset.py index 89ef357c89..63f23ecc11 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_uasset.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_uasset.py @@ -17,7 +17,7 @@ class UAssetLoader(plugin.Loader): product_types = {"uasset"} label = "Load UAsset" - representations = ["uasset"] + representations = {"uasset"} icon = "cube" color = "orange" @@ -166,6 +166,6 @@ class UMapLoader(UAssetLoader): product_types = {"uasset"} label = "Load Level" - representations = ["umap"] + representations = {"umap"} extension = "umap" diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_yeticache.py b/client/ayon_core/hosts/unreal/plugins/load/load_yeticache.py index 21715a24c6..708fc83745 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_yeticache.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_yeticache.py @@ -17,7 +17,7 @@ class YetiLoader(plugin.Loader): product_types = {"yeticacheUE"} label = "Import Yeti" - representations = ["abc"] + representations = {"abc"} icon = "pagelines" color = "orange" diff --git a/client/ayon_core/plugins/load/copy_file.py b/client/ayon_core/plugins/load/copy_file.py index 5e6daa866b..08dad03be3 100644 --- a/client/ayon_core/plugins/load/copy_file.py +++ b/client/ayon_core/plugins/load/copy_file.py @@ -5,7 +5,7 @@ from ayon_core.pipeline import load class CopyFile(load.LoaderPlugin): """Copy the published file to be pasted at the desired location""" - representations = ["*"] + representations = {"*"} product_types = {"*"} label = "Copy File" diff --git a/client/ayon_core/plugins/load/copy_file_path.py b/client/ayon_core/plugins/load/copy_file_path.py index ecde3bc55f..fdf31b5e02 100644 --- a/client/ayon_core/plugins/load/copy_file_path.py +++ b/client/ayon_core/plugins/load/copy_file_path.py @@ -5,7 +5,7 @@ from ayon_core.pipeline import load class CopyFilePath(load.LoaderPlugin): """Copy published file path to clipboard""" - representations = ["*"] + representations = {"*"} product_types = {"*"} label = "Copy File Path" diff --git a/client/ayon_core/plugins/load/delete_old_versions.py b/client/ayon_core/plugins/load/delete_old_versions.py index 04873d8b5c..8e04fd9827 100644 --- a/client/ayon_core/plugins/load/delete_old_versions.py +++ b/client/ayon_core/plugins/load/delete_old_versions.py @@ -26,7 +26,7 @@ # is_multiple_contexts_compatible = True # sequence_splitter = "__sequence_splitter__" # -# representations = ["*"] +# representations = {"*"} # product_types = {"*"} # tool_names = ["library_loader"] # diff --git a/client/ayon_core/plugins/load/delivery.py b/client/ayon_core/plugins/load/delivery.py index cd358846ea..c7954a18b2 100644 --- a/client/ayon_core/plugins/load/delivery.py +++ b/client/ayon_core/plugins/load/delivery.py @@ -28,7 +28,7 @@ class Delivery(load.ProductLoaderPlugin): is_multiple_contexts_compatible = True sequence_splitter = "__sequence_splitter__" - representations = ["*"] + representations = {"*"} product_types = {"*"} tool_names = ["library_loader"] diff --git a/client/ayon_core/plugins/load/open_file.py b/client/ayon_core/plugins/load/open_file.py index fc57708cd6..3b5fbbc0c9 100644 --- a/client/ayon_core/plugins/load/open_file.py +++ b/client/ayon_core/plugins/load/open_file.py @@ -19,7 +19,7 @@ class OpenFile(load.LoaderPlugin): """Open Image Sequence or Video with system default""" product_types = {"render2d"} - representations = ["*"] + representations = {"*"} label = "Open" order = -10 diff --git a/client/ayon_core/plugins/load/push_to_library.py b/client/ayon_core/plugins/load/push_to_library.py index 02d834bc95..981028d734 100644 --- a/client/ayon_core/plugins/load/push_to_library.py +++ b/client/ayon_core/plugins/load/push_to_library.py @@ -11,7 +11,7 @@ class PushToLibraryProject(load.ProductLoaderPlugin): is_multiple_contexts_compatible = True - representations = ["*"] + representations = {"*"} product_types = {"*"} label = "Push to Library project" From 84f8a61cc64d85f71441bf253a45042ec67efc4e Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 9 Apr 2024 17:28:49 +0200 Subject: [PATCH 100/111] add docstring --- client/ayon_core/pipeline/load/plugins.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/client/ayon_core/pipeline/load/plugins.py b/client/ayon_core/pipeline/load/plugins.py index 3f47ec421e..2475800cbb 100644 --- a/client/ayon_core/pipeline/load/plugins.py +++ b/client/ayon_core/pipeline/load/plugins.py @@ -162,6 +162,15 @@ class LoaderPlugin(list): @classmethod def get_representations(cls): + """Representation names with which is plugin compatible. + + Empty set makes the plugin incompatible with any representation. To + allow compatibility with all representations use '{"*"}'. + + Returns: + set[str]: Names with which is plugin compatible. + + """ return cls.representations @classmethod From 590f1db63e1254d6fb2be4eac1ea22fb60762afb Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 10 Apr 2024 09:54:31 +0200 Subject: [PATCH 101/111] Bump Maya addon version --- server_addon/maya/server/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server_addon/maya/server/version.py b/server_addon/maya/server/version.py index e332ce4b6e..75b463f198 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.14" +__version__ = "0.1.15" From a782d4bc1982e063b30d1795a17c09d4f594dd32 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 10 Apr 2024 11:24:16 +0200 Subject: [PATCH 102/111] added constants to __all__ --- .../ayon_core/addons/applications/ayon_applications/__init__.py | 1 + client/ayon_core/hosts/unreal/api/__init__.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/client/ayon_core/addons/applications/ayon_applications/__init__.py b/client/ayon_core/addons/applications/ayon_applications/__init__.py index b4a50279ab..c9b72f9914 100644 --- a/client/ayon_core/addons/applications/ayon_applications/__init__.py +++ b/client/ayon_core/addons/applications/ayon_applications/__init__.py @@ -31,6 +31,7 @@ from .addon import ApplicationsAddon __all__ = ( + "APPLICATIONS_ADDON_ROOT", "DEFAULT_ENV_SUBGROUP", "PLATFORM_NAMES", diff --git a/client/ayon_core/hosts/unreal/api/__init__.py b/client/ayon_core/hosts/unreal/api/__init__.py index ac6a91eae9..defad8b3c9 100644 --- a/client/ayon_core/hosts/unreal/api/__init__.py +++ b/client/ayon_core/hosts/unreal/api/__init__.py @@ -30,6 +30,8 @@ from .pipeline import ( __all__ = [ "install", "uninstall", + "UnrealActorCreator", + "UnrealAssetCreator", "Loader", "ls", "publish", From ebfcd364cd51876339d7e99498fd77b506fdb5ba Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 10 Apr 2024 11:24:33 +0200 Subject: [PATCH 103/111] don't use single char variable --- .../ayon_core/tools/utils/color_widgets/color_inputs.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/ayon_core/tools/utils/color_widgets/color_inputs.py b/client/ayon_core/tools/utils/color_widgets/color_inputs.py index 9c8e7b92e8..795b80fc1e 100644 --- a/client/ayon_core/tools/utils/color_widgets/color_inputs.py +++ b/client/ayon_core/tools/utils/color_widgets/color_inputs.py @@ -562,11 +562,11 @@ class HSLInputs(QtWidgets.QWidget): return self._block_changes = True - h, s, l, _ = self.color.getHsl() + hue, sat, lum, _ = self.color.getHsl() - self.input_hue.setValue(h) - self.input_sat.setValue(s) - self.input_light.setValue(l) + self.input_hue.setValue(hue) + self.input_sat.setValue(sat) + self.input_light.setValue(lum) self._block_changes = False From d1243d74e34ff18e2f5baec764a53ec0b88d4e93 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 10 Apr 2024 11:24:41 +0200 Subject: [PATCH 104/111] define function instead of lambda --- client/ayon_core/tools/utils/widgets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/tools/utils/widgets.py b/client/ayon_core/tools/utils/widgets.py index 1d4f85246f..21cab5d682 100644 --- a/client/ayon_core/tools/utils/widgets.py +++ b/client/ayon_core/tools/utils/widgets.py @@ -578,7 +578,8 @@ class OptionalAction(QtWidgets.QWidgetAction): def set_option_tip(self, options): sep = "\n\n" if not options or not isinstance(options[0], AbstractAttrDef): - mak = (lambda opt: opt["name"] + " :\n " + opt["help"]) + def mak(opt): + return opt["name"] + " :\n " + opt["help"] self.option_tip = sep.join(mak(opt) for opt in options) return From 9cb8b3b84ca1cfc7be8aecb54852ccb55fd7ae2c Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 10 Apr 2024 11:24:55 +0200 Subject: [PATCH 105/111] comment out example implementation --- client/ayon_core/tools/publisher/control_qt.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/tools/publisher/control_qt.py b/client/ayon_core/tools/publisher/control_qt.py index ee08899cac..bef3a5af3b 100644 --- a/client/ayon_core/tools/publisher/control_qt.py +++ b/client/ayon_core/tools/publisher/control_qt.py @@ -343,8 +343,9 @@ class QtRemotePublishController(BasePublisherController): @abstractmethod def _send_instance_changes_to_client(self): - instance_changes = self._get_instance_changes_for_client() - # Implement to send 'instance_changes' value to client + # TODO Implement to send 'instance_changes' value to client + # instance_changes = self._get_instance_changes_for_client() + pass @abstractmethod def save_changes(self): From 2f9834ba3bbb68828a01851ea99599b3d6ca1719 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 10 Apr 2024 11:25:05 +0200 Subject: [PATCH 106/111] removed duplicated methods in slates --- client/ayon_core/scripts/slates/slate_base/base.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/client/ayon_core/scripts/slates/slate_base/base.py b/client/ayon_core/scripts/slates/slate_base/base.py index 35ef46769c..e1648c916a 100644 --- a/client/ayon_core/scripts/slates/slate_base/base.py +++ b/client/ayon_core/scripts/slates/slate_base/base.py @@ -82,20 +82,6 @@ class BaseObj: def main_style(self): return load_default_style() - def height(self): - raise NotImplementedError( - "Attribute `height` is not implemented for <{}>".format( - self.__clas__.__name__ - ) - ) - - def width(self): - raise NotImplementedError( - "Attribute `width` is not implemented for <{}>".format( - self.__clas__.__name__ - ) - ) - def collect_data(self): return None From 40c41f82ece7331020a185166d1437a16045b3c9 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 10 Apr 2024 11:25:18 +0200 Subject: [PATCH 107/111] ignore unused import in loader action --- client/ayon_core/modules/loader_action.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/modules/loader_action.py b/client/ayon_core/modules/loader_action.py index a0cc417b66..1e45db05dc 100644 --- a/client/ayon_core/modules/loader_action.py +++ b/client/ayon_core/modules/loader_action.py @@ -13,7 +13,7 @@ class LoaderAddon(AYONAddon, ITrayAddon): # Add library tool self._loader_imported = False try: - from ayon_core.tools.loader.ui import LoaderWindow + from ayon_core.tools.loader.ui import LoaderWindow # noqa F401 self._loader_imported = True except Exception: From 55b60fc7e224fb1d27c24d31482ed94939899eec Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 10 Apr 2024 11:25:33 +0200 Subject: [PATCH 108/111] do not store output to unused variable --- .../hosts/traypublisher/plugins/create/create_editorial.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 843729786c..4057aee9a6 100644 --- a/client/ayon_core/hosts/traypublisher/plugins/create/create_editorial.py +++ b/client/ayon_core/hosts/traypublisher/plugins/create/create_editorial.py @@ -402,7 +402,7 @@ or updating already created. Publishing will create OTIO file. ): continue - instance = self._make_product_instance( + self._make_product_instance( otio_clip, product_type_preset, deepcopy(base_instance_data), From 7c994ee1f0d0c87784d40e0f3b1f1ef157ff51cd Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 10 Apr 2024 11:25:45 +0200 Subject: [PATCH 109/111] ignore unused variable in tray --- client/ayon_core/tools/tray/tray.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/tools/tray/tray.py b/client/ayon_core/tools/tray/tray.py index 3c6c529be8..957518afe4 100644 --- a/client/ayon_core/tools/tray/tray.py +++ b/client/ayon_core/tools/tray/tray.py @@ -552,7 +552,7 @@ class TrayStarter(QtCore.QObject): def main(): app = get_ayon_qt_app() - starter = TrayStarter(app) + starter = TrayStarter(app) # noqa F841 if not is_running_from_build() and os.name == "nt": import ctypes From 6366998d57b1914e1552923edc8ad9ef97fdc2b3 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 10 Apr 2024 12:02:12 +0200 Subject: [PATCH 110/111] change order to match imports order Co-authored-by: Roy Nieterau --- client/ayon_core/hosts/unreal/api/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/hosts/unreal/api/__init__.py b/client/ayon_core/hosts/unreal/api/__init__.py index defad8b3c9..7e7f839f27 100644 --- a/client/ayon_core/hosts/unreal/api/__init__.py +++ b/client/ayon_core/hosts/unreal/api/__init__.py @@ -28,11 +28,11 @@ from .pipeline import ( ) __all__ = [ - "install", - "uninstall", "UnrealActorCreator", "UnrealAssetCreator", "Loader", + "install", + "uninstall", "ls", "publish", "containerise", From cad45cee4c00ea92bfcda92687fda52f4eb1e29b Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 10 Apr 2024 17:37:52 +0200 Subject: [PATCH 111/111] check for correct first argument --- client/ayon_core/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/cli.py b/client/ayon_core/cli.py index 80fbb57340..bd47dc1aac 100644 --- a/client/ayon_core/cli.py +++ b/client/ayon_core/cli.py @@ -176,9 +176,9 @@ def run(script): # future versions might remove it. first_arg = sys.argv[0] if is_running_from_build(): - comp_path = os.path.join(os.environ["AYON_ROOT"], "start.py") - else: comp_path = os.getenv("AYON_EXECUTABLE") + else: + comp_path = os.path.join(os.environ["AYON_ROOT"], "start.py") # Compare paths and remove first argument if it is the same as AYON if Path(first_arg).resolve() == Path(comp_path).resolve(): sys.argv.pop(0)