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/18] :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 @@ class CollectVrayROPRenderProducts(pyblish.api.InstancePlugin): 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 @@ class CollectVrayROPRenderProducts(pyblish.api.InstancePlugin): 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/18] 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,10 +54,14 @@ class BasicValidateModel(BaseSettingsModel): class PublishersModel(BaseSettingsModel): + ValidateInstanceInContext: BasicValidateModel = SettingsField( + default_factory=BasicValidateModel, + title="Validate Instance In Context", + section="Validators" + ) ValidateFrameRange: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, - title="Validate Frame Range", - section="Validators" + title="Validate Frame Range" ) ValidateAttributes: ValidateAttributesModel = SettingsField( default_factory=ValidateAttributesModel, 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/18] 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/18] 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 @@ class SelectInvalidAction(pyblish.api.Action): 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/18] 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 @@ class SelectInvalidAction(pyblish.api.Action): 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/18] 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 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, @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/18] 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/18] 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 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, 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 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, @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 3597efbe9f14f06caafb1e0cec1feb48a4a9d56a Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 28 Feb 2024 19:48:28 +0800 Subject: [PATCH 09/18] 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 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, 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 446160f758f2bed3225bb898c9ca605808fbffa4 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 28 Feb 2024 20:15:31 +0800 Subject: [PATCH 10/18] 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 ce94823a0f09a707bbcbc51f87941c4d756e0df4 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 28 Feb 2024 20:51:16 +0800 Subject: [PATCH 11/18] 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 12/18] 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 13/18] 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 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, 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 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, @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 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, 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 34cca056153b0ae6d6805c90d14822851a0f21e5 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 29 Feb 2024 20:42:32 +0800 Subject: [PATCH 14/18] 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 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, 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 48c64c9cafa5e09edbeb10ec7d47329975a7b07d Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 1 Mar 2024 17:44:01 +0800 Subject: [PATCH 15/18] 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 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, 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 16/18] 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 @@ from pymxs import runtime as rt 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 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, 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 17/18] 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 @@ from pymxs import runtime as rt 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 18/18] 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 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin, 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." )