Attach any functionality to a plug-in and tailor it to a particular state; like an action only available via a failed validator, or a successful extraction, or just all-round functionality associated with a particular plug-in.
image
Each action is passed both the Context and it's parent plug-in at run-time and can be accessed via their argument signature, similar to plug-ins.
Actions in QML are arranged in a menu with optional customisable groups and separators. Actions with any kind of implementation error show up as well, including a helpful error message for simplified debugging.
Argument signature
These objects are available via the argument signature.
context: The global context
plugin: The parent plug-in
Full list of features
Per-plugin actions
Action API ~= Plug-in API, it is more or less a 1-1 match between their interfaces, including process() and label.
Standard logging and exception reporting, identical to plug-ins
failed: After plug-in has been processed, and failed
succeeded: After plug-in has been processed, and succeeded
Example
class OpenInExplorer(pyblish.api.Action):
label = "Open in Explorer"
on = "failed" # This action is only available on a failed plug-in
icon = "hand-o-up" # Icon from Awesome Icon
def process(self, context, plugin):
import subprocess
subprocess.call("start .", shell=True) # Launch explorer at the cwd
class Validate(pyblish.api.InstancePlugin):
order = pyblish.api.ValidatorOrder
actions = [
# Order of items is preserved
pyblish.api.Category("My Actions"),
MyAction,
pyblish.api.Separator,
]
def process(self, instance):
self.log.info("Standard log messages apply here.")
raise Exception("Exceptions too.")
Extended Example
Every possible combination of an action.
class ContextAction(pyblish.api.Action):
label = "Context action"
def process(self, context):
self.log.info("I have access to the context")
self.log.info("Context.instances: %s" % str(list(context)))
class FailingAction(pyblish.api.Action):
label = "Failing action"
def process(self, context, plugin):
self.log.info("About to fail..")
raise Exception("I failed")
class LongRunningAction(pyblish.api.Action):
label = "Long-running action"
def process(self, context, plugin):
self.log.info("Sleeping for 2 seconds..")
time.sleep(2)
self.log.info("Ah, that's better")
class IconAction(pyblish.api.Action):
label = "Icon action"
icon = "crop"
def process(self, context, plugin):
self.log.info("I have an icon")
class PluginAction(pyblish.api.Action):
label = "Plugin action"
def process(self, context, plugin):
self.log.info("I have access to my parent plug-in")
self.log.info("Which is %s" % plugin.id)
class LaunchExplorerAction(pyblish.api.Action):
label = "Open in Explorer"
icon = "folder-open"
def process(self, context, plugin):
import os
import subprocess
cwd = context.data["cwd"]
self.log.info("Opening %s in Explorer" % cwd)
result = subprocess.call("start .", cwd=cwd, shell=True)
self.log.debug(result)
class ProcessedAction(pyblish.api.Action):
label = "Success action"
icon = "check"
on = "processed"
def process(self, context, plugin):
self.log.info("I am only available on a successful plug-in")
class FailedAction(pyblish.api.Action):
label = "Failure action"
icon = "close"
on = "failed"
class SucceededAction(pyblish.api.Action):
label = "Success action"
icon = "check"
on = "succeeded"
def process(self, context, plugin):
self.log.info("I am only available on a successful plug-in")
class BadEventAction(pyblish.api.Action):
label = "Bad event action"
on = "not exist"
class InactiveAction(pyblish.api.Action):
active = False
class PluginWithActions(pyblish.api.InstancePlugin):
order = pyblish.api.ValidatorOrder
optional = True
actions = [
pyblish.api.Category("General"),
ContextAction,
FailingAction,
LongRunningAction,
IconAction,
PluginAction,
pyblish.api.Category("OS"),
LaunchExplorerAction,
pyblish.api.Separator,
FailedAction,
SucceededAction,
pyblish.api.Category("Debug"),
BadEventAction,
InactiveAction,
]
def process(self, instance):
self.log.info("Ran PluginWithActions")
Maya Example
import time
import pyblish.api
import pyblish_qml
class Collect(pyblish.api.Collector):
def process(self, context):
i = context.create_instance("MyInstance")
i.data["family"] = "default"
i.append("pCube1")
class SelectInvalidNodes(pyblish.api.Action):
label = "Select broken nodes"
on = "failed"
icon = "hand-o-up"
def process(self, context):
self.log.info("Finding bad nodes..")
nodes = []
for result in context.data["results"]:
if result["error"]:
instance = result["instance"]
nodes.extend(instance)
self.log.info("Selecting bad nodes: %s" % ", ".join(nodes))
cmds.select(deselect=True)
cmds.select(nodes)
class Validate(pyblish.api.Validator):
actions = [
pyblish.api.Category("Scene"),
SelectInvalidNodes
]
def process(self, instance):
raise Exception("I failed")
pyblish.api.register_plugin(Collect)
pyblish.api.register_plugin(Validate)
import pyblish_maya
pyblish_maya.show()