Enhancement: Callbacks and groups with Publisher attributes
Is there an existing issue for this?
- [X] I have searched the existing issues.
Please describe the feature you have in mind and explain what the current shortcomings are?
In publisher, both creator and publish plugins can define attributes that can be set to control specifics of the publishing process. Right now, all those attributes are basically standalone without having any connection to others.
We need to define relationship between individual attributes, so changing value of one can affect the whole group (or other groups, or other controls).
How would you imagine the implementation of the feature?
Since attributes are defined in individual plugins there are few things that needs to be implemented to overcome this:
- attribute identifier: to be able to reference one attribute from somewhere else
- callbacks: ability for plugin to define custom callback to be called when some attribute state is changed (connected to event system). Those callbacks should be able to report back to UI - for example to report invalid state.
- labeling: show what controls belongs together, either plugin-wise, or logical group related
Are there any labels you wish to add?
- [X] I have added the relevant labels to the enhancement request.
Describe alternatives you've considered:
No response
Additional context:
Rreferences
https://github.com/ynput/ayon-workgroups/issues/4
[cuID:AY-2420]
So, based on our discussion with @BigRoy and @iLLiCiTiT , this is example mockup code that might be solution:
import subprocess
from ayon_core.lib import EnumDef, BoolDef, TextDef, ButtonDef
from ayon_core.pipeline.create import CreateContext
import pyblish.api
class ExamplePlugin(pyblish.api.InstancePlugin):
"""Example plugin for demonstration purposes.
Attributes:
id (str): Unique identifier for this plugin.
It is using reverse domain name notation.
"""
@classmethod
def get_attribute_defs(cls):
"""Get the attribute definitions for this plugin.
Every attribute can be uniquely identified by its id. To get it's value,
you need also instance itself.
"""
return [
BoolDef(
"groupEnabled", # io.ayon.publish.examplePlugin.attributes.groupEnabled
label="Group Enabled",
default=True,
),
EnumDef("groupEnum", # io.ayon.publish.examplePlugin.attributes.groupEnum
label="Enum Example",
items=["Foo", "Bar", "Baz"],
default="Foo"),
TextDef("groupText", # io.ayon.publish.examplePlugin.attributes.groupText
label="Text Example",
default="Hello World"),
ButtonDef("groupButton", # io.ayon.publish.examplePlugin.attributes.groupButton
label="Button Example")
]
@classmethod
def register_attribute_callback(cls, create_context):
"""Register attribute callbacks for this plugin.
These callbacks are called when the value of the attribute changes.
"""
# register callback should take either list of attribute ids or a single attribute id
create_context.register_callback(
["io.ayon.publish.examplePlugin.attributes.groupEnabled"], cls.on_attribute_changed)
create_context.register_callback("io.ayon.publish.examplePlugin.attributes.groupButton", cls.on_button_pressed)
@classmethod
def on_attribute_changed(cls, create_context: CreateContext, changes: list):
"""Callback for when the attribute changes.
Args:
create_context (CreateContext): The create context.
changes (list): List of changes that happened.
This should be a list of tuples where the first element is instance id,
the second one is original value, the third one is new value.
"""
enabled_attr = create_context.get_attribute_by_id("io.ayon.publish.examplePlugin.attributes.groupEnabled")
group_attrs = create_context.get_attribute_by_group("io.ayon.publish.examplePlugin.attributes")
if enabled_attr.value:
print("Group is enabled")
group_attrs["groupEnum"] = "Bar"
group_attrs["groupText"] = "Hello Bar Enabled"
else:
print("Group is disabled")
group_attrs["groupEnum"].set_disabled(True)
group_attrs["groupText"].set_disabled(True)
@classmethod
def on_button_pressed(cls, create_context: CreateContext, changes: list):
print("Button Pressed")
output = subprocess.check_output(["ls", "-l"])
instance_ids = []
for instance in create_context.get_instances():
if instance.family == "exampleFamily":
instance_ids.append(instance.id)
try:
create_context.set_instance_attribute(instance_ids, "groupText", output)
except AttributeError:
# instance does not have the attribute
pass
there are some mixed approaches together, but main idea is event based system where every plugin could express it's interest in changes of certain attribute values. Create context would then execute callback whenever attribute value changes and pass itself and information about changes to the callback. Callback will then decide what to do.
Pros
- Flexible way where every plugin can decide what to do with changes
- Tt can solve some issues where certain attribute definition can't be shown because we don't know all instances beforehand
Cons
- There might be conflicting callbacks defined plugins (should we allow of forbid?)
- It might be really slow
Notes Maybe changes can be passed as object with some helper methods to access instance, check types, etc.
This is just a quick summary, lets elaborate more on this (and other ways) here
I quickly prototyped something in the following PR. This is without any guidance. So its a very rudimentary solution.
This was done before you posted your code example above
I had a look at your code @antirotor.
and I'm not sure how I would implement something like this especially in regards to signals. I'm not assigned to the ticket yet.
perhaps this one is better handled by someone more experienced.
I quickly prototyped something in the following PR. This is without any guidance. So its a very rudimentary solution.
This was done before you posted your code example above
This is not directly connected with your PR - this is mostly about ability to define custom logic in individual plugins that has access to all defined attributes within the system. Default values are definitely touching this, but are not the main topic.
Sorry the PR was named incorrectly, I meant this one. Same code. https://github.com/ynput/ayon-core/compare/enhancement/AY-2420_callbacks_and_groups_with_publisher_attributes?expand=1