From 2fdd13738066f320359a2cf7d84407bcd93e8fbd Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 28 Nov 2022 09:40:42 +0000 Subject: [PATCH 01/54] Optional control of display lights on playblast. --- openpype/hosts/maya/plugins/create/create_review.py | 2 ++ openpype/hosts/maya/plugins/publish/extract_playblast.py | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/openpype/hosts/maya/plugins/create/create_review.py b/openpype/hosts/maya/plugins/create/create_review.py index ba51ffa009..65aeb2d76a 100644 --- a/openpype/hosts/maya/plugins/create/create_review.py +++ b/openpype/hosts/maya/plugins/create/create_review.py @@ -25,6 +25,7 @@ class CreateReview(plugin.Creator): "depth peeling", "alpha cut" ] + displayLights = ["default", "all", "selected", "active", "none"] def __init__(self, *args, **kwargs): super(CreateReview, self).__init__(*args, **kwargs) @@ -41,5 +42,6 @@ class CreateReview(plugin.Creator): data["keepImages"] = self.keepImages data["imagePlane"] = self.imagePlane data["transparency"] = self.transparency + data["displayLights"] = self.displayLights self.data = data diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index b19d24fad7..cbf99eccaa 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -97,6 +97,10 @@ class ExtractPlayblast(publish.Extractor): refreshFrameInt = int(pm.playbackOptions(q=True, minTime=True)) pm.currentTime(refreshFrameInt - 1, edit=True) pm.currentTime(refreshFrameInt, edit=True) + + # Show lighting mode. + index = instance.data.get("displayLights", 0) + preset["viewport_options"]["displayLights"] = self.displayLights[index] # Override transparency if requested. transparency = instance.data.get("transparency", 0) From e214062047f09e6b0879cb015e6445b889b0d33a Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 2 Dec 2022 12:19:57 +0000 Subject: [PATCH 02/54] Missing class data. --- openpype/hosts/maya/plugins/publish/extract_playblast.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index cbf99eccaa..c6bbe44efc 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -23,6 +23,7 @@ class ExtractPlayblast(publish.Extractor): families = ["review"] optional = True capture_preset = {} + displayLights = ["default", "all", "selected", "active", "none"] def process(self, instance): self.log.info("Extracting capture..") @@ -97,7 +98,7 @@ class ExtractPlayblast(publish.Extractor): refreshFrameInt = int(pm.playbackOptions(q=True, minTime=True)) pm.currentTime(refreshFrameInt - 1, edit=True) pm.currentTime(refreshFrameInt, edit=True) - + # Show lighting mode. index = instance.data.get("displayLights", 0) preset["viewport_options"]["displayLights"] = self.displayLights[index] From 6bc8748b99e58894479071e14b04780a3da9cd15 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 14 Dec 2022 09:18:45 +0000 Subject: [PATCH 03/54] Collect display lights list in lib. --- openpype/hosts/maya/api/lib.py | 2 ++ openpype/hosts/maya/plugins/create/create_review.py | 3 +-- openpype/hosts/maya/plugins/publish/extract_playblast.py | 3 +-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 2530021eba..617e4e3d3a 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -113,6 +113,8 @@ FLOAT_FPS = {23.98, 23.976, 29.97, 47.952, 59.94} RENDERLIKE_INSTANCE_FAMILIES = ["rendering", "vrayscene"] +DISPLAY_LIGHTS = ["default", "all", "selected", "active", "none"] + def get_main_window(): """Acquire Maya's main window""" diff --git a/openpype/hosts/maya/plugins/create/create_review.py b/openpype/hosts/maya/plugins/create/create_review.py index 65aeb2d76a..1935d18deb 100644 --- a/openpype/hosts/maya/plugins/create/create_review.py +++ b/openpype/hosts/maya/plugins/create/create_review.py @@ -25,7 +25,6 @@ class CreateReview(plugin.Creator): "depth peeling", "alpha cut" ] - displayLights = ["default", "all", "selected", "active", "none"] def __init__(self, *args, **kwargs): super(CreateReview, self).__init__(*args, **kwargs) @@ -42,6 +41,6 @@ class CreateReview(plugin.Creator): data["keepImages"] = self.keepImages data["imagePlane"] = self.imagePlane data["transparency"] = self.transparency - data["displayLights"] = self.displayLights + data["displayLights"] = lib.DISPLAY_LIGHTS self.data = data diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index c6bbe44efc..d8e1184335 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -23,7 +23,6 @@ class ExtractPlayblast(publish.Extractor): families = ["review"] optional = True capture_preset = {} - displayLights = ["default", "all", "selected", "active", "none"] def process(self, instance): self.log.info("Extracting capture..") @@ -101,7 +100,7 @@ class ExtractPlayblast(publish.Extractor): # Show lighting mode. index = instance.data.get("displayLights", 0) - preset["viewport_options"]["displayLights"] = self.displayLights[index] + preset["viewport_options"]["displayLights"] = lib.DISPLAY_LIGHTS[index] # Override transparency if requested. transparency = instance.data.get("transparency", 0) From c921bc14c56ec3780981e6a432a26bc32fd84235 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 15 Dec 2022 08:57:22 +0000 Subject: [PATCH 04/54] Convert enum to string in collector --- openpype/hosts/maya/plugins/publish/collect_review.py | 5 +++++ openpype/hosts/maya/plugins/publish/extract_playblast.py | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_review.py b/openpype/hosts/maya/plugins/publish/collect_review.py index eb872c2935..995bd23687 100644 --- a/openpype/hosts/maya/plugins/publish/collect_review.py +++ b/openpype/hosts/maya/plugins/publish/collect_review.py @@ -5,6 +5,7 @@ import pyblish.api from openpype.client import get_subset_by_name from openpype.pipeline import legacy_io +from openpype.hosts.maya.api import lib class CollectReview(pyblish.api.InstancePlugin): @@ -139,3 +140,7 @@ class CollectReview(pyblish.api.InstancePlugin): "filename": node.filename.get() } ) + + # Convert enum attribute to string. + index = instance.data.get("displayLights", 0) + instance.data["displayLights"] = lib.DISPLAY_LIGHTS[index] diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index d8e1184335..08eb754c6d 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -99,8 +99,8 @@ class ExtractPlayblast(publish.Extractor): pm.currentTime(refreshFrameInt, edit=True) # Show lighting mode. - index = instance.data.get("displayLights", 0) - preset["viewport_options"]["displayLights"] = lib.DISPLAY_LIGHTS[index] + display_lights = instance.data["displayLights"] + preset["viewport_options"]["displayLights"] = display_lights # Override transparency if requested. transparency = instance.data.get("transparency", 0) From 9284e986d1f3d3131bb4b4cce1a2808cad141bb0 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 15 Dec 2022 08:57:36 +0000 Subject: [PATCH 05/54] Use display lights in thumbnail --- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 712159c2be..bb9cef2c5c 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -105,6 +105,10 @@ class ExtractThumbnail(publish.Extractor): pm.currentTime(refreshFrameInt - 1, edit=True) pm.currentTime(refreshFrameInt, edit=True) + # Show lighting mode. + display_lights = instance.data["displayLights"] + preset["viewport_options"]["displayLights"] = display_lights + # Isolate view is requested by having objects in the set besides a # camera. if preset.pop("isolate_view", False) and instance.data.get("isolate"): From 67b95c218b51e5c87132e5270d0a7c47760ed7e5 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Thu, 15 Dec 2022 13:13:48 +0000 Subject: [PATCH 06/54] Update openpype/hosts/maya/plugins/publish/collect_review.py Co-authored-by: Roy Nieterau --- openpype/hosts/maya/plugins/publish/collect_review.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_review.py b/openpype/hosts/maya/plugins/publish/collect_review.py index 995bd23687..d15eb7a12b 100644 --- a/openpype/hosts/maya/plugins/publish/collect_review.py +++ b/openpype/hosts/maya/plugins/publish/collect_review.py @@ -141,6 +141,6 @@ class CollectReview(pyblish.api.InstancePlugin): } ) - # Convert enum attribute to string. + # Convert enum attribute index to string. index = instance.data.get("displayLights", 0) instance.data["displayLights"] = lib.DISPLAY_LIGHTS[index] From ae496b9712bafc77a0d8350b92b0e84505eee512 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 9 Jan 2023 07:30:29 +0000 Subject: [PATCH 07/54] Use project settings by default. --- openpype/hosts/maya/api/lib.py | 4 +++- openpype/hosts/maya/plugins/publish/extract_playblast.py | 3 ++- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 4b8b6b1949..9aa2325e25 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -113,7 +113,9 @@ FLOAT_FPS = {23.98, 23.976, 29.97, 47.952, 59.94} RENDERLIKE_INSTANCE_FAMILIES = ["rendering", "vrayscene"] -DISPLAY_LIGHTS = ["default", "all", "selected", "active", "none"] +DISPLAY_LIGHTS = [ + "project_settings", "default", "all", "selected", "active", "none" +] def get_main_window(): diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index a1e6b2d503..7542785152 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -100,7 +100,8 @@ class ExtractPlayblast(publish.Extractor): # Show lighting mode. display_lights = instance.data["displayLights"] - preset["viewport_options"]["displayLights"] = display_lights + if display_lights != "project_settings": + preset["viewport_options"]["displayLights"] = display_lights # Override transparency if requested. transparency = instance.data.get("transparency", 0) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 80e94303a6..de6bc3895e 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -107,7 +107,8 @@ class ExtractThumbnail(publish.Extractor): # Show lighting mode. display_lights = instance.data["displayLights"] - preset["viewport_options"]["displayLights"] = display_lights + if display_lights != "project_settings": + preset["viewport_options"]["displayLights"] = display_lights # Override transparency if requested. transparency = instance.data.get("transparency", 0) From 3860fe36926aad704cf6d0ef66c89542e2acf922 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 23 Mar 2023 18:09:11 +0100 Subject: [PATCH 08/54] OP-3951 - updated validator to use special pattern Handles numbers (version, instance number) in file names. --- .../publish/validate_sequence_frames.py | 45 ++++++++++++++----- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/openpype/plugins/publish/validate_sequence_frames.py b/openpype/plugins/publish/validate_sequence_frames.py index f03229da22..c932c0e779 100644 --- a/openpype/plugins/publish/validate_sequence_frames.py +++ b/openpype/plugins/publish/validate_sequence_frames.py @@ -1,3 +1,8 @@ +import os.path + +import clique +import re + import pyblish.api @@ -7,6 +12,11 @@ class ValidateSequenceFrames(pyblish.api.InstancePlugin): The files found in the folder are checked against the startFrame and endFrame of the instance. If the first or last file is not corresponding with the first or last frame it is flagged as invalid. + + Used regular expression pattern handles numbers in the file names + (eg "Main_beauty.v001.1001.exr", "Main_beauty_v001.1001.exr", + "Main_beauty.1001.1001.exr") but not numbers behind frames (eg. + "Main_beauty.1001.v001.exr") """ order = pyblish.api.ValidatorOrder @@ -15,20 +25,31 @@ class ValidateSequenceFrames(pyblish.api.InstancePlugin): hosts = ["shell"] def process(self, instance): + representations = instance.data.get("representations") + for repr in representations: + if isinstance(repr["files"], str): + repr["files"] = [repr["files"]] - collection = instance[0] - self.log.info(collection) + _, ext = os.path.splitext(repr["files"][0]) + pattern = r"\D?(?P(?P0*)\d+){}$".format( + re.escape(ext)) + patterns = [pattern] - frames = list(collection.indexes) + collections, remainder = clique.assemble( + repr["files"], minimum_items=1, patterns=patterns) - current_range = (frames[0], frames[-1]) - required_range = (instance.data["frameStart"], - instance.data["frameEnd"]) + assert not remainder, "Must not have remainder" + assert len(collections) == 1, "Must detect single collection" + collection = collections[0] + frames = list(collection.indexes) - if current_range != required_range: - raise ValueError("Invalid frame range: {0} - " - "expected: {1}".format(current_range, - required_range)) + current_range = (frames[0], frames[-1]) + required_range = (instance.data["frameStart"], + instance.data["frameEnd"]) - missing = collection.holes().indexes - assert not missing, "Missing frames: %s" % (missing,) + if current_range != required_range: + raise ValueError(f"Invalid frame range: {current_range} - " + f"expected: {required_range}") + + missing = collection.holes().indexes + assert not missing, "Missing frames: %s" % (missing,) From e8f9c130bbb7b805f6ea68a3bbc37d81168d5893 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 23 Mar 2023 18:11:28 +0100 Subject: [PATCH 09/54] OP-3951 - merged global validator and unreal one Both should do same thing. Combination of host and family should be safe. --- .../publish/validate_sequence_frames.py | 41 ------------------- .../publish/validate_sequence_frames.py | 4 +- 2 files changed, 2 insertions(+), 43 deletions(-) delete mode 100644 openpype/hosts/unreal/plugins/publish/validate_sequence_frames.py diff --git a/openpype/hosts/unreal/plugins/publish/validate_sequence_frames.py b/openpype/hosts/unreal/plugins/publish/validate_sequence_frames.py deleted file mode 100644 index 87f1338ee8..0000000000 --- a/openpype/hosts/unreal/plugins/publish/validate_sequence_frames.py +++ /dev/null @@ -1,41 +0,0 @@ -import clique - -import pyblish.api - - -class ValidateSequenceFrames(pyblish.api.InstancePlugin): - """Ensure the sequence of frames is complete - - The files found in the folder are checked against the frameStart and - frameEnd of the instance. If the first or last file is not - corresponding with the first or last frame it is flagged as invalid. - """ - - order = pyblish.api.ValidatorOrder - label = "Validate Sequence Frames" - families = ["render"] - hosts = ["unreal"] - optional = True - - def process(self, instance): - representations = instance.data.get("representations") - for repr in representations: - patterns = [clique.PATTERNS["frames"]] - collections, remainder = clique.assemble( - repr["files"], minimum_items=1, patterns=patterns) - - assert not remainder, "Must not have remainder" - assert len(collections) == 1, "Must detect single collection" - collection = collections[0] - frames = list(collection.indexes) - - current_range = (frames[0], frames[-1]) - required_range = (instance.data["frameStart"], - instance.data["frameEnd"]) - - if current_range != required_range: - raise ValueError(f"Invalid frame range: {current_range} - " - f"expected: {required_range}") - - missing = collection.holes().indexes - assert not missing, "Missing frames: %s" % (missing,) diff --git a/openpype/plugins/publish/validate_sequence_frames.py b/openpype/plugins/publish/validate_sequence_frames.py index c932c0e779..56641fbf57 100644 --- a/openpype/plugins/publish/validate_sequence_frames.py +++ b/openpype/plugins/publish/validate_sequence_frames.py @@ -21,8 +21,8 @@ class ValidateSequenceFrames(pyblish.api.InstancePlugin): order = pyblish.api.ValidatorOrder label = "Validate Sequence Frames" - families = ["imagesequence"] - hosts = ["shell"] + families = ["imagesequence", "render"] + hosts = ["shell", "unreal"] def process(self, instance): representations = instance.data.get("representations") From 0648271ec784824fef1c7ffe373d0ae1034b9ec6 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 23 Mar 2023 18:15:11 +0100 Subject: [PATCH 10/54] OP-3951 - added tests for validate_sequence_frames Introduced conftest with dummy environment for basic tests --- tests/unit/openpype/conftest.py | 38 +++++ .../publish/test_validate_sequence_frames.py | 143 ++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 tests/unit/openpype/conftest.py create mode 100644 tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py diff --git a/tests/unit/openpype/conftest.py b/tests/unit/openpype/conftest.py new file mode 100644 index 0000000000..e5355a3120 --- /dev/null +++ b/tests/unit/openpype/conftest.py @@ -0,0 +1,38 @@ +"""Dummy environment that allows importing Openpype modules and run +tests in parent folder and all subfolders manually from IDE. + +This should not get triggered if the tests are running from `runtests` as it +is expected there that environment is handled by OP itself. + +This environment should be enough to run simple `BaseTest` where no +external preparation is necessary (eg. no prepared DB, no source files). +These tests might be enough to import and run simple pyblish plugins to +validate logic. + +Please be aware that these tests might use values in real databases, so use +`BaseTest` only for logic without side effects or special configuration. For +these there is `tests.lib.testing_classes.ModuleUnitTest` which would setup +proper test DB (but it requires `mongorestore` on the sys.path) + +If pyblish plugins require any host dependent communication, it would need + to be mocked. + +This setting of env vars is necessary to run before any imports of OP code! +(This is why it is in `conftest.py` file.) +If your test requires any additional env var, copy this file to folder of your +test, it should only that folder. +""" + +import os + + +if not os.environ.get("IS_TEST"): # running tests from cmd or CI + os.environ["AVALON_MONGO"] = "mongodb://localhost:27017" + os.environ["OPENPYPE_MONGO"] = "mongodb://localhost:27017" + os.environ["AVALON_DB"] = "avalon" + os.environ["OPENPYPE_DATABASE_NAME"] = "avalon" + os.environ["AVALON_TIMEOUT"] = '3000' + os.environ["OPENPYPE_DEBUG"] = "3" + os.environ["AVALON_CONFIG"] = "pype" + os.environ["AVALON_ASSET"] = "test_asset" + os.environ["AVALON_PROJECT"] = "test_project" diff --git a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py new file mode 100644 index 0000000000..5580621cfb --- /dev/null +++ b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py @@ -0,0 +1,143 @@ + + +"""Test Publish_plugins pipeline publish modul, tests API methods + + File: + creates temporary directory and downloads .zip file from GDrive + unzips .zip file + uses content of .zip file (MongoDB's dumps) to import to new databases + with use of 'monkeypatch_session' modifies required env vars + temporarily + runs battery of tests checking that site operation for Sync Server + module are working + removes temporary folder + removes temporary databases (?) +""" +import pytest +import logging + +from pyblish.api import Instance as PyblishInstance + +from tests.lib.testing_classes import BaseTest +from openpype.plugins.publish.validate_sequence_frames import ( + ValidateSequenceFrames +) + +log = logging.getLogger(__name__) + + +class TestValidateSequenceFrames(BaseTest): + """ Testing ValidateSequenceFrames plugin + + """ + + @pytest.fixture + def instance(self): + + class Instance(PyblishInstance): + data = { + "frameStart": 1001, + "frameEnd": 1001, + "representations": [] + } + yield Instance + + @pytest.fixture(scope="module") + def plugin(self): + plugin = ValidateSequenceFrames() + plugin.log = log + + yield plugin + + def test_validate_sequence_frames_single_frame(self, instance, plugin): + representations = [ + { + "ext": "exr", + "files": "Main_beauty.1001.exr", + } + ] + instance.data["representations"] = representations + + plugin.process(instance) + + @pytest.mark.parametrize("files", + ["Main_beauty.v001.1001.exr", + "Main_beauty_v001.1001.exr", + "Main_beauty.1001.1001.exr"]) + def test_validate_sequence_frames_single_frame_name(self, instance, + plugin, + files): + # tests for names with number inside, caused clique failure before + representations = [ + { + "ext": "exr", + "files": files, + } + ] + instance.data["representations"] = representations + + plugin.process(instance) + + @pytest.mark.parametrize("files", + ["Main_beauty.1001.v001.exr"]) + def test_validate_sequence_frames_single_frame_wrong_name(self, instance, + plugin, + files): + # tests for names with number inside, caused clique failure before + representations = [ + { + "ext": "exr", + "files": files, + } + ] + instance.data["representations"] = representations + + with pytest.raises(ValueError) as excinfo: + plugin.process(instance) + assert ("Invalid frame range: (1, 1) - expected: (1001, 1001)" in + str(excinfo.value)) + + def test_validate_sequence_frames_multi_frame(self, instance, plugin): + representations = [ + { + "ext": "exr", + "files": ["Main_beauty.1001.exr", "Main_beauty.1002.exr", + "Main_beauty.1003.exr"] + } + ] + instance.data["representations"] = representations + instance.data["frameEnd"] = 1003 + + plugin.process(instance) + + def test_validate_sequence_frames_multi_frame_missing(self, instance, + plugin): + representations = [ + { + "ext": "exr", + "files": ["Main_beauty.1001.exr", "Main_beauty.1002.exr"] + } + ] + instance.data["representations"] = representations + instance.data["frameEnd"] = 1003 + + with pytest.raises(ValueError) as excinfo: + plugin.process(instance) + assert ("Invalid frame range: (1001, 1002) - expected: (1001, 1003)" in + str(excinfo.value)) + + def test_validate_sequence_frames_multi_frame_hole(self, instance, plugin): + representations = [ + { + "ext": "exr", + "files": ["Main_beauty.1001.exr", "Main_beauty.1003.exr"] + } + ] + instance.data["representations"] = representations + instance.data["frameEnd"] = 1003 + + with pytest.raises(AssertionError) as excinfo: + plugin.process(instance) + assert ("Missing frames: [1002]" in str(excinfo.value)) + +test_case = TestValidateSequenceFrames() From 87fe237aa718d5e387b288bb7ad430d586712ec6 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 24 Mar 2023 11:14:51 +0100 Subject: [PATCH 11/54] OP-3951 - fix - do not change files in place Integrator depends that single files is not in list. --- openpype/plugins/publish/validate_sequence_frames.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openpype/plugins/publish/validate_sequence_frames.py b/openpype/plugins/publish/validate_sequence_frames.py index 56641fbf57..98df259cc8 100644 --- a/openpype/plugins/publish/validate_sequence_frames.py +++ b/openpype/plugins/publish/validate_sequence_frames.py @@ -27,16 +27,17 @@ class ValidateSequenceFrames(pyblish.api.InstancePlugin): def process(self, instance): representations = instance.data.get("representations") for repr in representations: - if isinstance(repr["files"], str): - repr["files"] = [repr["files"]] + repr_files = repr["files"] + if isinstance(repr_files, str): + repr_files = [repr_files] - _, ext = os.path.splitext(repr["files"][0]) + _, ext = os.path.splitext(repr_files[0]) pattern = r"\D?(?P(?P0*)\d+){}$".format( re.escape(ext)) patterns = [pattern] collections, remainder = clique.assemble( - repr["files"], minimum_items=1, patterns=patterns) + repr_files, minimum_items=1, patterns=patterns) assert not remainder, "Must not have remainder" assert len(collections) == 1, "Must detect single collection" From f95007b660c9d573d9c41b4ec6169e022434daed Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 24 Mar 2023 11:15:27 +0100 Subject: [PATCH 12/54] OP-3951 - Hound --- .../openpype/plugins/publish/test_validate_sequence_frames.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py index 5580621cfb..8e690f4f65 100644 --- a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py +++ b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py @@ -124,7 +124,7 @@ class TestValidateSequenceFrames(BaseTest): with pytest.raises(ValueError) as excinfo: plugin.process(instance) assert ("Invalid frame range: (1001, 1002) - expected: (1001, 1003)" in - str(excinfo.value)) + str(excinfo.value)) def test_validate_sequence_frames_multi_frame_hole(self, instance, plugin): representations = [ @@ -140,4 +140,5 @@ class TestValidateSequenceFrames(BaseTest): plugin.process(instance) assert ("Missing frames: [1002]" in str(excinfo.value)) + test_case = TestValidateSequenceFrames() From 30916962c8bc0f6fbfb557c286014efe62065bd2 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 24 Mar 2023 12:34:23 +0100 Subject: [PATCH 13/54] OP-3951 - refactor Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/plugins/publish/validate_sequence_frames.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/plugins/publish/validate_sequence_frames.py b/openpype/plugins/publish/validate_sequence_frames.py index 98df259cc8..409d9ac17e 100644 --- a/openpype/plugins/publish/validate_sequence_frames.py +++ b/openpype/plugins/publish/validate_sequence_frames.py @@ -26,6 +26,8 @@ class ValidateSequenceFrames(pyblish.api.InstancePlugin): def process(self, instance): representations = instance.data.get("representations") + if not representations: + return for repr in representations: repr_files = repr["files"] if isinstance(repr_files, str): From bc50139ec8ef7d93636f7ccfc861bd98dbdc2ba0 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 24 Mar 2023 15:20:01 +0000 Subject: [PATCH 14/54] Only parent to world on extraction if nested. --- openpype/hosts/maya/plugins/publish/extract_xgen.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_xgen.py b/openpype/hosts/maya/plugins/publish/extract_xgen.py index 0cc842b4ec..fb097ca84a 100644 --- a/openpype/hosts/maya/plugins/publish/extract_xgen.py +++ b/openpype/hosts/maya/plugins/publish/extract_xgen.py @@ -65,9 +65,10 @@ class ExtractXgen(publish.Extractor): ) cmds.delete(set(children) - set(shapes)) - duplicate_transform = cmds.parent( - duplicate_transform, world=True - )[0] + if cmds.listRelatives(duplicate_transform, parent=True): + duplicate_transform = cmds.parent( + duplicate_transform, world=True + )[0] duplicate_nodes.append(duplicate_transform) From 399541602898ce342f3f8639a1969a144c9824c7 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 24 Mar 2023 15:27:33 +0000 Subject: [PATCH 15/54] Validation for required namespace. --- .../hosts/maya/plugins/publish/validate_xgen.py | 13 +++++++++++++ website/docs/artist_hosts_maya_xgen.md | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/openpype/hosts/maya/plugins/publish/validate_xgen.py b/openpype/hosts/maya/plugins/publish/validate_xgen.py index 2870909974..47b24e218c 100644 --- a/openpype/hosts/maya/plugins/publish/validate_xgen.py +++ b/openpype/hosts/maya/plugins/publish/validate_xgen.py @@ -57,3 +57,16 @@ class ValidateXgen(pyblish.api.InstancePlugin): json.dumps(inactive_modifiers, indent=4, sort_keys=True) ) ) + + # We need a namespace else there will be a naming conflict when + # extracting because of stripping namespaces and parenting to world. + node_names = [instance.data["xgmPalette"]] + for _, connections in instance.data["xgenConnections"].items(): + node_names.append(connections["transform"].split(".")[0]) + + non_namespaced_nodes = [n for n in node_names if ":" not in n] + if non_namespaced_nodes: + raise PublishValidationError( + "Could not find namespace on {}. Namespace is required for" + " xgen publishing.".format(non_namespaced_nodes) + ) diff --git a/website/docs/artist_hosts_maya_xgen.md b/website/docs/artist_hosts_maya_xgen.md index ec5f2ed921..db7bbd0557 100644 --- a/website/docs/artist_hosts_maya_xgen.md +++ b/website/docs/artist_hosts_maya_xgen.md @@ -43,6 +43,10 @@ Create an Xgen instance to publish. This needs to contain only **one Xgen collec You can create multiple Xgen instances if you have multiple collections to publish. +:::note +The Xgen publishing requires a namespace on the Xgen collection (palette) and the geometry used. +::: + ### Publish The publishing process will grab geometry used for Xgen along with any external files used in the collection's descriptions. This creates an isolated Maya file with just the Xgen collection's dependencies, so you can use any nested geometry when creating the Xgen description. An Xgen version will consist of: From 94ceba790edf1cb4c8d04f9ed67ab518f6722455 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 24 Mar 2023 16:49:43 +0100 Subject: [PATCH 16/54] OP-3951 - updated tests --- .../publish/test_validate_sequence_frames.py | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py index 8e690f4f65..232557b76d 100644 --- a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py +++ b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py @@ -63,7 +63,8 @@ class TestValidateSequenceFrames(BaseTest): @pytest.mark.parametrize("files", ["Main_beauty.v001.1001.exr", "Main_beauty_v001.1001.exr", - "Main_beauty.1001.1001.exr"]) + "Main_beauty.1001.1001.exr", + "Main_beauty_v001_1001.exr"]) def test_validate_sequence_frames_single_frame_name(self, instance, plugin, files): @@ -97,6 +98,24 @@ class TestValidateSequenceFrames(BaseTest): assert ("Invalid frame range: (1, 1) - expected: (1001, 1001)" in str(excinfo.value)) + @pytest.mark.parametrize("files", + ["Main_beauty.1001.v001.ass.gz"]) + def test_validate_sequence_frames_single_frame_possible_wrong_name(self, + instance, plugin, files): + # currently pattern fails on extensions with dots + representations = [ + { + "ext": "exr", + "files": files, + } + ] + instance.data["representations"] = representations + + with pytest.raises(AssertionError) as excinfo: + plugin.process(instance) + assert ("Must not have remainder" in + str(excinfo.value)) + def test_validate_sequence_frames_multi_frame(self, instance, plugin): representations = [ { From 7dc59ece7b245e3bf47daf5bb7cbbd76cf49cf33 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 27 Mar 2023 09:46:35 +0100 Subject: [PATCH 17/54] Define settings --- .../projects_schema/schema_project_maya.json | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json index 47dfb37024..80e2d43411 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json @@ -10,6 +10,41 @@ "key": "open_workfile_post_initialization", "label": "Open Workfile Post Initialization" }, + { + "type": "dict", + "key": "explicit_plugins_loading", + "label": "Explicit Plugins Loading", + "collapsible": true, + "is_group": true, + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "list", + "key": "plugins_to_load", + "label": "Plugins To Load", + "object_type": { + "type": "dict", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "text", + "key": "name", + "label": "Name" + } + ] + } + } + ] + }, { "key": "imageio", "type": "dict", From 5349579f748bc1522d0ade1ef24da3c07337ad7c Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 27 Mar 2023 09:46:46 +0100 Subject: [PATCH 18/54] Define setting defaults --- .../defaults/project_settings/maya.json | 409 ++++++++++++++++++ 1 file changed, 409 insertions(+) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index 2aa95fd1be..cc3a76c599 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -1,5 +1,414 @@ { "open_workfile_post_initialization": false, + "explicit_plugins_loading": { + "enabled": false, + "plugins_to_load": [ + { + "enabled": false, + "name": "AbcBullet" + }, + { + "enabled": true, + "name": "AbcExport" + }, + { + "enabled": true, + "name": "AbcImport" + }, + { + "enabled": false, + "name": "animImportExport" + }, + { + "enabled": false, + "name": "ArubaTessellator" + }, + { + "enabled": false, + "name": "ATFPlugin" + }, + { + "enabled": false, + "name": "atomImportExport" + }, + { + "enabled": false, + "name": "AutodeskPacketFile" + }, + { + "enabled": false, + "name": "autoLoader" + }, + { + "enabled": false, + "name": "bifmeshio" + }, + { + "enabled": false, + "name": "bifrostGraph" + }, + { + "enabled": false, + "name": "bifrostshellnode" + }, + { + "enabled": false, + "name": "bifrostvisplugin" + }, + { + "enabled": false, + "name": "blast2Cmd" + }, + { + "enabled": false, + "name": "bluePencil" + }, + { + "enabled": false, + "name": "Boss" + }, + { + "enabled": false, + "name": "bullet" + }, + { + "enabled": true, + "name": "cacheEvaluator" + }, + { + "enabled": false, + "name": "cgfxShader" + }, + { + "enabled": false, + "name": "cleanPerFaceAssignment" + }, + { + "enabled": false, + "name": "clearcoat" + }, + { + "enabled": false, + "name": "convertToComponentTags" + }, + { + "enabled": false, + "name": "curveWarp" + }, + { + "enabled": false, + "name": "ddsFloatReader" + }, + { + "enabled": true, + "name": "deformerEvaluator" + }, + { + "enabled": false, + "name": "dgProfiler" + }, + { + "enabled": false, + "name": "drawUfe" + }, + { + "enabled": false, + "name": "dx11Shader" + }, + { + "enabled": false, + "name": "fbxmaya" + }, + { + "enabled": false, + "name": "fltTranslator" + }, + { + "enabled": false, + "name": "freeze" + }, + { + "enabled": false, + "name": "Fur" + }, + { + "enabled": false, + "name": "gameFbxExporter" + }, + { + "enabled": false, + "name": "gameInputDevice" + }, + { + "enabled": false, + "name": "GamePipeline" + }, + { + "enabled": false, + "name": "gameVertexCount" + }, + { + "enabled": false, + "name": "geometryReport" + }, + { + "enabled": false, + "name": "geometryTools" + }, + { + "enabled": false, + "name": "glslShader" + }, + { + "enabled": true, + "name": "GPUBuiltInDeformer" + }, + { + "enabled": false, + "name": "gpuCache" + }, + { + "enabled": false, + "name": "hairPhysicalShader" + }, + { + "enabled": false, + "name": "ik2Bsolver" + }, + { + "enabled": false, + "name": "ikSpringSolver" + }, + { + "enabled": false, + "name": "invertShape" + }, + { + "enabled": false, + "name": "lges" + }, + { + "enabled": false, + "name": "lookdevKit" + }, + { + "enabled": false, + "name": "MASH" + }, + { + "enabled": false, + "name": "matrixNodes" + }, + { + "enabled": false, + "name": "mayaCharacterization" + }, + { + "enabled": false, + "name": "mayaHIK" + }, + { + "enabled": false, + "name": "MayaMuscle" + }, + { + "enabled": false, + "name": "mayaUsdPlugin" + }, + { + "enabled": false, + "name": "mayaVnnPlugin" + }, + { + "enabled": false, + "name": "melProfiler" + }, + { + "enabled": false, + "name": "meshReorder" + }, + { + "enabled": false, + "name": "modelingToolkit" + }, + { + "enabled": false, + "name": "mtoa" + }, + { + "enabled": false, + "name": "mtoh" + }, + { + "enabled": false, + "name": "nearestPointOnMesh" + }, + { + "enabled": true, + "name": "objExport" + }, + { + "enabled": false, + "name": "OneClick" + }, + { + "enabled": false, + "name": "OpenEXRLoader" + }, + { + "enabled": false, + "name": "pgYetiMaya" + }, + { + "enabled": false, + "name": "pgyetiVrayMaya" + }, + { + "enabled": false, + "name": "polyBoolean" + }, + { + "enabled": false, + "name": "poseInterpolator" + }, + { + "enabled": false, + "name": "quatNodes" + }, + { + "enabled": false, + "name": "randomizerDevice" + }, + { + "enabled": false, + "name": "redshift4maya" + }, + { + "enabled": true, + "name": "renderSetup" + }, + { + "enabled": false, + "name": "retargeterNodes" + }, + { + "enabled": false, + "name": "RokokoMotionLibrary" + }, + { + "enabled": false, + "name": "rotateHelper" + }, + { + "enabled": false, + "name": "sceneAssembly" + }, + { + "enabled": false, + "name": "shaderFXPlugin" + }, + { + "enabled": false, + "name": "shotCamera" + }, + { + "enabled": false, + "name": "snapTransform" + }, + { + "enabled": false, + "name": "stage" + }, + { + "enabled": true, + "name": "stereoCamera" + }, + { + "enabled": false, + "name": "stlTranslator" + }, + { + "enabled": false, + "name": "studioImport" + }, + { + "enabled": false, + "name": "Substance" + }, + { + "enabled": false, + "name": "substancelink" + }, + { + "enabled": false, + "name": "substancemaya" + }, + { + "enabled": false, + "name": "substanceworkflow" + }, + { + "enabled": false, + "name": "svgFileTranslator" + }, + { + "enabled": false, + "name": "sweep" + }, + { + "enabled": false, + "name": "testify" + }, + { + "enabled": false, + "name": "tiffFloatReader" + }, + { + "enabled": false, + "name": "timeSliderBookmark" + }, + { + "enabled": false, + "name": "Turtle" + }, + { + "enabled": false, + "name": "Type" + }, + { + "enabled": false, + "name": "udpDevice" + }, + { + "enabled": false, + "name": "ufeSupport" + }, + { + "enabled": false, + "name": "Unfold3D" + }, + { + "enabled": false, + "name": "VectorRender" + }, + { + "enabled": false, + "name": "vrayformaya" + }, + { + "enabled": false, + "name": "vrayvolumegrid" + }, + { + "enabled": false, + "name": "xgenToolkit" + }, + { + "enabled": false, + "name": "xgenVray" + } + ] + }, "imageio": { "ocio_config": { "enabled": false, From f99c968df3dca4949e2e12a24ee908d5bf1ca997 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 27 Mar 2023 09:48:13 +0100 Subject: [PATCH 19/54] Add launch arguments and env --- openpype/hooks/pre_add_last_workfile_arg.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/openpype/hooks/pre_add_last_workfile_arg.py b/openpype/hooks/pre_add_last_workfile_arg.py index 2558daef30..3d5f59cc67 100644 --- a/openpype/hooks/pre_add_last_workfile_arg.py +++ b/openpype/hooks/pre_add_last_workfile_arg.py @@ -44,10 +44,20 @@ class AddLastWorkfileToLaunchArgs(PreLaunchHook): # Determine whether to open workfile post initialization. if self.host_name == "maya": - key = "open_workfile_post_initialization" - if self.data["project_settings"]["maya"][key]: + maya_settings = self.data["project_settings"]["maya"] + + if maya_settings["explicit_plugins_loading"]["enabled"]: + self.log.debug("Explicit plugins loading.") + self.launch_context.launch_args.append("-noAutoloadPlugins") + + keys = [ + "open_workfile_post_initialization", "explicit_plugins_loading" + ] + values = [maya_settings[k] for k in keys] + if any(values): self.log.debug("Opening workfile post initialization.") - self.data["env"]["OPENPYPE_" + key.upper()] = "1" + key = "OPENPYPE_OPEN_WORKFILE_POST_INITIALIZATION" + self.data["env"][key] = "1" return # Add path to workfile to arguments From ae4468bd209144fa406ba17b15a5c4d54c147516 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 27 Mar 2023 09:48:25 +0100 Subject: [PATCH 20/54] Load plugins explicitly --- openpype/hosts/maya/startup/userSetup.py | 34 +++++++++++++++++------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/maya/startup/userSetup.py b/openpype/hosts/maya/startup/userSetup.py index c77ecb829e..4932bf14c0 100644 --- a/openpype/hosts/maya/startup/userSetup.py +++ b/openpype/hosts/maya/startup/userSetup.py @@ -1,5 +1,4 @@ import os -from functools import partial from openpype.settings import get_project_settings from openpype.pipeline import install_host @@ -13,23 +12,40 @@ install_host(host) print("Starting OpenPype usersetup...") +settings = get_project_settings(os.environ['AVALON_PROJECT']) + +# Loading plugins explicitly. +if settings["maya"]["explicit_plugins_loading"]["enabled"]: + def _explicit_load_plugins(): + project_settings = get_project_settings(os.environ["AVALON_PROJECT"]) + maya_settings = project_settings["maya"] + explicit_plugins_loading = maya_settings["explicit_plugins_loading"] + if explicit_plugins_loading["enabled"]: + for plugin in explicit_plugins_loading["plugins_to_load"]: + if plugin["enabled"]: + print("Loading " + plugin["name"]) + try: + cmds.loadPlugin(plugin["name"], quiet=True) + except RuntimeError as e: + print(e) + + cmds.evalDeferred( + _explicit_load_plugins, + lowestPriority=True + ) # Open Workfile Post Initialization. key = "OPENPYPE_OPEN_WORKFILE_POST_INITIALIZATION" if bool(int(os.environ.get(key, "0"))): + def _log_and_open(): + print("Opening \"{}\"".format(os.environ["AVALON_LAST_WORKFILE"])) + cmds.file(os.environ["AVALON_LAST_WORKFILE"], open=True, force=True) cmds.evalDeferred( - partial( - cmds.file, - os.environ["AVALON_LAST_WORKFILE"], - open=True, - force=True - ), + _log_and_open, lowestPriority=True ) - # Build a shelf. -settings = get_project_settings(os.environ['AVALON_PROJECT']) shelf_preset = settings['maya'].get('project_shelf') if shelf_preset: From 53361fe9dfae15bd4a1f318561dd4ea8393ce353 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 27 Mar 2023 09:53:41 +0100 Subject: [PATCH 21/54] Modeling Toolkit is default loaded. --- openpype/settings/defaults/project_settings/maya.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index cc3a76c599..9b71b97d75 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -228,7 +228,7 @@ "name": "meshReorder" }, { - "enabled": false, + "enabled": true, "name": "modelingToolkit" }, { From 4bfb4aa75779cdd75d380cb0a976b5cb1757cbbd Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 27 Mar 2023 10:03:53 +0100 Subject: [PATCH 22/54] Docs --- website/docs/admin_hosts_maya.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/website/docs/admin_hosts_maya.md b/website/docs/admin_hosts_maya.md index 23cacb4193..edbfa8da36 100644 --- a/website/docs/admin_hosts_maya.md +++ b/website/docs/admin_hosts_maya.md @@ -172,3 +172,12 @@ Fill in the necessary fields (the optional fields are regex filters) - Build your workfile ![maya build template](assets/maya-build_workfile_from_template.png) + +## Explicit Plugins Loading +You can define which plugins to load on launch of Maya here; `project_settings/maya/explicit_plugins_loading`. This can help improve Maya's launch speed, if you know which plugins are needed. + +By default only the required plugins are enabled. You can also add any plugin to the list to enable on launch. + +:::note technical +When enabling this feature, the workfile will be launched post initialization no matter the setting on `project_settings/maya/open_workfile_post_initialization`. This is to avoid any issues with references needing plugins. +::: From 93d98c3f9c48da9477cd6ac7ffda186b57a202b8 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 27 Mar 2023 16:55:19 +0200 Subject: [PATCH 23/54] OP-3951 - use ext on representation Without it ass.gz files won't work --- .../publish/validate_sequence_frames.py | 6 ++++- .../publish/test_validate_sequence_frames.py | 22 +++++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/openpype/plugins/publish/validate_sequence_frames.py b/openpype/plugins/publish/validate_sequence_frames.py index 409d9ac17e..a804a6d9dd 100644 --- a/openpype/plugins/publish/validate_sequence_frames.py +++ b/openpype/plugins/publish/validate_sequence_frames.py @@ -33,7 +33,11 @@ class ValidateSequenceFrames(pyblish.api.InstancePlugin): if isinstance(repr_files, str): repr_files = [repr_files] - _, ext = os.path.splitext(repr_files[0]) + ext = repr.get("ext") + if not ext: + _, ext = os.path.splitext(repr_files[0]) + elif not ext.startswith("."): + ext = ".{}".format(ext) pattern = r"\D?(?P(?P0*)\d+){}$".format( re.escape(ext)) patterns = [pattern] diff --git a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py index 232557b76d..e1facdc37b 100644 --- a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py +++ b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py @@ -99,13 +99,12 @@ class TestValidateSequenceFrames(BaseTest): str(excinfo.value)) @pytest.mark.parametrize("files", - ["Main_beauty.1001.v001.ass.gz"]) - def test_validate_sequence_frames_single_frame_possible_wrong_name(self, - instance, plugin, files): + ["Main_beauty.v001.1001.ass.gz"]) + def test_validate_sequence_frames_single_frame_possible_wrong_name( + self, instance, plugin, files): # currently pattern fails on extensions with dots representations = [ { - "ext": "exr", "files": files, } ] @@ -116,6 +115,21 @@ class TestValidateSequenceFrames(BaseTest): assert ("Must not have remainder" in str(excinfo.value)) + @pytest.mark.parametrize("files", + ["Main_beauty.v001.1001.ass.gz"]) + def test_validate_sequence_frames_single_frame_correct_ext( + self, instance, plugin, files): + # currently pattern fails on extensions with dots + representations = [ + { + "ext": "ass.gz", + "files": files, + } + ] + instance.data["representations"] = representations + + plugin.process(instance) + def test_validate_sequence_frames_multi_frame(self, instance, plugin): representations = [ { From 6d2a45e9516ef55b84a181d0b30a8abe5405afbd Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 27 Mar 2023 16:42:35 +0100 Subject: [PATCH 24/54] Move -noAutoLoadPlugins flag to separate hook. --- openpype/hooks/pre_add_last_workfile_arg.py | 7 +------ .../hosts/maya/hooks/pre_auto_load_plugins.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 openpype/hosts/maya/hooks/pre_auto_load_plugins.py diff --git a/openpype/hooks/pre_add_last_workfile_arg.py b/openpype/hooks/pre_add_last_workfile_arg.py index 3d5f59cc67..df4aa5cc5d 100644 --- a/openpype/hooks/pre_add_last_workfile_arg.py +++ b/openpype/hooks/pre_add_last_workfile_arg.py @@ -44,15 +44,10 @@ class AddLastWorkfileToLaunchArgs(PreLaunchHook): # Determine whether to open workfile post initialization. if self.host_name == "maya": - maya_settings = self.data["project_settings"]["maya"] - - if maya_settings["explicit_plugins_loading"]["enabled"]: - self.log.debug("Explicit plugins loading.") - self.launch_context.launch_args.append("-noAutoloadPlugins") - keys = [ "open_workfile_post_initialization", "explicit_plugins_loading" ] + maya_settings = self.data["project_settings"]["maya"] values = [maya_settings[k] for k in keys] if any(values): self.log.debug("Opening workfile post initialization.") diff --git a/openpype/hosts/maya/hooks/pre_auto_load_plugins.py b/openpype/hosts/maya/hooks/pre_auto_load_plugins.py new file mode 100644 index 0000000000..3c3ddbe4dc --- /dev/null +++ b/openpype/hosts/maya/hooks/pre_auto_load_plugins.py @@ -0,0 +1,15 @@ +from openpype.lib import PreLaunchHook + + +class PreAutoLoadPlugins(PreLaunchHook): + """Define -noAutoloadPlugins command flag.""" + + # Execute before workfile argument. + order = 0 + app_groups = ["maya"] + + def execute(self): + maya_settings = self.data["project_settings"]["maya"] + if maya_settings["explicit_plugins_loading"]["enabled"]: + self.log.debug("Explicit plugins loading.") + self.launch_context.launch_args.append("-noAutoloadPlugins") From 72af67fc657fd7e52eca302d86f887c9af041212 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 27 Mar 2023 16:42:45 +0100 Subject: [PATCH 25/54] Warn about render farm support. --- website/docs/admin_hosts_maya.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/admin_hosts_maya.md b/website/docs/admin_hosts_maya.md index edbfa8da36..5211760632 100644 --- a/website/docs/admin_hosts_maya.md +++ b/website/docs/admin_hosts_maya.md @@ -180,4 +180,6 @@ By default only the required plugins are enabled. You can also add any plugin to :::note technical When enabling this feature, the workfile will be launched post initialization no matter the setting on `project_settings/maya/open_workfile_post_initialization`. This is to avoid any issues with references needing plugins. + +Renderfarm integration is not supported for this feature. ::: From c5172b74101dda2be4a797c0bc61056dfa134569 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 29 Mar 2023 13:17:24 +0200 Subject: [PATCH 26/54] OP-3951 - update imports Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/plugins/publish/validate_sequence_frames.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openpype/plugins/publish/validate_sequence_frames.py b/openpype/plugins/publish/validate_sequence_frames.py index a804a6d9dd..db71f2e23c 100644 --- a/openpype/plugins/publish/validate_sequence_frames.py +++ b/openpype/plugins/publish/validate_sequence_frames.py @@ -1,8 +1,7 @@ -import os.path - -import clique +import os import re +import clique import pyblish.api From 36328f8b1abbb03051795646bec8ceed5d78a874 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 29 Mar 2023 13:18:07 +0200 Subject: [PATCH 27/54] OP-3951 - removed unnecessary key Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- tests/unit/openpype/conftest.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/openpype/conftest.py b/tests/unit/openpype/conftest.py index e5355a3120..220ec3ba86 100644 --- a/tests/unit/openpype/conftest.py +++ b/tests/unit/openpype/conftest.py @@ -33,6 +33,5 @@ if not os.environ.get("IS_TEST"): # running tests from cmd or CI os.environ["OPENPYPE_DATABASE_NAME"] = "avalon" os.environ["AVALON_TIMEOUT"] = '3000' os.environ["OPENPYPE_DEBUG"] = "3" - os.environ["AVALON_CONFIG"] = "pype" os.environ["AVALON_ASSET"] = "test_asset" os.environ["AVALON_PROJECT"] = "test_project" From e2546e5547b10d085ff6b57375355361e8bda5f7 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 29 Mar 2023 13:18:37 +0200 Subject: [PATCH 28/54] OP-3951 - removed unnecessary key Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- tests/unit/openpype/conftest.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/openpype/conftest.py b/tests/unit/openpype/conftest.py index 220ec3ba86..0bc3f0dcfe 100644 --- a/tests/unit/openpype/conftest.py +++ b/tests/unit/openpype/conftest.py @@ -27,7 +27,6 @@ import os if not os.environ.get("IS_TEST"): # running tests from cmd or CI - os.environ["AVALON_MONGO"] = "mongodb://localhost:27017" os.environ["OPENPYPE_MONGO"] = "mongodb://localhost:27017" os.environ["AVALON_DB"] = "avalon" os.environ["OPENPYPE_DATABASE_NAME"] = "avalon" From 0a642d475cda961e033f2b4aa58e5dd09e7ec781 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 29 Mar 2023 13:19:02 +0200 Subject: [PATCH 29/54] OP-3951 - changed debug value Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- tests/unit/openpype/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/openpype/conftest.py b/tests/unit/openpype/conftest.py index 0bc3f0dcfe..9b5be54a0d 100644 --- a/tests/unit/openpype/conftest.py +++ b/tests/unit/openpype/conftest.py @@ -31,6 +31,6 @@ if not os.environ.get("IS_TEST"): # running tests from cmd or CI os.environ["AVALON_DB"] = "avalon" os.environ["OPENPYPE_DATABASE_NAME"] = "avalon" os.environ["AVALON_TIMEOUT"] = '3000' - os.environ["OPENPYPE_DEBUG"] = "3" + os.environ["OPENPYPE_DEBUG"] = "1" os.environ["AVALON_ASSET"] = "test_asset" os.environ["AVALON_PROJECT"] = "test_project" From 53d395e7087c2b4bd65c33706be25b3fb2dafb4d Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 29 Mar 2023 13:19:21 +0200 Subject: [PATCH 30/54] OP-3951 - updated value Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- tests/unit/openpype/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/openpype/conftest.py b/tests/unit/openpype/conftest.py index 9b5be54a0d..0aec25becb 100644 --- a/tests/unit/openpype/conftest.py +++ b/tests/unit/openpype/conftest.py @@ -29,7 +29,7 @@ import os if not os.environ.get("IS_TEST"): # running tests from cmd or CI os.environ["OPENPYPE_MONGO"] = "mongodb://localhost:27017" os.environ["AVALON_DB"] = "avalon" - os.environ["OPENPYPE_DATABASE_NAME"] = "avalon" + os.environ["OPENPYPE_DATABASE_NAME"] = "openpype" os.environ["AVALON_TIMEOUT"] = '3000' os.environ["OPENPYPE_DEBUG"] = "1" os.environ["AVALON_ASSET"] = "test_asset" From 97d5b187e81601864d70a84ec54f13baf885a509 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 30 Mar 2023 13:42:30 +0200 Subject: [PATCH 31/54] OP-3951 - updated logic Doesn't make sense to validate sequence for single frame. Updated tests accordingly. No sense in testing single frames so widely. --- .../publish/validate_sequence_frames.py | 2 +- .../publish/test_validate_sequence_frames.py | 36 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/openpype/plugins/publish/validate_sequence_frames.py b/openpype/plugins/publish/validate_sequence_frames.py index a804a6d9dd..6c14d0cbbf 100644 --- a/openpype/plugins/publish/validate_sequence_frames.py +++ b/openpype/plugins/publish/validate_sequence_frames.py @@ -31,7 +31,7 @@ class ValidateSequenceFrames(pyblish.api.InstancePlugin): for repr in representations: repr_files = repr["files"] if isinstance(repr_files, str): - repr_files = [repr_files] + continue ext = repr.get("ext") if not ext: diff --git a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py index e1facdc37b..f9d1e59096 100644 --- a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py +++ b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py @@ -37,7 +37,7 @@ class TestValidateSequenceFrames(BaseTest): class Instance(PyblishInstance): data = { "frameStart": 1001, - "frameEnd": 1001, + "frameEnd": 1002, "representations": [] } yield Instance @@ -57,17 +57,18 @@ class TestValidateSequenceFrames(BaseTest): } ] instance.data["representations"] = representations + instance.data["frameEnd"] = 1001 plugin.process(instance) @pytest.mark.parametrize("files", - ["Main_beauty.v001.1001.exr", - "Main_beauty_v001.1001.exr", - "Main_beauty.1001.1001.exr", - "Main_beauty_v001_1001.exr"]) - def test_validate_sequence_frames_single_frame_name(self, instance, - plugin, - files): + [ + ["Main_beauty.v001.1001.exr", "Main_beauty.v001.1002.exr"], + ["Main_beauty_v001.1001.exr", "Main_beauty_v001.1002.exr"], + ["Main_beauty.1001.1001.exr", "Main_beauty.1001.1002.exr"], + ["Main_beauty_v001_1001.exr", "Main_beauty_v001_1002.exr"]]) + def test_validate_sequence_frames_name(self, instance, + plugin, files): # tests for names with number inside, caused clique failure before representations = [ { @@ -80,10 +81,9 @@ class TestValidateSequenceFrames(BaseTest): plugin.process(instance) @pytest.mark.parametrize("files", - ["Main_beauty.1001.v001.exr"]) - def test_validate_sequence_frames_single_frame_wrong_name(self, instance, - plugin, - files): + [["Main_beauty.1001.v001.exr", "Main_beauty.1002.v001.exr"]]) + def test_validate_sequence_frames_wrong_name(self, instance, + plugin, files): # tests for names with number inside, caused clique failure before representations = [ { @@ -93,14 +93,14 @@ class TestValidateSequenceFrames(BaseTest): ] instance.data["representations"] = representations - with pytest.raises(ValueError) as excinfo: + with pytest.raises(AssertionError) as excinfo: plugin.process(instance) - assert ("Invalid frame range: (1, 1) - expected: (1001, 1001)" in + assert ("Must detect single collection" in str(excinfo.value)) @pytest.mark.parametrize("files", - ["Main_beauty.v001.1001.ass.gz"]) - def test_validate_sequence_frames_single_frame_possible_wrong_name( + [["Main_beauty.v001.1001.ass.gz", "Main_beauty.v001.1002.ass.gz"]]) + def test_validate_sequence_frames_possible_wrong_name( self, instance, plugin, files): # currently pattern fails on extensions with dots representations = [ @@ -116,8 +116,8 @@ class TestValidateSequenceFrames(BaseTest): str(excinfo.value)) @pytest.mark.parametrize("files", - ["Main_beauty.v001.1001.ass.gz"]) - def test_validate_sequence_frames_single_frame_correct_ext( + [["Main_beauty.v001.1001.ass.gz", "Main_beauty.v001.1002.ass.gz"]]) + def test_validate_sequence_frames__correct_ext( self, instance, plugin, files): # currently pattern fails on extensions with dots representations = [ From 80c50af2b903737c3d4635063423876cc3b9d210 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 30 Mar 2023 13:45:37 +0200 Subject: [PATCH 32/54] OP-3951 - Hound --- .../publish/test_validate_sequence_frames.py | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py index f9d1e59096..58d9de011d 100644 --- a/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py +++ b/tests/unit/openpype/plugins/publish/test_validate_sequence_frames.py @@ -63,10 +63,14 @@ class TestValidateSequenceFrames(BaseTest): @pytest.mark.parametrize("files", [ - ["Main_beauty.v001.1001.exr", "Main_beauty.v001.1002.exr"], - ["Main_beauty_v001.1001.exr", "Main_beauty_v001.1002.exr"], - ["Main_beauty.1001.1001.exr", "Main_beauty.1001.1002.exr"], - ["Main_beauty_v001_1001.exr", "Main_beauty_v001_1002.exr"]]) + ["Main_beauty.v001.1001.exr", + "Main_beauty.v001.1002.exr"], + ["Main_beauty_v001.1001.exr", + "Main_beauty_v001.1002.exr"], + ["Main_beauty.1001.1001.exr", + "Main_beauty.1001.1002.exr"], + ["Main_beauty_v001_1001.exr", + "Main_beauty_v001_1002.exr"]]) def test_validate_sequence_frames_name(self, instance, plugin, files): # tests for names with number inside, caused clique failure before @@ -81,7 +85,8 @@ class TestValidateSequenceFrames(BaseTest): plugin.process(instance) @pytest.mark.parametrize("files", - [["Main_beauty.1001.v001.exr", "Main_beauty.1002.v001.exr"]]) + [["Main_beauty.1001.v001.exr", + "Main_beauty.1002.v001.exr"]]) def test_validate_sequence_frames_wrong_name(self, instance, plugin, files): # tests for names with number inside, caused clique failure before @@ -99,7 +104,8 @@ class TestValidateSequenceFrames(BaseTest): str(excinfo.value)) @pytest.mark.parametrize("files", - [["Main_beauty.v001.1001.ass.gz", "Main_beauty.v001.1002.ass.gz"]]) + [["Main_beauty.v001.1001.ass.gz", + "Main_beauty.v001.1002.ass.gz"]]) def test_validate_sequence_frames_possible_wrong_name( self, instance, plugin, files): # currently pattern fails on extensions with dots @@ -116,7 +122,8 @@ class TestValidateSequenceFrames(BaseTest): str(excinfo.value)) @pytest.mark.parametrize("files", - [["Main_beauty.v001.1001.ass.gz", "Main_beauty.v001.1002.ass.gz"]]) + [["Main_beauty.v001.1001.ass.gz", + "Main_beauty.v001.1002.ass.gz"]]) def test_validate_sequence_frames__correct_ext( self, instance, plugin, files): # currently pattern fails on extensions with dots From 2278478598dbda1b465f2d9108ce27106d807e21 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Sun, 2 Apr 2023 08:25:06 +0100 Subject: [PATCH 33/54] Update openpype/hosts/maya/plugins/publish/collect_review.py Co-authored-by: Roy Nieterau --- openpype/hosts/maya/plugins/publish/collect_review.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_review.py b/openpype/hosts/maya/plugins/publish/collect_review.py index d15eb7a12b..a184865602 100644 --- a/openpype/hosts/maya/plugins/publish/collect_review.py +++ b/openpype/hosts/maya/plugins/publish/collect_review.py @@ -143,4 +143,8 @@ class CollectReview(pyblish.api.InstancePlugin): # Convert enum attribute index to string. index = instance.data.get("displayLights", 0) - instance.data["displayLights"] = lib.DISPLAY_LIGHTS[index] + display_lights = lib.DISPLAY_LIGHTS[index] + if display_lights == "project_settings": + # project_settings/maya/publish/ExtractPlayblast/capture_preset/Viewport Options/displayLights + display_lights = instance.context.data["project_settings"]["maya"]["publish"]["ExtractPlayblast"]["capture_preset"]["Viewport Options"]["displayLights"] # noqa + instance.data["displayLights"] = display_lights From b9e9750377d44836c94013f2222422bca736c644 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Sun, 2 Apr 2023 08:25:25 +0100 Subject: [PATCH 34/54] Update openpype/hosts/maya/plugins/publish/extract_playblast.py Co-authored-by: Roy Nieterau --- openpype/hosts/maya/plugins/publish/extract_playblast.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 801f05a770..2167f2c5b3 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -95,10 +95,8 @@ class ExtractPlayblast(publish.Extractor): pm.currentTime(refreshFrameInt - 1, edit=True) pm.currentTime(refreshFrameInt, edit=True) - # Show lighting mode. - display_lights = instance.data["displayLights"] - if display_lights != "project_settings": - preset["viewport_options"]["displayLights"] = display_lights + # Use displayLights setting from instance + preset["viewport_options"]["displayLights"] = instance.data["displayLights"] # Override transparency if requested. transparency = instance.data.get("transparency", 0) From 3ebac0b326e4f06aaa5a396554e4fff16df5efeb Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Sun, 2 Apr 2023 08:25:34 +0100 Subject: [PATCH 35/54] Update openpype/hosts/maya/plugins/publish/extract_thumbnail.py Co-authored-by: Roy Nieterau --- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 79c768228f..92d0141f01 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -105,11 +105,8 @@ class ExtractThumbnail(publish.Extractor): pm.currentTime(refreshFrameInt - 1, edit=True) pm.currentTime(refreshFrameInt, edit=True) - # Show lighting mode. - display_lights = instance.data["displayLights"] - if display_lights != "project_settings": - preset["viewport_options"]["displayLights"] = display_lights - + # Use displayLights setting from instance + preset["viewport_options"]["displayLights"] = instance.data["displayLights"] # Override transparency if requested. transparency = instance.data.get("transparency", 0) if transparency != 0: From 2e234a84dc791bf3452fb9e0610a23bda3cec233 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Sun, 2 Apr 2023 08:34:26 +0100 Subject: [PATCH 36/54] Hound --- openpype/hosts/maya/plugins/publish/extract_playblast.py | 3 ++- openpype/hosts/maya/plugins/publish/extract_thumbnail.py | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_playblast.py b/openpype/hosts/maya/plugins/publish/extract_playblast.py index 0381a8adc1..f790d08ae3 100644 --- a/openpype/hosts/maya/plugins/publish/extract_playblast.py +++ b/openpype/hosts/maya/plugins/publish/extract_playblast.py @@ -117,7 +117,8 @@ class ExtractPlayblast(publish.Extractor): pm.currentTime(refreshFrameInt, edit=True) # Use displayLights setting from instance - preset["viewport_options"]["displayLights"] = instance.data["displayLights"] + key = "displayLights" + preset["viewport_options"][key] = instance.data[key] # Override transparency if requested. transparency = instance.data.get("transparency", 0) diff --git a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py index 430322c911..d66f65ce88 100644 --- a/openpype/hosts/maya/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/maya/plugins/publish/extract_thumbnail.py @@ -106,7 +106,9 @@ class ExtractThumbnail(publish.Extractor): pm.currentTime(refreshFrameInt, edit=True) # Use displayLights setting from instance - preset["viewport_options"]["displayLights"] = instance.data["displayLights"] + key = "displayLights" + preset["viewport_options"][key] = instance.data[key] + # Override transparency if requested. transparency = instance.data.get("transparency", 0) if transparency != 0: From 0ff0b6b645e1f7293347a24a638bb2afb80556e9 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 5 Apr 2023 07:39:53 +0100 Subject: [PATCH 37/54] Move launch logic to host module. --- openpype/hooks/pre_add_last_workfile_arg.py | 13 ---------- .../hosts/maya/hooks/pre_auto_load_plugins.py | 22 +++++++++++++--- .../pre_open_workfile_post_initialization.py | 25 +++++++++++++++++++ 3 files changed, 43 insertions(+), 17 deletions(-) create mode 100644 openpype/hosts/maya/hooks/pre_open_workfile_post_initialization.py diff --git a/openpype/hooks/pre_add_last_workfile_arg.py b/openpype/hooks/pre_add_last_workfile_arg.py index df4aa5cc5d..2a35db869a 100644 --- a/openpype/hooks/pre_add_last_workfile_arg.py +++ b/openpype/hooks/pre_add_last_workfile_arg.py @@ -42,18 +42,5 @@ class AddLastWorkfileToLaunchArgs(PreLaunchHook): self.log.info("Current context does not have any workfile yet.") return - # Determine whether to open workfile post initialization. - if self.host_name == "maya": - keys = [ - "open_workfile_post_initialization", "explicit_plugins_loading" - ] - maya_settings = self.data["project_settings"]["maya"] - values = [maya_settings[k] for k in keys] - if any(values): - self.log.debug("Opening workfile post initialization.") - key = "OPENPYPE_OPEN_WORKFILE_POST_INITIALIZATION" - self.data["env"][key] = "1" - return - # Add path to workfile to arguments self.launch_context.launch_args.append(last_workfile) diff --git a/openpype/hosts/maya/hooks/pre_auto_load_plugins.py b/openpype/hosts/maya/hooks/pre_auto_load_plugins.py index 3c3ddbe4dc..689d7adb4f 100644 --- a/openpype/hosts/maya/hooks/pre_auto_load_plugins.py +++ b/openpype/hosts/maya/hooks/pre_auto_load_plugins.py @@ -1,15 +1,29 @@ from openpype.lib import PreLaunchHook -class PreAutoLoadPlugins(PreLaunchHook): +class MayaPreAutoLoadPlugins(PreLaunchHook): """Define -noAutoloadPlugins command flag.""" - # Execute before workfile argument. - order = 0 + # Before AddLastWorkfileToLaunchArgs + order = 9 app_groups = ["maya"] def execute(self): + + # Ignore if there's no last workfile to start. + if not self.data.get("start_last_workfile"): + return + maya_settings = self.data["project_settings"]["maya"] - if maya_settings["explicit_plugins_loading"]["enabled"]: + enabled = maya_settings["explicit_plugins_loading"]["enabled"] + if enabled: + # Force disable the `AddLastWorkfileToLaunchArgs`. + self.data.pop("start_last_workfile") + + # Force post initialization so our dedicated plug-in load can run + # prior to Maya opening a scene file. + key = "OPENPYPE_OPEN_WORKFILE_POST_INITIALIZATION" + self.launch_context.env[key] = "1" + self.log.debug("Explicit plugins loading.") self.launch_context.launch_args.append("-noAutoloadPlugins") diff --git a/openpype/hosts/maya/hooks/pre_open_workfile_post_initialization.py b/openpype/hosts/maya/hooks/pre_open_workfile_post_initialization.py new file mode 100644 index 0000000000..7582ce0591 --- /dev/null +++ b/openpype/hosts/maya/hooks/pre_open_workfile_post_initialization.py @@ -0,0 +1,25 @@ +from openpype.lib import PreLaunchHook + + +class MayaPreOpenWorkfilePostInitialization(PreLaunchHook): + """Define whether open last workfile should run post initialize.""" + + # Before AddLastWorkfileToLaunchArgs. + order = 9 + app_groups = ["maya"] + + def execute(self): + + # Ignore if there's no last workfile to start. + if not self.data.get("start_last_workfile"): + return + + maya_settings = self.data["project_settings"]["maya"] + enabled = maya_settings["open_workfile_post_initialization"] + if enabled: + # Force disable the `AddLastWorkfileToLaunchArgs`. + self.data.pop("start_last_workfile") + + self.log.debug("Opening workfile post initialization.") + key = "OPENPYPE_OPEN_WORKFILE_POST_INITIALIZATION" + self.launch_context.env[key] = "1" From bc004453edd0cc42648ce228e1249c9eb05a2700 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 5 Apr 2023 08:33:18 +0100 Subject: [PATCH 38/54] Update openpype/hosts/maya/startup/userSetup.py Co-authored-by: Roy Nieterau --- openpype/hosts/maya/startup/userSetup.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/startup/userSetup.py b/openpype/hosts/maya/startup/userSetup.py index 4932bf14c0..b28d89e7bd 100644 --- a/openpype/hosts/maya/startup/userSetup.py +++ b/openpype/hosts/maya/startup/userSetup.py @@ -38,8 +38,9 @@ if settings["maya"]["explicit_plugins_loading"]["enabled"]: key = "OPENPYPE_OPEN_WORKFILE_POST_INITIALIZATION" if bool(int(os.environ.get(key, "0"))): def _log_and_open(): - print("Opening \"{}\"".format(os.environ["AVALON_LAST_WORKFILE"])) - cmds.file(os.environ["AVALON_LAST_WORKFILE"], open=True, force=True) + path = os.environ["AVALON_LAST_WORKFILE"] + print("Opening \"{}\"".format(path)) + cmds.file(path, open=True, force=True) cmds.evalDeferred( _log_and_open, lowestPriority=True From b5e80e565b5de71625531beb7818d34d9b7da1df Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 5 Apr 2023 08:34:42 +0100 Subject: [PATCH 39/54] Update openpype/hosts/maya/startup/userSetup.py Co-authored-by: Roy Nieterau --- openpype/hosts/maya/startup/userSetup.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/maya/startup/userSetup.py b/openpype/hosts/maya/startup/userSetup.py index b28d89e7bd..4a00c3dce7 100644 --- a/openpype/hosts/maya/startup/userSetup.py +++ b/openpype/hosts/maya/startup/userSetup.py @@ -20,14 +20,13 @@ if settings["maya"]["explicit_plugins_loading"]["enabled"]: project_settings = get_project_settings(os.environ["AVALON_PROJECT"]) maya_settings = project_settings["maya"] explicit_plugins_loading = maya_settings["explicit_plugins_loading"] - if explicit_plugins_loading["enabled"]: - for plugin in explicit_plugins_loading["plugins_to_load"]: - if plugin["enabled"]: - print("Loading " + plugin["name"]) - try: - cmds.loadPlugin(plugin["name"], quiet=True) - except RuntimeError as e: - print(e) + for plugin in explicit_plugins_loading["plugins_to_load"]: + if plugin["enabled"]: + print("Loading plug-in: " + plugin["name"]) + try: + cmds.loadPlugin(plugin["name"], quiet=True) + except RuntimeError as e: + print(e) cmds.evalDeferred( _explicit_load_plugins, From 0c626f54c5aa69730692f50a6de3123a555d3419 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 5 Apr 2023 08:52:53 +0100 Subject: [PATCH 40/54] Refactor settings variables. --- openpype/hosts/maya/startup/userSetup.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/maya/startup/userSetup.py b/openpype/hosts/maya/startup/userSetup.py index 4a00c3dce7..b58ebb0f7f 100644 --- a/openpype/hosts/maya/startup/userSetup.py +++ b/openpype/hosts/maya/startup/userSetup.py @@ -12,14 +12,12 @@ install_host(host) print("Starting OpenPype usersetup...") -settings = get_project_settings(os.environ['AVALON_PROJECT']) +project_settings = get_project_settings(os.environ['AVALON_PROJECT']) # Loading plugins explicitly. -if settings["maya"]["explicit_plugins_loading"]["enabled"]: +explicit_plugins_loading = project_settings["maya"]["explicit_plugins_loading"] +if explicit_plugins_loading["enabled"]: def _explicit_load_plugins(): - project_settings = get_project_settings(os.environ["AVALON_PROJECT"]) - maya_settings = project_settings["maya"] - explicit_plugins_loading = maya_settings["explicit_plugins_loading"] for plugin in explicit_plugins_loading["plugins_to_load"]: if plugin["enabled"]: print("Loading plug-in: " + plugin["name"]) @@ -46,7 +44,7 @@ if bool(int(os.environ.get(key, "0"))): ) # Build a shelf. -shelf_preset = settings['maya'].get('project_shelf') +shelf_preset = project_settings['maya'].get('project_shelf') if shelf_preset: project = os.environ["AVALON_PROJECT"] From 4b3f96af5e41ccc29461fd5e0fec9306a062edd1 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 5 Apr 2023 08:53:08 +0100 Subject: [PATCH 41/54] Comment deferred evaluation --- openpype/hosts/maya/startup/userSetup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/hosts/maya/startup/userSetup.py b/openpype/hosts/maya/startup/userSetup.py index b58ebb0f7f..ae6a999d98 100644 --- a/openpype/hosts/maya/startup/userSetup.py +++ b/openpype/hosts/maya/startup/userSetup.py @@ -26,6 +26,8 @@ if explicit_plugins_loading["enabled"]: except RuntimeError as e: print(e) + # We need to load plugins deferred as loading them directly does not work + # correctly due to Maya's initialization. cmds.evalDeferred( _explicit_load_plugins, lowestPriority=True From 2d6d1ba88200fbf0cd9813dbe8b56553a86c6c55 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 5 Apr 2023 10:11:20 +0100 Subject: [PATCH 42/54] Fix OP-5542 # Traceback (most recent call last): # File "C:\Users\florianbehr\AppData\Local\pypeclub\openpype\3.15\openpype-v3.15.4-thescope230404\openpype\hosts\maya\tools\mayalookassigner\app.py", line 272, in on_process_selected # nodes = list(set(item["nodes"]).difference(arnold_standins)) # UnboundLocalError: local variable 'arnold_standins' referenced before assignment --- openpype/hosts/maya/tools/mayalookassigner/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/tools/mayalookassigner/app.py b/openpype/hosts/maya/tools/mayalookassigner/app.py index 2a8775fff6..4619c80913 100644 --- a/openpype/hosts/maya/tools/mayalookassigner/app.py +++ b/openpype/hosts/maya/tools/mayalookassigner/app.py @@ -263,14 +263,14 @@ class MayaLookAssignerWindow(QtWidgets.QWidget): for standin in arnold_standins: if standin in nodes: arnold_standin.assign_look(standin, subset_name) + + nodes = list(set(item["nodes"]).difference(arnold_standins)) else: self.echo( "Could not assign to aiStandIn because mtoa plugin is not " "loaded." ) - nodes = list(set(item["nodes"]).difference(arnold_standins)) - # Assign look if nodes: assign_look_by_version(nodes, version_id=version["_id"]) From 94cd27fbc27d1c11a1b2fd0edb193257fc2717e9 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 5 Apr 2023 10:25:35 +0100 Subject: [PATCH 43/54] Update openpype/hosts/maya/tools/mayalookassigner/app.py --- openpype/hosts/maya/tools/mayalookassigner/app.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/maya/tools/mayalookassigner/app.py b/openpype/hosts/maya/tools/mayalookassigner/app.py index 4619c80913..a8d0f243e9 100644 --- a/openpype/hosts/maya/tools/mayalookassigner/app.py +++ b/openpype/hosts/maya/tools/mayalookassigner/app.py @@ -263,7 +263,6 @@ class MayaLookAssignerWindow(QtWidgets.QWidget): for standin in arnold_standins: if standin in nodes: arnold_standin.assign_look(standin, subset_name) - nodes = list(set(item["nodes"]).difference(arnold_standins)) else: self.echo( From 09f5e3ecc1eb067b60524c66618cbce0e6514e86 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Fri, 31 Mar 2023 14:43:10 +0200 Subject: [PATCH 44/54] remove placeholder parent to root at cleanup --- .../maya/api/workfile_template_builder.py | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/openpype/hosts/maya/api/workfile_template_builder.py b/openpype/hosts/maya/api/workfile_template_builder.py index 4bee0664ef..d65e4c74d2 100644 --- a/openpype/hosts/maya/api/workfile_template_builder.py +++ b/openpype/hosts/maya/api/workfile_template_builder.py @@ -234,26 +234,10 @@ class MayaPlaceholderLoadPlugin(PlaceholderPlugin, PlaceholderLoadMixin): return self.get_load_plugin_options(options) def cleanup_placeholder(self, placeholder, failed): - """Hide placeholder, parent them to root - add them to placeholder set and register placeholder's parent - to keep placeholder info available for future use + """Hide placeholder, add them to placeholder set """ - node = placeholder._scene_identifier - node_parent = placeholder.data["parent"] - if node_parent: - cmds.setAttr(node + ".parent", node_parent, type="string") - if cmds.getAttr(node + ".index") < 0: - cmds.setAttr(node + ".index", placeholder.data["index"]) - - holding_sets = cmds.listSets(object=node) - if holding_sets: - for set in holding_sets: - cmds.sets(node, remove=set) - - if cmds.listRelatives(node, p=True): - node = cmds.parent(node, world=True)[0] cmds.sets(node, addElement=PLACEHOLDER_SET) cmds.hide(node) cmds.setAttr(node + ".hiddenInOutliner", True) @@ -286,8 +270,6 @@ class MayaPlaceholderLoadPlugin(PlaceholderPlugin, PlaceholderLoadMixin): elif not cmds.sets(root, q=True): return - if placeholder.data["parent"]: - cmds.parent(nodes_to_parent, placeholder.data["parent"]) # Move loaded nodes to correct index in outliner hierarchy placeholder_form = cmds.xform( placeholder.scene_identifier, From 9aa8aa469fc3a81e714207809af786b520043bf6 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Fri, 31 Mar 2023 14:44:18 +0200 Subject: [PATCH 45/54] fix missing var standard --- openpype/client/entities.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/client/entities.py b/openpype/client/entities.py index 7054658c64..376157d210 100644 --- a/openpype/client/entities.py +++ b/openpype/client/entities.py @@ -1216,7 +1216,7 @@ def get_representations( version_ids=version_ids, context_filters=context_filters, names_by_version_ids=names_by_version_ids, - standard=True, + standard=standard, archived=archived, fields=fields ) From 9be576c2147e712db4d257f95c187e951eca40ec Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Fri, 31 Mar 2023 14:45:49 +0200 Subject: [PATCH 46/54] fix linked asset import --- .../workfile/workfile_template_builder.py | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index 0ce59de8ad..a3d7340367 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -158,7 +158,7 @@ class AbstractTemplateBuilder(object): def linked_asset_docs(self): if self._linked_asset_docs is None: self._linked_asset_docs = get_linked_assets( - self.current_asset_doc + self.project_name, self.current_asset_doc ) return self._linked_asset_docs @@ -1151,13 +1151,10 @@ class PlaceholderItem(object): return self._log def __repr__(self): - name = None - if hasattr("name", self): - name = self.name - if hasattr("_scene_identifier ", self): - name = self._scene_identifier - - return "< {} {} >".format(self.__class__.__name__, name) + return "< {} {} >".format( + self.__class__.__name__, + self._scene_identifier + ) @property def order(self): @@ -1419,16 +1416,7 @@ class PlaceholderLoadMixin(object): "family": [placeholder.data["family"]] } - elif builder_type != "linked_asset": - context_filters = { - "asset": [re.compile(placeholder.data["asset"])], - "subset": [re.compile(placeholder.data["subset"])], - "hierarchy": [re.compile(placeholder.data["hierarchy"])], - "representation": [placeholder.data["representation"]], - "family": [placeholder.data["family"]] - } - - else: + elif builder_type == "linked_asset": asset_regex = re.compile(placeholder.data["asset"]) linked_asset_names = [] for asset_doc in linked_asset_docs: @@ -1444,6 +1432,15 @@ class PlaceholderLoadMixin(object): "family": [placeholder.data["family"]], } + else: + context_filters = { + "asset": [re.compile(placeholder.data["asset"])], + "subset": [re.compile(placeholder.data["subset"])], + "hierarchy": [re.compile(placeholder.data["hierarchy"])], + "representation": [placeholder.data["representation"]], + "family": [placeholder.data["family"]] + } + return list(get_representations( project_name, context_filters=context_filters From 9c9a1c08399184d863f8f5be4c6688bf183e488d Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Thu, 6 Apr 2023 16:47:46 +0100 Subject: [PATCH 47/54] Discard vray proxies and aistandin from same variable. --- openpype/hosts/maya/tools/mayalookassigner/app.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/tools/mayalookassigner/app.py b/openpype/hosts/maya/tools/mayalookassigner/app.py index a8d0f243e9..fe7f460588 100644 --- a/openpype/hosts/maya/tools/mayalookassigner/app.py +++ b/openpype/hosts/maya/tools/mayalookassigner/app.py @@ -250,7 +250,7 @@ class MayaLookAssignerWindow(QtWidgets.QWidget): if vp in nodes: vrayproxy_assign_look(vp, subset_name) - nodes = list(set(item["nodes"]).difference(vray_proxies)) + nodes = list(set(nodes).difference(vray_proxies)) else: self.echo( "Could not assign to VRayProxy because vrayformaya plugin " @@ -260,10 +260,12 @@ class MayaLookAssignerWindow(QtWidgets.QWidget): # Assign Arnold Standin look. if cmds.pluginInfo("mtoa", query=True, loaded=True): arnold_standins = set(cmds.ls(type="aiStandIn", long=True)) + for standin in arnold_standins: if standin in nodes: arnold_standin.assign_look(standin, subset_name) - nodes = list(set(item["nodes"]).difference(arnold_standins)) + + nodes = list(set(nodes).difference(arnold_standins)) else: self.echo( "Could not assign to aiStandIn because mtoa plugin is not " From 0cb647c0b20732ced4c1229429be4d256a98c792 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Thu, 6 Apr 2023 16:48:40 +0100 Subject: [PATCH 48/54] Hound --- openpype/hosts/maya/tools/mayalookassigner/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/tools/mayalookassigner/app.py b/openpype/hosts/maya/tools/mayalookassigner/app.py index fe7f460588..13da999c2d 100644 --- a/openpype/hosts/maya/tools/mayalookassigner/app.py +++ b/openpype/hosts/maya/tools/mayalookassigner/app.py @@ -260,11 +260,11 @@ class MayaLookAssignerWindow(QtWidgets.QWidget): # Assign Arnold Standin look. if cmds.pluginInfo("mtoa", query=True, loaded=True): arnold_standins = set(cmds.ls(type="aiStandIn", long=True)) - + for standin in arnold_standins: if standin in nodes: arnold_standin.assign_look(standin, subset_name) - + nodes = list(set(nodes).difference(arnold_standins)) else: self.echo( From 33a52f1a5282ba308aeb2861a79f8184642ef362 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 7 Apr 2023 10:43:30 +0100 Subject: [PATCH 49/54] Fix No Lights in project settings. --- .../schemas/projects_schema/schemas/schema_maya_capture.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json index a4a986bad8..d468f098e5 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json @@ -176,7 +176,7 @@ { "all": "All Lights"}, { "selected": "Selected Lights"}, { "flat": "Flat Lighting"}, - { "nolights": "No Lights"} + { "none": "No Lights"} ] }, { From 273d87f8b8dec02b80e07da9eea038ac840f319b Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 7 Apr 2023 10:44:08 +0100 Subject: [PATCH 50/54] Fix flat lighting and sync labels with project settings. --- openpype/hosts/maya/api/lib.py | 12 ++++++++++-- openpype/hosts/maya/plugins/create/create_review.py | 2 +- .../hosts/maya/plugins/publish/collect_review.py | 4 +--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 931c0f9e5b..f94b32d917 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -112,8 +112,16 @@ FLOAT_FPS = {23.98, 23.976, 29.97, 47.952, 59.94} RENDERLIKE_INSTANCE_FAMILIES = ["rendering", "vrayscene"] -DISPLAY_LIGHTS = [ - "project_settings", "default", "all", "selected", "active", "none" +DISPLAY_LIGHTS_VALUES = [ + "project_settings", "default", "all", "selected", "flat", "none" +] +DISPLAY_LIGHTS_LABELS = [ + "Use Project Settings", + "Default Lighting", + "All Lights", + "Selected Lights", + "Flat Lighting", + "No Lights" ] diff --git a/openpype/hosts/maya/plugins/create/create_review.py b/openpype/hosts/maya/plugins/create/create_review.py index de92bbb6b5..094c9ebf8c 100644 --- a/openpype/hosts/maya/plugins/create/create_review.py +++ b/openpype/hosts/maya/plugins/create/create_review.py @@ -47,6 +47,6 @@ class CreateReview(plugin.Creator): data["imagePlane"] = self.imagePlane data["transparency"] = self.transparency data["panZoom"] = self.panZoom - data["displayLights"] = lib.DISPLAY_LIGHTS + data["displayLights"] = lib.DISPLAY_LIGHTS_LABELS self.data = data diff --git a/openpype/hosts/maya/plugins/publish/collect_review.py b/openpype/hosts/maya/plugins/publish/collect_review.py index 516a83de64..3ca45deb3a 100644 --- a/openpype/hosts/maya/plugins/publish/collect_review.py +++ b/openpype/hosts/maya/plugins/publish/collect_review.py @@ -150,10 +150,8 @@ class CollectReview(pyblish.api.InstancePlugin): # Convert enum attribute index to string. index = instance.data.get("displayLights", 0) - display_lights = lib.DISPLAY_LIGHTS[index] + display_lights = lib.DISPLAY_LIGHTS_VALUES[index] if display_lights == "project_settings": - # project_settings/maya/publish/ExtractPlayblast/capture_preset - # /Viewport Options/displayLights settings = instance.context.data["project_settings"] settings = settings["maya"]["publish"]["ExtractPlayblast"] settings = settings["capture_preset"]["Viewport Options"] From 1663a309a67e4abc78435d9b7189cc70bcff6160 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 12 Apr 2023 12:06:54 +0100 Subject: [PATCH 51/54] Fix tile rendering --- .../plugins/publish/submit_maya_deadline.py | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py index 062732c059..5542435387 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -327,6 +327,11 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): job_info = copy.deepcopy(payload_job_info) plugin_info = copy.deepcopy(payload_plugin_info) + # Force plugin reload for vray cause the region does not get flushed + # between tile renders. + if plugin_info["Renderer"] == "vray": + job_info.ForceReloadPlugin = True + # if we have sequence of files, we need to create tile job for # every frame job_info.TileJob = True @@ -436,6 +441,7 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): assembly_payloads = [] output_dir = self.job_info.OutputDirectory[0] + config_files = [] for file in assembly_files: frame = re.search(R_FRAME_NUMBER, file).group("frame") @@ -461,6 +467,7 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): datetime.now().strftime("%Y_%m_%d_%H_%M_%S") ) ) + config_files.append(config_file) try: if not os.path.isdir(output_dir): os.makedirs(output_dir) @@ -469,8 +476,6 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): self.log.warning("Path is unreachable: " "`{}`".format(output_dir)) - assembly_plugin_info["ConfigFile"] = config_file - with open(config_file, "w") as cf: print("TileCount={}".format(tiles_count), file=cf) print("ImageFileName={}".format(file), file=cf) @@ -479,6 +484,10 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): print("ImageHeight={}".format( instance.data.get("resolutionHeight")), file=cf) + reversed_y = False + if plugin_info["Renderer"] == "arnold": + reversed_y = True + with open(config_file, "a") as cf: # Need to reverse the order of the y tiles, because image # coordinates are calculated from bottom left corner. @@ -489,7 +498,7 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): instance.data.get("resolutionWidth"), instance.data.get("resolutionHeight"), payload_plugin_info["OutputFilePrefix"], - reversed_y=True + reversed_y=reversed_y )[1] for k, v in sorted(tiles.items()): print("{}={}".format(k, v), file=cf) @@ -518,6 +527,11 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): instance.data["assemblySubmissionJobs"] = assembly_job_ids + # Remove config files to avoid confusion about where data is coming + # from in Deadline. + for config_file in config_files: + os.remove(config_file) + def _get_maya_payload(self, data): job_info = copy.deepcopy(self.job_info) @@ -878,8 +892,6 @@ def _format_tiles( out["PluginInfo"]["RegionRight{}".format(tile)] = right # Tile config - cfg["Tile{}".format(tile)] = new_filename - cfg["Tile{}Tile".format(tile)] = new_filename cfg["Tile{}FileName".format(tile)] = new_filename cfg["Tile{}X".format(tile)] = left cfg["Tile{}Y".format(tile)] = top From 55ccf73ebb7a82ca9e8d8293225f6357426d9707 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 13 Apr 2023 13:31:16 +0200 Subject: [PATCH 52/54] Remove single assembly validation for animation instances --- openpype/hosts/maya/plugins/publish/validate_single_assembly.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_single_assembly.py b/openpype/hosts/maya/plugins/publish/validate_single_assembly.py index 8771ca58d1..b768c9c4e8 100644 --- a/openpype/hosts/maya/plugins/publish/validate_single_assembly.py +++ b/openpype/hosts/maya/plugins/publish/validate_single_assembly.py @@ -19,7 +19,7 @@ class ValidateSingleAssembly(pyblish.api.InstancePlugin): order = ValidateContentsOrder hosts = ['maya'] - families = ['rig', 'animation'] + families = ['rig'] label = 'Single Assembly' def process(self, instance): From ce18ab98b9ddd5d4c3c46ef9cf7636cd9d74079e Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 13 Apr 2023 16:42:05 +0200 Subject: [PATCH 53/54] TrayPublisher: Move 'BatchMovieCreator' settings to 'create' subcategory (#4827) * move 'BatchMovieCreator' settings to 'create' subcategory * change label of simple creators * added label to create plugins --- .../plugins/create/create_movie_batch.py | 7 +- .../project_settings/traypublisher.json | 22 +++--- .../schema_project_traypublisher.json | 68 +++++++++++-------- 3 files changed, 52 insertions(+), 45 deletions(-) diff --git a/openpype/hosts/traypublisher/plugins/create/create_movie_batch.py b/openpype/hosts/traypublisher/plugins/create/create_movie_batch.py index d077131e4c..1bed07f785 100644 --- a/openpype/hosts/traypublisher/plugins/create/create_movie_batch.py +++ b/openpype/hosts/traypublisher/plugins/create/create_movie_batch.py @@ -36,11 +36,9 @@ class BatchMovieCreator(TrayPublishCreator): # Position batch creator after simple creators order = 110 - def __init__(self, project_settings, *args, **kwargs): - super(BatchMovieCreator, self).__init__(project_settings, - *args, **kwargs) + def apply_settings(self, project_settings, system_settings): creator_settings = ( - project_settings["traypublisher"]["BatchMovieCreator"] + project_settings["traypublisher"]["create"]["BatchMovieCreator"] ) self.default_variants = creator_settings["default_variants"] self.default_tasks = creator_settings["default_tasks"] @@ -151,4 +149,3 @@ class BatchMovieCreator(TrayPublishCreator): File names must then contain only asset name, or asset name + version. (eg. 'chair.mov', 'chair_v001.mov', not really safe `my_chair_v001.mov` """ - diff --git a/openpype/settings/defaults/project_settings/traypublisher.json b/openpype/settings/defaults/project_settings/traypublisher.json index fdea4aeaba..1b4253a1f8 100644 --- a/openpype/settings/defaults/project_settings/traypublisher.json +++ b/openpype/settings/defaults/project_settings/traypublisher.json @@ -303,16 +303,18 @@ ] } }, - "BatchMovieCreator": { - "default_variants": [ - "Main" - ], - "default_tasks": [ - "Compositing" - ], - "extensions": [ - ".mov" - ] + "create": { + "BatchMovieCreator": { + "default_variants": [ + "Main" + ], + "default_tasks": [ + "Compositing" + ], + "extensions": [ + ".mov" + ] + } }, "publish": { "ValidateFrameRange": { diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json b/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json index 2ef1d2a414..f05f3433b0 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_traypublisher.json @@ -26,7 +26,7 @@ "type": "list", "collapsible": true, "key": "simple_creators", - "label": "Creator plugins", + "label": "Simple Create Plugins", "use_label_wrap": true, "collapsible_key": true, "object_type": { @@ -292,40 +292,48 @@ ] }, { + "key": "create", + "label": "Create plugins", "type": "dict", "collapsible": true, - "key": "BatchMovieCreator", - "label": "Batch Movie Creator", - "collapsible_key": true, "children": [ { - "type": "label", - "label": "Allows to publish multiple video files in one go.
Name of matching asset is parsed from file names ('asset.mov', 'asset_v001.mov', 'my_asset_to_publish.mov')" - }, - { - "type": "list", - "key": "default_variants", - "label": "Default variants", - "object_type": { - "type": "text" - } - }, - { - "type": "list", - "key": "default_tasks", - "label": "Default tasks", - "object_type": { - "type": "text" - } - }, - { - "type": "list", - "key": "extensions", - "label": "Extensions", - "use_label_wrap": true, + "type": "dict", + "collapsible": true, + "key": "BatchMovieCreator", + "label": "Batch Movie Creator", "collapsible_key": true, - "collapsed": false, - "object_type": "text" + "children": [ + { + "type": "label", + "label": "Allows to publish multiple video files in one go.
Name of matching asset is parsed from file names ('asset.mov', 'asset_v001.mov', 'my_asset_to_publish.mov')" + }, + { + "type": "list", + "key": "default_variants", + "label": "Default variants", + "object_type": { + "type": "text" + } + }, + { + "type": "list", + "key": "default_tasks", + "label": "Default tasks", + "object_type": { + "type": "text" + } + }, + { + "type": "list", + "key": "extensions", + "label": "Extensions", + "use_label_wrap": true, + "collapsible_key": true, + "collapsed": false, + "object_type": "text" + } + ] } ] }, From 9a5f86ea1b065a7cf847836b8148e2bc4cb79c59 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 13 Apr 2023 18:42:50 +0200 Subject: [PATCH 54/54] add review tag to output of extract sequence if instance is marked for review (#4843) --- openpype/hosts/tvpaint/plugins/publish/extract_sequence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/tvpaint/plugins/publish/extract_sequence.py b/openpype/hosts/tvpaint/plugins/publish/extract_sequence.py index 1a21715aa2..8a610cf388 100644 --- a/openpype/hosts/tvpaint/plugins/publish/extract_sequence.py +++ b/openpype/hosts/tvpaint/plugins/publish/extract_sequence.py @@ -144,7 +144,7 @@ class ExtractSequence(pyblish.api.Extractor): # Fill tags and new families from project settings tags = [] - if family_lowered == "review": + if "review" in instance.data["families"]: tags.append("review") # Sequence of one frame