Skip to content

Instantly share code, notes, and snippets.

@davidlatwe
Created September 1, 2019 10:17
Show Gist options
  • Save davidlatwe/9c43ce89b39de86e19bd0d58690301a0 to your computer and use it in GitHub Desktop.
Save davidlatwe/9c43ce89b39de86e19bd0d58690301a0 to your computer and use it in GitHub Desktop.
Maya scene modification aware via Pyblish
"""Implement scene modification awareness
By tracking Maya's undo queue, if there are any undo command that is not
a simple select after collecting completed, consider this scene has been
modified and require to reset Pyblish.
"""
import collections
import maya.OpenMaya as om
import pyblish.api
class AvalonSceneReady(pyblish.api.ContextPlugin):
"""Define current scene in ready state
Collecte current undo count for later validation.
"""
order = pyblish.api.CollectorOrder + 0.49999
label = "Scene Ready"
hosts = ["maya"]
def process(self, context):
from maya import cmds
# Ensure undo queue is active
cmds.undoInfo(state=True)
with OutputDeque() as undo_list:
cmds.undoInfo(query=True, printQueue=True)
context.data["_undoCount"] = len(undo_list)
class AvalonCheckSceneReady(pyblish.api.ContextPlugin):
"""Validate current scene still fit the definition of *ready*
By checking new undo commands in undo queue after collecting, and consider
scene is not ready if there are any non-select command.
"""
order = pyblish.api.ValidatorOrder - 0.49998
label = "Is Scene Ready"
hosts = ["maya"]
def process(self, context):
from maya import cmds
if not cmds.undoInfo(query=True, state=True):
raise Exception("Undo queue is not open, please reset.")
undo_count = context.data["_undoCount"]
# self.log.debug(undo_count)
with OutputDeque(format=lambda l: l.split(": ", 1)[-1].strip(),
skip=undo_count,
) as undo_list:
cmds.undoInfo(query=True, printQueue=True)
while undo_list:
history = undo_list.pop()
# self.log.debug(history)
if history.startswith("select"):
continue
raise Exception("Scene has been modified, no longer in *ready* "
"state. Please reset.")
class OutputDeque(collections.deque):
"""Record Maya command output during the context
A context manager, subclass of `collections.deque`.
Maya command output will be added into this deque during the context.
Args:
ignore_empty (bool, optional): Whether to ignore empty formatted
output line. Default True.
format (callable, optional): Function for formatting output.
skip (int, optional): Skip first numbers of outputs.
max (int, optional): Max length of the deque.
"""
def __init__(self,
ignore_empty=True,
format=None,
skip=0,
max=None):
self.ignore_empty = ignore_empty
self.format = format or (lambda line: line)
self.skip = skip
self.__callback_id = None
self.__count = 0
super(OutputDeque, self).__init__(maxlen=max)
def __enter__(self):
add_callback = om.MCommandMessage.addCommandOutputCallback
def catch_output(msg, *args):
self.__count += 1
if self.__count <= self.skip:
return
formatted = self.format(msg)
if formatted or not self.ignore_empty:
self.append(formatted)
self.__callback_id = add_callback(catch_output)
return self
def __exit__(self, *args):
om.MCommandMessage.removeCallback(self.__callback_id)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment