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.
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
classOpenInExplorer(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 Icondefprocess(self,context,plugin):import subprocess subprocess.call("start .", shell=True)# Launch explorer at the cwdclassValidate(pyblish.api.InstancePlugin): order = pyblish.api.ValidatorOrder actions = [# Order of items is preserved pyblish.api.Category("My Actions"), MyAction, pyblish.api.Separator, ]defprocess(self,instance): self.log.info("Standard log messages apply here.")raiseException("Exceptions too.")
Extended Example
Every possible combination of an action.
classContextAction(pyblish.api.Action): label ="Context action"defprocess(self,context): self.log.info("I have access to the context") self.log.info("Context.instances: %s"%str(list(context)))classFailingAction(pyblish.api.Action): label ="Failing action"defprocess(self,context,plugin): self.log.info("About to fail..")raiseException("I failed")classLongRunningAction(pyblish.api.Action): label ="Long-running action"defprocess(self,context,plugin): self.log.info("Sleeping for 2 seconds..") time.sleep(2) self.log.info("Ah, that's better")classIconAction(pyblish.api.Action): label ="Icon action" icon ="crop"defprocess(self,context,plugin): self.log.info("I have an icon")classPluginAction(pyblish.api.Action): label ="Plugin action"defprocess(self,context,plugin): self.log.info("I have access to my parent plug-in") self.log.info("Which is %s"% plugin.id)classLaunchExplorerAction(pyblish.api.Action): label ="Open in Explorer" icon ="folder-open"defprocess(self,context,plugin):import osimport 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)classProcessedAction(pyblish.api.Action): label ="Success action" icon ="check" on ="processed"defprocess(self,context,plugin): self.log.info("I am only available on a successful plug-in")classFailedAction(pyblish.api.Action): label ="Failure action" icon ="close" on ="failed"classSucceededAction(pyblish.api.Action): label ="Success action" icon ="check" on ="succeeded"defprocess(self,context,plugin): self.log.info("I am only available on a successful plug-in")classBadEventAction(pyblish.api.Action): label ="Bad event action" on ="not exist"classInactiveAction(pyblish.api.Action): active =FalseclassPluginWithActions(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, ]defprocess(self,instance): self.log.info("Ran PluginWithActions")
Maya Example
import timeimport pyblish.apiimport pyblish_qmlclassCollect(pyblish.api.Collector):defprocess(self,context): i = context.create_instance("MyInstance") i.data["family"]="default" i.append("pCube1")classSelectInvalidNodes(pyblish.api.Action): label ="Select broken nodes" on ="failed" icon ="hand-o-up"defprocess(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)classValidate(pyblish.api.Validator): actions = [ pyblish.api.Category("Scene"), SelectInvalidNodes ]defprocess(self,instance):raiseException("I failed")pyblish.api.register_plugin(Collect)pyblish.api.register_plugin(Validate)import pyblish_mayapyblish_maya.show()