Merge pull request #1143 from BigRoy/enhancement/1142-attach-reviewables-to-other-instances-using-enumdef-on-attachable-integrator

Implement Integrator to allow attaching reviewables to other products easily
This commit is contained in:
Roy Nieterau 2025-03-27 10:55:33 +01:00 committed by GitHub
commit c76d45929f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 156 additions and 0 deletions

View file

@ -0,0 +1,138 @@
import copy
import pyblish.api
from typing import List
from ayon_core.lib import EnumDef
from ayon_core.pipeline import OptionalPyblishPluginMixin
class AttachReviewables(
pyblish.api.InstancePlugin, OptionalPyblishPluginMixin
):
"""Attach reviewable to other instances
This pre-integrator plugin allows instances to be 'attached to' other
instances by moving all its representations over to the other instance.
Even though this technically could work for any representation the current
intent is to use for reviewables only, like e.g. `review` or `render`
product type.
When the reviewable is attached to another instance, the instance itself
will not be published as a separate entity. Instead, the representations
will be copied/moved to the instances it is attached to.
"""
families = ["render", "review"]
order = pyblish.api.IntegratorOrder - 0.499
label = "Attach reviewables"
settings_category = "core"
def process(self, instance):
# TODO: Support farm.
# If instance is being submitted to the farm we should pass through
# the 'attached reviewables' metadata to the farm job
# TODO: Reviewable frame range and resolutions
# Because we are attaching the data to another instance, how do we
# correctly propagate the resolution + frame rate to the other
# instance? Do we even need to?
# TODO: If this were to attach 'renders' to another instance that would
# mean there wouldn't necessarily be a render publish separate as a
# result. Is that correct expected behavior?
attr_values = self.get_attr_values_from_data(instance.data)
attach_to = attr_values.get("attach", [])
if not attach_to:
self.log.debug(
"Reviewable is not set to attach to another instance."
)
return
attach_instances: List[pyblish.api.Instance] = []
for attach_instance_id in attach_to:
# Find the `pyblish.api.Instance` matching the `CreatedInstance.id`
# in the `attach_to` list
attach_instance = next(
(
_inst
for _inst in instance.context
if _inst.data.get("instance_id") == attach_instance_id
),
None,
)
if attach_instance is None:
continue
# Skip inactive instances
if not attach_instance.data.get("active", True):
continue
# For now do not support attaching to 'farm' instances until we
# can pass the 'attaching' on to the farm jobs.
if attach_instance.data.get("farm"):
self.log.warning(
"Attaching to farm instances is not supported yet."
)
continue
attach_instances.append(attach_instance)
instances_names = ", ".join(
instance.name for instance in attach_instances
)
self.log.info(
f"Attaching reviewable to other instances: {instances_names}"
)
# Copy the representations of this reviewable instance to the other
# instance
representations = instance.data.get("representations", [])
for attach_instance in attach_instances:
self.log.info(f"Attaching to {attach_instance.name}")
attach_instance.data.setdefault("representations", []).extend(
copy.deepcopy(representations)
)
# Delete representations on the reviewable instance itself
for repre in representations:
self.log.debug(
"Marking representation as deleted because it was "
f"attached to other instances instead: {repre}"
)
repre.setdefault("tags", []).append("delete")
# Stop integrator from trying to integrate this instance
if attach_to:
instance.data["integrate"] = False
@classmethod
def get_attr_defs_for_instance(cls, create_context, instance):
# TODO: Check if instance is actually a 'reviewable'
# Filtering of instance, if needed, can be customized
if not cls.instance_matches_plugin_families(instance):
return []
items = []
for other_instance in create_context.instances:
if other_instance == instance:
continue
# Do not allow attaching to other reviewable instances
if other_instance.data["productType"] in cls.families:
continue
items.append(
{
"label": other_instance.label,
"value": str(other_instance.id),
}
)
return [
EnumDef(
"attach",
label="Attach reviewable",
multiselection=True,
items=items,
tooltip="Attach this reviewable to another instance",
)
]

View file

@ -12,6 +12,10 @@ from ayon_server.settings import (
from ayon_server.types import ColorRGBA_uint8
class EnabledModel(BaseSettingsModel):
enabled: bool = SettingsField(True)
class ValidateBaseModel(BaseSettingsModel):
_isGroup = True
enabled: bool = SettingsField(True)
@ -1026,6 +1030,17 @@ class PublishPuginsModel(BaseSettingsModel):
default_factory=IntegrateHeroVersionModel,
title="Integrate Hero Version"
)
AttachReviewables: EnabledModel = SettingsField(
default_factory=EnabledModel,
title="Attach Reviewables",
description=(
"When enabled, expose an 'Attach Reviewables' attribute on review"
" and render instances in the publisher to allow including the"
" media to be attached to another instance.\n\n"
"If a reviewable is attached to another instance it will not be "
"published as a render/review product of its own."
)
)
CleanUp: CleanUpModel = SettingsField(
default_factory=CleanUpModel,
title="Clean Up"
@ -1410,6 +1425,9 @@ DEFAULT_PUBLISH_VALUES = {
],
"use_hardlinks": False
},
"AttachReviewables": {
"enabled": True,
},
"CleanUp": {
"paterns": [], # codespell:ignore paterns
"remove_temp_renders": False