From 6c04a6df1a120eead69fb90b192e26017e95f334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Thu, 21 Dec 2023 11:53:35 +0100 Subject: [PATCH 01/50] :bug: fix default render product name --- openpype/hosts/houdini/plugins/publish/collect_vray_rop.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/houdini/plugins/publish/collect_vray_rop.py b/openpype/hosts/houdini/plugins/publish/collect_vray_rop.py index a1f4554726..f60d8c664c 100644 --- a/openpype/hosts/houdini/plugins/publish/collect_vray_rop.py +++ b/openpype/hosts/houdini/plugins/publish/collect_vray_rop.py @@ -67,7 +67,7 @@ def process(self, instance): beauty_product = self.get_render_product_name(default_prefix) render_products.append(beauty_product) files_by_aov = { - "RGB Color": self.generate_expected_files(instance, + "": self.generate_expected_files(instance, beauty_product)} if instance.data.get("RenderElement", True): @@ -75,7 +75,9 @@ def process(self, instance): if render_element: for aov, renderpass in render_element.items(): render_products.append(renderpass) - files_by_aov[aov] = self.generate_expected_files(instance, renderpass) # noqa + files_by_aov[aov] = self.generate_expected_files( + instance, renderpass) + for product in render_products: self.log.debug("Found render product: %s" % product) From 02dea53a17449572897fb1ee30255f8c4aa6ddfc Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 5 Feb 2024 18:54:26 +0800 Subject: [PATCH 02/50] optional validator to check invalid context data --- openpype/hosts/max/api/action.py | 39 ++++++ .../publish/validate_instance_in_context.py | 111 ++++++++++++++++++ .../defaults/project_settings/max.json | 5 + .../schemas/schema_max_publish.json | 25 ++++ .../max/server/settings/publishers.py | 8 +- server_addon/max/server/version.py | 2 +- 6 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 openpype/hosts/max/api/action.py create mode 100644 openpype/hosts/max/plugins/publish/validate_instance_in_context.py diff --git a/openpype/hosts/max/api/action.py b/openpype/hosts/max/api/action.py new file mode 100644 index 0000000000..506847652b --- /dev/null +++ b/openpype/hosts/max/api/action.py @@ -0,0 +1,39 @@ +from pymxs import runtime as rt + +import pyblish.api + +from openpype.pipeline.publish import get_errored_instances_from_context + + +class SelectInvalidAction(pyblish.api.Action): + """Select invalid objects in Blender when a publish plug-in failed.""" + label = "Select Invalid" + on = "failed" + icon = "search" + + def process(self, context, plugin): + errored_instances = get_errored_instances_from_context(context, + plugin=plugin) + + # Get the invalid nodes for the plug-ins + self.log.info("Finding invalid nodes...") + invalid = list() + for instance in errored_instances: + invalid_nodes = plugin.get_invalid(instance) + if invalid_nodes: + if isinstance(invalid_nodes, (list, tuple)): + invalid.extend(invalid_nodes) + else: + self.log.warning( + "Failed plug-in doesn't have any selectable objects." + ) + + if not invalid: + self.log.info("No invalid nodes found.") + return + invalid_names = [obj.name for obj in invalid] + self.log.info( + "Selecting invalid objects: %s", ", ".join(invalid_names) + ) + + rt.Select(invalid) diff --git a/openpype/hosts/max/plugins/publish/validate_instance_in_context.py b/openpype/hosts/max/plugins/publish/validate_instance_in_context.py new file mode 100644 index 0000000000..afe5ca5a7f --- /dev/null +++ b/openpype/hosts/max/plugins/publish/validate_instance_in_context.py @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- +"""Validate if instance asset is the same as context asset.""" +from __future__ import absolute_import + +import pyblish.api +from openpype import AYON_SERVER_ENABLED +from openpype.pipeline.publish import ( + RepairAction, + ValidateContentsOrder, + PublishValidationError, + OptionalPyblishPluginMixin +) +from openpype.hosts.max.api.action import SelectInvalidAction +from pymxs import runtime as rt + + +class ValidateInstanceInContext(pyblish.api.InstancePlugin, + OptionalPyblishPluginMixin): + """Validator to check if instance asset match context asset. + + When working in per-shot style you always publish data in context of + current asset (shot). This validator checks if this is so. It is optional + so it can be disabled when needed. + + Action on this validator will select invalid instances. + """ + + order = ValidateContentsOrder + label = "Instance in same Context" + optional = True + hosts = ["max"] + actions = [SelectInvalidAction, RepairAction] + + def process(self, instance): + if not self.is_active(instance.data): + return + + instance_node = rt.getNodeByName(instance.data.get( + "instance_node", "")) + if not instance_node: + return + asset_name_attr = "folderPath" if AYON_SERVER_ENABLED else "asset" + asset = rt.getUserProp(instance_node, asset_name_attr) + context_asset = self.get_context_asset(instance) + task = rt.getUserProp(instance_node, "task") + context_task = self.get_context_task(instance) + if asset != context_asset: + raise PublishValidationError( + message=( + "Instance '{}' publishes to different asset than current " + "context: {}. Current context: {}".format( + instance.name, asset, context_asset + ) + ), + description=( + "## Publishing to a different asset\n" + "There are publish instances present which are publishing " + "into a different asset than your current context.\n\n" + "Usually this is not what you want but there can be cases " + "where you might want to publish into another asset or " + "shot. If that's the case you can disable the validation " + "on the instance to ignore it." + ) + ) + if task != context_task: + raise PublishValidationError( + message=( + "Instance '{}' publishes to different task than current " + "context: {}. Current context: {}".format( + instance.name, task, context_task + ) + ), + description=( + "## Publishing to a different asset\n" + "There are publish instances present which are publishing " + "into a different asset than your current context.\n\n" + "Usually this is not what you want but there can be cases " + "where you might want to publish into another asset or " + "shot. If that's the case you can disable the validation " + "on the instance to ignore it." + ) + ) + + @classmethod + def get_invalid(cls, instance): + asset_name_attr = "folderPath" if AYON_SERVER_ENABLED else "asset" + node = rt.getNodeByName(instance.data["instance_node"]) + asset = rt.getUserProp(node, asset_name_attr) + context_asset = cls.get_context_asset(instance) + if asset != context_asset: + return instance.data["instance_node"] + + @classmethod + def repair(cls, instance): + context_asset = cls.get_context_asset(instance) + context_task = cls.get_context_task(instance) + instance_node = rt.getNodeByName(instance.data.get( + "instance_node", "")) + if not instance_node: + return + asset_name_attr = "folderPath" if AYON_SERVER_ENABLED else "asset" + rt.SetUserProp(instance_node, asset_name_attr, context_asset) + rt.SetUserProp(instance_node, "task", context_task) + + @staticmethod + def get_context_asset(instance): + return instance.context.data["asset"] + + @staticmethod + def get_context_task(instance): + return instance.context.data["task"] diff --git a/openpype/settings/defaults/project_settings/max.json b/openpype/settings/defaults/project_settings/max.json index d1610610dc..eb4667c36e 100644 --- a/openpype/settings/defaults/project_settings/max.json +++ b/openpype/settings/defaults/project_settings/max.json @@ -47,6 +47,11 @@ } }, "publish": { + "ValidateInstanceInContext": { + "enabled": true, + "optional": true, + "active": true + }, "ValidateFrameRange": { "enabled": true, "optional": true, diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_max_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_max_publish.json index b4d85bda98..fc563ff372 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_max_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_max_publish.json @@ -4,6 +4,31 @@ "key": "publish", "label": "Publish plugins", "children": [ + { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "key": "ValidateInstanceInContext", + "label": "Validate Instance In Context", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "active", + "label": "Active" + } + ] + }, { "type": "dict", "collapsible": true, diff --git a/server_addon/max/server/settings/publishers.py b/server_addon/max/server/settings/publishers.py index da782cb494..03cfefa303 100644 --- a/server_addon/max/server/settings/publishers.py +++ b/server_addon/max/server/settings/publishers.py @@ -54,11 +54,15 @@ class BasicValidateModel(BaseSettingsModel): class PublishersModel(BaseSettingsModel): - ValidateFrameRange: BasicValidateModel = SettingsField( + ValidateInstanceInContext: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, - title="Validate Frame Range", + title="Validate Instance In Context", section="Validators" ) + ValidateFrameRange: BasicValidateModel = SettingsField( + default_factory=BasicValidateModel, + title="Validate Frame Range" + ) ValidateAttributes: ValidateAttributesModel = SettingsField( default_factory=ValidateAttributesModel, title="Validate Attributes" diff --git a/server_addon/max/server/version.py b/server_addon/max/server/version.py index bbab0242f6..1276d0254f 100644 --- a/server_addon/max/server/version.py +++ b/server_addon/max/server/version.py @@ -1 +1 @@ -__version__ = "0.1.4" +__version__ = "0.1.5" From 83c8239a4918804af3379b44bf45698a965a377d Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 6 Feb 2024 14:32:04 +0800 Subject: [PATCH 03/50] add missing ayon settings in json for validate instance in context --- server_addon/max/server/settings/publishers.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/server_addon/max/server/settings/publishers.py b/server_addon/max/server/settings/publishers.py index 03cfefa303..58c71d977d 100644 --- a/server_addon/max/server/settings/publishers.py +++ b/server_addon/max/server/settings/publishers.py @@ -96,6 +96,11 @@ class PublishersModel(BaseSettingsModel): DEFAULT_PUBLISH_SETTINGS = { + "ValidateInstanceInContext": { + "enabled": True, + "optional": True, + "active": True + }, "ValidateFrameRange": { "enabled": True, "optional": True, From e27b6e902822c7295f948b5f0e687abf344413c3 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 8 Feb 2024 20:09:40 +0800 Subject: [PATCH 04/50] change action.py as regard to #6164 --- openpype/hosts/max/api/action.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/max/api/action.py b/openpype/hosts/max/api/action.py index 506847652b..c3c1957af1 100644 --- a/openpype/hosts/max/api/action.py +++ b/openpype/hosts/max/api/action.py @@ -31,7 +31,10 @@ def process(self, context, plugin): if not invalid: self.log.info("No invalid nodes found.") return - invalid_names = [obj.name for obj in invalid] + invalid_names = [obj.name for obj in invalid if isinstance(obj, str)] + if not invalid_names: + invalid_names = [obj.name for obj, _ in invalid] + invalid = [obj for obj, _ in invalid] self.log.info( "Selecting invalid objects: %s", ", ".join(invalid_names) ) From 8d608f72981d1e7b440b948153c2eb65cdbbdda4 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 21 Feb 2024 21:01:58 +0800 Subject: [PATCH 05/50] fix the bug in action.py --- client/ayon_core/hosts/max/api/action.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/max/api/action.py b/client/ayon_core/hosts/max/api/action.py index 58834d0172..bed72bc493 100644 --- a/client/ayon_core/hosts/max/api/action.py +++ b/client/ayon_core/hosts/max/api/action.py @@ -31,7 +31,7 @@ def process(self, context, plugin): if not invalid: self.log.info("No invalid nodes found.") return - invalid_names = [obj.name for obj in invalid if isinstance(obj, str)] + invalid_names = [obj.name for obj in invalid if not isinstance(obj, tuple)] if not invalid_names: invalid_names = [obj.name for obj, _ in invalid] invalid = [obj for obj, _ in invalid] From 6f875f8799544d685e298cf8b19d025ecf179d20 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 22 Feb 2024 18:18:04 +0800 Subject: [PATCH 06/50] make sure all instance.context.data['asset'] converted to instance.context.data['folderPath'] --- .../hosts/max/plugins/publish/validate_instance_in_context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py index 872a687597..5d544513c0 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py @@ -100,7 +100,7 @@ def repair(cls, instance): @staticmethod def get_context_asset(instance): - return instance.context.data["asset"] + return instance.context.data["folderPath"] @staticmethod def get_context_task(instance): From 3edbf698a039905917b34b5e9f2c9509ce0eeb15 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 22 Feb 2024 22:17:21 +0100 Subject: [PATCH 07/50] Update issue template titles to remove prefixes. Improve clarity and consistency in issue reporting templates. --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- .github/ISSUE_TEMPLATE/enhancement_request.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 655ffe289e..5a0ed1ae1d 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,6 +1,6 @@ name: Bug Report description: File a bug report -title: 'Bug: ' +title: '' labels: - 'type: bug' body: diff --git a/.github/ISSUE_TEMPLATE/enhancement_request.yml b/.github/ISSUE_TEMPLATE/enhancement_request.yml index 52b49e0481..da4d0d9319 100644 --- a/.github/ISSUE_TEMPLATE/enhancement_request.yml +++ b/.github/ISSUE_TEMPLATE/enhancement_request.yml @@ -1,6 +1,6 @@ name: Enhancement Request description: Create a report to help us enhance a particular feature -title: "Enhancement: " +title: "" labels: - "type: enhancement" body: From c90ddbcb6b387b100f99acf6b759393c96f0e3bc Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 26 Feb 2024 19:14:56 +0800 Subject: [PATCH 08/50] tweak on get_invalid function and clean up code for getting folderPath and task data --- .../publish/validate_instance_in_context.py | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py index 5d544513c0..e4d078b36c 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py @@ -39,9 +39,9 @@ def process(self, instance): if not instance_node: return asset = rt.getUserProp(instance_node, "folderPath") - context_asset = self.get_context_asset(instance) + context_asset = instance.context.data["folderPath"] task = rt.getUserProp(instance_node, "task") - context_task = self.get_context_task(instance) + context_task = instance.context.data["task"] if asset != context_asset: raise PublishValidationError( message=( @@ -81,27 +81,26 @@ def process(self, instance): @classmethod def get_invalid(cls, instance): + invalid = [] node = rt.getNodeByName(instance.data["instance_node"]) asset = rt.getUserProp(node, "folderPath") - context_asset = cls.get_context_asset(instance) + context_asset = instance.context.data["folderPath"] if asset != context_asset: - return instance.data["instance_node"] + invalid.append(node) + task = rt.getUserProp(node, "task") + context_task = instance.context.data["task"] + if task != context_task: + invalid.append(node) + + return invalid @classmethod def repair(cls, instance): - context_asset = cls.get_context_asset(instance) - context_task = cls.get_context_task(instance) + context_asset = instance.context.data["folderPath"] + context_task = instance.context.data["task"] instance_node = rt.getNodeByName(instance.data.get( "instance_node", "")) if not instance_node: return rt.SetUserProp(instance_node, "folderPath", context_asset) rt.SetUserProp(instance_node, "task", context_task) - - @staticmethod - def get_context_asset(instance): - return instance.context.data["folderPath"] - - @staticmethod - def get_context_task(instance): - return instance.context.data["task"] From 4ddfc7e00cfeae5e290862cbca59b9655940091a Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 26 Feb 2024 17:51:34 +0100 Subject: [PATCH 09/50] switch and update expecte representation context --- client/ayon_core/pipeline/load/plugins.py | 6 +++--- client/ayon_core/pipeline/load/utils.py | 20 +++++++++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/client/ayon_core/pipeline/load/plugins.py b/client/ayon_core/pipeline/load/plugins.py index 962417c6f2..77b78a9ae3 100644 --- a/client/ayon_core/pipeline/load/plugins.py +++ b/client/ayon_core/pipeline/load/plugins.py @@ -192,13 +192,13 @@ def load(self, context, name=None, namespace=None, options=None): raise NotImplementedError("Loader.load() must be " "implemented by subclass") - def update(self, container, representation): + def update(self, container, context): """Update `container` to `representation` - Arguments: + Args: container (avalon-core:container-1.0): Container to update, from `host.ls()`. - representation (dict): Update the container to this representation. + context (dict): Update the container to this representation. """ raise NotImplementedError("Loader.update() must be " diff --git a/client/ayon_core/pipeline/load/utils.py b/client/ayon_core/pipeline/load/utils.py index 056836d712..e2bc1c7a26 100644 --- a/client/ayon_core/pipeline/load/utils.py +++ b/client/ayon_core/pipeline/load/utils.py @@ -1,7 +1,6 @@ import os import platform import copy -import getpass import logging import inspect import collections @@ -11,7 +10,9 @@ from ayon_core.client import ( get_project, get_assets, + get_asset_by_id, get_subsets, + get_subset_by_id, get_versions, get_version_by_id, get_last_version_by_subset_id, @@ -481,6 +482,8 @@ def update_container(container, version=-1): new_version = get_version_by_name( project_name, version, current_version["parent"], fields=["_id"] ) + subset_doc = get_subset_by_id(project_name, current_version["parent"]) + asset_doc = get_asset_by_id(project_name, subset_doc["parent"]) assert new_version is not None, "This is a bug" @@ -499,8 +502,19 @@ def update_container(container, version=-1): "Can't update container because loader '{}' was not found." .format(container.get("loader")) ) + project_doc = get_project(project_name) + context = { + "project": { + "name": project_doc["name"], + "code": project_doc["data"]["code"], + }, + "asset": asset_doc, + "subset": subset_doc, + "version": new_version, + "representation": new_representation, + } - return Loader().update(container, new_representation) + return Loader().update(container, context) def switch_container(container, representation, loader_plugin=None): @@ -549,7 +563,7 @@ def switch_container(container, representation, loader_plugin=None): loader = loader_plugin(new_context) - return loader.switch(container, new_representation) + return loader.switch(container, new_context) def get_representation_path_from_context(context): From 54a71203ef34481fb8cd393de50d87770f7357cb Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 26 Feb 2024 17:52:45 +0100 Subject: [PATCH 10/50] unreal load plugins are expecting representation context --- .../plugins/load/load_alembic_animation.py | 15 +++++--- .../unreal/plugins/load/load_animation.py | 13 ++++--- .../hosts/unreal/plugins/load/load_camera.py | 9 +++-- .../plugins/load/load_geometrycache_abc.py | 37 +++++++++++-------- .../hosts/unreal/plugins/load/load_layout.py | 14 ++++--- .../plugins/load/load_layout_existing.py | 12 +++--- .../plugins/load/load_skeletalmesh_abc.py | 32 +++++++++------- .../plugins/load/load_skeletalmesh_fbx.py | 30 +++++++++------ .../plugins/load/load_staticmesh_abc.py | 24 ++++++------ .../plugins/load/load_staticmesh_fbx.py | 30 +++++++++------ .../hosts/unreal/plugins/load/load_uasset.py | 17 ++++++--- .../unreal/plugins/load/load_yeticache.py | 11 +++--- 12 files changed, 142 insertions(+), 102 deletions(-) diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_alembic_animation.py b/client/ayon_core/hosts/unreal/plugins/load/load_alembic_animation.py index 4d7760e385..f51c37dee6 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_alembic_animation.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_alembic_animation.py @@ -126,12 +126,15 @@ def load(self, context, name, namespace, data): return asset_content - def update(self, container, representation): - name = container["asset_name"] - source_path = get_representation_path(representation) + def update(self, container, context): + folder_name = container["asset_name"] + repre_doc = context["representation"] + source_path = get_representation_path(repre_doc) destination_path = container["namespace"] - task = self.get_task(source_path, destination_path, name, True) + task = self.get_task( + source_path, destination_path, folder_name, True + ) # do import fbx and replace existing data asset_tools = unreal.AssetToolsHelpers.get_asset_tools() @@ -143,8 +146,8 @@ def update(self, container, representation): unreal_pipeline.imprint( container_path, { - "representation": str(representation["_id"]), - "parent": str(representation["parent"]) + "representation": str(repre_doc["_id"]), + "parent": str(repre_doc["parent"]) }) asset_content = unreal.EditorAssetLibrary.list_assets( diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_animation.py b/client/ayon_core/hosts/unreal/plugins/load/load_animation.py index 4d44b6c0c2..1258fea198 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_animation.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_animation.py @@ -246,9 +246,10 @@ def load(self, context, name, namespace, options=None): unreal.EditorLevelLibrary.save_current_level() unreal.EditorLevelLibrary.load_level(master_level) - def update(self, container, representation): - name = container["asset_name"] - source_path = get_representation_path(representation) + def update(self, container, context): + repre_doc = context["representation"] + folder_name = container["asset_name"] + source_path = get_representation_path(repre_doc) asset_doc = get_current_project_asset(fields=["data.fps"]) destination_path = container["namespace"] @@ -258,7 +259,7 @@ def update(self, container, representation): task.set_editor_property('filename', source_path) task.set_editor_property('destination_path', destination_path) # strip suffix - task.set_editor_property('destination_name', name) + task.set_editor_property('destination_name', folder_name) task.set_editor_property('replace_existing', True) task.set_editor_property('automated', True) task.set_editor_property('save', True) @@ -305,8 +306,8 @@ def update(self, container, representation): unreal_pipeline.imprint( container_path, { - "representation": str(representation["_id"]), - "parent": str(representation["parent"]) + "representation": str(repre_doc["_id"]), + "parent": str(repre_doc["parent"]) }) asset_content = EditorAssetLibrary.list_assets( diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_camera.py b/client/ayon_core/hosts/unreal/plugins/load/load_camera.py index faba561085..09441d5a32 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_camera.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_camera.py @@ -260,7 +260,7 @@ def load(self, context, name, namespace, data): return asset_content - def update(self, container, representation): + def update(self, container, context): ar = unreal.AssetRegistryHelpers.get_asset_registry() curr_level_sequence = LevelSequenceLib.get_current_level_sequence() @@ -379,12 +379,13 @@ def update(self, container, representation): sub_scene.set_sequence(new_sequence) + repre_doc = context["representation"] self._import_camera( EditorLevelLibrary.get_editor_world(), new_sequence, new_sequence.get_bindings(), settings, - str(representation["data"]["path"]) + str(repre_doc["data"]["path"]) ) # Set range of all sections @@ -412,8 +413,8 @@ def update(self, container, representation): key.set_time(unreal.FrameNumber(value=new_time)) data = { - "representation": str(representation["_id"]), - "parent": str(representation["parent"]) + "representation": str(repre_doc["_id"]), + "parent": str(repre_doc["parent"]) } imprint(f"{asset_dir}/{container.get('container_name')}", data) diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_geometrycache_abc.py b/client/ayon_core/hosts/unreal/plugins/load/load_geometrycache_abc.py index 360737cbc5..bca99f202f 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_geometrycache_abc.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_geometrycache_abc.py @@ -108,7 +108,7 @@ def load(self, context, name, namespace, options): Args: context (dict): application context - name (str): subset name + name (str): Product name namespace (str): in Unreal this is basically path to container. This is not passed here, so namespace is set by `containerise()` because only then we know @@ -163,25 +163,30 @@ def load(self, context, name, namespace, options): return asset_content - def update(self, container, representation): - context = representation.get("context", {}) - - unreal.log_warning(context) - - if not context: - raise RuntimeError("No context found in representation") + def update(self, container, context): + asset_doc = context["asset"] + subset_doc = context["subset"] + version_doc = context["version"] + repre_doc = context["representation"] # Create directory for asset and Ayon container - asset = context.get('asset') - name = context.get('subset') + folder_name = asset_doc["name"] + product_name = subset_doc["name"] + suffix = "_CON" - asset_name = f"{asset}_{name}" if asset else f"{name}" - version = context.get('version') + asset_name = product_name + if folder_name: + asset_name = f"{folder_name}_{product_name}" + # Check if version is hero version and use different name - name_version = f"{name}_v{version:03d}" if version else f"{name}_hero" + version = version_doc.get("name", -1) + if version < 0: + name_version = f"{product_name}_hero" + else: + name_version = f"{product_name}_v{version:03d}" tools = unreal.AssetToolsHelpers().get_asset_tools() asset_dir, container_name = tools.create_unique_asset_name( - f"{self.root}/{asset}/{name_version}", suffix="") + f"{self.root}/{folder_name}/{name_version}", suffix="") container_name += suffix @@ -189,14 +194,14 @@ def update(self, container, representation): frame_end = int(container.get("frame_end")) if not unreal.EditorAssetLibrary.does_directory_exist(asset_dir): - path = get_representation_path(representation) + path = get_representation_path(repre_doc) self.import_and_containerize( path, asset_dir, asset_name, container_name, frame_start, frame_end) self.imprint( - asset, asset_dir, container_name, asset_name, representation, + folder_name, asset_dir, container_name, asset_name, repre_doc, frame_start, frame_end) asset_content = unreal.EditorAssetLibrary.list_assets( diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_layout.py b/client/ayon_core/hosts/unreal/plugins/load/load_layout.py index a1cc2e785a..94454e8fc4 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_layout.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_layout.py @@ -659,7 +659,7 @@ def load(self, context, name, namespace, options): return asset_content - def update(self, container, representation): + def update(self, container, context): data = get_current_project_settings() create_sequences = data["unreal"]["level_sequences_for_layouts"] @@ -675,9 +675,11 @@ def update(self, container, representation): root = "/Game/Ayon" asset_dir = container.get('namespace') - context = representation.get("context") - hierarchy = context.get('hierarchy').split("/") + asset_doc = context["asset"] + repre_doc = context["representation"] + + hierarchy = list(asset_doc["data"]["parents"]) sequence = None master_level = None @@ -726,13 +728,13 @@ def update(self, container, representation): EditorAssetLibrary.delete_directory(f"{asset_dir}/animations/") - source_path = get_representation_path(representation) + source_path = get_representation_path(repre_doc) loaded_assets = self._process(source_path, asset_dir, sequence) data = { - "representation": str(representation["_id"]), - "parent": str(representation["parent"]), + "representation": str(repre_doc["_id"]), + "parent": str(repre_doc["parent"]), "loaded_assets": loaded_assets } imprint( diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_layout_existing.py b/client/ayon_core/hosts/unreal/plugins/load/load_layout_existing.py index 6f390b4920..c4b5246488 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_layout_existing.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_layout_existing.py @@ -407,16 +407,18 @@ def load(self, context, name, namespace, options): } upipeline.imprint(f"{curr_level_path}/{container_name}", data) - def update(self, container, representation): + def update(self, container, context): asset_dir = container.get('namespace') - source_path = get_representation_path(representation) - project_name = get_current_project_name() + project_name = context["project"]["name"] + repre_doc = context["representation"] + + source_path = get_representation_path(repre_doc) containers = self._process(source_path, project_name) data = { - "representation": str(representation["_id"]), - "parent": str(representation["parent"]), + "representation": str(repre_doc["_id"]), + "parent": str(repre_doc["parent"]), "loaded_assets": containers } upipeline.imprint( diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_skeletalmesh_abc.py b/client/ayon_core/hosts/unreal/plugins/load/load_skeletalmesh_abc.py index 225df3b440..4de05d1171 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_skeletalmesh_abc.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_skeletalmesh_abc.py @@ -144,34 +144,40 @@ def load(self, context, name, namespace, options): return asset_content - def update(self, container, representation): - context = representation.get("context", {}) + def update(self, container, context): + asset_doc = context["asset"] + subset_doc = context["subset"] + version_doc = context["version"] + repre_doc = context["representation"] - if not context: - raise RuntimeError("No context found in representation") + folder_name = asset_doc["name"] + product_name = subset_doc["name"] - # Create directory for asset and Ayon container - asset = context.get('asset') - name = context.get('subset') + # Create directory for folder and Ayon container suffix = "_CON" - asset_name = f"{asset}_{name}" if asset else f"{name}" - version = context.get('version') + asset_name = product_name + if folder_name: + asset_name = f"{folder_name}_{product_name}" # Check if version is hero version and use different name - name_version = f"{name}_v{version:03d}" if version else f"{name}_hero" + version = version_doc.get("name", -1) + if version < 0: + name_version = f"{product_name}_hero" + else: + name_version = f"{product_name}_v{version:03d}" tools = unreal.AssetToolsHelpers().get_asset_tools() asset_dir, container_name = tools.create_unique_asset_name( - f"{self.root}/{asset}/{name_version}", suffix="") + f"{self.root}/{folder_name}/{name_version}", suffix="") container_name += suffix if not unreal.EditorAssetLibrary.does_directory_exist(asset_dir): - path = get_representation_path(representation) + path = get_representation_path(repre_doc) self.import_and_containerize(path, asset_dir, asset_name, container_name) self.imprint( - asset, asset_dir, container_name, asset_name, representation) + folder_name, asset_dir, container_name, asset_name, repre_doc) asset_content = unreal.EditorAssetLibrary.list_assets( asset_dir, recursive=True, include_folder=False diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_skeletalmesh_fbx.py b/client/ayon_core/hosts/unreal/plugins/load/load_skeletalmesh_fbx.py index 1c45c58d02..865d609a89 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_skeletalmesh_fbx.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_skeletalmesh_fbx.py @@ -146,34 +146,40 @@ def load(self, context, name, namespace, options): return asset_content - def update(self, container, representation): - context = representation.get("context", {}) + def update(self, container, context): + asset_doc = context["asse"] + subset_doc = context["subset"] + version_doc = context["version"] + repre_doc = context["representation"] - if not context: - raise RuntimeError("No context found in representation") + folder_name = asset_doc["name"] + product_name = subset_doc["name"] # Create directory for asset and Ayon container - asset = context.get('asset') - name = context.get('subset') suffix = "_CON" - asset_name = f"{asset}_{name}" if asset else f"{name}" - version = context.get('version') + asset_name = product_name + if folder_name: + asset_name = f"{folder_name}_{product_name}" # Check if version is hero version and use different name - name_version = f"{name}_v{version:03d}" if version else f"{name}_hero" + version = version_doc.get("name", -1) + if version < 0: + name_version = f"{product_name}_hero" + else: + name_version = f"{product_name}_v{version:03d}" tools = unreal.AssetToolsHelpers().get_asset_tools() asset_dir, container_name = tools.create_unique_asset_name( - f"{self.root}/{asset}/{name_version}", suffix="") + f"{self.root}/{folder_name}/{name_version}", suffix="") container_name += suffix if not unreal.EditorAssetLibrary.does_directory_exist(asset_dir): - path = get_representation_path(representation) + path = get_representation_path(repre_doc) self.import_and_containerize( path, asset_dir, asset_name, container_name) self.imprint( - asset, asset_dir, container_name, asset_name, representation) + folder_name, asset_dir, container_name, asset_name, repre_doc) asset_content = unreal.EditorAssetLibrary.list_assets( asset_dir, recursive=True, include_folder=False diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_staticmesh_abc.py b/client/ayon_core/hosts/unreal/plugins/load/load_staticmesh_abc.py index a0814b5b07..1db7cbcfaf 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_staticmesh_abc.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_staticmesh_abc.py @@ -145,34 +145,36 @@ def load(self, context, name, namespace, options): return asset_content - def update(self, container, representation): - context = representation.get("context", {}) + def update(self, container, context): + asset_doc = context["asset"] + subset_doc = context["subset"] + repre_doc = context["representation"] - if not context: - raise RuntimeError("No context found in representation") + folder_name = asset_doc["name"] + product_name = subset_doc["name"] # Create directory for asset and Ayon container - asset = context.get('asset') - name = context.get('subset') suffix = "_CON" - asset_name = f"{asset}_{name}" if asset else f"{name}" + asset_name = product_name + if folder_name: + asset_name = f"{folder_name}_{product_name}" version = context.get('version') # Check if version is hero version and use different name - name_version = f"{name}_v{version:03d}" if version else f"{name}_hero" + name_version = f"{product_name}_v{version:03d}" if version else f"{product_name}_hero" tools = unreal.AssetToolsHelpers().get_asset_tools() asset_dir, container_name = tools.create_unique_asset_name( - f"{self.root}/{asset}/{name_version}", suffix="") + f"{self.root}/{folder_name}/{name_version}", suffix="") container_name += suffix if not unreal.EditorAssetLibrary.does_directory_exist(asset_dir): - path = get_representation_path(representation) + path = get_representation_path(repre_doc) self.import_and_containerize(path, asset_dir, asset_name, container_name) self.imprint( - asset, asset_dir, container_name, asset_name, representation) + folder_name, asset_dir, container_name, asset_name, repre_doc) asset_content = unreal.EditorAssetLibrary.list_assets( asset_dir, recursive=True, include_folder=False diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_staticmesh_fbx.py b/client/ayon_core/hosts/unreal/plugins/load/load_staticmesh_fbx.py index a78b1bc959..680b9dfe29 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_staticmesh_fbx.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_staticmesh_fbx.py @@ -134,34 +134,40 @@ def load(self, context, name, namespace, options): return asset_content - def update(self, container, representation): - context = representation.get("context", {}) + def update(self, container, context): + asset_doc = context["asset"] + subset_doc = context["subset"] + version_doc = context["version"] + repre_doc = context["representation"] - if not context: - raise RuntimeError("No context found in representation") + folder_name = asset_doc["name"] + product_name = subset_doc["name"] # Create directory for asset and Ayon container - asset = context.get('asset') - name = context.get('subset') suffix = "_CON" - asset_name = f"{asset}_{name}" if asset else f"{name}" - version = context.get('version') + asset_name = product_name + if folder_name: + asset_name = f"{folder_name}_{product_name}" # Check if version is hero version and use different name - name_version = f"{name}_v{version:03d}" if version else f"{name}_hero" + version = version_doc.get("name", -1) + if version < 0: + name_version = f"{product_name}_hero" + else: + name_version = f"{product_name}_v{version:03d}" tools = unreal.AssetToolsHelpers().get_asset_tools() asset_dir, container_name = tools.create_unique_asset_name( - f"{self.root}/{asset}/{name_version}", suffix="") + f"{self.root}/{folder_name}/{name_version}", suffix="") container_name += suffix if not unreal.EditorAssetLibrary.does_directory_exist(asset_dir): - path = get_representation_path(representation) + path = get_representation_path(repre_doc) self.import_and_containerize( path, asset_dir, asset_name, container_name) self.imprint( - asset, asset_dir, container_name, asset_name, representation) + folder_name, asset_dir, container_name, asset_name, repre_doc) asset_content = unreal.EditorAssetLibrary.list_assets( asset_dir, recursive=True, include_folder=False diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_uasset.py b/client/ayon_core/hosts/unreal/plugins/load/load_uasset.py index 048ec8eaba..46e685d1bc 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_uasset.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_uasset.py @@ -96,11 +96,15 @@ def load(self, context, name, namespace, options): return asset_content - def update(self, container, representation): + def update(self, container, context): ar = unreal.AssetRegistryHelpers.get_asset_registry() asset_dir = container["namespace"] - name = representation["context"]["subset"] + + subset_doc = context["subset"] + repre_doc = context["representation"] + + product_name = subset_doc["name"] unique_number = container["container_name"].split("_")[-2] @@ -116,19 +120,20 @@ def update(self, container, representation): if obj.get_class().get_name() != "AyonAssetContainer": unreal.EditorAssetLibrary.delete_asset(asset) - update_filepath = get_representation_path(representation) + update_filepath = get_representation_path(repre_doc) shutil.copy( update_filepath, - f"{destination_path}/{name}_{unique_number}.{self.extension}") + f"{destination_path}/{product_name}_{unique_number}.{self.extension}" + ) container_path = f'{container["namespace"]}/{container["objectName"]}' # update metadata unreal_pipeline.imprint( container_path, { - "representation": str(representation["_id"]), - "parent": str(representation["parent"]), + "representation": str(repre_doc["_id"]), + "parent": str(repre_doc["parent"]), } ) diff --git a/client/ayon_core/hosts/unreal/plugins/load/load_yeticache.py b/client/ayon_core/hosts/unreal/plugins/load/load_yeticache.py index b643f352b7..c6e275c844 100644 --- a/client/ayon_core/hosts/unreal/plugins/load/load_yeticache.py +++ b/client/ayon_core/hosts/unreal/plugins/load/load_yeticache.py @@ -69,7 +69,7 @@ def load(self, context, name, namespace, options): Args: context (dict): application context - name (str): subset name + name (str): Product name namespace (str): in Unreal this is basically path to container. This is not passed here, so namespace is set by `containerise()` because only then we know @@ -139,9 +139,10 @@ def load(self, context, name, namespace, options): return asset_content - def update(self, container, representation): + def update(self, container, context): + repre_doc = context["representation"] name = container["asset_name"] - source_path = get_representation_path(representation) + source_path = get_representation_path(repre_doc) destination_path = container["namespace"] task = self.get_task(source_path, destination_path, name, True) @@ -154,8 +155,8 @@ def update(self, container, representation): unreal_pipeline.imprint( container_path, { - "representation": str(representation["_id"]), - "parent": str(representation["parent"]) + "representation": str(repre_doc["_id"]), + "parent": str(repre_doc["parent"]) }) asset_content = unreal.EditorAssetLibrary.list_assets( From 6d71830e32cb759114efcf2ad8397b07232d4ec2 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 26 Feb 2024 17:53:00 +0100 Subject: [PATCH 11/50] tvpaint load plugins are expecting representation context --- .../hosts/tvpaint/plugins/load/load_reference_image.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/hosts/tvpaint/plugins/load/load_reference_image.py b/client/ayon_core/hosts/tvpaint/plugins/load/load_reference_image.py index 0a12e93f44..ea670996a4 100644 --- a/client/ayon_core/hosts/tvpaint/plugins/load/load_reference_image.py +++ b/client/ayon_core/hosts/tvpaint/plugins/load/load_reference_image.py @@ -210,15 +210,17 @@ def remove(self, container): def switch(self, container, representation): self.update(container, representation) - def update(self, container, representation): + def update(self, container, context): """Replace container with different version. New layers are loaded as first step. Then is tried to change data in new layers with data from old layers. When that is done old layers are removed. """ + + repre_doc = context["representation"] # Create new containers first - context = get_representation_context(representation) + context = get_representation_context(repre_doc) # Get layer ids from previous container old_layer_names = self.get_members_from_container(container) From d790d2e41162e2f7fe037f6f7ee908393b33b699 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 26 Feb 2024 17:53:16 +0100 Subject: [PATCH 12/50] substance load plugins are expecting representation context --- .../hosts/substancepainter/plugins/load/load_mesh.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/client/ayon_core/hosts/substancepainter/plugins/load/load_mesh.py b/client/ayon_core/hosts/substancepainter/plugins/load/load_mesh.py index 48aa99d357..810fecb8e5 100644 --- a/client/ayon_core/hosts/substancepainter/plugins/load/load_mesh.py +++ b/client/ayon_core/hosts/substancepainter/plugins/load/load_mesh.py @@ -97,12 +97,13 @@ def on_mesh_reload(status: substance_painter.project.ReloadMeshStatus): # noqa set_container_metadata(project_mesh_object_name, container) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) - def update(self, container, representation): + def update(self, container, context): + repre_doc = context["representation"] - path = get_representation_path(representation) + path = get_representation_path(repre_doc) # Reload the mesh container_options = container.get("options", {}) @@ -121,7 +122,7 @@ def on_mesh_reload(status: substance_painter.project.ReloadMeshStatus): # Update container representation object_name = container["objectName"] - update_data = {"representation": str(representation["_id"])} + update_data = {"representation": str(repre_doc["_id"])} set_container_metadata(object_name, update_data, update=True) def remove(self, container): From 3c67c4fdd09ed7b1813f751c2b6a2544c8b7cd5c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 26 Feb 2024 17:53:47 +0100 Subject: [PATCH 13/50] photoshop load plugins are expecting representation context --- .../ayon_core/hosts/photoshop/api/README.md | 12 +++++------ .../photoshop/plugins/load/load_image.py | 12 +++++------ .../plugins/load/load_image_from_sequence.py | 2 +- .../photoshop/plugins/load/load_reference.py | 21 ++++++++++++------- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/client/ayon_core/hosts/photoshop/api/README.md b/client/ayon_core/hosts/photoshop/api/README.md index 02868753d1..42feeb4142 100644 --- a/client/ayon_core/hosts/photoshop/api/README.md +++ b/client/ayon_core/hosts/photoshop/api/README.md @@ -224,23 +224,23 @@ class ImageLoader(load.LoaderPlugin): self.__class__.__name__ ) - def update(self, container, representation): + def update(self, container, context): layer = container.pop("layer") - + repre_doc = context["representation"] with photoshop.maintained_selection(): stub.replace_smart_object( - layer, get_representation_path(representation) + layer, get_representation_path(repre_doc) ) stub.imprint( - layer, {"representation": str(representation["_id"])} + layer, {"representation": str(repre_doc["_id"])} ) def remove(self, container): container["layer"].Delete() - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) ``` For easier debugging of Javascript: https://community.adobe.com/t5/download-install/adobe-extension-debuger-problem/td-p/10911704?page=1 diff --git a/client/ayon_core/hosts/photoshop/plugins/load/load_image.py b/client/ayon_core/hosts/photoshop/plugins/load/load_image.py index 0fa6bca901..ec6392bade 100644 --- a/client/ayon_core/hosts/photoshop/plugins/load/load_image.py +++ b/client/ayon_core/hosts/photoshop/plugins/load/load_image.py @@ -36,13 +36,13 @@ def load(self, context, name=None, namespace=None, data=None): self.__class__.__name__ ) - def update(self, container, representation): + def update(self, container, context): """ Switch asset or change version """ stub = self.get_stub() layer = container.pop("layer") - context = representation.get("context", {}) + repre_doc = context["representation"] namespace_from_container = re.sub(r'_\d{3}$', '', container["namespace"]) @@ -55,14 +55,14 @@ def update(self, container, representation): else: # switching version - keep same name layer_name = container["namespace"] - path = get_representation_path(representation) + path = get_representation_path(repre_doc) with photoshop.maintained_selection(): stub.replace_smart_object( layer, path, layer_name ) stub.imprint( - layer.id, {"representation": str(representation["_id"])} + layer.id, {"representation": str(repre_doc["_id"])} ) def remove(self, container): @@ -77,8 +77,8 @@ def remove(self, container): stub.imprint(layer.id, {}) stub.delete_layer(layer.id) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def import_layer(self, file_name, layer_name, stub): return stub.import_smart_object(file_name, layer_name) diff --git a/client/ayon_core/hosts/photoshop/plugins/load/load_image_from_sequence.py b/client/ayon_core/hosts/photoshop/plugins/load/load_image_from_sequence.py index 06ac70041e..49ca513bd2 100644 --- a/client/ayon_core/hosts/photoshop/plugins/load/load_image_from_sequence.py +++ b/client/ayon_core/hosts/photoshop/plugins/load/load_image_from_sequence.py @@ -86,7 +86,7 @@ def get_options(cls, repre_contexts): ) ] - def update(self, container, representation): + def update(self, container, context): """No update possible, not containerized.""" pass diff --git a/client/ayon_core/hosts/photoshop/plugins/load/load_reference.py b/client/ayon_core/hosts/photoshop/plugins/load/load_reference.py index e2fec039d0..f83272f97d 100644 --- a/client/ayon_core/hosts/photoshop/plugins/load/load_reference.py +++ b/client/ayon_core/hosts/photoshop/plugins/load/load_reference.py @@ -37,32 +37,37 @@ def load(self, context, name=None, namespace=None, data=None): self.__class__.__name__ ) - def update(self, container, representation): + def update(self, container, context): """ Switch asset or change version """ stub = self.get_stub() layer = container.pop("layer") - context = representation.get("context", {}) + asset_doc = context["asset"] + subset_doc = context["subset"] + repre_doc = context["representation"] + + folder_name = asset_doc["name"] + product_name = subset_doc["name"] namespace_from_container = re.sub(r'_\d{3}$', '', container["namespace"]) - layer_name = "{}_{}".format(context["asset"], context["subset"]) + layer_name = "{}_{}".format(folder_name, product_name) # switching assets if namespace_from_container != layer_name: layer_name = get_unique_layer_name( - stub.get_layers(), context["asset"], context["subset"] + stub.get_layers(), folder_name, product_name ) else: # switching version - keep same name layer_name = container["namespace"] - path = get_representation_path(representation) + path = get_representation_path(repre_doc) with photoshop.maintained_selection(): stub.replace_smart_object( layer, path, layer_name ) stub.imprint( - layer.id, {"representation": str(representation["_id"])} + layer.id, {"representation": str(repre_doc["_id"])} ) def remove(self, container): @@ -76,8 +81,8 @@ def remove(self, container): stub.imprint(layer.id, {}) stub.delete_layer(layer.id) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def import_layer(self, file_name, layer_name, stub): return stub.import_smart_object( From c575d081e48e1737af00494cb2a1da0c091de249 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 26 Feb 2024 17:54:30 +0100 Subject: [PATCH 14/50] resolve load plugins are expecting representation context --- client/ayon_core/hosts/resolve/api/plugin.py | 2 +- .../hosts/resolve/plugins/load/load_clip.py | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/client/ayon_core/hosts/resolve/api/plugin.py b/client/ayon_core/hosts/resolve/api/plugin.py index ccb20f712f..42c88000f0 100644 --- a/client/ayon_core/hosts/resolve/api/plugin.py +++ b/client/ayon_core/hosts/resolve/api/plugin.py @@ -538,7 +538,7 @@ def load( ): pass - def update(self, container, representation): + def update(self, container, context): """Update an existing `container` """ pass diff --git a/client/ayon_core/hosts/resolve/plugins/load/load_clip.py b/client/ayon_core/hosts/resolve/plugins/load/load_clip.py index 47aeac213b..2579b6a735 100644 --- a/client/ayon_core/hosts/resolve/plugins/load/load_clip.py +++ b/client/ayon_core/hosts/resolve/plugins/load/load_clip.py @@ -59,21 +59,21 @@ def load(self, context, name, namespace, options): self.__class__.__name__, data_imprint) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) - def update(self, container, representation): + def update(self, container, context): """ Updating previously loaded clips """ - context = get_representation_context(representation) + repre_doc = context["representation"] name = container['name'] namespace = container['namespace'] timeline_item = container["_timeline_item"] media_pool_item = timeline_item.GetMediaPoolItem() - files = plugin.get_representation_files(representation) + files = plugin.get_representation_files(repre_doc) loader = plugin.ClipLoader(self, context) timeline_item = loader.update(timeline_item, files) @@ -92,10 +92,10 @@ def update(self, container, representation): def get_tag_data(self, context, name, namespace): """Return data to be imprinted on the timeline item marker""" - representation = context["representation"] - version = context['version'] - version_data = version.get("data", {}) - version_name = version.get("name", None) + repre_doc = context["representation"] + version_doc = context["version"] + version_data = version_doc.get("data", {}) + version_name = version_doc.get("name", None) colorspace = version_data.get("colorspace", None) object_name = "{}_{}".format(name, namespace) @@ -111,7 +111,7 @@ def get_tag_data(self, context, name, namespace): # add variables related to version context data.update({ - "representation": str(representation["_id"]), + "representation": str(repre_doc["_id"]), "version": version_name, "colorspace": colorspace, "objectName": object_name From 05e8ebabe62acc1cf16bcc4850045ec17aac00d8 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 26 Feb 2024 17:54:35 +0100 Subject: [PATCH 15/50] nuke load plugins are expecting representation context --- .../hosts/nuke/plugins/load/load_backdrop.py | 15 ++++++----- .../nuke/plugins/load/load_camera_abc.py | 14 +++++----- .../hosts/nuke/plugins/load/load_clip.py | 26 ++++++++++--------- .../hosts/nuke/plugins/load/load_effects.py | 15 ++++++----- .../nuke/plugins/load/load_effects_ip.py | 15 ++++++----- .../hosts/nuke/plugins/load/load_gizmo.py | 15 ++++++----- .../hosts/nuke/plugins/load/load_gizmo_ip.py | 15 ++++++----- .../hosts/nuke/plugins/load/load_image.py | 20 +++++++------- .../hosts/nuke/plugins/load/load_model.py | 16 ++++++------ .../hosts/nuke/plugins/load/load_ociolook.py | 15 +++++------ .../nuke/plugins/load/load_script_precomp.py | 16 +++++++----- 11 files changed, 96 insertions(+), 86 deletions(-) diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_backdrop.py b/client/ayon_core/hosts/nuke/plugins/load/load_backdrop.py index ed512c86ab..642e20c979 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_backdrop.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_backdrop.py @@ -178,7 +178,7 @@ def load(self, context, name, namespace, data): loader=self.__class__.__name__, data=data_imprint) - def update(self, container, representation): + def update(self, container, context): """Update the Loader's path Nuke automatically tries to reset some variables when changing @@ -189,13 +189,14 @@ def update(self, container, representation): # get main variables # Get version from io - project_name = get_current_project_name() - version_doc = get_version_by_id(project_name, representation["parent"]) + project_name = context["project"]["name"] + version_doc = context["version"] + repre_doc = context["representation"] # get corresponding node GN = container["node"] - file = get_representation_path(representation).replace("\\", "/") + file = get_representation_path(repre_doc).replace("\\", "/") name = container['name'] version_data = version_doc.get("data", {}) @@ -207,7 +208,7 @@ def update(self, container, representation): add_keys = ["source", "author", "fps"] data_imprint = { - "representation": str(representation["_id"]), + "representation": str(repre_doc["_id"]), "version": vname, "colorspaceInput": colorspace, } @@ -248,8 +249,8 @@ def update(self, container, representation): return update_container(GN, data_imprint) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): node = container["node"] diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_camera_abc.py b/client/ayon_core/hosts/nuke/plugins/load/load_camera_abc.py index 919a3beb06..e3511a4e8b 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_camera_abc.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_camera_abc.py @@ -92,7 +92,7 @@ def load(self, context, name, namespace, data): loader=self.__class__.__name__, data=data_imprint) - def update(self, container, representation): + def update(self, container, context): """ Called by Scene Inventory when look should be updated to current version. @@ -109,8 +109,8 @@ def update(self, container, representation): None """ # Get version from io - project_name = get_current_project_name() - version_doc = get_version_by_id(project_name, representation["parent"]) + version_doc = context["version"] + repre_doc = context["representation"] # get main variables version_data = version_doc.get("data", {}) @@ -124,7 +124,7 @@ def update(self, container, representation): add_keys = ["source", "author", "fps"] data_imprint = { - "representation": str(representation["_id"]), + "representation": str(repre_doc["_id"]), "frameStart": first, "frameEnd": last, "version": vname @@ -134,7 +134,7 @@ def update(self, container, representation): data_imprint.update({k: version_data[k]}) # getting file path - file = get_representation_path(representation).replace("\\", "/") + file = get_representation_path(repre_doc).replace("\\", "/") with maintained_selection(): camera_node = container["node"] @@ -191,8 +191,8 @@ def node_version_color(self, version_doc, node): color_value = "0xd88467ff" node["tile_color"].setValue(int(color_value, 16)) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): node = container["node"] diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_clip.py b/client/ayon_core/hosts/nuke/plugins/load/load_clip.py index 31b523fbc8..e9e71baa76 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_clip.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_clip.py @@ -209,8 +209,8 @@ def load(self, context, name, namespace, options): return container - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def _representation_with_hash_in_frame(self, representation): """Convert frame key value to padded hash @@ -241,7 +241,7 @@ def _representation_with_hash_in_frame(self, representation): representation["context"]["frame"] = hashed_frame return representation - def update(self, container, representation): + def update(self, container, context): """Update the Loader's path Nuke automatically tries to reset some variables when changing @@ -250,16 +250,18 @@ def update(self, container, representation): """ - is_sequence = len(representation["files"]) > 1 + repre_doc = context["representation"] + + is_sequence = len(repre_doc["files"]) > 1 read_node = container["node"] if is_sequence: - representation = self._representation_with_hash_in_frame( - representation + repre_doc = self._representation_with_hash_in_frame( + repre_doc ) - filepath = get_representation_path(representation).replace("\\", "/") + filepath = get_representation_path(repre_doc).replace("\\", "/") self.log.debug("_ filepath: {}".format(filepath)) start_at_workfile = "start at" in read_node['frame_mode'].value() @@ -270,13 +272,13 @@ def update(self, container, representation): ] project_name = get_current_project_name() - version_doc = get_version_by_id(project_name, representation["parent"]) + version_doc = get_version_by_id(project_name, repre_doc["parent"]) version_data = version_doc.get("data", {}) - repre_id = representation["_id"] + repre_id = repre_doc["_id"] # colorspace profile - colorspace = representation["data"].get("colorspace") + colorspace = repre_doc["data"].get("colorspace") colorspace = colorspace or version_data.get("colorspace") self.handle_start = version_data.get("handleStart", 0) @@ -303,12 +305,12 @@ def update(self, container, representation): # we will switch off undo-ing with viewer_update_and_undo_stop(): used_colorspace = self._set_colorspace( - read_node, version_data, representation["data"], filepath) + read_node, version_data, repre_doc["data"], filepath) self._set_range_to_node(read_node, first, last, start_at_workfile) updated_dict = { - "representation": str(representation["_id"]), + "representation": str(repre_doc["_id"]), "frameStart": str(first), "frameEnd": str(last), "version": str(version_doc.get("name")), diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_effects.py b/client/ayon_core/hosts/nuke/plugins/load/load_effects.py index 0b5f31033e..3e87c9cf60 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_effects.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_effects.py @@ -146,7 +146,7 @@ def load(self, context, name, namespace, data): loader=self.__class__.__name__, data=data_imprint) - def update(self, container, representation): + def update(self, container, context): """Update the Loader's path Nuke automatically tries to reset some variables when changing @@ -156,13 +156,14 @@ def update(self, container, representation): """ # get main variables # Get version from io - project_name = get_current_project_name() - version_doc = get_version_by_id(project_name, representation["parent"]) + project_name = context["project"]["name"] + version_doc = context["version"] + repre_doc = context["representation"] # get corresponding node GN = container["node"] - file = get_representation_path(representation).replace("\\", "/") + file = get_representation_path(repre_doc).replace("\\", "/") name = container['name'] version_data = version_doc.get("data", {}) vname = version_doc.get("name", None) @@ -177,7 +178,7 @@ def update(self, container, representation): "source", "author", "fps"] data_imprint = { - "representation": str(representation["_id"]), + "representation": str(repre_doc["_id"]), "frameStart": first, "frameEnd": last, "version": vname, @@ -344,8 +345,8 @@ def byteify(self, input): else: return input - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): node = container["node"] diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_effects_ip.py b/client/ayon_core/hosts/nuke/plugins/load/load_effects_ip.py index 4d8a8518f2..5c363cddc4 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_effects_ip.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_effects_ip.py @@ -150,7 +150,7 @@ def load(self, context, name, namespace, data): loader=self.__class__.__name__, data=data_imprint) - def update(self, container, representation): + def update(self, container, context): """Update the Loader's path Nuke automatically tries to reset some variables when changing @@ -161,13 +161,14 @@ def update(self, container, representation): # get main variables # Get version from io - project_name = get_current_project_name() - version_doc = get_version_by_id(project_name, representation["parent"]) + project_name = context["project"]["name"] + version_doc = context["version"] + repre_doc = context["representation"] # get corresponding node GN = container["node"] - file = get_representation_path(representation).replace("\\", "/") + file = get_representation_path(repre_doc).replace("\\", "/") version_data = version_doc.get("data", {}) vname = version_doc.get("name", None) first = version_data.get("frameStart", None) @@ -179,7 +180,7 @@ def update(self, container, representation): "source", "author", "fps"] data_imprint = { - "representation": str(representation["_id"]), + "representation": str(repre_doc["_id"]), "frameStart": first, "frameEnd": last, "version": vname, @@ -355,8 +356,8 @@ def byteify(self, input): else: return input - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): node = container["node"] diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_gizmo.py b/client/ayon_core/hosts/nuke/plugins/load/load_gizmo.py index 54daa74405..058228a145 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_gizmo.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_gizmo.py @@ -97,7 +97,7 @@ def load(self, context, name, namespace, data): loader=self.__class__.__name__, data=data_imprint) - def update(self, container, representation): + def update(self, container, context): """Update the Loader's path Nuke automatically tries to reset some variables when changing @@ -108,13 +108,14 @@ def update(self, container, representation): # get main variables # Get version from io - project_name = get_current_project_name() - version_doc = get_version_by_id(project_name, representation["parent"]) + project_name = context["project"]["name"] + version_doc = context["version"] + repre_doc = context["representation"] # get corresponding node group_node = container["node"] - file = get_representation_path(representation).replace("\\", "/") + file = get_representation_path(repre_doc).replace("\\", "/") name = container['name'] version_data = version_doc.get("data", {}) vname = version_doc.get("name", None) @@ -128,7 +129,7 @@ def update(self, container, representation): "source", "author", "fps"] data_imprint = { - "representation": str(representation["_id"]), + "representation": str(repre_doc["_id"]), "frameStart": first, "frameEnd": last, "version": vname, @@ -173,8 +174,8 @@ def update(self, container, representation): return update_container(new_group_node, data_imprint) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): node = container["node"] diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_gizmo_ip.py b/client/ayon_core/hosts/nuke/plugins/load/load_gizmo_ip.py index 677d9868f1..61e1c34028 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_gizmo_ip.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_gizmo_ip.py @@ -104,7 +104,7 @@ def load(self, context, name, namespace, data): loader=self.__class__.__name__, data=data_imprint) - def update(self, container, representation): + def update(self, container, context): """Update the Loader's path Nuke automatically tries to reset some variables when changing @@ -115,13 +115,14 @@ def update(self, container, representation): # get main variables # Get version from io - project_name = get_current_project_name() - version_doc = get_version_by_id(project_name, representation["parent"]) + project_name = context["project"]["name"] + version_doc = context["version"] + repre_doc = context["representation"] # get corresponding node group_node = container["node"] - file = get_representation_path(representation).replace("\\", "/") + file = get_representation_path(repre_doc).replace("\\", "/") name = container['name'] version_data = version_doc.get("data", {}) vname = version_doc.get("name", None) @@ -135,7 +136,7 @@ def update(self, container, representation): "source", "author", "fps"] data_imprint = { - "representation": str(representation["_id"]), + "representation": str(repre_doc["_id"]), "frameStart": first, "frameEnd": last, "version": vname, @@ -254,8 +255,8 @@ def byteify(self, input): else: return input - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): node = container["node"] diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_image.py b/client/ayon_core/hosts/nuke/plugins/load/load_image.py index e9435ec10a..4f7a5ccc27 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_image.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_image.py @@ -155,10 +155,10 @@ def load(self, context, name, namespace, options): loader=self.__class__.__name__, data=data_imprint) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) - def update(self, container, representation): + def update(self, container, context): """Update the Loader's path Nuke automatically tries to reset some variables when changing @@ -171,12 +171,16 @@ def update(self, container, representation): assert node.Class() == "Read", "Must be Read" - repr_cont = representation["context"] + project_name = context["project"]["name"] + version_doc = context["version"] + repre_doc = context["representation"] + + repr_cont = repre_doc["context"] - file = get_representation_path(representation) + file = get_representation_path(repre_doc) if not file: - repr_id = representation["_id"] + repr_id = repre_doc["_id"] self.log.warning( "Representation id `{}` is failing to load".format(repr_id)) return @@ -191,8 +195,6 @@ def update(self, container, representation): format(frame_number, "0{}".format(padding))) # Get start frame from version data - project_name = get_current_project_name() - version_doc = get_version_by_id(project_name, representation["parent"]) last_version_doc = get_last_version_by_subset_id( project_name, version_doc["parent"], fields=["_id"] ) @@ -210,7 +212,7 @@ def update(self, container, representation): updated_dict = {} updated_dict.update({ - "representation": str(representation["_id"]), + "representation": str(repre_doc["_id"]), "frameStart": str(first), "frameEnd": str(last), "version": str(version_doc.get("name")), diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_model.py b/client/ayon_core/hosts/nuke/plugins/load/load_model.py index 125cb28e27..cd4b72df91 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_model.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_model.py @@ -96,7 +96,7 @@ def load(self, context, name, namespace, data): loader=self.__class__.__name__, data=data_imprint) - def update(self, container, representation): + def update(self, container, context): """ Called by Scene Inventory when look should be updated to current version. @@ -106,15 +106,15 @@ def update(self, container, representation): Args: container: object that has look to be updated - representation: (dict): relationship data to get proper + context: (dict): relationship data to get proper representation from DB and persisted data in .json Returns: None """ # Get version from io - project_name = get_current_project_name() - version_doc = get_version_by_id(project_name, representation["parent"]) + version_doc = context["version"] + repre_doc = context["representation"] # get corresponding node model_node = container["node"] @@ -131,7 +131,7 @@ def update(self, container, representation): add_keys = ["source", "author", "fps"] data_imprint = { - "representation": str(representation["_id"]), + "representation": str(repre_doc["_id"]), "frameStart": first, "frameEnd": last, "version": vname @@ -141,7 +141,7 @@ def update(self, container, representation): data_imprint.update({k: version_data[k]}) # getting file path - file = get_representation_path(representation).replace("\\", "/") + file = get_representation_path(repre_doc).replace("\\", "/") with maintained_selection(): model_node['selected'].setValue(True) @@ -202,8 +202,8 @@ def node_version_color(self, version, node): color_value = "0xd88467ff" node["tile_color"].setValue(int(color_value, 16)) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): node = nuke.toNode(container['objectName']) diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_ociolook.py b/client/ayon_core/hosts/nuke/plugins/load/load_ociolook.py index e168c2bac1..e2e7cd3262 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_ociolook.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_ociolook.py @@ -219,14 +219,13 @@ def _create_group_node( return group_node - def update(self, container, representation): - - project_name = get_current_project_name() - version_doc = get_version_by_id(project_name, representation["parent"]) + def update(self, container, context): + version_doc = context["version"] + repre_doc = context["representation"] group_node = container["node"] - filepath = get_representation_path(representation) + filepath = get_representation_path(repre_doc) json_f = self._load_json_data(filepath) @@ -242,7 +241,7 @@ def update(self, container, representation): group_node["name"].value())) return update_container( - group_node, {"representation": str(representation["_id"])}) + group_node, {"representation": str(repre_doc["_id"])}) def _load_json_data(self, filepath): # getting data from json file with unicode conversion @@ -280,8 +279,8 @@ def _bytify(self, input): else: return input - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): node = nuke.toNode(container['objectName']) diff --git a/client/ayon_core/hosts/nuke/plugins/load/load_script_precomp.py b/client/ayon_core/hosts/nuke/plugins/load/load_script_precomp.py index 1c91e51a09..5d62a7ca0f 100644 --- a/client/ayon_core/hosts/nuke/plugins/load/load_script_precomp.py +++ b/client/ayon_core/hosts/nuke/plugins/load/load_script_precomp.py @@ -104,10 +104,10 @@ def load(self, context, name, namespace, data): loader=self.__class__.__name__, data=data_imprint) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) - def update(self, container, representation): + def update(self, container, context): """Update the Loader's path Nuke automatically tries to reset some variables when changing @@ -117,11 +117,13 @@ def update(self, container, representation): """ node = container["node"] - root = get_representation_path(representation).replace("\\", "/") + project_name = context["project"]["name"] + version_doc = context["version"] + repre_doc = context["representation"] + + root = get_representation_path(repre_doc).replace("\\", "/") # Get start frame from version data - project_name = get_current_project_name() - version_doc = get_version_by_id(project_name, representation["parent"]) last_version_doc = get_last_version_by_subset_id( project_name, version_doc["parent"], fields=["_id"] ) @@ -129,7 +131,7 @@ def update(self, container, representation): updated_dict = {} version_data = version_doc["data"] updated_dict.update({ - "representation": str(representation["_id"]), + "representation": str(repre_doc["_id"]), "frameEnd": version_data.get("frameEnd"), "version": version_doc.get("name"), "colorspace": version_data.get("colorspace"), From 1db78bafd31afcc818616ee718c071c8aa4c876c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 26 Feb 2024 17:55:44 +0100 Subject: [PATCH 16/50] aftereffects load plugins are expecting representation context --- .../plugins/load/load_background.py | 25 +++++++++++-------- .../aftereffects/plugins/load/load_file.py | 23 ++++++++++------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/client/ayon_core/hosts/aftereffects/plugins/load/load_background.py b/client/ayon_core/hosts/aftereffects/plugins/load/load_background.py index f23d7ec0bd..b834875e89 100644 --- a/client/ayon_core/hosts/aftereffects/plugins/load/load_background.py +++ b/client/ayon_core/hosts/aftereffects/plugins/load/load_background.py @@ -11,7 +11,7 @@ class BackgroundLoader(api.AfterEffectsLoader): """ - Load images from Background family + Load images from Background product type Creates for each background separate folder with all imported images from background json AND automatically created composition with layers, each layer for separate image. @@ -56,16 +56,21 @@ def load(self, context, name=None, namespace=None, data=None): self.__class__.__name__ ) - def update(self, container, representation): + def update(self, container, context): """ Switch asset or change version """ stub = self.get_stub() - context = representation.get("context", {}) + asset_doc = context["asset"] + subset_doc = context["subset"] + repre_doc = context["representation"] + + folder_name = asset_doc["name"] + product_name = subset_doc["name"] _ = container.pop("layer") # without iterator number (_001, 002...) namespace_from_container = re.sub(r'_\d{3}$', '', container["namespace"]) - comp_name = "{}_{}".format(context["asset"], context["subset"]) + comp_name = "{}_{}".format(folder_name, product_name) # switching assets if namespace_from_container != comp_name: @@ -73,11 +78,11 @@ def update(self, container, representation): existing_items = [layer.name for layer in items] comp_name = get_unique_layer_name( existing_items, - "{}_{}".format(context["asset"], context["subset"])) + "{}_{}".format(folder_name, product_name)) else: # switching version - keep same name comp_name = container["namespace"] - path = get_representation_path(representation) + path = get_representation_path(repre_doc) layers = get_background_layers(path) comp = stub.reload_background(container["members"][1], @@ -85,8 +90,8 @@ def update(self, container, representation): layers) # update container - container["representation"] = str(representation["_id"]) - container["name"] = context["subset"] + container["representation"] = str(repre_doc["_id"]) + container["name"] = product_name container["namespace"] = comp_name container["members"] = comp.members @@ -104,5 +109,5 @@ def remove(self, container): stub.imprint(layer.id, {}) stub.delete_item(layer.id) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) diff --git a/client/ayon_core/hosts/aftereffects/plugins/load/load_file.py b/client/ayon_core/hosts/aftereffects/plugins/load/load_file.py index a8e67e9f88..bceea66e8e 100644 --- a/client/ayon_core/hosts/aftereffects/plugins/load/load_file.py +++ b/client/ayon_core/hosts/aftereffects/plugins/load/load_file.py @@ -64,31 +64,36 @@ def load(self, context, name=None, namespace=None, data=None): self.__class__.__name__ ) - def update(self, container, representation): + def update(self, container, context): """ Switch asset or change version """ stub = self.get_stub() layer = container.pop("layer") - context = representation.get("context", {}) + asset_doc = context["asset"] + subset_doc = context["subset"] + repre_doc = context["representation"] + + folder_name = asset_doc["name"] + product_name = subset_doc["name"] namespace_from_container = re.sub(r'_\d{3}$', '', container["namespace"]) - layer_name = "{}_{}".format(context["asset"], context["subset"]) + layer_name = "{}_{}".format(folder_name, product_name) # switching assets if namespace_from_container != layer_name: layers = stub.get_items(comps=True) existing_layers = [layer.name for layer in layers] layer_name = get_unique_layer_name( existing_layers, - "{}_{}".format(context["asset"], context["subset"])) + "{}_{}".format(folder_name, product_name)) else: # switching version - keep same name layer_name = container["namespace"] - path = get_representation_path(representation) + path = get_representation_path(repre_doc) # with aftereffects.maintained_selection(): # TODO stub.replace_item(layer.id, path, stub.LOADED_ICON + layer_name) stub.imprint( - layer.id, {"representation": str(representation["_id"]), - "name": context["subset"], + layer.id, {"representation": str(repre_doc["_id"]), + "name": product_name, "namespace": layer_name} ) @@ -103,5 +108,5 @@ def remove(self, container): stub.imprint(layer.id, {}) stub.delete_item(layer.id) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) From cd74ae7d88b85584e700d5a9ead35ae746ee6bcf Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 26 Feb 2024 17:56:25 +0100 Subject: [PATCH 17/50] blender load plugins are expecting representation context --- client/ayon_core/hosts/blender/api/plugin.py | 6 +++--- .../ayon_core/hosts/blender/plugins/load/load_abc.py | 9 +++++---- .../hosts/blender/plugins/load/load_action.py | 10 +++++----- .../hosts/blender/plugins/load/load_audio.py | 11 ++++++----- .../hosts/blender/plugins/load/load_blend.py | 9 +++++---- .../hosts/blender/plugins/load/load_blendscene.py | 9 +++++---- .../hosts/blender/plugins/load/load_camera_abc.py | 9 +++++---- .../hosts/blender/plugins/load/load_camera_fbx.py | 9 +++++---- .../ayon_core/hosts/blender/plugins/load/load_fbx.py | 9 +++++---- .../hosts/blender/plugins/load/load_layout_json.py | 9 +++++---- .../ayon_core/hosts/blender/plugins/load/load_look.py | 9 +++++---- 11 files changed, 54 insertions(+), 45 deletions(-) diff --git a/client/ayon_core/hosts/blender/api/plugin.py b/client/ayon_core/hosts/blender/api/plugin.py index d72754f148..8d72c488e5 100644 --- a/client/ayon_core/hosts/blender/api/plugin.py +++ b/client/ayon_core/hosts/blender/api/plugin.py @@ -507,13 +507,13 @@ def _load(self, # return self._get_instance_collection(instance_name, nodes) - def exec_update(self, container: Dict, representation: Dict): + def exec_update(self, container: Dict, context: Dict): """Must be implemented by a sub-class""" raise NotImplementedError("Must be implemented by a sub-class") - def update(self, container: Dict, representation: Dict): + def update(self, container: Dict, context: Dict): """ Run the update on Blender main thread""" - mti = MainThreadItem(self.exec_update, container, representation) + mti = MainThreadItem(self.exec_update, container, context) execute_in_main_thread(mti) def exec_remove(self, container: Dict) -> bool: diff --git a/client/ayon_core/hosts/blender/plugins/load/load_abc.py b/client/ayon_core/hosts/blender/plugins/load/load_abc.py index b25f4eb277..23c919ac59 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_abc.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_abc.py @@ -176,7 +176,7 @@ def process_asset( self[:] = objects return objects - def exec_update(self, container: Dict, representation: Dict): + def exec_update(self, container: Dict, context: Dict): """Update the loaded asset. This will remove all objects of the current collection, load the new @@ -188,15 +188,16 @@ def exec_update(self, container: Dict, representation: Dict): Warning: No nested collections are supported at the moment! """ + repre_doc = context["representation"] object_name = container["objectName"] asset_group = bpy.data.objects.get(object_name) - libpath = Path(get_representation_path(representation)) + libpath = Path(get_representation_path(repre_doc)) extension = libpath.suffix.lower() self.log.info( "Container: %s\nRepresentation: %s", pformat(container, indent=2), - pformat(representation, indent=2), + pformat(repre_doc, indent=2), ) assert asset_group, ( @@ -241,7 +242,7 @@ def exec_update(self, container: Dict, representation: Dict): asset_group.matrix_basis = mat metadata["libpath"] = str(libpath) - metadata["representation"] = str(representation["_id"]) + metadata["representation"] = str(repre_doc["_id"]) def exec_remove(self, container: Dict) -> bool: """Remove an existing container from a Blender scene. diff --git a/client/ayon_core/hosts/blender/plugins/load/load_action.py b/client/ayon_core/hosts/blender/plugins/load/load_action.py index 5c8ba0df44..9afcefbab5 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_action.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_action.py @@ -114,7 +114,7 @@ def process_asset( self[:] = nodes return nodes - def update(self, container: Dict, representation: Dict): + def update(self, container: Dict, context: Dict): """Update the loaded asset. This will remove all objects of the current collection, load the new @@ -126,18 +126,18 @@ def update(self, container: Dict, representation: Dict): Warning: No nested collections are supported at the moment! """ - + repre_doc = context["representation"] collection = bpy.data.collections.get( container["objectName"] ) - libpath = Path(get_representation_path(representation)) + libpath = Path(get_representation_path(repre_doc)) extension = libpath.suffix.lower() logger.info( "Container: %s\nRepresentation: %s", pformat(container, indent=2), - pformat(representation, indent=2), + pformat(repre_doc, indent=2), ) assert collection, ( @@ -241,7 +241,7 @@ def update(self, container: Dict, representation: Dict): # Save the list of objects in the metadata container collection_metadata["objects"] = objects_list collection_metadata["libpath"] = str(libpath) - collection_metadata["representation"] = str(representation["_id"]) + collection_metadata["representation"] = str(repre_doc["_id"]) bpy.ops.object.select_all(action='DESELECT') diff --git a/client/ayon_core/hosts/blender/plugins/load/load_audio.py b/client/ayon_core/hosts/blender/plugins/load/load_audio.py index 007889f6f6..62b0586eb2 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_audio.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_audio.py @@ -94,7 +94,7 @@ def process_asset( self[:] = objects return [objects] - def exec_update(self, container: Dict, representation: Dict): + def exec_update(self, container: Dict, context: Dict): """Update an audio strip in the sequence editor. Arguments: @@ -103,14 +103,15 @@ def exec_update(self, container: Dict, representation: Dict): representation (openpype:representation-1.0): Representation to update, from `host.ls()`. """ + repre_doc = context["representation"] object_name = container["objectName"] asset_group = bpy.data.objects.get(object_name) - libpath = Path(get_representation_path(representation)) + libpath = Path(get_representation_path(repre_doc)) self.log.info( "Container: %s\nRepresentation: %s", pformat(container, indent=2), - pformat(representation, indent=2), + pformat(repre_doc, indent=2), ) assert asset_group, ( @@ -173,8 +174,8 @@ def exec_update(self, container: Dict, representation: Dict): window_manager.windows[-1].screen.areas[0].type = old_type metadata["libpath"] = str(libpath) - metadata["representation"] = str(representation["_id"]) - metadata["parent"] = str(representation["parent"]) + metadata["representation"] = str(repre_doc["_id"]) + metadata["parent"] = str(repre_doc["parent"]) metadata["audio"] = new_audio def exec_remove(self, container: Dict) -> bool: diff --git a/client/ayon_core/hosts/blender/plugins/load/load_blend.py b/client/ayon_core/hosts/blender/plugins/load/load_blend.py index c9862f9841..cec800a557 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_blend.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_blend.py @@ -179,13 +179,14 @@ def process_asset( self[:] = objects return objects - def exec_update(self, container: Dict, representation: Dict): + def exec_update(self, container: Dict, context: Dict): """ Update the loaded asset. """ + repre_doc = context["representation"] group_name = container["objectName"] asset_group = bpy.data.objects.get(group_name) - libpath = Path(get_representation_path(representation)).as_posix() + libpath = Path(get_representation_path(repre_doc)).as_posix() assert asset_group, ( f"The asset is not loaded: {container['objectName']}" @@ -232,8 +233,8 @@ def exec_update(self, container: Dict, representation: Dict): new_data = { "libpath": libpath, - "representation": str(representation["_id"]), - "parent": str(representation["parent"]), + "representation": str(repre_doc["_id"]), + "parent": str(repre_doc["parent"]), "members": members, } diff --git a/client/ayon_core/hosts/blender/plugins/load/load_blendscene.py b/client/ayon_core/hosts/blender/plugins/load/load_blendscene.py index 248bf5a901..d9491c0749 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_blendscene.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_blendscene.py @@ -129,13 +129,14 @@ def process_asset( self[:] = objects return objects - def exec_update(self, container: Dict, representation: Dict): + def exec_update(self, container: Dict, context: Dict): """ Update the loaded asset. """ + repre_doc = context["representation"] group_name = container["objectName"] asset_group = bpy.data.collections.get(group_name) - libpath = Path(get_representation_path(representation)).as_posix() + libpath = Path(get_representation_path(repre_doc)).as_posix() assert asset_group, ( f"The asset is not loaded: {container['objectName']}" @@ -193,8 +194,8 @@ def exec_update(self, container: Dict, representation: Dict): new_data = { "libpath": libpath, - "representation": str(representation["_id"]), - "parent": str(representation["parent"]), + "representation": str(repre_doc["_id"]), + "parent": str(repre_doc["parent"]), "members": members, } diff --git a/client/ayon_core/hosts/blender/plugins/load/load_camera_abc.py b/client/ayon_core/hosts/blender/plugins/load/load_camera_abc.py index 8f0bd6741d..0a111b54d0 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_camera_abc.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_camera_abc.py @@ -128,7 +128,7 @@ def process_asset( self[:] = objects return objects - def exec_update(self, container: Dict, representation: Dict): + def exec_update(self, container: Dict, context: Dict): """Update the loaded asset. This will remove all objects of the current collection, load the new @@ -140,15 +140,16 @@ def exec_update(self, container: Dict, representation: Dict): Warning: No nested collections are supported at the moment! """ + repre_doc = context["representation"] object_name = container["objectName"] asset_group = bpy.data.objects.get(object_name) - libpath = Path(get_representation_path(representation)) + libpath = Path(get_representation_path(repre_doc)) extension = libpath.suffix.lower() self.log.info( "Container: %s\nRepresentation: %s", pformat(container, indent=2), - pformat(representation, indent=2), + pformat(repre_doc, indent=2), ) assert asset_group, ( @@ -183,7 +184,7 @@ def exec_update(self, container: Dict, representation: Dict): asset_group.matrix_basis = mat metadata["libpath"] = str(libpath) - metadata["representation"] = str(representation["_id"]) + metadata["representation"] = str(repre_doc["_id"]) def exec_remove(self, container: Dict) -> bool: """Remove an existing container from a Blender scene. diff --git a/client/ayon_core/hosts/blender/plugins/load/load_camera_fbx.py b/client/ayon_core/hosts/blender/plugins/load/load_camera_fbx.py index 7642871dc7..4c512cbeaa 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_camera_fbx.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_camera_fbx.py @@ -131,7 +131,7 @@ def process_asset( self[:] = objects return objects - def exec_update(self, container: Dict, representation: Dict): + def exec_update(self, container: Dict, context: Dict): """Update the loaded asset. This will remove all objects of the current collection, load the new @@ -143,15 +143,16 @@ def exec_update(self, container: Dict, representation: Dict): Warning: No nested collections are supported at the moment! """ + repre_doc = context["representation"] object_name = container["objectName"] asset_group = bpy.data.objects.get(object_name) - libpath = Path(get_representation_path(representation)) + libpath = Path(get_representation_path(repre_doc)) extension = libpath.suffix.lower() self.log.info( "Container: %s\nRepresentation: %s", pformat(container, indent=2), - pformat(representation, indent=2), + pformat(repre_doc, indent=2), ) assert asset_group, ( @@ -193,7 +194,7 @@ def exec_update(self, container: Dict, representation: Dict): asset_group.matrix_basis = mat metadata["libpath"] = str(libpath) - metadata["representation"] = str(representation["_id"]) + metadata["representation"] = str(repre_doc["_id"]) def exec_remove(self, container: Dict) -> bool: """Remove an existing container from a Blender scene. diff --git a/client/ayon_core/hosts/blender/plugins/load/load_fbx.py b/client/ayon_core/hosts/blender/plugins/load/load_fbx.py index 03993c9f5e..977e3db970 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_fbx.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_fbx.py @@ -175,7 +175,7 @@ def process_asset( self[:] = objects return objects - def exec_update(self, container: Dict, representation: Dict): + def exec_update(self, container: Dict, context: Dict): """Update the loaded asset. This will remove all objects of the current collection, load the new @@ -187,15 +187,16 @@ def exec_update(self, container: Dict, representation: Dict): Warning: No nested collections are supported at the moment! """ + repre_doc = context["representation"] object_name = container["objectName"] asset_group = bpy.data.objects.get(object_name) - libpath = Path(get_representation_path(representation)) + libpath = Path(get_representation_path(repre_doc)) extension = libpath.suffix.lower() self.log.info( "Container: %s\nRepresentation: %s", pformat(container, indent=2), - pformat(representation, indent=2), + pformat(repre_doc, indent=2), ) assert asset_group, ( @@ -248,7 +249,7 @@ def exec_update(self, container: Dict, representation: Dict): asset_group.matrix_basis = mat metadata["libpath"] = str(libpath) - metadata["representation"] = str(representation["_id"]) + metadata["representation"] = str(repre_doc["_id"]) def exec_remove(self, container: Dict) -> bool: """Remove an existing container from a Blender scene. diff --git a/client/ayon_core/hosts/blender/plugins/load/load_layout_json.py b/client/ayon_core/hosts/blender/plugins/load/load_layout_json.py index f48862a803..740dd9dd53 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_layout_json.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_layout_json.py @@ -184,7 +184,7 @@ def process_asset(self, self[:] = asset_group.children return asset_group.children - def exec_update(self, container: Dict, representation: Dict): + def exec_update(self, container: Dict, context: Dict): """Update the loaded asset. This will remove all objects of the current collection, load the new @@ -193,15 +193,16 @@ def exec_update(self, container: Dict, representation: Dict): will not be removed, only unlinked. Normally this should not be the case though. """ + repre_doc = context["representation"] object_name = container["objectName"] asset_group = bpy.data.objects.get(object_name) - libpath = Path(get_representation_path(representation)) + libpath = Path(get_representation_path(repre_doc)) extension = libpath.suffix.lower() self.log.info( "Container: %s\nRepresentation: %s", pformat(container, indent=2), - pformat(representation, indent=2), + pformat(repre_doc, indent=2), ) assert asset_group, ( @@ -262,7 +263,7 @@ def exec_update(self, container: Dict, representation: Dict): asset_group.matrix_basis = mat metadata["libpath"] = str(libpath) - metadata["representation"] = str(representation["_id"]) + metadata["representation"] = str(repre_doc["_id"]) def exec_remove(self, container: Dict) -> bool: """Remove an existing container from a Blender scene. diff --git a/client/ayon_core/hosts/blender/plugins/load/load_look.py b/client/ayon_core/hosts/blender/plugins/load/load_look.py index f9ebf98912..507c940846 100644 --- a/client/ayon_core/hosts/blender/plugins/load/load_look.py +++ b/client/ayon_core/hosts/blender/plugins/load/load_look.py @@ -138,15 +138,16 @@ def process_asset( self[:] = nodes return nodes - def update(self, container: Dict, representation: Dict): + def update(self, container: Dict, context: Dict): collection = bpy.data.collections.get(container["objectName"]) - libpath = Path(get_representation_path(representation)) + repre_doc = context["representation"] + libpath = Path(get_representation_path(repre_doc)) extension = libpath.suffix.lower() self.log.info( "Container: %s\nRepresentation: %s", pformat(container, indent=2), - pformat(representation, indent=2), + pformat(repre_doc, indent=2), ) assert collection, ( @@ -201,7 +202,7 @@ def update(self, container: Dict, representation: Dict): collection_metadata["objects"] = objects collection_metadata["materials"] = materials collection_metadata["libpath"] = str(libpath) - collection_metadata["representation"] = str(representation["_id"]) + collection_metadata["representation"] = str(repre_doc["_id"]) def remove(self, container: Dict) -> bool: collection = bpy.data.collections.get(container["objectName"]) From 00bfee8289a36f414a4f4897f4d53bbfc70ce876 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 26 Feb 2024 17:56:31 +0100 Subject: [PATCH 18/50] flame load plugins are expecting representation context --- .../hosts/flame/plugins/load/load_clip.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/client/ayon_core/hosts/flame/plugins/load/load_clip.py b/client/ayon_core/hosts/flame/plugins/load/load_clip.py index 47d0331255..72a6f2a585 100644 --- a/client/ayon_core/hosts/flame/plugins/load/load_clip.py +++ b/client/ayon_core/hosts/flame/plugins/load/load_clip.py @@ -11,7 +11,7 @@ class LoadClip(opfapi.ClipLoader): - """Load a subset to timeline as clip + """Load a product to timeline as clip Place clip to timeline on its asset origin timings collected during conforming to project @@ -31,14 +31,14 @@ class LoadClip(opfapi.ClipLoader): # settings reel_group_name = "OpenPype_Reels" reel_name = "Loaded" - clip_name_template = "{asset}_{subset}<_{output}>" + clip_name_template = "{folder[name]}_{product[name]}<_{output}>" """ Anatomy keys from version context data and dynamically added: - {layerName} - original layer name token - {layerUID} - original layer UID token - {originalBasename} - original clip name taken from file """ - layer_rename_template = "{asset}_{subset}<_{output}>" + layer_rename_template = "{folder[name]}_{product[name]}<_{output}>" layer_rename_patterns = [] def load(self, context, name, namespace, options): @@ -180,27 +180,27 @@ def _get_segment_from_clip(self, clip): # unwrapping segment from input clip pass - # def switch(self, container, representation): - # self.update(container, representation) + # def switch(self, container, context): + # self.update(container, context) - # def update(self, container, representation): + # def update(self, container, context): # """ Updating previously loaded clips # """ - # # load clip to timeline and get main variables + # repre_doc = context['representation'] # name = container['name'] # namespace = container['namespace'] # track_item = phiero.get_track_items( # track_item_name=namespace) # version = io.find_one({ # "type": "version", - # "_id": representation["parent"] + # "_id": repre_doc["parent"] # }) # version_data = version.get("data", {}) # version_name = version.get("name", None) # colorspace = version_data.get("colorspace", None) # object_name = "{}_{}".format(name, namespace) - # file = get_representation_path(representation).replace("\\", "/") + # file = get_representation_path(repre_doc).replace("\\", "/") # clip = track_item.source() # # reconnect media to new path @@ -225,7 +225,7 @@ def _get_segment_from_clip(self, clip): # # add variables related to version context # data_imprint.update({ - # "representation": str(representation["_id"]), + # "representation": str(repre_doc["_id"]), # "version": version_name, # "colorspace": colorspace, # "objectName": object_name From 63acc96fd0579762ab1bb4635a19e6ad39d34117 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 26 Feb 2024 17:56:43 +0100 Subject: [PATCH 19/50] fusion load plugins are expecting representation context --- .../hosts/fusion/plugins/load/load_alembic.py | 11 ++++++----- .../ayon_core/hosts/fusion/plugins/load/load_fbx.py | 11 ++++++----- .../hosts/fusion/plugins/load/load_sequence.py | 11 ++++++----- .../ayon_core/hosts/fusion/plugins/load/load_usd.py | 11 ++++++----- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/client/ayon_core/hosts/fusion/plugins/load/load_alembic.py b/client/ayon_core/hosts/fusion/plugins/load/load_alembic.py index 0bc7ffd180..17f043bb34 100644 --- a/client/ayon_core/hosts/fusion/plugins/load/load_alembic.py +++ b/client/ayon_core/hosts/fusion/plugins/load/load_alembic.py @@ -44,23 +44,24 @@ def load(self, context, name, namespace, data): context=context, loader=self.__class__.__name__) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) - def update(self, container, representation): + def update(self, container, context): """Update Alembic path""" tool = container["_tool"] assert tool.ID == self.tool_type, f"Must be {self.tool_type}" comp = tool.Comp() - path = get_representation_path(representation) + repre_doc = context["representation"] + path = get_representation_path(repre_doc) with comp_lock_and_undo_chunk(comp, "Update tool"): tool["Filename"] = path # Update the imprinted representation - tool.SetData("avalon.representation", str(representation["_id"])) + tool.SetData("avalon.representation", str(repre_doc["_id"])) def remove(self, container): tool = container["_tool"] diff --git a/client/ayon_core/hosts/fusion/plugins/load/load_fbx.py b/client/ayon_core/hosts/fusion/plugins/load/load_fbx.py index 3751d7cc39..75320431a8 100644 --- a/client/ayon_core/hosts/fusion/plugins/load/load_fbx.py +++ b/client/ayon_core/hosts/fusion/plugins/load/load_fbx.py @@ -59,23 +59,24 @@ def load(self, context, name, namespace, data): loader=self.__class__.__name__, ) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) - def update(self, container, representation): + def update(self, container, context): """Update path""" tool = container["_tool"] assert tool.ID == self.tool_type, f"Must be {self.tool_type}" comp = tool.Comp() - path = get_representation_path(representation) + repre_doc = context["representation"] + path = get_representation_path(repre_doc) with comp_lock_and_undo_chunk(comp, "Update tool"): tool["ImportFile"] = path # Update the imprinted representation - tool.SetData("avalon.representation", str(representation["_id"])) + tool.SetData("avalon.representation", str(repre_doc["_id"])) def remove(self, container): tool = container["_tool"] diff --git a/client/ayon_core/hosts/fusion/plugins/load/load_sequence.py b/client/ayon_core/hosts/fusion/plugins/load/load_sequence.py index 5c183f5159..753d50ee34 100644 --- a/client/ayon_core/hosts/fusion/plugins/load/load_sequence.py +++ b/client/ayon_core/hosts/fusion/plugins/load/load_sequence.py @@ -175,10 +175,10 @@ def load(self, context, name, namespace, data): loader=self.__class__.__name__, ) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) - def update(self, container, representation): + def update(self, container, context): """Update the Loader's path Fusion automatically tries to reset some variables when changing @@ -224,7 +224,8 @@ def update(self, container, representation): assert tool.ID == "Loader", "Must be Loader" comp = tool.Comp() - context = get_representation_context(representation) + repre_doc = context["representation"] + context = get_representation_context(repre_doc) path = self.filepath_from_context(context) # Get start frame from version data @@ -255,7 +256,7 @@ def update(self, container, representation): ) # Update the imprinted representation - tool.SetData("avalon.representation", str(representation["_id"])) + tool.SetData("avalon.representation", str(repre_doc["_id"])) def remove(self, container): tool = container["_tool"] diff --git a/client/ayon_core/hosts/fusion/plugins/load/load_usd.py b/client/ayon_core/hosts/fusion/plugins/load/load_usd.py index 9c61894d66..a5630fac1b 100644 --- a/client/ayon_core/hosts/fusion/plugins/load/load_usd.py +++ b/client/ayon_core/hosts/fusion/plugins/load/load_usd.py @@ -61,22 +61,23 @@ def load(self, context, name, namespace, data): context=context, loader=self.__class__.__name__) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) - def update(self, container, representation): + def update(self, container, context): tool = container["_tool"] assert tool.ID == self.tool_type, f"Must be {self.tool_type}" comp = tool.Comp() - path = get_representation_path(representation) + repre_doc = context["representation"] + path = get_representation_path(repre_doc) with comp_lock_and_undo_chunk(comp, "Update tool"): tool["Filename"] = path # Update the imprinted representation - tool.SetData("avalon.representation", str(representation["_id"])) + tool.SetData("avalon.representation", str(repre_doc["_id"])) def remove(self, container): tool = container["_tool"] From 1bd67ab083702a5a0c4051abc11057e2a74b2763 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 26 Feb 2024 17:56:50 +0100 Subject: [PATCH 20/50] harmony load plugins are expecting representation context --- client/ayon_core/hosts/harmony/api/README.md | 15 ++++++------ .../hosts/harmony/plugins/load/load_audio.py | 8 +++---- .../harmony/plugins/load/load_background.py | 24 +++++++++++-------- .../plugins/load/load_imagesequence.py | 21 ++++++++-------- .../harmony/plugins/load/load_palette.py | 23 ++++++++++-------- .../harmony/plugins/load/load_template.py | 13 +++++----- .../plugins/load/load_template_workfile.py | 8 +++---- 7 files changed, 61 insertions(+), 51 deletions(-) diff --git a/client/ayon_core/hosts/harmony/api/README.md b/client/ayon_core/hosts/harmony/api/README.md index 457e22fb2e..151b2bce9e 100644 --- a/client/ayon_core/hosts/harmony/api/README.md +++ b/client/ayon_core/hosts/harmony/api/README.md @@ -204,7 +204,7 @@ class CreateComposite(harmony.Creator): name = "compositeDefault" label = "Composite" - family = "mindbender.template" + product_type = "mindbender.template" def __init__(self, *args, **kwargs): super(CreateComposite, self).__init__(*args, **kwargs) @@ -221,7 +221,7 @@ class CreateRender(harmony.Creator): name = "writeDefault" label = "Write" - family = "mindbender.imagesequence" + product_type = "mindbender.imagesequence" node_type = "WRITE" def __init__(self, *args, **kwargs): @@ -611,11 +611,12 @@ class ImageSequenceLoader(load.LoaderPlugin): self.__class__.__name__ ) - def update(self, container, representation): + def update(self, container, context): node = container.pop("node") + repre_doc = context["representation"] project_name = get_current_project_name() - version = get_version_by_id(project_name, representation["parent"]) + version = get_version_by_id(project_name, repre_doc["parent"]) files = [] for f in version["data"]["files"]: files.append( @@ -632,7 +633,7 @@ class ImageSequenceLoader(load.LoaderPlugin): ) harmony.imprint( - node, {"representation": str(representation["_id"])} + node, {"representation": str(repre_doc["_id"])} ) def remove(self, container): @@ -648,8 +649,8 @@ class ImageSequenceLoader(load.LoaderPlugin): {"function": func, "args": [node]} ) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) ``` ## Resources diff --git a/client/ayon_core/hosts/harmony/plugins/load/load_audio.py b/client/ayon_core/hosts/harmony/plugins/load/load_audio.py index 14389166d7..b73c82197a 100644 --- a/client/ayon_core/hosts/harmony/plugins/load/load_audio.py +++ b/client/ayon_core/hosts/harmony/plugins/load/load_audio.py @@ -45,17 +45,17 @@ def load(self, context, name=None, namespace=None, data=None): {"function": func, "args": [context["subset"]["name"], wav_file]} ) - subset_name = context["subset"]["name"] + product_name = context["subset"]["name"] return harmony.containerise( - subset_name, + product_name, namespace, - subset_name, + product_name, context, self.__class__.__name__ ) - def update(self, container, representation): + def update(self, container, context): pass def remove(self, container): diff --git a/client/ayon_core/hosts/harmony/plugins/load/load_background.py b/client/ayon_core/hosts/harmony/plugins/load/load_background.py index 1c61cfa7a4..bf454a9ec7 100644 --- a/client/ayon_core/hosts/harmony/plugins/load/load_background.py +++ b/client/ayon_core/hosts/harmony/plugins/load/load_background.py @@ -254,7 +254,7 @@ def load(self, context, name=None, namespace=None, data=None): bg_folder = os.path.dirname(path) - subset_name = context["subset"]["name"] + product_name = context["subset"]["name"] # read_node_name += "_{}".format(uuid.uuid4()) container_nodes = [] @@ -272,16 +272,17 @@ def load(self, context, name=None, namespace=None, data=None): container_nodes.append(read_node) return harmony.containerise( - subset_name, + product_name, namespace, - subset_name, + product_name, context, self.__class__.__name__, nodes=container_nodes ) - def update(self, container, representation): - path = get_representation_path(representation) + def update(self, container, context): + repre_doc = context["representation"] + path = get_representation_path(repre_doc) with open(path) as json_file: data = json.load(json_file) @@ -301,7 +302,7 @@ def update(self, container, representation): print(container) - is_latest = is_representation_from_latest(representation) + is_latest = is_representation_from_latest(repre_doc) for layer in sorted(layers): file_to_import = [ os.path.join(bg_folder, layer).replace("\\", "/") @@ -351,8 +352,11 @@ def update(self, container, representation): harmony.send({"function": func, "args": [node, "red"]}) harmony.imprint( - container['name'], {"representation": str(representation["_id"]), - "nodes": container['nodes']} + container['name'], + { + "representation": str(repre_doc["_id"]), + "nodes": container["nodes"] + } ) def remove(self, container): @@ -369,5 +373,5 @@ def remove(self, container): ) harmony.imprint(container['name'], {}, remove=True) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) diff --git a/client/ayon_core/hosts/harmony/plugins/load/load_imagesequence.py b/client/ayon_core/hosts/harmony/plugins/load/load_imagesequence.py index 4d87272de8..60b90fe42d 100644 --- a/client/ayon_core/hosts/harmony/plugins/load/load_imagesequence.py +++ b/client/ayon_core/hosts/harmony/plugins/load/load_imagesequence.py @@ -47,7 +47,7 @@ def load(self, context, name=None, namespace=None, data=None): files.append(fname.parent.joinpath(remainder[0]).as_posix()) asset = context["asset"]["name"] - subset = context["subset"]["name"] + product_name = context["subset"]["name"] group_id = str(uuid.uuid4()) read_node = harmony.send( @@ -56,7 +56,7 @@ def load(self, context, name=None, namespace=None, data=None): "args": [ files, asset, - subset, + product_name, 1, group_id ] @@ -64,7 +64,7 @@ def load(self, context, name=None, namespace=None, data=None): )["result"] return harmony.containerise( - f"{asset}_{subset}", + f"{asset}_{product_name}", namespace, read_node, context, @@ -72,18 +72,19 @@ def load(self, context, name=None, namespace=None, data=None): nodes=[read_node] ) - def update(self, container, representation): + def update(self, container, context): """Update loaded containers. Args: container (dict): Container data. - representation (dict): Representation data. + context (dict): Representation context data. """ self_name = self.__class__.__name__ node = container.get("nodes").pop() - path = get_representation_path(representation) + repre_doc = context["representation"] + path = get_representation_path(repre_doc) collections, remainder = clique.assemble( os.listdir(os.path.dirname(path)) ) @@ -110,7 +111,7 @@ def update(self, container, representation): ) # Colour node. - if is_representation_from_latest(representation): + if is_representation_from_latest(repre_doc): harmony.send( { "function": "PypeHarmony.setColor", @@ -124,7 +125,7 @@ def update(self, container, representation): }) harmony.imprint( - node, {"representation": str(representation["_id"])} + node, {"representation": str(repre_doc["_id"])} ) def remove(self, container): @@ -140,6 +141,6 @@ def remove(self, container): ) harmony.imprint(node, {}, remove=True) - def switch(self, container, representation): + def switch(self, container, context): """Switch loaded representations.""" - self.update(container, representation) + self.update(container, context) diff --git a/client/ayon_core/hosts/harmony/plugins/load/load_palette.py b/client/ayon_core/hosts/harmony/plugins/load/load_palette.py index aa5894e026..f9ce888f93 100644 --- a/client/ayon_core/hosts/harmony/plugins/load/load_palette.py +++ b/client/ayon_core/hosts/harmony/plugins/load/load_palette.py @@ -26,15 +26,17 @@ def load(self, context, name=None, namespace=None, data=None): self.__class__.__name__ ) - def load_palette(self, representation): - subset_name = representation["context"]["subset"] - name = subset_name.replace("palette", "") + def load_palette(self, context): + subset_doc = context["subset"] + repre_doc = context["representation"] + product_name = subset_doc["name"] + name = product_name.replace("palette", "") # Overwrite palette on disk. scene_path = harmony.send( {"function": "scene.currentProjectPath"} )["result"] - src = get_representation_path(representation) + src = get_representation_path(repre_doc) dst = os.path.join( scene_path, "palette-library", @@ -44,7 +46,7 @@ def load_palette(self, representation): harmony.save_scene() - msg = "Updated {}.".format(subset_name) + msg = "Updated {}.".format(product_name) msg += " You need to reload the scene to see the changes.\n" msg += "Please save workfile when ready and use Workfiles " msg += "to reopen it." @@ -59,13 +61,14 @@ def load_palette(self, representation): def remove(self, container): harmony.remove(container["name"]) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) - def update(self, container, representation): + def update(self, container, context): self.remove(container) - name = self.load_palette(representation) + name = self.load_palette(context) - container["representation"] = str(representation["_id"]) + repre_doc = context["representation"] + container["representation"] = str(repre_doc["_id"]) container["name"] = name harmony.imprint(name, container) diff --git a/client/ayon_core/hosts/harmony/plugins/load/load_template.py b/client/ayon_core/hosts/harmony/plugins/load/load_template.py index d26f148c09..e981340c68 100644 --- a/client/ayon_core/hosts/harmony/plugins/load/load_template.py +++ b/client/ayon_core/hosts/harmony/plugins/load/load_template.py @@ -70,19 +70,20 @@ def load(self, context, name=None, namespace=None, data=None): self_name ) - def update(self, container, representation): + def update(self, container, context): """Update loaded containers. Args: container (dict): Container data. - representation (dict): Representation data. + context (dict): Representation context data. """ node_name = container["name"] node = harmony.find_node_by_name(node_name, "GROUP") self_name = self.__class__.__name__ - if is_representation_from_latest(representation): + repre_doc = context["representation"] + if is_representation_from_latest(repre_doc): self._set_green(node) else: self._set_red(node) @@ -110,7 +111,7 @@ def update(self, container, representation): None, container["data"]) harmony.imprint( - node, {"representation": str(representation["_id"])} + node, {"representation": str(repre_doc["_id"])} ) def remove(self, container): @@ -125,9 +126,9 @@ def remove(self, container): {"function": "PypeHarmony.deleteNode", "args": [node]} ) - def switch(self, container, representation): + def switch(self, container, context): """Switch representation containers.""" - self.update(container, representation) + self.update(container, context) def _set_green(self, node): """Set node color to green `rgba(0, 255, 0, 255)`.""" diff --git a/client/ayon_core/hosts/harmony/plugins/load/load_template_workfile.py b/client/ayon_core/hosts/harmony/plugins/load/load_template_workfile.py index 0ea46f8f67..1b127c5bc4 100644 --- a/client/ayon_core/hosts/harmony/plugins/load/load_template_workfile.py +++ b/client/ayon_core/hosts/harmony/plugins/load/load_template_workfile.py @@ -40,17 +40,17 @@ def load(self, context, name=None, namespace=None, data=None): shutil.rmtree(temp_dir) - subset_name = context["subset"]["name"] + product_name = context["subset"]["name"] return harmony.containerise( - subset_name, + product_name, namespace, - subset_name, + product_name, context, self.__class__.__name__ ) - def update(self, container, representation): + def update(self, container, context): pass def remove(self, container): From 548b7f27375493ed7629145bb5fde619b7ca9a99 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 26 Feb 2024 17:56:56 +0100 Subject: [PATCH 21/50] maya load plugins are expecting representation context --- client/ayon_core/hosts/maya/api/plugin.py | 125 ++++++++++-------- client/ayon_core/hosts/maya/api/setdress.py | 30 +++-- .../maya/plugins/load/load_arnold_standin.py | 11 +- .../hosts/maya/plugins/load/load_assembly.py | 4 +- .../hosts/maya/plugins/load/load_audio.py | 11 +- .../hosts/maya/plugins/load/load_gpucache.py | 11 +- .../hosts/maya/plugins/load/load_image.py | 10 +- .../maya/plugins/load/load_image_plane.py | 26 ++-- .../hosts/maya/plugins/load/load_look.py | 13 +- .../hosts/maya/plugins/load/load_maya_usd.py | 11 +- .../maya/plugins/load/load_multiverse_usd.py | 13 +- .../plugins/load/load_multiverse_usd_over.py | 13 +- .../maya/plugins/load/load_redshift_proxy.py | 12 +- .../hosts/maya/plugins/load/load_reference.py | 8 +- .../maya/plugins/load/load_rendersetup.py | 11 +- .../maya/plugins/load/load_vdb_to_arnold.py | 14 +- .../maya/plugins/load/load_vdb_to_redshift.py | 13 +- .../maya/plugins/load/load_vdb_to_vray.py | 11 +- .../hosts/maya/plugins/load/load_vrayproxy.py | 13 +- .../hosts/maya/plugins/load/load_vrayscene.py | 11 +- .../hosts/maya/plugins/load/load_xgen.py | 7 +- .../maya/plugins/load/load_yeti_cache.py | 12 +- 22 files changed, 209 insertions(+), 181 deletions(-) diff --git a/client/ayon_core/hosts/maya/api/plugin.py b/client/ayon_core/hosts/maya/api/plugin.py index 7a01f1a174..2772081f3c 100644 --- a/client/ayon_core/hosts/maya/api/plugin.py +++ b/client/ayon_core/hosts/maya/api/plugin.py @@ -29,7 +29,7 @@ ) from ayon_core.pipeline.load import LoadError from ayon_core.client import get_asset_by_name -from ayon_core.pipeline.create import get_subset_name +from ayon_core.pipeline.create import get_product_name from . import lib from .lib import imprint, read @@ -89,16 +89,16 @@ def process(self): class MayaCreatorBase(object): @staticmethod - def cache_subsets(shared_data): + def cache_instance_data(shared_data): """Cache instances for Creators to shared data. - Create `maya_cached_subsets` key when needed in shared data and + Create `maya_cached_instance_data` key when needed in shared data and fill it with all collected instances from the scene under its respective creator identifiers. If legacy instances are detected in the scene, create - `maya_cached_legacy_subsets` there and fill it with - all legacy subsets under family as a key. + `maya_cached_legacy_instances` there and fill it with + all legacy products under product type as a key. Args: Dict[str, Any]: Shared data. @@ -107,7 +107,7 @@ def cache_subsets(shared_data): Dict[str, Any]: Shared data dictionary. """ - if shared_data.get("maya_cached_subsets") is None: + if shared_data.get("maya_cached_instance_data") is None: cache = dict() cache_legacy = dict() @@ -131,8 +131,8 @@ def cache_subsets(shared_data): cache_legacy.setdefault(family, []).append(node) - shared_data["maya_cached_subsets"] = cache - shared_data["maya_cached_legacy_subsets"] = cache_legacy + shared_data["maya_cached_instance_data"] = cache + shared_data["maya_cached_legacy_instances"] = cache_legacy return shared_data def get_publish_families(self): @@ -143,8 +143,7 @@ def get_publish_families(self): specify `usd` but apply different extractors like `usdMultiverse`. There is no need to override this method if you only have the - primary family defined by the `family` property as that will always - be set. + 'product_type' required for publish filtering. Returns: list: families for instances of this creator @@ -165,7 +164,7 @@ def imprint_instance_node(self, node, data): data.pop("families", None) # We store creator attributes at the root level and assume they - # will not clash in names with `subset`, `task`, etc. and other + # will not clash in names with `product`, `task`, etc. and other # default names. This is just so these attributes in many cases # are still editable in the maya UI by artists. # note: pop to move to end of dict to sort attributes last on the node @@ -244,9 +243,11 @@ def read_instance_node(self, node): return node_data def _default_collect_instances(self): - self.cache_subsets(self.collection_shared_data) - cached_subsets = self.collection_shared_data["maya_cached_subsets"] - for node in cached_subsets.get(self.identifier, []): + self.cache_instance_data(self.collection_shared_data) + cached_instances = ( + self.collection_shared_data["maya_cached_instance_data"] + ) + for node in cached_instances.get(self.identifier, []): node_data = self.read_instance_node(node) created_instance = CreatedInstance.from_existing(node_data, self) @@ -279,7 +280,7 @@ class MayaCreator(NewCreator, MayaCreatorBase): settings_category = "maya" - def create(self, subset_name, instance_data, pre_create_data): + def create(self, product_name, instance_data, pre_create_data): members = list() if pre_create_data.get("use_selection"): @@ -294,11 +295,11 @@ def create(self, subset_name, instance_data, pre_create_data): families.append(family) with lib.undo_chunk(): - instance_node = cmds.sets(members, name=subset_name) + instance_node = cmds.sets(members, name=product_name) instance_data["instance_node"] = instance_node instance = CreatedInstance( - self.family, - subset_name, + self.product_type, + product_name, instance_data, self) self._add_instance_to_context(instance) @@ -385,7 +386,7 @@ def ensure_namespace(namespace): class RenderlayerCreator(NewCreator, MayaCreatorBase): """Creator which creates an instance per renderlayer in the workfile. - Create and manages renderlayer subset per renderLayer in workfile. + Create and manages renderlayer product per renderLayer in workfile. This generates a singleton node in the scene which, if it exists, tells the Creator to collect Maya rendersetup renderlayers as individual instances. As such, triggering create doesn't actually create the instance node per @@ -405,7 +406,7 @@ def _get_singleton_node(self, return_all=False): if nodes: return nodes if return_all else nodes[0] - def create(self, subset_name, instance_data, pre_create_data): + def create(self, product_name, instance_data, pre_create_data): # A Renderlayer is never explicitly created using the create method. # Instead, renderlayers from the scene are collected. Thus "create" # would only ever be called to say, 'hey, please refresh collect' @@ -462,15 +463,15 @@ def collect_instances(self): "variant": layer.name(), } asset_doc = get_asset_by_name(project_name, asset_name) - subset_name = self.get_subset_name( + product_name = self.get_product_name( layer.name(), instance_data["task"], asset_doc, project_name) instance = CreatedInstance( - family=self.family, - subset_name=subset_name, + product_type=self.product_type, + product_name=product_name, data=instance_data, creator=self ) @@ -574,7 +575,7 @@ def remove_instances(self, instances): if node and cmds.objExists(node): cmds.delete(node) - def get_subset_name( + def get_product_name( self, variant, task_name, @@ -583,19 +584,27 @@ def get_subset_name( host_name=None, instance=None ): - # creator.family != 'render' as expected - return get_subset_name(self.layer_instance_prefix, - variant, - task_name, - asset_doc, - project_name) + dynamic_data = self.get_dynamic_data( + variant, task_name, asset_doc, project_name, host_name, instance + ) + # creator.product_type != 'render' as expected + return get_product_name( + project_name, + asset_doc, + task_name, + host_name, + self.layer_instance_prefix or self.product_type, + variant, + dynamic_data=dynamic_data, + project_settings=self.project_settings + ) -def get_load_color_for_family(family, settings=None): - """Get color for family from settings. +def get_load_color_for_product_type(product_type, settings=None): + """Get color for product type from settings. Args: - family (str): Family name. + product_type (str): Family name. settings (Optional[dict]): Settings dictionary. Returns: @@ -606,7 +615,7 @@ def get_load_color_for_family(family, settings=None): settings = get_project_settings(get_current_project_name()) colors = settings["maya"]["load"]["colors"] - color = colors.get(family) + color = colors.get(product_type) if not color: return None @@ -657,24 +666,24 @@ def get_custom_namespace_and_group(self, context, options, loader_key): self.log.debug("No custom group_name, no group will be created.") options["attach_to_root"] = False - asset = context["asset"] - subset = context["subset"] - family = ( - subset["data"].get("family") - or subset["data"]["families"][0] + asset_doc = context["asset"] + subset_doc = context["subset"] + product_type = ( + subset_doc["data"].get("family") + or subset_doc["data"]["families"][0] ) formatting_data = { - "asset_name": asset["name"], - "asset_type": asset["type"], + "asset_name": asset_doc["name"], + "asset_type": asset_doc["type"], "folder": { - "name": asset["name"], + "name": asset_doc["name"], }, - "subset": subset["name"], + "subset": subset_doc["name"], "product": { - "name": subset["name"], - "type": family, + "name": subset_doc["name"], + "type": product_type, }, - "family": family + "family": product_type } custom_namespace = custom_naming["namespace"].format( @@ -745,7 +754,7 @@ def load( options['group_name'] = group_name - # Offset loaded subset + # Offset loaded product if "offset" in options: offset = [i * c for i in options["offset"]] options["translate"] = offset @@ -782,14 +791,17 @@ def process_reference(self, context, name, namespace, options): """To be implemented by subclass""" raise NotImplementedError("Must be implemented by subclass") - def update(self, container, representation): + def update(self, container, context): from maya import cmds from ayon_core.hosts.maya.api.lib import get_container_members node = container["objectName"] - path = get_representation_path(representation) + project_name = context["project"]["name"] + repre_doc = context["representation"] + + path = get_representation_path(repre_doc) # Get reference node from container members members = get_container_members(node) @@ -802,9 +814,9 @@ def update(self, container, representation): "abc": "Alembic", "fbx": "FBX", "usd": "USD Import" - }.get(representation["name"]) + }.get(repre_doc["name"]) - assert file_type, "Unsupported representation: %s" % representation + assert file_type, "Unsupported representation: %s" % repre_doc assert os.path.exists(path), "%s does not exist." % path @@ -812,7 +824,7 @@ def update(self, container, representation): # them to incoming data. alembic_attrs = ["speed", "offset", "cycleType", "time"] alembic_data = {} - if representation["name"] == "abc": + if repre_doc["name"] == "abc": alembic_nodes = cmds.ls( "{}:*".format(namespace), type="AlembicNode" ) @@ -829,10 +841,7 @@ def update(self, container, representation): self.log.debug("No alembic nodes found in {}".format(members)) try: - path = self.prepare_root_value(path, - representation["context"] - ["project"] - ["name"]) + path = self.prepare_root_value(path, project_name) content = cmds.file(path, loadReference=reference_node, type=file_type, @@ -856,7 +865,7 @@ def update(self, container, representation): self._organize_containers(content, container["objectName"]) # Reapply alembic settings. - if representation["name"] == "abc" and alembic_data: + if repre_doc["name"] == "abc" and alembic_data: alembic_nodes = cmds.ls( "{}:*".format(namespace), type="AlembicNode" ) @@ -890,7 +899,7 @@ def update(self, container, representation): # Update metadata cmds.setAttr("{}.representation".format(node), - str(representation["_id"]), + str(repre_doc["_id"]), type="string") # When an animation or pointcache gets connected to an Xgen container, diff --git a/client/ayon_core/hosts/maya/api/setdress.py b/client/ayon_core/hosts/maya/api/setdress.py index 7a1054cc49..03b18927ac 100644 --- a/client/ayon_core/hosts/maya/api/setdress.py +++ b/client/ayon_core/hosts/maya/api/setdress.py @@ -315,16 +315,27 @@ def update_package_version(container, version): new_representation = get_representation_by_name( project_name, current_representation["name"], new_version["_id"] ) - - update_package(container, new_representation) - - -def update_package(set_container, representation): + # TODO there is 'get_representation_context' to get the context which + # could be possible to use here + new_context = { + "project": { + "name": project_doc["name"], + "code": project_doc["data"].get("code", "") + }, + "asset": asset_doc, + "subset": subset_doc, + "version": version_doc, + "representation": new_representation, + } + update_package(container, new_context) + + +def update_package(set_container, context): """Update any matrix changes in the scene based on the new data Args: set_container (dict): container data from `ls()` - representation (dict): the representation document from the database + context (dict): the representation document from the database Returns: None @@ -332,7 +343,8 @@ def update_package(set_container, representation): """ # Load the original package data - project_name = get_current_project_name() + project_name = context["project"]["name"] + repre_doc = context["representation"] current_representation = get_representation_by_id( project_name, set_container["representation"] ) @@ -343,7 +355,7 @@ def update_package(set_container, representation): current_data = json.load(fp) # Load the new package data - new_file = get_representation_path(representation) + new_file = get_representation_path(repre_doc) assert new_file.endswith(".json") with open(new_file, "r") as fp: new_data = json.load(fp) @@ -354,7 +366,7 @@ def update_package(set_container, representation): # TODO: This should be handled by the pipeline itself cmds.setAttr(set_container['objectName'] + ".representation", - str(representation['_id']), type="string") + str(repre_doc['_id']), type="string") def update_scene(set_container, containers, current_data, new_data, new_file): diff --git a/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py b/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py index 16ac460cf7..04d9084175 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_arnold_standin.py @@ -177,7 +177,7 @@ def _setup_proxy(self, shape, path, namespace): return proxy_path, string_replace_operator - def update(self, container, representation): + def update(self, container, context): # Update the standin members = cmds.sets(container['objectName'], query=True) for member in members: @@ -190,7 +190,8 @@ def update(self, container, representation): if cmds.nodeType(shapes[0]) == "aiStandIn": standin = shapes[0] - path = get_representation_path(representation) + repre_doc = context["representation"] + path = get_representation_path(repre_doc) proxy_basename, proxy_path = self._get_proxy_path(path) # Whether there is proxy or so, we still update the string operator. @@ -216,12 +217,12 @@ def update(self, container, representation): cmds.setAttr( container["objectName"] + ".representation", - str(representation["_id"]), + str(repre_doc["_id"]), type="string" ) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): members = cmds.sets(container['objectName'], query=True) diff --git a/client/ayon_core/hosts/maya/plugins/load/load_assembly.py b/client/ayon_core/hosts/maya/plugins/load/load_assembly.py index e119dfe1c3..1f06655dad 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_assembly.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_assembly.py @@ -49,9 +49,9 @@ def load(self, context, name, namespace, data): context=context, loader=self.__class__.__name__) - def update(self, container, representation): + def update(self, container, context): - return setdress.update_package(container, representation) + return setdress.update_package(container, context) def remove(self, container): """Remove all sub containers""" diff --git a/client/ayon_core/hosts/maya/plugins/load/load_audio.py b/client/ayon_core/hosts/maya/plugins/load/load_audio.py index deeeac66f2..df811a585c 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_audio.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_audio.py @@ -45,7 +45,8 @@ def load(self, context, name, namespace, data): loader=self.__class__.__name__ ) - def update(self, container, representation): + def update(self, container, context): + repre_doc = context["representation"] members = get_container_members(container) audio_nodes = cmds.ls(members, type="audio") @@ -60,7 +61,7 @@ def update(self, container, representation): ) activate_sound = current_sound == audio_node - path = get_representation_path(representation) + path = get_representation_path(repre_doc) cmds.sound( audio_node, @@ -93,12 +94,12 @@ def update(self, container, representation): cmds.setAttr( container["objectName"] + ".representation", - str(representation["_id"]), + str(repre_doc["_id"]), type="string" ) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): members = cmds.sets(container['objectName'], query=True) diff --git a/client/ayon_core/hosts/maya/plugins/load/load_gpucache.py b/client/ayon_core/hosts/maya/plugins/load/load_gpucache.py index cdaaeeae6a..6b632f2343 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_gpucache.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_gpucache.py @@ -74,8 +74,9 @@ def load(self, context, name, namespace, data): context=context, loader=self.__class__.__name__) - def update(self, container, representation): - path = get_representation_path(representation) + def update(self, container, context): + repre_doc = context["representation"] + path = get_representation_path(repre_doc) # Update the cache members = cmds.sets(container['objectName'], query=True) @@ -87,11 +88,11 @@ def update(self, container, representation): cmds.setAttr(cache + ".cacheFileName", path, type="string") cmds.setAttr(container["objectName"] + ".representation", - str(representation["_id"]), + str(repre_doc["_id"]), type="string") - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): members = cmds.sets(container['objectName'], query=True) diff --git a/client/ayon_core/hosts/maya/plugins/load/load_image.py b/client/ayon_core/hosts/maya/plugins/load/load_image.py index aedeb63e3d..7b324986f0 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_image.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_image.py @@ -146,23 +146,23 @@ def load(self, context, name, namespace, data): loader=self.__class__.__name__ ) - def update(self, container, representation): + def update(self, container, context): + repre_doc = context["representation"] members = cmds.sets(container['objectName'], query=True) file_node = cmds.ls(members, type="file")[0] - context = get_representation_context(representation) self._apply_representation_context(context, file_node) # Update representation cmds.setAttr( container["objectName"] + ".representation", - str(representation["_id"]), + str(repre_doc["_id"]), type="string" ) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): members = cmds.sets(container['objectName'], query=True) diff --git a/client/ayon_core/hosts/maya/plugins/load/load_image_plane.py b/client/ayon_core/hosts/maya/plugins/load/load_image_plane.py index fb27e6597a..2366f6edd7 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_image_plane.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_image_plane.py @@ -205,34 +205,26 @@ def load(self, context, name, namespace, data, options=None): loader=self.__class__.__name__ ) - def update(self, container, representation): + def update(self, container, context): + asset_doc = context["asset"] + repre_doc = context["representation"] members = get_container_members(container) image_planes = cmds.ls(members, type="imagePlane") assert image_planes, "Image plane not found." image_plane_shape = image_planes[0] - path = get_representation_path(representation) + path = get_representation_path(repre_doc) cmds.setAttr("{}.imageName".format(image_plane_shape), path, type="string") cmds.setAttr("{}.representation".format(container["objectName"]), - str(representation["_id"]), + str(repre_doc["_id"]), type="string") # Set frame range. - project_name = get_current_project_name() - version = get_version_by_id( - project_name, representation["parent"], fields=["parent"] - ) - subset = get_subset_by_id( - project_name, version["parent"], fields=["parent"] - ) - asset = get_asset_by_id( - project_name, subset["parent"], fields=["parent"] - ) - start_frame = asset["data"]["frameStart"] - end_frame = asset["data"]["frameEnd"] + start_frame = asset_doc["data"]["frameStart"] + end_frame = asset_doc["data"]["frameEnd"] for attr, value in { "frameOffset": 0, @@ -243,8 +235,8 @@ def update(self, container, representation): plug = "{}.{}".format(image_plane_shape, attr) cmds.setAttr(plug, value) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): members = cmds.sets(container['objectName'], query=True) diff --git a/client/ayon_core/hosts/maya/plugins/load/load_look.py b/client/ayon_core/hosts/maya/plugins/load/load_look.py index ba5891469d..fb5be14aa1 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_look.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_look.py @@ -43,10 +43,10 @@ def process_reference(self, context, name, namespace, options): self[:] = nodes - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) - def update(self, container, representation): + def update(self, container, context): """ Called by Scene Inventory when look should be updated to current version. @@ -56,7 +56,7 @@ def update(self, container, representation): Args: container: object that has look to be updated - representation: (dict): relationship data to get proper + context: (dict): relationship data to get proper representation from DB and persisted data in .json Returns: @@ -72,15 +72,16 @@ def update(self, container, representation): orig_nodes = set(self._get_nodes_with_shader(shader_nodes)) # Trigger the regular reference update on the ReferenceLoader - super(LookLoader, self).update(container, representation) + super(LookLoader, self).update(container, context) # get new applied shaders and nodes from new version shader_nodes = cmds.ls(members, type='shadingEngine') nodes = set(self._get_nodes_with_shader(shader_nodes)) + version_doc = context["version"] project_name = get_current_project_name() json_representation = get_representation_by_name( - project_name, "json", representation["parent"] + project_name, "json", version_doc["_id"] ) # Load relationships diff --git a/client/ayon_core/hosts/maya/plugins/load/load_maya_usd.py b/client/ayon_core/hosts/maya/plugins/load/load_maya_usd.py index c2bea1501c..cb9fde7b33 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_maya_usd.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_maya_usd.py @@ -69,7 +69,7 @@ def load(self, context, name=None, namespace=None, options=None): context=context, loader=self.__class__.__name__) - def update(self, container, representation): + def update(self, container, context): # type: (dict, dict) -> None """Update container with specified representation.""" node = container['objectName'] @@ -78,16 +78,17 @@ def update(self, container, representation): members = cmds.sets(node, query=True) or [] shapes = cmds.ls(members, type="mayaUsdProxyShape") - path = get_representation_path(representation) + repre_doc = context["representation"] + path = get_representation_path(repre_doc) for shape in shapes: cmds.setAttr("{}.filePath".format(shape), path, type="string") cmds.setAttr("{}.representation".format(node), - str(representation["_id"]), + str(repre_doc["_id"]), type="string") - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): # type: (dict) -> None diff --git a/client/ayon_core/hosts/maya/plugins/load/load_multiverse_usd.py b/client/ayon_core/hosts/maya/plugins/load/load_multiverse_usd.py index a9ba2b8773..64e6048c31 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_multiverse_usd.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_multiverse_usd.py @@ -60,7 +60,7 @@ def load(self, context, name=None, namespace=None, options=None): context=context, loader=self.__class__.__name__) - def update(self, container, representation): + def update(self, container, context): # type: (dict, dict) -> None """Update container with specified representation.""" node = container['objectName'] @@ -70,7 +70,9 @@ def update(self, container, representation): shapes = cmds.ls(members, type="mvUsdCompoundShape") assert shapes, "Cannot find mvUsdCompoundShape in container" - project_name = representation["context"]["project"]["name"] + project_name = context["project"]["name"] + repre_doc = context["representation"] + path = get_representation_path(repre_doc) prev_representation_id = cmds.getAttr("{}.representation".format(node)) prev_representation = get_representation_by_id(project_name, prev_representation_id) @@ -89,18 +91,17 @@ def update(self, container, representation): "Couldn't find matching path (or too many)" prev_path_idx = asset_paths.index(prev_path) - path = get_representation_path(representation) asset_paths[prev_path_idx] = path multiverse.SetUsdCompoundAssetPaths(shape, asset_paths) cmds.setAttr("{}.representation".format(node), - str(representation["_id"]), + str(repre_doc["_id"]), type="string") mel.eval('refreshEditorTemplates;') - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): # type: (dict) -> None diff --git a/client/ayon_core/hosts/maya/plugins/load/load_multiverse_usd_over.py b/client/ayon_core/hosts/maya/plugins/load/load_multiverse_usd_over.py index d448dc74a8..6de03fe306 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_multiverse_usd_over.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_multiverse_usd_over.py @@ -71,7 +71,7 @@ def load(self, context, name=None, namespace=None, options=None): return container - def update(self, container, representation): + def update(self, container, context): # type: (dict, dict) -> None """Update container with specified representation.""" @@ -88,13 +88,14 @@ def update(self, container, representation): mvShape = container['mvUsdCompoundShape'] assert mvShape, "Missing mv source" - project_name = representation["context"]["project"]["name"] + project_name = context["project"]["name"] + repre_doc = context["representation"] prev_representation_id = cmds.getAttr("{}.representation".format(node)) prev_representation = get_representation_by_id(project_name, prev_representation_id) prev_path = os.path.normpath(prev_representation["data"]["path"]) - path = get_representation_path(representation) + path = get_representation_path(repre_doc) for shape in shapes: asset_paths = multiverse.GetUsdCompoundAssetPaths(shape) @@ -107,12 +108,12 @@ def update(self, container, representation): multiverse.SetUsdCompoundAssetPaths(shape, asset_paths) cmds.setAttr("{}.representation".format(node), - str(representation["_id"]), + str(repre_doc["_id"]), type="string") mel.eval('refreshEditorTemplates;') - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): # type: (dict) -> None diff --git a/client/ayon_core/hosts/maya/plugins/load/load_redshift_proxy.py b/client/ayon_core/hosts/maya/plugins/load/load_redshift_proxy.py index 8910d0fcd0..4c6b93ad45 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_redshift_proxy.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_redshift_proxy.py @@ -75,7 +75,7 @@ def load(self, context, name=None, namespace=None, options=None): context=context, loader=self.__class__.__name__) - def update(self, container, representation): + def update(self, container, context): node = container['objectName'] assert cmds.objExists(node), "Missing container" @@ -83,8 +83,8 @@ def update(self, container, representation): members = cmds.sets(node, query=True) or [] rs_meshes = cmds.ls(members, type="RedshiftProxyMesh") assert rs_meshes, "Cannot find RedshiftProxyMesh in container" - - filename = get_representation_path(representation) + repre_doc = context["representation"] + filename = get_representation_path(repre_doc) for rs_mesh in rs_meshes: cmds.setAttr("{}.fileName".format(rs_mesh), @@ -93,7 +93,7 @@ def update(self, container, representation): # Update metadata cmds.setAttr("{}.representation".format(node), - str(representation["_id"]), + str(repre_doc["_id"]), type="string") def remove(self, container): @@ -113,8 +113,8 @@ def remove(self, container): self.log.warning("Namespace not deleted because it " "still has members: %s", namespace) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def create_rs_proxy(self, name, path): """Creates Redshift Proxies showing a proxy object. diff --git a/client/ayon_core/hosts/maya/plugins/load/load_reference.py b/client/ayon_core/hosts/maya/plugins/load/load_reference.py index 75f42a9fe6..32b456ed86 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_reference.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_reference.py @@ -228,12 +228,12 @@ def process_reference(self, context, name, namespace, options): *options["translate"]) return new_nodes - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) - def update(self, container, representation): + def update(self, container, context): with preserve_modelpanel_cameras(container, log=self.log): - super(ReferenceLoader, self).update(container, representation) + super(ReferenceLoader, self).update(container, context) # We also want to lock camera transforms on any new cameras in the # reference or for a camera which might have changed names. diff --git a/client/ayon_core/hosts/maya/plugins/load/load_rendersetup.py b/client/ayon_core/hosts/maya/plugins/load/load_rendersetup.py index e77e270663..58f161afc1 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_rendersetup.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_rendersetup.py @@ -84,14 +84,15 @@ def remove(self, container): # Already implicitly deleted by Maya upon removing reference pass - def update(self, container, representation): + def update(self, container, context): """Update RenderSetup setting by overwriting existing settings.""" lib.show_message( "Render setup update", "Render setup setting will be overwritten by new version. All " "setting specified by user not included in loaded version " "will be lost.") - path = get_representation_path(representation) + repre_doc = context["representation"] + path = get_representation_path(repre_doc) with open(path, "r") as file: try: renderSetup.instance().decode( @@ -103,10 +104,10 @@ def update(self, container, representation): # Update metadata node = container["objectName"] cmds.setAttr("{}.representation".format(node), - str(representation["_id"]), + str(repre_doc["_id"]), type="string") self.log.info("... updated") - def switch(self, container, representation): + def switch(self, container, context): """Switch representations.""" - self.update(container, representation) + self.update(container, context) diff --git a/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_arnold.py b/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_arnold.py index c68fddc60a..e2f3fe57e9 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_arnold.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_arnold.py @@ -81,11 +81,13 @@ def load(self, context, name, namespace, data): context=context, loader=self.__class__.__name__) - def update(self, container, representation): + def update(self, container, context): from maya import cmds - path = get_representation_path(representation) + repre_doc = context["representation"] + + path = get_representation_path(repre_doc) # Find VRayVolumeGrid members = cmds.sets(container['objectName'], query=True) @@ -93,15 +95,15 @@ def update(self, container, representation): assert len(grid_nodes) == 1, "This is a bug" # Update the VRayVolumeGrid - self._set_path(grid_nodes[0], path=path, representation=representation) + self._set_path(grid_nodes[0], path=path, representation=repre_doc) # Update container representation cmds.setAttr(container["objectName"] + ".representation", - str(representation["_id"]), + str(repre_doc["_id"]), type="string") - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): diff --git a/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_redshift.py b/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_redshift.py index 1bc75ae4c6..60a044b20d 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_redshift.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_redshift.py @@ -95,10 +95,11 @@ def load(self, context, name=None, namespace=None, data=None): context=context, loader=self.__class__.__name__) - def update(self, container, representation): + def update(self, container, context): from maya import cmds - path = get_representation_path(representation) + repre_doc = context["representation"] + path = get_representation_path(repre_doc) # Find VRayVolumeGrid members = cmds.sets(container['objectName'], query=True) @@ -106,11 +107,11 @@ def update(self, container, representation): assert len(grid_nodes) == 1, "This is a bug" # Update the VRayVolumeGrid - self._set_path(grid_nodes[0], path=path, representation=representation) + self._set_path(grid_nodes[0], path=path, representation=repre_doc) # Update container representation cmds.setAttr(container["objectName"] + ".representation", - str(representation["_id"]), + str(repre_doc["_id"]), type="string") def remove(self, container): @@ -129,8 +130,8 @@ def remove(self, container): except RuntimeError: pass - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) @staticmethod def _set_path(grid_node, diff --git a/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_vray.py b/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_vray.py index 0c87162629..c1cfa8de3b 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_vray.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_vdb_to_vray.py @@ -254,9 +254,10 @@ def _get_filename_from_folder(path): restored_mapping, type="string") - def update(self, container, representation): + def update(self, container, context): + repre_doc = context["representation"] - path = get_representation_path(representation) + path = get_representation_path(repre_doc) # Find VRayVolumeGrid members = cmds.sets(container['objectName'], query=True) @@ -269,11 +270,11 @@ def update(self, container, representation): # Update container representation cmds.setAttr(container["objectName"] + ".representation", - str(representation["_id"]), + str(repre_doc["_id"]), type="string") - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): diff --git a/client/ayon_core/hosts/maya/plugins/load/load_vrayproxy.py b/client/ayon_core/hosts/maya/plugins/load/load_vrayproxy.py index 50b63f4f11..7838556219 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_vrayproxy.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_vrayproxy.py @@ -96,7 +96,7 @@ def load(self, context, name=None, namespace=None, options=None): context=context, loader=self.__class__.__name__) - def update(self, container, representation): + def update(self, container, context): # type: (dict, dict) -> None """Update container with specified representation.""" node = container['objectName'] @@ -107,9 +107,10 @@ def update(self, container, representation): assert vraymeshes, "Cannot find VRayMesh in container" # get all representations for this version + repre_doc = context["representation"] filename = ( - self._get_abc(representation["parent"]) - or get_representation_path(representation) + self._get_abc(repre_doc["parent"]) + or get_representation_path(repre_doc) ) for vray_mesh in vraymeshes: @@ -119,7 +120,7 @@ def update(self, container, representation): # Update metadata cmds.setAttr("{}.representation".format(node), - str(representation["_id"]), + str(repre_doc["_id"]), type="string") def remove(self, container): @@ -140,10 +141,10 @@ def remove(self, container): self.log.warning("Namespace not deleted because it " "still has members: %s", namespace) - def switch(self, container, representation): + def switch(self, container, context): # type: (dict, dict) -> None """Switch loaded representation.""" - self.update(container, representation) + self.update(container, context) def create_vray_proxy(self, name, filename): # type: (str, str) -> (list, str) diff --git a/client/ayon_core/hosts/maya/plugins/load/load_vrayscene.py b/client/ayon_core/hosts/maya/plugins/load/load_vrayscene.py index 7b4edb0567..f8b938a082 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_vrayscene.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_vrayscene.py @@ -73,7 +73,7 @@ def load(self, context, name, namespace, data): context=context, loader=self.__class__.__name__) - def update(self, container, representation): + def update(self, container, context): node = container['objectName'] assert cmds.objExists(node), "Missing container" @@ -82,7 +82,8 @@ def update(self, container, representation): vraymeshes = cmds.ls(members, type="VRayScene") assert vraymeshes, "Cannot find VRayScene in container" - filename = get_representation_path(representation) + repre_doc = context["representation"] + filename = get_representation_path(repre_doc) for vray_mesh in vraymeshes: cmds.setAttr("{}.FilePath".format(vray_mesh), @@ -91,7 +92,7 @@ def update(self, container, representation): # Update metadata cmds.setAttr("{}.representation".format(node), - str(representation["_id"]), + str(repre_doc["_id"]), type="string") def remove(self, container): @@ -111,8 +112,8 @@ def remove(self, container): self.log.warning("Namespace not deleted because it " "still has members: %s", namespace) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def create_vray_scene(self, name, filename): """Re-create the structure created by VRay to support vrscenes diff --git a/client/ayon_core/hosts/maya/plugins/load/load_xgen.py b/client/ayon_core/hosts/maya/plugins/load/load_xgen.py index 4c38835350..fdac62a250 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_xgen.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_xgen.py @@ -113,7 +113,7 @@ def set_palette_attributes(self, xgen_palette, xgen_file, xgd_file): ) cmds.setAttr("{}.xgExportAsDelta".format(xgen_palette), True) - def update(self, container, representation): + def update(self, container, context): """Workflow for updating Xgen. - Export changes to delta file. @@ -147,7 +147,8 @@ def update(self, container, representation): self.set_palette_attributes(xgen_palette, xgen_file, xgd_file) - maya_file = get_representation_path(representation) + repre_doc = context["representation"] + maya_file = get_representation_path(repre_doc) _, extension = os.path.splitext(maya_file) new_xgen_file = maya_file.replace(extension, ".xgen") data_path = "" @@ -173,7 +174,7 @@ def update(self, container, representation): "{}.xgExportAsDelta".format(xgen_palette): False } with attribute_values(attribute_data): - super().update(container, representation) + super().update(container, context) xgenm.applyDelta(xgen_palette.replace("|", ""), xgd_file) diff --git a/client/ayon_core/hosts/maya/plugins/load/load_yeti_cache.py b/client/ayon_core/hosts/maya/plugins/load/load_yeti_cache.py index afbb632d87..9dc169e6e4 100644 --- a/client/ayon_core/hosts/maya/plugins/load/load_yeti_cache.py +++ b/client/ayon_core/hosts/maya/plugins/load/load_yeti_cache.py @@ -122,12 +122,12 @@ def remove(self, container): cmds.namespace(removeNamespace=namespace, deleteNamespaceContent=True) - def update(self, container, representation): - + def update(self, container, context): + repre_doc = context["representation"] namespace = container["namespace"] container_node = container["objectName"] - path = get_representation_path(representation) + path = get_representation_path(repre_doc) settings = self.read_settings(path) # Collect scene information of asset @@ -216,11 +216,11 @@ def update(self, container, representation): set_attribute(attr, value, yeti_node) cmds.setAttr("{}.representation".format(container_node), - str(representation["_id"]), + str(repre_doc["_id"]), typ="string") - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) # helper functions def create_namespace(self, asset): From 24e9f924257fd1caa823008c5b4e9aadae1f5d07 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 26 Feb 2024 17:57:03 +0100 Subject: [PATCH 22/50] 3dsmax load plugins are expecting representation context --- .../hosts/max/plugins/load/load_camera_fbx.py | 11 ++++++----- .../hosts/max/plugins/load/load_max_scene.py | 11 ++++++----- client/ayon_core/hosts/max/plugins/load/load_model.py | 11 ++++++----- .../hosts/max/plugins/load/load_model_fbx.py | 11 ++++++----- .../hosts/max/plugins/load/load_model_obj.py | 11 ++++++----- .../hosts/max/plugins/load/load_model_usd.py | 11 ++++++----- .../hosts/max/plugins/load/load_pointcache.py | 11 ++++++----- .../max/plugins/load/load_pointcache_ornatrix.py | 11 ++++++----- .../hosts/max/plugins/load/load_pointcloud.py | 11 ++++++----- .../hosts/max/plugins/load/load_redshift_proxy.py | 11 ++++++----- .../ayon_core/hosts/max/plugins/load/load_tycache.py | 11 ++++++----- 11 files changed, 66 insertions(+), 55 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/load/load_camera_fbx.py b/client/ayon_core/hosts/max/plugins/load/load_camera_fbx.py index 8387d7a837..d56445c695 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_camera_fbx.py +++ b/client/ayon_core/hosts/max/plugins/load/load_camera_fbx.py @@ -51,10 +51,11 @@ def load(self, context, name=None, namespace=None, data=None): name, selections, context, namespace, loader=self.__class__.__name__) - def update(self, container, representation): + def update(self, container, context): from pymxs import runtime as rt - path = get_representation_path(representation) + repre_doc = context["representation"] + path = get_representation_path(repre_doc) node_name = container["instance_node"] node = rt.getNodeByName(node_name) namespace, _ = get_namespace(node_name) @@ -87,11 +88,11 @@ def update(self, container, representation): update_custom_attribute_data(node, fbx_objects) lib.imprint(container["instance_node"], { - "representation": str(representation["_id"]) + "representation": str(repre_doc["_id"]) }) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): from pymxs import runtime as rt diff --git a/client/ayon_core/hosts/max/plugins/load/load_max_scene.py b/client/ayon_core/hosts/max/plugins/load/load_max_scene.py index ead77cd2f2..39bb3b568d 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_max_scene.py +++ b/client/ayon_core/hosts/max/plugins/load/load_max_scene.py @@ -48,10 +48,11 @@ def load(self, context, name=None, namespace=None, data=None): name, max_container, context, namespace, loader=self.__class__.__name__) - def update(self, container, representation): + def update(self, container, context): from pymxs import runtime as rt - path = get_representation_path(representation) + repre_doc = context["representation"] + path = get_representation_path(repre_doc) node_name = container["instance_node"] node = rt.getNodeByName(node_name) namespace, _ = get_namespace(node_name) @@ -86,11 +87,11 @@ def update(self, container, representation): update_custom_attribute_data(node, max_objects) lib.imprint(container["instance_node"], { - "representation": str(representation["_id"]) + "representation": str(repre_doc["_id"]) }) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): from pymxs import runtime as rt diff --git a/client/ayon_core/hosts/max/plugins/load/load_model.py b/client/ayon_core/hosts/max/plugins/load/load_model.py index cf35e107c2..e0241bdb73 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_model.py +++ b/client/ayon_core/hosts/max/plugins/load/load_model.py @@ -70,10 +70,11 @@ def load(self, context, name=None, namespace=None, data=None): namespace, loader=self.__class__.__name__ ) - def update(self, container, representation): + def update(self, container, context): from pymxs import runtime as rt - path = get_representation_path(representation) + repre_doc = context["representation"] + path = get_representation_path(repre_doc) node = rt.GetNodeByName(container["instance_node"]) node_list = [n for n in get_previous_loaded_object(node) if rt.ClassOf(n) == rt.AlembicContainer] @@ -90,11 +91,11 @@ def update(self, container, representation): abc_obj.source = path lib.imprint( container["instance_node"], - {"representation": str(representation["_id"])}, + {"representation": str(repre_doc["_id"])}, ) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): from pymxs import runtime as rt diff --git a/client/ayon_core/hosts/max/plugins/load/load_model_fbx.py b/client/ayon_core/hosts/max/plugins/load/load_model_fbx.py index c0bacca33a..03ba901b32 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_model_fbx.py +++ b/client/ayon_core/hosts/max/plugins/load/load_model_fbx.py @@ -47,10 +47,11 @@ def load(self, context, name=None, namespace=None, data=None): name, selections, context, namespace, loader=self.__class__.__name__) - def update(self, container, representation): + def update(self, container, context): from pymxs import runtime as rt - path = get_representation_path(representation) + repre_doc = context["representation"] + path = get_representation_path(repre_doc) node_name = container["instance_node"] node = rt.getNodeByName(node_name) if not node: @@ -85,11 +86,11 @@ def update(self, container, representation): rt.Select(node) update_custom_attribute_data(node, fbx_objects) lib.imprint(container["instance_node"], { - "representation": str(representation["_id"]) + "representation": str(repre_doc["_id"]) }) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): from pymxs import runtime as rt diff --git a/client/ayon_core/hosts/max/plugins/load/load_model_obj.py b/client/ayon_core/hosts/max/plugins/load/load_model_obj.py index 1023b67f0c..a6c3d2a2fe 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_model_obj.py +++ b/client/ayon_core/hosts/max/plugins/load/load_model_obj.py @@ -47,10 +47,11 @@ def load(self, context, name=None, namespace=None, data=None): name, selections, context, namespace, loader=self.__class__.__name__) - def update(self, container, representation): + def update(self, container, context): from pymxs import runtime as rt - path = get_representation_path(representation) + repre_doc = context["representation"] + path = get_representation_path(repre_doc) node_name = container["instance_node"] node = rt.getNodeByName(node_name) namespace, _ = get_namespace(node_name) @@ -77,11 +78,11 @@ def update(self, container, representation): rt.Select(node) lib.imprint(node_name, { - "representation": str(representation["_id"]) + "representation": str(repre_doc["_id"]) }) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): from pymxs import runtime as rt diff --git a/client/ayon_core/hosts/max/plugins/load/load_model_usd.py b/client/ayon_core/hosts/max/plugins/load/load_model_usd.py index 0ec6e5e8e7..6673a2e48b 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_model_usd.py +++ b/client/ayon_core/hosts/max/plugins/load/load_model_usd.py @@ -65,8 +65,9 @@ def load(self, context, name=None, namespace=None, data=None): name, usd_objects, context, namespace, loader=self.__class__.__name__) - def update(self, container, representation): - path = get_representation_path(representation) + def update(self, container, context): + repre_doc = context["representation"] + path = get_representation_path(repre_doc) node_name = container["instance_node"] node = rt.GetNodeByName(node_name) namespace, name = get_namespace(node_name) @@ -107,11 +108,11 @@ def update(self, container, representation): rt.Select(node) lib.imprint(node_name, { - "representation": str(representation["_id"]) + "representation": str(repre_doc["_id"]) }) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): from pymxs import runtime as rt diff --git a/client/ayon_core/hosts/max/plugins/load/load_pointcache.py b/client/ayon_core/hosts/max/plugins/load/load_pointcache.py index e9cde4c654..6f79caea42 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_pointcache.py +++ b/client/ayon_core/hosts/max/plugins/load/load_pointcache.py @@ -76,10 +76,11 @@ def load(self, context, name=None, namespace=None, data=None): namespace, loader=self.__class__.__name__ ) - def update(self, container, representation): + def update(self, container, context): from pymxs import runtime as rt - path = get_representation_path(representation) + repre_doc = context["representation"] + path = get_representation_path(repre_doc) node = rt.GetNodeByName(container["instance_node"]) abc_container = [n for n in get_previous_loaded_object(node) if rt.ClassOf(n) == rt.AlembicContainer] @@ -96,11 +97,11 @@ def update(self, container, representation): abc_obj.source = path lib.imprint( container["instance_node"], - {"representation": str(representation["_id"])}, + {"representation": str(repre_doc["_id"])}, ) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): from pymxs import runtime as rt diff --git a/client/ayon_core/hosts/max/plugins/load/load_pointcache_ornatrix.py b/client/ayon_core/hosts/max/plugins/load/load_pointcache_ornatrix.py index 338cbfafb9..67d1374266 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_pointcache_ornatrix.py +++ b/client/ayon_core/hosts/max/plugins/load/load_pointcache_ornatrix.py @@ -62,8 +62,9 @@ def load(self, context, name=None, namespace=None, data=None): namespace, loader=self.__class__.__name__ ) - def update(self, container, representation): - path = get_representation_path(representation) + def update(self, container, context): + repre_doc = context["representation"] + path = get_representation_path(repre_doc) node_name = container["instance_node"] namespace, name = get_namespace(node_name) node = rt.getNodeByName(node_name) @@ -98,11 +99,11 @@ def update(self, container, representation): update_custom_attribute_data(node, ox_abc_objects) lib.imprint( container["instance_node"], - {"representation": str(representation["_id"])}, + {"representation": str(repre_doc["_id"])}, ) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): from pymxs import runtime as rt diff --git a/client/ayon_core/hosts/max/plugins/load/load_pointcloud.py b/client/ayon_core/hosts/max/plugins/load/load_pointcloud.py index 7f4fba50b3..894648ff23 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_pointcloud.py +++ b/client/ayon_core/hosts/max/plugins/load/load_pointcloud.py @@ -41,11 +41,12 @@ def load(self, context, name=None, namespace=None, data=None): name, [obj], context, namespace, loader=self.__class__.__name__) - def update(self, container, representation): + def update(self, container, context): """update the container""" from pymxs import runtime as rt - path = get_representation_path(representation) + repre_doc = context["representation"] + path = get_representation_path(repre_doc) node = rt.GetNodeByName(container["instance_node"]) node_list = get_previous_loaded_object(node) update_custom_attribute_data( @@ -55,11 +56,11 @@ def update(self, container, representation): for prt in rt.Selection: prt.filename = path lib.imprint(container["instance_node"], { - "representation": str(representation["_id"]) + "representation": str(repre_doc["_id"]) }) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): """remove the container""" diff --git a/client/ayon_core/hosts/max/plugins/load/load_redshift_proxy.py b/client/ayon_core/hosts/max/plugins/load/load_redshift_proxy.py index 5f2f5ec1ad..7395a6eca5 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_redshift_proxy.py +++ b/client/ayon_core/hosts/max/plugins/load/load_redshift_proxy.py @@ -52,10 +52,11 @@ def load(self, context, name=None, namespace=None, data=None): name, [rs_proxy], context, namespace, loader=self.__class__.__name__) - def update(self, container, representation): + def update(self, container, context): from pymxs import runtime as rt - path = get_representation_path(representation) + repre_doc = context["representation"] + path = get_representation_path(repre_doc) node = rt.getNodeByName(container["instance_node"]) node_list = get_previous_loaded_object(node) rt.Select(node_list) @@ -65,11 +66,11 @@ def update(self, container, representation): proxy.file = path lib.imprint(container["instance_node"], { - "representation": str(representation["_id"]) + "representation": str(repre_doc["_id"]) }) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): from pymxs import runtime as rt diff --git a/client/ayon_core/hosts/max/plugins/load/load_tycache.py b/client/ayon_core/hosts/max/plugins/load/load_tycache.py index 7ae1aea72c..5acc759b4a 100644 --- a/client/ayon_core/hosts/max/plugins/load/load_tycache.py +++ b/client/ayon_core/hosts/max/plugins/load/load_tycache.py @@ -39,11 +39,12 @@ def load(self, context, name=None, namespace=None, data=None): name, [obj], context, namespace, loader=self.__class__.__name__) - def update(self, container, representation): + def update(self, container, context): """update the container""" from pymxs import runtime as rt - path = get_representation_path(representation) + repre_doc = context["representation"] + path = get_representation_path(repre_doc) node = rt.GetNodeByName(container["instance_node"]) node_list = get_previous_loaded_object(node) update_custom_attribute_data(node, node_list) @@ -51,11 +52,11 @@ def update(self, container, representation): for tyc in node_list: tyc.filename = path lib.imprint(container["instance_node"], { - "representation": str(representation["_id"]) + "representation": str(repre_doc["_id"]) }) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): """remove the container""" From 8bdf0552beb56c14f2c1921e62ee877aaf660773 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 26 Feb 2024 17:57:09 +0100 Subject: [PATCH 23/50] houdini load plugins are expecting representation context --- .../hosts/houdini/plugins/load/load_alembic.py | 12 ++++++------ .../houdini/plugins/load/load_alembic_archive.py | 12 ++++++------ .../hosts/houdini/plugins/load/load_ass.py | 11 ++++++----- .../hosts/houdini/plugins/load/load_bgeo.py | 14 +++++++------- .../hosts/houdini/plugins/load/load_camera.py | 8 ++++---- .../hosts/houdini/plugins/load/load_fbx.py | 12 ++++++------ .../hosts/houdini/plugins/load/load_hda.py | 7 ++++--- .../hosts/houdini/plugins/load/load_image.py | 12 ++++++------ .../houdini/plugins/load/load_redshift_proxy.py | 10 +++++----- .../hosts/houdini/plugins/load/load_usd_layer.py | 12 ++++++------ .../houdini/plugins/load/load_usd_reference.py | 12 ++++++------ .../hosts/houdini/plugins/load/load_vdb.py | 14 +++++++------- 12 files changed, 69 insertions(+), 67 deletions(-) diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_alembic.py b/client/ayon_core/hosts/houdini/plugins/load/load_alembic.py index 6996b0d117..5e138cde83 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_alembic.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_alembic.py @@ -81,8 +81,8 @@ def load(self, context, name=None, namespace=None, data=None): suffix="", ) - def update(self, container, representation): - + def update(self, container, context): + repre_doc = context["representation"] node = container["node"] try: alembic_node = next( @@ -93,18 +93,18 @@ def update(self, container, representation): return # Update the file path - file_path = get_representation_path(representation) + file_path = get_representation_path(repre_doc) file_path = file_path.replace("\\", "/") alembic_node.setParms({"fileName": file_path}) # Update attribute - node.setParms({"representation": str(representation["_id"])}) + node.setParms({"representation": str(repre_doc["_id"])}) def remove(self, container): node = container["node"] node.destroy() - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_alembic_archive.py b/client/ayon_core/hosts/houdini/plugins/load/load_alembic_archive.py index cfe3b16ebb..0d505806ff 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_alembic_archive.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_alembic_archive.py @@ -55,17 +55,17 @@ def load(self, context, name=None, namespace=None, data=None): self.__class__.__name__, suffix="") - def update(self, container, representation): - + def update(self, container, context): + repre_doc = context["representation"] node = container["node"] # Update the file path - file_path = get_representation_path(representation) + file_path = get_representation_path(repre_doc) file_path = file_path.replace("\\", "/") # Update attributes node.setParms({"fileName": file_path, - "representation": str(representation["_id"])}) + "representation": str(repre_doc["_id"])}) # Rebuild node.parm("buildHierarchy").pressButton() @@ -75,5 +75,5 @@ def remove(self, container): node = container["node"] node.destroy() - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_ass.py b/client/ayon_core/hosts/houdini/plugins/load/load_ass.py index 6fbe315adb..396eb3a9f7 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_ass.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_ass.py @@ -48,13 +48,14 @@ def load(self, context, name=None, namespace=None, data=None): suffix="", ) - def update(self, container, representation): + def update(self, container, context): # Update the file path + repre_doc = context["representation"] procedural = container["node"] - procedural.setParms({"ar_filename": self.format_path(representation)}) + procedural.setParms({"ar_filename": self.format_path(repre_doc)}) # Update attribute - procedural.setParms({"representation": str(representation["_id"])}) + procedural.setParms({"representation": str(repre_doc["_id"])}) def remove(self, container): node = container["node"] @@ -86,5 +87,5 @@ def format_path(representation): return os.path.normpath(path).replace("\\", "/") - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_bgeo.py b/client/ayon_core/hosts/houdini/plugins/load/load_bgeo.py index afcf82562c..4817e40961 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_bgeo.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_bgeo.py @@ -82,8 +82,8 @@ def format_path(path, representation): return filename - def update(self, container, representation): - + def update(self, container, context): + repre_doc = context["representation"] node = container["node"] try: file_node = next( @@ -94,18 +94,18 @@ def update(self, container, representation): return # Update the file path - file_path = get_representation_path(representation) - file_path = self.format_path(file_path, representation) + file_path = get_representation_path(repre_doc) + file_path = self.format_path(file_path, repre_doc) file_node.setParms({"file": file_path}) # Update attribute - node.setParms({"representation": str(representation["_id"])}) + node.setParms({"representation": str(repre_doc["_id"])}) def remove(self, container): node = container["node"] node.destroy() - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_camera.py b/client/ayon_core/hosts/houdini/plugins/load/load_camera.py index 11826fb30d..6f6560facc 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_camera.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_camera.py @@ -132,17 +132,17 @@ def load(self, context, name=None, namespace=None, data=None): self.__class__.__name__, suffix="") - def update(self, container, representation): - + def update(self, container, context): + repre_doc = context["representation"] node = container["node"] # Update the file path - file_path = get_representation_path(representation) + file_path = get_representation_path(repre_doc) file_path = file_path.replace("\\", "/") # Update attributes node.setParms({"fileName": file_path, - "representation": str(representation["_id"])}) + "representation": str(repre_doc["_id"])}) # Store the cam temporarily next to the Alembic Archive # so that we can preserve parm values the user set on it diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_fbx.py b/client/ayon_core/hosts/houdini/plugins/load/load_fbx.py index cc1a746d93..c26b12303d 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_fbx.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_fbx.py @@ -47,8 +47,8 @@ def load(self, context, name=None, namespace=None, data=None): return containerised_nodes - def update(self, container, representation): - + def update(self, container, context): + repre_doc = context["representation"] node = container["node"] try: file_node = next( @@ -59,21 +59,21 @@ def update(self, container, representation): return # Update the file path from representation - file_path = get_representation_path(representation) + file_path = get_representation_path(repre_doc) file_path = file_path.replace("\\", "/") file_node.setParms({"file": file_path}) # Update attribute - node.setParms({"representation": str(representation["_id"])}) + node.setParms({"representation": str(repre_doc["_id"])}) def remove(self, container): node = container["node"] node.destroy() - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def get_node_name(self, context, name=None, namespace=None): """Define node name.""" diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_hda.py b/client/ayon_core/hosts/houdini/plugins/load/load_hda.py index 288152f2bd..ffe9e55036 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_hda.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_hda.py @@ -48,11 +48,12 @@ def load(self, context, name=None, namespace=None, data=None): suffix="", ) - def update(self, container, representation): + def update(self, container, context): import hou + repre_doc = context["representation"] hda_node = container["node"] - file_path = get_representation_path(representation) + file_path = get_representation_path(repre_doc) file_path = file_path.replace("\\", "/") hou.hda.installFile(file_path) defs = hda_node.type().allInstalledDefinitions() @@ -60,7 +61,7 @@ def update(self, container, representation): new = def_paths.index(file_path) defs[new].setIsPreferred(True) hda_node.setParms({ - "representation": str(representation["_id"]) + "representation": str(repre_doc["_id"]) }) def remove(self, container): diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_image.py b/client/ayon_core/hosts/houdini/plugins/load/load_image.py index 20fe2f87ca..c89cc3b173 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_image.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_image.py @@ -87,12 +87,12 @@ def load(self, context, name=None, namespace=None, data=None): return node - def update(self, container, representation): - + def update(self, container, context): + repre_doc = context["representation"] node = container["node"] # Update the file path - file_path = get_representation_path(representation) + file_path = get_representation_path(repre_doc) file_path = file_path.replace("\\", "/") file_path = self._get_file_sequence(file_path) @@ -100,7 +100,7 @@ def update(self, container, representation): node.setParms( { "filename1": file_path, - "representation": str(representation["_id"]), + "representation": str(repre_doc["_id"]), } ) @@ -128,5 +128,5 @@ def _get_file_sequence(self, file_path): fname = ".".join([prefix, "$F{}".format(len(padding)), suffix]) return os.path.join(root, fname).replace("\\", "/") - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_redshift_proxy.py b/client/ayon_core/hosts/houdini/plugins/load/load_redshift_proxy.py index dd6e78b3bc..3e9ce1ff2e 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_redshift_proxy.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_redshift_proxy.py @@ -72,19 +72,19 @@ def load(self, context, name=None, namespace=None, data=None): suffix="", ) - def update(self, container, representation): - + def update(self, container, context): + repre_doc = context["representation"] # Update the file path - file_path = get_representation_path(representation) + file_path = get_representation_path(repre_doc) node = container["node"] node.setParms({ "RS_objprop_proxy_file": self.format_path( - file_path, representation) + file_path, repre_doc) }) # Update attribute - node.setParms({"representation": str(representation["_id"])}) + node.setParms({"representation": str(repre_doc["_id"])}) def remove(self, container): diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_usd_layer.py b/client/ayon_core/hosts/houdini/plugins/load/load_usd_layer.py index 2c37c24884..f4f8a718ad 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_usd_layer.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_usd_layer.py @@ -57,19 +57,19 @@ def load(self, context, name=None, namespace=None, data=None): return container - def update(self, container, representation): - + def update(self, container, context): + repre_doc = context["representation"] node = container["node"] # Update the file path - file_path = get_representation_path(representation) + file_path = get_representation_path(repre_doc) file_path = file_path.replace("\\", "/") # Update attributes node.setParms( { "filepath1": file_path, - "representation": str(representation["_id"]), + "representation": str(repre_doc["_id"]), } ) @@ -81,5 +81,5 @@ def remove(self, container): node = container["node"] node.destroy() - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_usd_reference.py b/client/ayon_core/hosts/houdini/plugins/load/load_usd_reference.py index 9396f00cce..cb83a9a22e 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_usd_reference.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_usd_reference.py @@ -57,19 +57,19 @@ def load(self, context, name=None, namespace=None, data=None): return container - def update(self, container, representation): - + def update(self, container, context): + repre_doc = context["representation"] node = container["node"] # Update the file path - file_path = get_representation_path(representation) + file_path = get_representation_path(repre_doc) file_path = file_path.replace("\\", "/") # Update attributes node.setParms( { "filepath1": file_path, - "representation": str(representation["_id"]), + "representation": str(repre_doc["_id"]), } ) @@ -81,5 +81,5 @@ def remove(self, container): node = container["node"] node.destroy() - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) diff --git a/client/ayon_core/hosts/houdini/plugins/load/load_vdb.py b/client/ayon_core/hosts/houdini/plugins/load/load_vdb.py index c3e374ee8d..ed38e5a5d9 100644 --- a/client/ayon_core/hosts/houdini/plugins/load/load_vdb.py +++ b/client/ayon_core/hosts/houdini/plugins/load/load_vdb.py @@ -79,8 +79,8 @@ def format_path(path, representation): return filename - def update(self, container, representation): - + def update(self, container, context): + repre_doc = context["representation"] node = container["node"] try: file_node = next( @@ -91,18 +91,18 @@ def update(self, container, representation): return # Update the file path - file_path = get_representation_path(representation) - file_path = self.format_path(file_path, representation) + file_path = get_representation_path(repre_doc) + file_path = self.format_path(file_path, repre_doc) file_node.setParms({"file": file_path}) # Update attribute - node.setParms({"representation": str(representation["_id"])}) + node.setParms({"representation": str(repre_doc["_id"])}) def remove(self, container): node = container["node"] node.destroy() - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) From bd58e9fa67431df3034ce3e1b6a52d17a9d282da Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 26 Feb 2024 17:57:18 +0100 Subject: [PATCH 24/50] hiero load plugins are expecting representation context --- client/ayon_core/hosts/hiero/api/plugin.py | 2 +- .../hosts/hiero/plugins/load/load_clip.py | 16 +++++++--------- .../hosts/hiero/plugins/load/load_effects.py | 14 +++++++------- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/client/ayon_core/hosts/hiero/api/plugin.py b/client/ayon_core/hosts/hiero/api/plugin.py index 574865488f..769b9f72c3 100644 --- a/client/ayon_core/hosts/hiero/api/plugin.py +++ b/client/ayon_core/hosts/hiero/api/plugin.py @@ -363,7 +363,7 @@ def load( ): pass - def update(self, container, representation): + def update(self, container, context): """Update an existing `container` """ pass diff --git a/client/ayon_core/hosts/hiero/plugins/load/load_clip.py b/client/ayon_core/hosts/hiero/plugins/load/load_clip.py index b8c51e7536..b2a8a2253d 100644 --- a/client/ayon_core/hosts/hiero/plugins/load/load_clip.py +++ b/client/ayon_core/hosts/hiero/plugins/load/load_clip.py @@ -146,27 +146,25 @@ def load(self, context, name, namespace, options): self.__class__.__name__, data_imprint) - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) - def update(self, container, representation): + def update(self, container, context): """ Updating previously loaded clips """ - + version_doc = context["version"] + repre_doc = context["representation"] # load clip to timeline and get main variables name = container['name'] namespace = container['namespace'] track_item = phiero.get_track_items( track_item_name=namespace).pop() - project_name = get_current_project_name() - version_doc = get_version_by_id(project_name, representation["parent"]) - version_data = version_doc.get("data", {}) version_name = version_doc.get("name", None) colorspace = version_data.get("colorspace", None) object_name = "{}_{}".format(name, namespace) - file = get_representation_path(representation).replace("\\", "/") + file = get_representation_path(repre_doc).replace("\\", "/") clip = track_item.source() # reconnect media to new path @@ -191,7 +189,7 @@ def update(self, container, representation): # add variables related to version context data_imprint.update({ - "representation": str(representation["_id"]), + "representation": str(repre_doc["_id"]), "version": version_name, "colorspace": colorspace, "objectName": object_name diff --git a/client/ayon_core/hosts/hiero/plugins/load/load_effects.py b/client/ayon_core/hosts/hiero/plugins/load/load_effects.py index 809080e87e..9a5e659451 100644 --- a/client/ayon_core/hosts/hiero/plugins/load/load_effects.py +++ b/client/ayon_core/hosts/hiero/plugins/load/load_effects.py @@ -157,19 +157,19 @@ def _shared_loading( return loaded - def update(self, container, representation): + def update(self, container, context): """ Updating previously loaded effects """ + version_doc = context["version"] + repre_doc = context["representation"] active_track = container["_item"] - file = get_representation_path(representation).replace("\\", "/") + file = get_representation_path(repre_doc).replace("\\", "/") # get main variables name = container['name'] namespace = container['namespace'] # get timeline in out data - project_name = get_current_project_name() - version_doc = get_version_by_id(project_name, representation["parent"]) version_data = version_doc["data"] clip_in = version_data["clipIn"] clip_out = version_data["clipOut"] @@ -197,7 +197,7 @@ def update(self, container, representation): data_imprint = { "objectName": object_name, "name": name, - "representation": str(representation["_id"]), + "representation": str(repre_doc["_id"]), "children_names": [] } @@ -256,8 +256,8 @@ def byteify(self, input): else: return input - def switch(self, container, representation): - self.update(container, representation) + def switch(self, container, context): + self.update(container, context) def remove(self, container): pass From 2c0cb76f35fb3530cc5762bbb61d1edbdba2b6e0 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 27 Feb 2024 17:39:30 +0800 Subject: [PATCH 25/50] validate the mesh has uv --- .../plugins/publish/validate_mesh_has_uv.py | 45 +++++++++++++++++++ .../max/server/settings/publishers.py | 9 ++++ server_addon/max/server/version.py | 2 +- 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py new file mode 100644 index 0000000000..3e966acc87 --- /dev/null +++ b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py @@ -0,0 +1,45 @@ + +import pyblish.api +from ayon_core.hosts.max.api.action import SelectInvalidAction +from ayon_core.pipeline.publish import ( + ValidateMeshOrder, + OptionalPyblishPluginMixin, + PublishValidationError +) +from pymxs import runtime as rt + + +class ValidateMeshHasUVs(pyblish.api.InstancePlugin, + OptionalPyblishPluginMixin): + + """Validate the current mesh has UVs. + + It validates whether the current UV set has non-zero UVs and + at least more than the vertex count. It's not really bulletproof, + but a simple quick validation to check if there are likely + UVs for every face. + """ + + order = ValidateMeshOrder + hosts = ['max'] + families = ['model'] + label = 'Validate Mesh Has UVs' + actions = [SelectInvalidAction] + optional = True + + + @classmethod + def get_invalid(cls, instance): + invalid = [member for member in instance.data["members"] + if not member.mesh.numTVerts > 0] + return invalid + + def process(self, instance): + invalid = self.get_invalid(instance) + if invalid: + raise PublishValidationError( + title="Mesh has missing UVs", + message="Model meshes are required to have UVs.

" + "Meshes detected with invalid or missing UVs:
" + "{0}".format(invalid) + ) diff --git a/server_addon/max/server/settings/publishers.py b/server_addon/max/server/settings/publishers.py index 5e28c1b467..6ea6a887d1 100644 --- a/server_addon/max/server/settings/publishers.py +++ b/server_addon/max/server/settings/publishers.py @@ -86,6 +86,10 @@ class PublishersModel(BaseSettingsModel): default_factory=ValidateLoadedPluginModel, title="Validate Loaded Plugin" ) + ValidateMeshHasUVs: BasicValidateModel = SettingsField( + default_factory=BasicValidateModel, + title="Validate Mesh Has UVs" + ) ExtractModelObj: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Extract OBJ", @@ -134,6 +138,11 @@ class PublishersModel(BaseSettingsModel): "optional": True, "family_plugins_mapping": [] }, + "ValidateMeshHasUVs": { + "enabled": True, + "optional": True, + "active": False + }, "ExtractModelObj": { "enabled": True, "optional": True, diff --git a/server_addon/max/server/version.py b/server_addon/max/server/version.py index 1276d0254f..0a8da88258 100644 --- a/server_addon/max/server/version.py +++ b/server_addon/max/server/version.py @@ -1 +1 @@ -__version__ = "0.1.5" +__version__ = "0.1.6" From d9a278e470af8f7542dd53e9f3c3976ccd6c3c00 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 27 Feb 2024 18:42:48 +0800 Subject: [PATCH 26/50] correct object name for the error message --- .../ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py index 3e966acc87..a55b49b515 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py @@ -41,5 +41,5 @@ def process(self, instance): title="Mesh has missing UVs", message="Model meshes are required to have UVs.

" "Meshes detected with invalid or missing UVs:
" - "{0}".format(invalid) + "{0}".format([err.name for err in invalid]) ) From f3ee01ba72cf25c9c1a9f8c540521025312ff619 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 27 Feb 2024 18:53:27 +0800 Subject: [PATCH 27/50] edit docstring --- .../hosts/max/plugins/publish/validate_mesh_has_uv.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py index a55b49b515..eda638daae 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py @@ -14,10 +14,9 @@ class ValidateMeshHasUVs(pyblish.api.InstancePlugin, """Validate the current mesh has UVs. - It validates whether the current UV set has non-zero UVs and - at least more than the vertex count. It's not really bulletproof, - but a simple quick validation to check if there are likely - UVs for every face. + It validates whether the current mesh has texture vertex(s). + If the mesh does not have texture vertex(s), it does not + have UVs in Max. """ order = ValidateMeshOrder From cd694266b8375e8b5e96974b869fe5360fcdf89c Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 27 Feb 2024 21:34:45 +0800 Subject: [PATCH 28/50] improve error message and docstring --- .../plugins/publish/validate_mesh_has_uv.py | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py index eda638daae..4cef1a5658 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py @@ -14,9 +14,12 @@ class ValidateMeshHasUVs(pyblish.api.InstancePlugin, """Validate the current mesh has UVs. - It validates whether the current mesh has texture vertex(s). - If the mesh does not have texture vertex(s), it does not + This validator only checks if the mesh has UVs but not + whether the faces of the mesh have UVs. + It validates whether the current mesh has texture vertices. + If the mesh does not have texture vertices, it does not have UVs in Max. + """ order = ValidateMeshOrder @@ -36,9 +39,18 @@ def get_invalid(cls, instance): def process(self, instance): invalid = self.get_invalid(instance) if invalid: - raise PublishValidationError( - title="Mesh has missing UVs", - message="Model meshes are required to have UVs.

" - "Meshes detected with invalid or missing UVs:
" - "{0}".format([err.name for err in invalid]) + bullet_point_invalid_statement = "\n".join( + "- {}".format(invalid.name) for invalid + in invalid ) + report = ( + "Model meshes are required to have UVs.\n\n" + "Meshes detected with invalid or missing UVs:\n" + f"{bullet_point_invalid_statement}\n\n" + ) + raise PublishValidationError( + report, + description=( + "Model meshes are required to have UVs.\n\n" + "Meshes detected with no texture vertice(s) or missing UVs"), + title="Mesh has missing UVs") From 16b28fe3bd3956974550a55f31cdf073dd3c9c15 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 28 Feb 2024 17:54:19 +0800 Subject: [PATCH 29/50] tweak docstring --- .../hosts/max/plugins/publish/validate_mesh_has_uv.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py index 4cef1a5658..846e537b69 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py @@ -15,7 +15,8 @@ class ValidateMeshHasUVs(pyblish.api.InstancePlugin, """Validate the current mesh has UVs. This validator only checks if the mesh has UVs but not - whether the faces of the mesh have UVs. + whether all the individual faces of the mesh have UVs. + It validates whether the current mesh has texture vertices. If the mesh does not have texture vertices, it does not have UVs in Max. @@ -52,5 +53,5 @@ def process(self, instance): report, description=( "Model meshes are required to have UVs.\n\n" - "Meshes detected with no texture vertice(s) or missing UVs"), + "Meshes detected with no texture vertice or missing UVs"), title="Mesh has missing UVs") From 3597efbe9f14f06caafb1e0cec1feb48a4a9d56a Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 28 Feb 2024 19:48:28 +0800 Subject: [PATCH 30/50] remove unneccessary settings --- .../publish/validate_instance_in_context.py | 38 ++- client/ayon_core/settings/__init__.py | 18 -- .../defaults/project_settings/max.json | 105 --------- client/ayon_core/settings/lib.py | 223 ------------------ client/ayon_core/settings/local_settings.md | 79 ------- 5 files changed, 16 insertions(+), 447 deletions(-) delete mode 100644 client/ayon_core/settings/__init__.py delete mode 100644 client/ayon_core/settings/defaults/project_settings/max.json delete mode 100644 client/ayon_core/settings/lib.py delete mode 100644 client/ayon_core/settings/local_settings.md diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py index e4d078b36c..788e9fb19c 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py @@ -42,36 +42,30 @@ def process(self, instance): context_asset = instance.context.data["folderPath"] task = rt.getUserProp(instance_node, "task") context_task = instance.context.data["task"] + invalid = [] if asset != context_asset: - raise PublishValidationError( - message=( - "Instance '{}' publishes to different asset than current " - "context: {}. Current context: {}".format( - instance.name, asset, context_asset - ) - ), - description=( - "## Publishing to a different asset\n" - "There are publish instances present which are publishing " - "into a different asset than your current context.\n\n" - "Usually this is not what you want but there can be cases " - "where you might want to publish into another asset or " - "shot. If that's the case you can disable the validation " - "on the instance to ignore it." + invalid.append( + "Instance '{}' publishes to different asset than current " + "context: {}. Current context: {}".format( + instance.name, asset, context_asset ) ) if task != context_task: + invalid.append( + "Instance '{}' publishes to different task than current " + "context: {}. Current context: {}".format( + instance.name, task, context_task + ) + ) + + if invalid: + message = "\n".join(invalid) raise PublishValidationError( - message=( - "Instance '{}' publishes to different task than current " - "context: {}. Current context: {}".format( - instance.name, task, context_task - ) - ), + message=message, description=( "## Publishing to a different asset\n" "There are publish instances present which are publishing " - "into a different asset than your current context.\n\n" + "into a different asset or task than your current context.\n\n" "Usually this is not what you want but there can be cases " "where you might want to publish into another asset or " "shot. If that's the case you can disable the validation " diff --git a/client/ayon_core/settings/__init__.py b/client/ayon_core/settings/__init__.py deleted file mode 100644 index d32b5f3391..0000000000 --- a/client/ayon_core/settings/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -from .lib import ( - get_ayon_settings, - get_studio_settings, - get_system_settings, - get_project_settings, - get_general_environments, - get_current_project_settings, -) - - -__all__ = ( - "get_ayon_settings", - "get_studio_settings", - "get_system_settings", - "get_general_environments", - "get_project_settings", - "get_current_project_settings", -) diff --git a/client/ayon_core/settings/defaults/project_settings/max.json b/client/ayon_core/settings/defaults/project_settings/max.json deleted file mode 100644 index 7927472489..0000000000 --- a/client/ayon_core/settings/defaults/project_settings/max.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "unit_scale_settings": { - "enabled": true, - "scene_unit_scale": "Meters" - }, - "imageio": { - "activate_host_color_management": true, - "ocio_config": { - "override_global_config": false, - "filepath": [] - }, - "file_rules": { - "activate_host_rules": false, - "rules": {} - } - }, - "RenderSettings": { - "default_render_image_folder": "renders/3dsmax", - "aov_separator": "underscore", - "image_format": "exr", - "multipass": true - }, - "CreateReview": { - "review_width": 1920, - "review_height": 1080, - "percentSize": 100.0, - "keep_images": false, - "image_format": "png", - "visual_style": "Realistic", - "viewport_preset": "Quality", - "anti_aliasing": "None", - "vp_texture": true - }, - "PointCloud": { - "attribute": { - "Age": "age", - "Radius": "radius", - "Position": "position", - "Rotation": "rotation", - "Scale": "scale", - "Velocity": "velocity", - "Color": "color", - "TextureCoordinate": "texcoord", - "MaterialID": "matid", - "custFloats": "custFloats", - "custVecs": "custVecs" - } - }, - "publish": { - "ValidateInstanceInContext": { - "enabled": true, - "optional": true, - "active": true - }, - "ValidateFrameRange": { - "enabled": true, - "optional": true, - "active": true - }, - "ValidateAttributes": { - "enabled": false, - "attributes": {} - }, - "ValidateCameraAttributes": { - "enabled": true, - "optional": true, - "active": false, - "fov": 45.0, - "nearrange": 0.0, - "farrange": 1000.0, - "nearclip": 1.0, - "farclip": 1000.0 - }, - "ValidateLoadedPlugin": { - "enabled": false, - "optional": true, - "family_plugins_mapping": [] - }, - "ExtractModelObj": { - "enabled": true, - "optional": true, - "active": false - }, - "ExtractModelFbx": { - "enabled": true, - "optional": true, - "active": false - }, - "ExtractModelUSD": { - "enabled": true, - "optional": true, - "active": false - }, - "ExtractModel": { - "enabled": true, - "optional": true, - "active": true - }, - "ExtractMaxSceneRaw": { - "enabled": true, - "optional": true, - "active": true - } - } -} diff --git a/client/ayon_core/settings/lib.py b/client/ayon_core/settings/lib.py deleted file mode 100644 index eadf3ba544..0000000000 --- a/client/ayon_core/settings/lib.py +++ /dev/null @@ -1,223 +0,0 @@ -import os -import json -import logging -import collections -import copy -import time - -from ayon_core.client import get_ayon_server_api_connection - -log = logging.getLogger(__name__) - - -class CacheItem: - lifetime = 10 - - def __init__(self, value, outdate_time=None): - self._value = value - if outdate_time is None: - outdate_time = time.time() + self.lifetime - self._outdate_time = outdate_time - - @classmethod - def create_outdated(cls): - return cls({}, 0) - - def get_value(self): - return copy.deepcopy(self._value) - - def update_value(self, value): - self._value = value - self._outdate_time = time.time() + self.lifetime - - @property - def is_outdated(self): - return time.time() > self._outdate_time - - -class _AyonSettingsCache: - use_bundles = None - variant = None - addon_versions = CacheItem.create_outdated() - studio_settings = CacheItem.create_outdated() - cache_by_project_name = collections.defaultdict( - CacheItem.create_outdated) - - @classmethod - def _use_bundles(cls): - if _AyonSettingsCache.use_bundles is None: - con = get_ayon_server_api_connection() - major, minor, _, _, _ = con.get_server_version_tuple() - use_bundles = True - if (major, minor) < (0, 3): - use_bundles = False - _AyonSettingsCache.use_bundles = use_bundles - return _AyonSettingsCache.use_bundles - - @classmethod - def _get_variant(cls): - if _AyonSettingsCache.variant is None: - from ayon_core.lib import is_staging_enabled, is_dev_mode_enabled - - variant = "production" - if is_dev_mode_enabled(): - variant = cls._get_bundle_name() - elif is_staging_enabled(): - variant = "staging" - - # Cache variant - _AyonSettingsCache.variant = variant - - # Set the variant to global ayon api connection - con = get_ayon_server_api_connection() - con.set_default_settings_variant(variant) - return _AyonSettingsCache.variant - - @classmethod - def _get_bundle_name(cls): - return os.environ["AYON_BUNDLE_NAME"] - - @classmethod - def get_value_by_project(cls, project_name): - cache_item = _AyonSettingsCache.cache_by_project_name[project_name] - if cache_item.is_outdated: - con = get_ayon_server_api_connection() - if cls._use_bundles(): - value = con.get_addons_settings( - bundle_name=cls._get_bundle_name(), - project_name=project_name, - variant=cls._get_variant() - ) - else: - value = con.get_addons_settings(project_name) - cache_item.update_value(value) - return cache_item.get_value() - - @classmethod - def _get_addon_versions_from_bundle(cls): - con = get_ayon_server_api_connection() - expected_bundle = cls._get_bundle_name() - bundles = con.get_bundles()["bundles"] - bundle = next( - ( - bundle - for bundle in bundles - if bundle["name"] == expected_bundle - ), - None - ) - if bundle is not None: - return bundle["addons"] - return {} - - @classmethod - def get_addon_versions(cls): - cache_item = _AyonSettingsCache.addon_versions - if cache_item.is_outdated: - if cls._use_bundles(): - addons = cls._get_addon_versions_from_bundle() - else: - con = get_ayon_server_api_connection() - settings_data = con.get_addons_settings( - only_values=False, - variant=cls._get_variant() - ) - addons = settings_data["versions"] - cache_item.update_value(addons) - - return cache_item.get_value() - - -def get_site_local_overrides(project_name, site_name, local_settings=None): - """Site overrides from local settings for passet project and site name. - - Deprecated: - This function is not implemented for AYON and will be removed. - - Args: - project_name (str): For which project are overrides. - site_name (str): For which site are overrides needed. - local_settings (dict): Preloaded local settings. They are loaded - automatically if not passed. - """ - - return {} - - -def get_ayon_settings(project_name=None): - """AYON studio settings. - - Raw AYON settings values. - - Args: - project_name (Optional[str]): Project name. - - Returns: - dict[str, Any]: AYON settings. - """ - - return _AyonSettingsCache.get_value_by_project(project_name) - - -def get_studio_settings(*args, **kwargs): - return _AyonSettingsCache.get_value_by_project(None) - - -# Backward compatibility -get_system_settings = get_studio_settings - - -def get_project_settings(project_name, *args, **kwargs): - return _AyonSettingsCache.get_value_by_project(project_name) - - -def get_general_environments(studio_settings=None): - """General studio environment variables. - - Args: - studio_settings (Optional[dict]): Pre-queried studio settings. - - Returns: - dict[str, Any]: General studio environment variables. - - """ - if studio_settings is None: - studio_settings = get_ayon_settings() - return json.loads(studio_settings["core"]["environments"]) - - -def get_project_environments(project_name, project_settings=None): - """Project environment variables. - - Args: - project_name (str): Project name. - project_settings (Optional[dict]): Pre-queried project settings. - - Returns: - dict[str, Any]: Project environment variables. - - """ - if project_settings is None: - project_settings = get_project_settings(project_name) - return json.loads( - project_settings["core"]["project_environments"] - ) - - -def get_current_project_settings(): - """Project settings for current context project. - - Project name should be stored in environment variable `AYON_PROJECT_NAME`. - This function should be used only in host context where environment - variable must be set and should not happen that any part of process will - change the value of the enviornment variable. - """ - project_name = os.environ.get("AYON_PROJECT_NAME") - if not project_name: - raise ValueError( - "Missing context project in environemt variable `AYON_PROJECT_NAME`." - ) - return get_project_settings(project_name) - - - diff --git a/client/ayon_core/settings/local_settings.md b/client/ayon_core/settings/local_settings.md deleted file mode 100644 index fbb5cf3df1..0000000000 --- a/client/ayon_core/settings/local_settings.md +++ /dev/null @@ -1,79 +0,0 @@ -# Structure of local settings -- local settings do not have any validation schemas right now this should help to see what is stored to local settings and how it works -- they are stored by identifier site_id which should be unified identifier of workstation -- all keys may and may not available on load -- contain main categories: `general`, `applications`, `projects` - -## Categories -### General -- ATM contain only label of site -```json -{ - "general": { - "site_label": "MySite" - } -} -``` - -### Applications -- modifications of application executables -- output should match application groups and variants -```json -{ - "applications": { - "": { - "": { - "executable": "/my/path/to/nuke_12_2" - } - } - } -} -``` - -### Projects -- project specific modifications -- default project is stored under constant key defined in `pype.settings.contants` -```json -{ - "projects": { - "": { - "active_site": "", - "remote_site": "", - "roots": { - "": { - "": "" - } - } - } - } -} -``` - -## Final document -```json -{ - "_id": "", - "site_id": "", - "general": { - "site_label": "MySite" - }, - "applications": { - "": { - "": { - "executable": "" - } - } - }, - "projects": { - "": { - "active_site": "", - "remote_site": "", - "roots": { - "": { - "": "" - } - } - } - } -} -``` From d98c055a048591168d64b3e0ec11243bbbf8bde6 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 28 Feb 2024 20:14:43 +0800 Subject: [PATCH 31/50] some tweaks on codes --- .../plugins/publish/validate_mesh_has_uv.py | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py index 846e537b69..21339c1d41 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py @@ -33,9 +33,21 @@ class ValidateMeshHasUVs(pyblish.api.InstancePlugin, @classmethod def get_invalid(cls, instance): - invalid = [member for member in instance.data["members"] - if not member.mesh.numTVerts > 0] - return invalid + invalid_mesh_type = [member for member in instance.data["members"] + if not rt.isProperty(member, "mesh")] + if invalid_mesh_type: + cls.log.error("Non-mesh type objects detected:\n".join( + "-{}".format(invalid.name) for invalid + in invalid_mesh_type)) + return invalid_mesh_type + + invalid_uv = [member for member in instance.data["members"] + if not member.mesh.numTVerts > 0] + if invalid_uv: + cls.log.error("Meshes detected with invalid UVs:\n".join( + "-{}".format(invalid.name) for invalid + in invalid_uv)) + return invalid_uv def process(self, instance): invalid = self.get_invalid(instance) @@ -47,7 +59,7 @@ def process(self, instance): report = ( "Model meshes are required to have UVs.\n\n" "Meshes detected with invalid or missing UVs:\n" - f"{bullet_point_invalid_statement}\n\n" + f"{bullet_point_invalid_statement}\n" ) raise PublishValidationError( report, From 446160f758f2bed3225bb898c9ca605808fbffa4 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 28 Feb 2024 20:15:31 +0800 Subject: [PATCH 32/50] cosmetic for docstring --- .../hosts/max/plugins/publish/validate_instance_in_context.py | 1 - 1 file changed, 1 deletion(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py index 788e9fb19c..93f977c15c 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py @@ -23,7 +23,6 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, Action on this validator will select invalid instances. """ - order = ValidateContentsOrder label = "Instance in same Context" optional = True From 05d308d975c33de04d01c24d8c58bbc1a2a3436a Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Wed, 28 Feb 2024 12:41:43 +0000 Subject: [PATCH 33/50] Added missing hosts to collect_audio --- client/ayon_core/plugins/publish/collect_audio.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/collect_audio.py b/client/ayon_core/plugins/publish/collect_audio.py index f0efd546e7..af6598ad59 100644 --- a/client/ayon_core/plugins/publish/collect_audio.py +++ b/client/ayon_core/plugins/publish/collect_audio.py @@ -40,7 +40,10 @@ class CollectAudio(pyblish.api.ContextPlugin): "webpublisher", "aftereffects", "flame", - "unreal" + "unreal", + "blender", + "houdini", + "max", ] audio_product_name = "audioMain" From 0e35253bdee1a0bdef553ab7b8d05823280de6f9 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 28 Feb 2024 20:44:33 +0800 Subject: [PATCH 34/50] add a check on non-mesh objects in the validator --- .../max/plugins/publish/validate_mesh_has_uv.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py index 21339c1d41..5594a6a789 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py @@ -36,17 +36,13 @@ def get_invalid(cls, instance): invalid_mesh_type = [member for member in instance.data["members"] if not rt.isProperty(member, "mesh")] if invalid_mesh_type: - cls.log.error("Non-mesh type objects detected:\n".join( - "-{}".format(invalid.name) for invalid - in invalid_mesh_type)) + cls.log.error("Non-mesh type objects detected") return invalid_mesh_type invalid_uv = [member for member in instance.data["members"] if not member.mesh.numTVerts > 0] if invalid_uv: - cls.log.error("Meshes detected with invalid UVs:\n".join( - "-{}".format(invalid.name) for invalid - in invalid_uv)) + cls.log.error("Meshes detected with invalid UVs") return invalid_uv def process(self, instance): @@ -57,13 +53,14 @@ def process(self, instance): in invalid ) report = ( - "Model meshes are required to have UVs.\n\n" + "Non-mesh objects found or mesh objects" + " do not have UVs.\n\n" "Meshes detected with invalid or missing UVs:\n" f"{bullet_point_invalid_statement}\n" ) raise PublishValidationError( report, description=( - "Model meshes are required to have UVs.\n\n" + "Non-mesh objects detected or the meshes do not have any UVs.\n\n" "Meshes detected with no texture vertice or missing UVs"), - title="Mesh has missing UVs") + title="Non-mesh objects found or mesh has missing UVs") From ce94823a0f09a707bbcbc51f87941c4d756e0df4 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 28 Feb 2024 20:51:16 +0800 Subject: [PATCH 35/50] restore unrelated deletion of unrelated code --- client/ayon_core/settings/local_settings.md | 79 +++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 client/ayon_core/settings/local_settings.md diff --git a/client/ayon_core/settings/local_settings.md b/client/ayon_core/settings/local_settings.md new file mode 100644 index 0000000000..6694bb60a8 --- /dev/null +++ b/client/ayon_core/settings/local_settings.md @@ -0,0 +1,79 @@ +# Structure of local settings +- local settings do not have any validation schemas right now this should help to see what is stored to local settings and how it works +- they are stored by identifier site_id which should be unified identifier of workstation +- all keys may and may not available on load +- contain main categories: `general`, `applications`, `projects` + +## Categories +### General +- ATM contain only label of site +```json +{ + "general": { + "site_label": "MySite" + } +} +``` + +### Applications +- modifications of application executables +- output should match application groups and variants +```json +{ + "applications": { + "": { + "": { + "executable": "/my/path/to/nuke_12_2" + } + } + } +} +``` + +### Projects +- project specific modifications +- default project is stored under constant key defined in `pype.settings.contants` +```json +{ + "projects": { + "": { + "active_site": "", + "remote_site": "", + "roots": { + "": { + "": "" + } + } + } + } +} +``` + +## Final document +```json +{ + "_id": "", + "site_id": "", + "general": { + "site_label": "MySite" + }, + "applications": { + "": { + "": { + "executable": "" + } + } + }, + "projects": { + "": { + "active_site": "", + "remote_site": "", + "roots": { + "": { + "": "" + } + } + } + } +} +``` \ No newline at end of file From 3cf206a61622e5e99fcdfa5706e9d3da16fbfe50 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 28 Feb 2024 20:54:00 +0800 Subject: [PATCH 36/50] restore unrelated deletion of unrelated code --- client/ayon_core/settings/local_settings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/settings/local_settings.md b/client/ayon_core/settings/local_settings.md index 6694bb60a8..fbb5cf3df1 100644 --- a/client/ayon_core/settings/local_settings.md +++ b/client/ayon_core/settings/local_settings.md @@ -76,4 +76,4 @@ } } } -``` \ No newline at end of file +``` From 9ad258997b38968eb126d752ec588f955f6446b1 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 29 Feb 2024 13:40:08 +0800 Subject: [PATCH 37/50] check instance data against context data rather than check user sertup properties against context data --- .../publish/validate_instance_in_context.py | 55 +++++++------------ 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py index 93f977c15c..dcd30da459 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py @@ -33,32 +33,18 @@ def process(self, instance): if not self.is_active(instance.data): return - instance_node = rt.getNodeByName(instance.data.get( - "instance_node", "")) - if not instance_node: - return - asset = rt.getUserProp(instance_node, "folderPath") - context_asset = instance.context.data["folderPath"] - task = rt.getUserProp(instance_node, "task") - context_task = instance.context.data["task"] - invalid = [] - if asset != context_asset: - invalid.append( - "Instance '{}' publishes to different asset than current " - "context: {}. Current context: {}".format( - instance.name, asset, context_asset + folderPath = instance.data.get("folderPath") + task = instance.data.get("task") + context = self.get_context(instance) + if (folderPath, task) != context: + context_label = "{} > {}".format(*context) + instance_label = "{} > {}".format(folderPath, task) + message = ( + "Instance '{}' publishes to different folderPath than current" + "context: {}. Current context:{}".format( + instance.name, instance_label, context_label ) ) - if task != context_task: - invalid.append( - "Instance '{}' publishes to different task than current " - "context: {}. Current context: {}".format( - instance.name, task, context_task - ) - ) - - if invalid: - message = "\n".join(invalid) raise PublishValidationError( message=message, description=( @@ -75,16 +61,11 @@ def process(self, instance): @classmethod def get_invalid(cls, instance): invalid = [] - node = rt.getNodeByName(instance.data["instance_node"]) - asset = rt.getUserProp(node, "folderPath") - context_asset = instance.context.data["folderPath"] - if asset != context_asset: - invalid.append(node) - task = rt.getUserProp(node, "task") - context_task = instance.context.data["task"] - if task != context_task: - invalid.append(node) - + folderPath = instance.data.get("folderPath") + task = instance.data.get("task") + context = cls.get_context(instance) + if (folderPath, task) != context: + invalid.append(rt.getNodeByName(instance.name)) return invalid @classmethod @@ -97,3 +78,9 @@ def repair(cls, instance): return rt.SetUserProp(instance_node, "folderPath", context_asset) rt.SetUserProp(instance_node, "task", context_task) + + @staticmethod + def get_context(instance): + """Return asset, task from publishing context data""" + context = instance.context + return context.data["folderPath"], context.data["task"] From 56f4f04d1c1b94b8afc41da66eaff99ba8c49bd6 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 29 Feb 2024 15:08:25 +0800 Subject: [PATCH 38/50] edit the code would pass only when the object is mesh type --- .../plugins/publish/validate_mesh_has_uv.py | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py index 5594a6a789..4d1490ac8f 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py @@ -30,20 +30,17 @@ class ValidateMeshHasUVs(pyblish.api.InstancePlugin, actions = [SelectInvalidAction] optional = True - @classmethod def get_invalid(cls, instance): invalid_mesh_type = [member for member in instance.data["members"] - if not rt.isProperty(member, "mesh")] + if rt.isProperty(member, "mesh")] if invalid_mesh_type: - cls.log.error("Non-mesh type objects detected") - return invalid_mesh_type + invalid_uv = [member for member in instance.data["members"] + if not member.mesh.numTVerts > 0] + if invalid_uv: + cls.log.error("Meshes detected with invalid UVs") - invalid_uv = [member for member in instance.data["members"] - if not member.mesh.numTVerts > 0] - if invalid_uv: - cls.log.error("Meshes detected with invalid UVs") - return invalid_uv + return invalid_uv def process(self, instance): invalid = self.get_invalid(instance) @@ -53,14 +50,13 @@ def process(self, instance): in invalid ) report = ( - "Non-mesh objects found or mesh objects" - " do not have UVs.\n\n" + "Model meshes are required to have UVs.\n\n" "Meshes detected with invalid or missing UVs:\n" f"{bullet_point_invalid_statement}\n" ) raise PublishValidationError( report, description=( - "Non-mesh objects detected or the meshes do not have any UVs.\n\n" + "Model meshes are required to have UVs.\n\n" "Meshes detected with no texture vertice or missing UVs"), title="Non-mesh objects found or mesh has missing UVs") From 8ca15394a340e6f7c6b8ca0b5b874bea4a840688 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 29 Feb 2024 11:59:10 +0100 Subject: [PATCH 39/50] implemented 'get_index_by_project_name' --- .../tools/ayon_utils/widgets/projects_widget.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/client/ayon_core/tools/ayon_utils/widgets/projects_widget.py b/client/ayon_core/tools/ayon_utils/widgets/projects_widget.py index d3bebecfd6..79ffc77640 100644 --- a/client/ayon_core/tools/ayon_utils/widgets/projects_widget.py +++ b/client/ayon_core/tools/ayon_utils/widgets/projects_widget.py @@ -47,6 +47,22 @@ def refresh(self): def has_content(self): return len(self._project_items) > 0 + def get_index_by_project_name(self, project_name): + """Get index of project by name. + + Args: + project_name (str): Project name. + + Returns: + QtCore.QModelIndex: Index of project item. Index is not valid + if project is not found. + + """ + item = self._project_items.get(project_name) + if item is None: + return QtCore.QModelIndex() + return self.indexFromItem(item) + def set_select_item_visible(self, visible): if self._select_item_visible is visible: return From 3b060d8abf6cb1a12e847e0562e488bedc5d5c20 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 29 Feb 2024 11:59:21 +0100 Subject: [PATCH 40/50] added project roles to init --- client/ayon_core/tools/ayon_utils/widgets/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/client/ayon_core/tools/ayon_utils/widgets/__init__.py b/client/ayon_core/tools/ayon_utils/widgets/__init__.py index b1b7dd7527..a62bab6751 100644 --- a/client/ayon_core/tools/ayon_utils/widgets/__init__.py +++ b/client/ayon_core/tools/ayon_utils/widgets/__init__.py @@ -3,6 +3,10 @@ ProjectsCombobox, ProjectsQtModel, ProjectSortFilterProxy, + PROJECT_NAME_ROLE, + PROJECT_IS_CURRENT_ROLE, + PROJECT_IS_ACTIVE_ROLE, + PROJECT_IS_LIBRARY_ROLE, ) from .folders_widget import ( @@ -28,6 +32,10 @@ "ProjectsCombobox", "ProjectsQtModel", "ProjectSortFilterProxy", + "PROJECT_NAME_ROLE", + "PROJECT_IS_CURRENT_ROLE", + "PROJECT_IS_ACTIVE_ROLE", + "PROJECT_IS_LIBRARY_ROLE", "FoldersWidget", "FoldersQtModel", From 28f1ab0fb5b6d95200f3aaccc3000df39b0f2b17 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 29 Feb 2024 12:00:46 +0100 Subject: [PATCH 41/50] use ayon projects model --- .../ayon_core/tools/traypublisher/window.py | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/client/ayon_core/tools/traypublisher/window.py b/client/ayon_core/tools/traypublisher/window.py index 78517b4185..f993b15d64 100644 --- a/client/ayon_core/tools/traypublisher/window.py +++ b/client/ayon_core/tools/traypublisher/window.py @@ -18,14 +18,19 @@ from ayon_core.tools.publisher.control_qt import QtPublisherController from ayon_core.tools.publisher.window import PublisherWindow from ayon_core.tools.utils import PlaceholderLineEdit, get_ayon_qt_app -from ayon_core.tools.utils.constants import PROJECT_NAME_ROLE -from ayon_core.tools.utils.models import ( - ProjectModel, - ProjectSortFilterProxy +from ayon_core.tools.ayon_utils.models import ProjectsModel +from ayon_core.tools.ayon_utils.widgets import ( + ProjectsQtModel, + ProjectSortFilterProxy, + PROJECT_NAME_ROLE, ) class TrayPublisherController(QtPublisherController): + def __init__(self, *args, **kwargs): + super(TrayPublisherController, self).__init__(*args, **kwargs) + self._projects_model = ProjectsModel(self) + @property def host(self): return self._host @@ -34,6 +39,9 @@ def reset_hierarchy_cache(self): self._hierarchy_model.reset() self._asset_docs_cache.reset() + def get_project_items(self, sender=None): + return self._projects_model.get_project_items(sender) + class TrayPublisherRegistry(JSONSettingRegistry): """Class handling AYON general settings registry. @@ -55,7 +63,7 @@ def __init__(self): class StandaloneOverlayWidget(QtWidgets.QFrame): project_selected = QtCore.Signal(str) - def __init__(self, publisher_window): + def __init__(self, controller, publisher_window): super(StandaloneOverlayWidget, self).__init__(publisher_window) self.setObjectName("OverlayFrame") @@ -67,7 +75,7 @@ def __init__(self, publisher_window): header_label = QtWidgets.QLabel("Choose project", content_widget) header_label.setObjectName("ChooseProjectLabel") # Create project models and view - projects_model = ProjectModel() + projects_model = ProjectsQtModel(controller) projects_proxy = ProjectSortFilterProxy() projects_proxy.setSourceModel(projects_model) projects_proxy.setFilterKeyColumn(0) @@ -138,12 +146,11 @@ def showEvent(self, event): project_name = None if project_name: - index = None - src_index = self._projects_model.find_project(project_name) - if src_index is not None: - index = self._projects_proxy.mapFromSource(src_index) - - if index is not None: + src_index = self._projects_model.get_index_by_project_name( + project_name + ) + index = self._projects_proxy.mapFromSource(src_index) + if index.isValid(): selection_model = self._projects_view.selectionModel() selection_model.select( index, @@ -202,7 +209,7 @@ def __init__(self, *args, **kwargs): self.setWindowFlags(flags) - overlay_widget = StandaloneOverlayWidget(self) + overlay_widget = StandaloneOverlayWidget(controller, self) btns_widget = self._header_extra_widget From 5e8119190492f9f7c058ef3d7c255bbf2a0af912 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 29 Feb 2024 12:01:13 +0100 Subject: [PATCH 42/50] use 'AYONSettingsRegistry' for traypublisher registry --- .../ayon_core/tools/traypublisher/window.py | 25 +++++-------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/client/ayon_core/tools/traypublisher/window.py b/client/ayon_core/tools/traypublisher/window.py index f993b15d64..210e77f0fa 100644 --- a/client/ayon_core/tools/traypublisher/window.py +++ b/client/ayon_core/tools/traypublisher/window.py @@ -10,9 +10,8 @@ from qtpy import QtWidgets, QtCore import qtawesome -import appdirs -from ayon_core.lib import JSONSettingRegistry, is_running_from_build +from ayon_core.lib import AYONSettingsRegistry, is_running_from_build from ayon_core.pipeline import install_host from ayon_core.hosts.traypublisher.api import TrayPublisherHost from ayon_core.tools.publisher.control_qt import QtPublisherController @@ -26,6 +25,11 @@ ) +class TrayPublisherRegistry(AYONSettingsRegistry): + def __init__(self): + super(TrayPublisherRegistry, self).__init__("traypublisher") + + class TrayPublisherController(QtPublisherController): def __init__(self, *args, **kwargs): super(TrayPublisherController, self).__init__(*args, **kwargs) @@ -43,23 +47,6 @@ def get_project_items(self, sender=None): return self._projects_model.get_project_items(sender) -class TrayPublisherRegistry(JSONSettingRegistry): - """Class handling AYON general settings registry. - - Attributes: - vendor (str): Name used for path construction. - product (str): Additional name used for path construction. - - """ - - def __init__(self): - self.vendor = "pypeclub" - self.product = "openpype" - name = "tray_publisher" - path = appdirs.user_data_dir(self.product, self.vendor) - super(TrayPublisherRegistry, self).__init__(name, path) - - class StandaloneOverlayWidget(QtWidgets.QFrame): project_selected = QtCore.Signal(str) From dff383bcedfa3793c4a5ce82ad33567165e26fd0 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 29 Feb 2024 12:01:41 +0100 Subject: [PATCH 43/50] removed 'ProjectModel' and 'ProjectSortFilterProxy' from utils --- client/ayon_core/tools/utils/models.py | 157 ------------------------- 1 file changed, 157 deletions(-) diff --git a/client/ayon_core/tools/utils/models.py b/client/ayon_core/tools/utils/models.py index e60d85b4e4..a4b6ad7885 100644 --- a/client/ayon_core/tools/utils/models.py +++ b/client/ayon_core/tools/utils/models.py @@ -243,160 +243,3 @@ def filterAcceptsRow(self, row, parent_index): return super(RecursiveSortFilterProxyModel, self).filterAcceptsRow( row, parent_index ) - - -# TODO remove 'ProjectModel' and 'ProjectSortFilterProxy' classes -# - replace their usage with current 'ayon_utils' models -class ProjectModel(QtGui.QStandardItemModel): - def __init__( - self, only_active=True, add_default_project=False, *args, **kwargs - ): - super(ProjectModel, self).__init__(*args, **kwargs) - - self._only_active = only_active - self._add_default_project = add_default_project - - self._default_item = None - self._items_by_name = {} - self._refreshed = False - - def set_default_project_available(self, available=True): - if available is None: - available = not self._add_default_project - - if self._add_default_project == available: - return - - self._add_default_project = available - if not available and self._default_item is not None: - root_item = self.invisibleRootItem() - root_item.removeRow(self._default_item.row()) - self._default_item = None - - def set_only_active(self, only_active=True): - if only_active is None: - only_active = not self._only_active - - if self._only_active == only_active: - return - - self._only_active = only_active - - if self._refreshed: - self.refresh() - - def project_name_is_available(self, project_name): - """Check availability of project name in current items.""" - return project_name in self._items_by_name - - def refresh(self): - # Change '_refreshed' state - self._refreshed = True - new_items = [] - # Add default item to model if should - if self._add_default_project and self._default_item is None: - item = QtGui.QStandardItem(DEFAULT_PROJECT_LABEL) - item.setData(None, PROJECT_NAME_ROLE) - item.setData(True, PROJECT_IS_ACTIVE_ROLE) - new_items.append(item) - self._default_item = item - - project_names = set() - project_docs = get_projects( - inactive=not self._only_active, - fields=["name", "data.active"] - ) - for project_doc in project_docs: - project_name = project_doc["name"] - project_names.add(project_name) - if project_name in self._items_by_name: - item = self._items_by_name[project_name] - else: - item = QtGui.QStandardItem(project_name) - - self._items_by_name[project_name] = item - new_items.append(item) - - is_active = project_doc.get("data", {}).get("active", True) - item.setData(project_name, PROJECT_NAME_ROLE) - item.setData(is_active, PROJECT_IS_ACTIVE_ROLE) - - if not is_active: - font = item.font() - font.setItalic(True) - item.setFont(font) - - root_item = self.invisibleRootItem() - for project_name in tuple(self._items_by_name.keys()): - if project_name not in project_names: - item = self._items_by_name.pop(project_name) - root_item.removeRow(item.row()) - - if new_items: - root_item.appendRows(new_items) - - def find_project(self, project_name): - """ - Get index of 'project_name' value. - - Args: - project_name (str): - Returns: - (QModelIndex) - """ - val = self._items_by_name.get(project_name) - if val: - return self.indexFromItem(val) - - -class ProjectSortFilterProxy(QtCore.QSortFilterProxyModel): - def __init__(self, *args, **kwargs): - super(ProjectSortFilterProxy, self).__init__(*args, **kwargs) - self._filter_enabled = True - # Disable case sensitivity - self.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive) - - def lessThan(self, left_index, right_index): - if left_index.data(PROJECT_NAME_ROLE) is None: - return True - - if right_index.data(PROJECT_NAME_ROLE) is None: - return False - - left_is_active = left_index.data(PROJECT_IS_ACTIVE_ROLE) - right_is_active = right_index.data(PROJECT_IS_ACTIVE_ROLE) - if right_is_active == left_is_active: - return super(ProjectSortFilterProxy, self).lessThan( - left_index, right_index - ) - - if left_is_active: - return True - return False - - def filterAcceptsRow(self, source_row, source_parent): - index = self.sourceModel().index(source_row, 0, source_parent) - string_pattern = self.filterRegularExpression().pattern() - if self._filter_enabled: - result = self._custom_index_filter(index) - if result is not None: - project_name = index.data(PROJECT_NAME_ROLE) - if project_name is None: - return result - return string_pattern.lower() in project_name.lower() - - return super(ProjectSortFilterProxy, self).filterAcceptsRow( - source_row, source_parent - ) - - def _custom_index_filter(self, index): - is_active = bool(index.data(PROJECT_IS_ACTIVE_ROLE)) - - return is_active - - def is_filter_enabled(self): - return self._filter_enabled - - def set_filter_enabled(self, value): - self._filter_enabled = value - self.invalidateFilter() From c7ba4be69c9e46f02b05976ab8aec4514de5306c Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 29 Feb 2024 20:37:23 +0800 Subject: [PATCH 44/50] code clean up with bigroy's comment --- .../max/plugins/publish/validate_mesh_has_uv.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py index 4d1490ac8f..cecc16c3c3 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py @@ -32,15 +32,11 @@ class ValidateMeshHasUVs(pyblish.api.InstancePlugin, @classmethod def get_invalid(cls, instance): - invalid_mesh_type = [member for member in instance.data["members"] - if rt.isProperty(member, "mesh")] - if invalid_mesh_type: - invalid_uv = [member for member in instance.data["members"] - if not member.mesh.numTVerts > 0] - if invalid_uv: - cls.log.error("Meshes detected with invalid UVs") - - return invalid_uv + meshes = [member for member in instance.data["members"] + if rt.isProperty(member, "mesh")] + invalid = [member for member in meshes + if not member.mesh.numTVerts > 0] + return invalid def process(self, instance): invalid = self.get_invalid(instance) From 34cca056153b0ae6d6805c90d14822851a0f21e5 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 29 Feb 2024 20:42:32 +0800 Subject: [PATCH 45/50] code clean up --- .../hosts/max/plugins/publish/validate_instance_in_context.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py index dcd30da459..cf285bfab6 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py @@ -1,7 +1,5 @@ # -*- coding: utf-8 -*- """Validate if instance asset is the same as context asset.""" -from __future__ import absolute_import - import pyblish.api from ayon_core.pipeline.publish import ( RepairAction, @@ -41,7 +39,7 @@ def process(self, instance): instance_label = "{} > {}".format(folderPath, task) message = ( "Instance '{}' publishes to different folderPath than current" - "context: {}. Current context:{}".format( + "context: {}. Current context: {}".format( instance.name, instance_label, context_label ) ) From 1bdac65841bc92d77c7df5353d7d96b5ab9f8b2d Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 29 Feb 2024 20:43:13 +0800 Subject: [PATCH 46/50] code clean up --- .../ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py index cecc16c3c3..109b7fe0b5 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_mesh_has_uv.py @@ -35,7 +35,7 @@ def get_invalid(cls, instance): meshes = [member for member in instance.data["members"] if rt.isProperty(member, "mesh")] invalid = [member for member in meshes - if not member.mesh.numTVerts > 0] + if member.mesh.numTVerts == 0] return invalid def process(self, instance): From 48c64c9cafa5e09edbeb10ec7d47329975a7b07d Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 1 Mar 2024 17:44:01 +0800 Subject: [PATCH 47/50] cosmetic fix --- .../hosts/max/plugins/publish/validate_instance_in_context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py index cf285bfab6..8104bfb5e3 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py @@ -38,7 +38,7 @@ def process(self, instance): context_label = "{} > {}".format(*context) instance_label = "{} > {}".format(folderPath, task) message = ( - "Instance '{}' publishes to different folderPath than current" + "Instance '{}' publishes to different folderPath than current " "context: {}. Current context: {}".format( instance.name, instance_label, context_label ) From 3b455730892304edc299e10dd43eabe14bdbcdd7 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 1 Mar 2024 17:54:43 +0800 Subject: [PATCH 48/50] make the docstring and comment more concise and align with ayon --- .../max/plugins/publish/validate_instance_in_context.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py index 8104bfb5e3..f116ec5609 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -"""Validate if instance asset is the same as context asset.""" +"""Validate if instance context is the same as current context.""" import pyblish.api from ayon_core.pipeline.publish import ( RepairAction, @@ -13,10 +13,10 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, OptionalPyblishPluginMixin): - """Validator to check if instance asset match context asset. + """Validator to check if instance context match current context . When working in per-shot style you always publish data in context of - current asset (shot). This validator checks if this is so. It is optional + current context (shot). This validator checks if this is so. It is optional so it can be disabled when needed. Action on this validator will select invalid instances. @@ -38,7 +38,7 @@ def process(self, instance): context_label = "{} > {}".format(*context) instance_label = "{} > {}".format(folderPath, task) message = ( - "Instance '{}' publishes to different folderPath than current " + "Instance '{}' publishes to different context than current " "context: {}. Current context: {}".format( instance.name, instance_label, context_label ) From 7ec4f6cc92d910ac2dbb0b1eb0614dc709500ff8 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 1 Mar 2024 18:21:13 +0800 Subject: [PATCH 49/50] cosmetic --- .../hosts/max/plugins/publish/validate_instance_in_context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py index f116ec5609..6f44356d9f 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py @@ -13,7 +13,7 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, OptionalPyblishPluginMixin): - """Validator to check if instance context match current context . + """Validator to check if instance context match current context. When working in per-shot style you always publish data in context of current context (shot). This validator checks if this is so. It is optional From 1f2b531a908eb4825233296bfa49ccdc3ef84196 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Sat, 2 Mar 2024 00:46:06 +0800 Subject: [PATCH 50/50] tweak on the description comment of publish validation error --- .../max/plugins/publish/validate_instance_in_context.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py index 6f44356d9f..963a601009 100644 --- a/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py +++ b/client/ayon_core/hosts/max/plugins/publish/validate_instance_in_context.py @@ -46,11 +46,11 @@ def process(self, instance): raise PublishValidationError( message=message, description=( - "## Publishing to a different asset\n" + "## Publishing to a different context data\n" "There are publish instances present which are publishing " - "into a different asset or task than your current context.\n\n" + "into a different folder path or task than your current context.\n\n" "Usually this is not what you want but there can be cases " - "where you might want to publish into another asset or " + "where you might want to publish into another context or " "shot. If that's the case you can disable the validation " "on the instance to ignore it." )