From fea156097833655787c9f9b252fac2633a425e59 Mon Sep 17 00:00:00 2001 From: aardschok Date: Wed, 9 Aug 2017 16:34:29 +0200 Subject: [PATCH] look validation improvements --- colorbleed/maya/__init__.py | 7 +- colorbleed/maya/lib.py | 20 ++++-- .../plugins/maya/publish/collect_look.py | 8 ++- .../maya/publish/validate_look_contents.py | 71 +++++-------------- .../publish/validate_look_members_node_ids.py | 22 +++--- .../validate_look_no_default_shaders.py | 17 +++-- .../publish/validate_look_single_shader.py | 2 +- .../plugins/maya/publish/validate_node_ids.py | 18 ++--- 8 files changed, 66 insertions(+), 99 deletions(-) diff --git a/colorbleed/maya/__init__.py b/colorbleed/maya/__init__.py index 071d2e91fe..94288646a0 100644 --- a/colorbleed/maya/__init__.py +++ b/colorbleed/maya/__init__.py @@ -97,11 +97,8 @@ def on_save(_): avalon.logger.info("Running callback on save..") - types = ["objectSet", "file", "mesh", "nurbsCurve", "nurbsSurface"] - type_nodes = set(cmds.ls(type=types, long=True)) - nodes = lib.filter_out_nodes(type_nodes, - defaults=True, - referenced_nodes=True) + nodes = lib.get_id_required_nodes(defaults=True, + referenced_nodes=True) # Lead with asset ID from the database asset = os.environ["AVALON_ASSET"] diff --git a/colorbleed/maya/lib.py b/colorbleed/maya/lib.py index 73f25bbe68..29160a339c 100644 --- a/colorbleed/maya/lib.py +++ b/colorbleed/maya/lib.py @@ -613,7 +613,7 @@ def remap_resource_nodes(resources, folder=None): cmds.file(save=True, type="mayaAscii") -def filter_out_nodes(nodes, defaults=False, referenced_nodes=False): +def get_id_required_nodes(defaults=True, referenced_nodes=True): """Filter out any node which are locked (reference) or readOnly Args: @@ -621,11 +621,13 @@ def filter_out_nodes(nodes, defaults=False, referenced_nodes=False): defaults (bool): set True to filter out default nodes referenced_nodes (bool): set True to filter out reference nodes Returns: - nodes (list): list of filtered nodes + nodes (set): list of filtered nodes """ - # establish set of nodes to ignore + + # `readOnly` flag is obsolete as of Maya 2016 therefor we explicitly remove # default nodes and reference nodes + camera_shapes = ["frontShape", "sideShape", "topShape", "perspShape"] ignore = set() if referenced_nodes: @@ -633,16 +635,26 @@ def filter_out_nodes(nodes, defaults=False, referenced_nodes=False): if defaults: ignore |= set(cmds.ls(long=True, defaultNodes=defaults)) + ignore |= set(cmds.ls(camera_shapes, long=True)) + + # establish set of nodes to ignore + types = ["objectSet", "file", "mesh", "nurbsCurve", "nurbsSurface"] + + # We *always* ignore intermediate shapes, so we filter them out + # directly + nodes = cmds.ls(type=types, long=True, noIntermediate=True) # The items which need to pass the id to their parent # Add the collected transform to the nodes - dag = cmds.ls(list(nodes), + dag = cmds.ls(nodes, type="dagNode", long=True) # query only dag nodes + transforms = cmds.listRelatives(dag, parent=True, fullPath=True) or [] + nodes = set(nodes) nodes |= set(transforms) nodes -= ignore # Remove the ignored nodes diff --git a/colorbleed/plugins/maya/publish/collect_look.py b/colorbleed/plugins/maya/publish/collect_look.py index d8f7ec08f9..4b76a17ce3 100644 --- a/colorbleed/plugins/maya/publish/collect_look.py +++ b/colorbleed/plugins/maya/publish/collect_look.py @@ -123,9 +123,11 @@ class CollectLook(pyblish.api.InstancePlugin): "relationships": sets.values(), "sets": looksets} - # Collect file nodes used by shading engines - history = cmds.listHistory(looksets) - files = cmds.ls(history, type="file", long=True) + # Collect file nodes used by shading engines (if we have any) + files = list() + if looksets: + history = cmds.listHistory(looksets) + files = cmds.ls(history, type="file", long=True) # Collect textures resources = [self.collect_resource(n) for n in files] diff --git a/colorbleed/plugins/maya/publish/validate_look_contents.py b/colorbleed/plugins/maya/publish/validate_look_contents.py index 9f0323c6cc..70aec3c70c 100644 --- a/colorbleed/plugins/maya/publish/validate_look_contents.py +++ b/colorbleed/plugins/maya/publish/validate_look_contents.py @@ -1,5 +1,3 @@ -import maya.cmds as cmds - import pyblish.api import colorbleed.api @@ -15,34 +13,27 @@ class ValidateLookContents(pyblish.api.InstancePlugin): order = colorbleed.api.ValidateContentsOrder families = ['colorbleed.lookdev'] hosts = ['maya'] - label = 'Look Contents' + label = 'Look Data Contents' actions = [colorbleed.api.SelectInvalidAction] - invalid = [] - errors = [] - def process(self, instance): """Process all the nodes in the instance""" if not instance[:]: raise RuntimeError("Instance is empty") - self.get_invalid(instance) - - if self.errors: - error_string = "\n".join(self.errors) - raise RuntimeError("Invalid look content. " - "Errors : {}".format(error_string)) + invalid = self.get_invalid(instance) + if invalid: + raise RuntimeError("Invalid look content") @classmethod def get_invalid(cls, instance): """Get all invalid nodes""" attributes = list(cls.validate_lookdata_attributes(instance)) - relationships = list(cls.validate_relationships(instance)) - non_defaults = cls.validate_non_defaults(instance) + relationships = list(cls.validate_relationship_ids(instance)) - invalid = attributes + relationships + non_defaults + invalid = attributes + relationships return invalid @@ -61,14 +52,18 @@ class ValidateLookContents(pyblish.api.InstancePlugin): lookdata = instance.data["lookData"] for attr in attributes: if attr not in lookdata: - cls.errors.append("Look Data has no attribute " - "'{}'".format(attr)) + cls.log.error("Look Data has no attribute " + "'{}'".format(attr)) invalid.add(instance.name) + if not lookdata["relationships"] or not lookdata["sets"]: + cls.log.error("Look has no `relationship` or `sets`") + invalid.add(instance.name) + return invalid @classmethod - def validate_relationships(cls, instance): + def validate_relationship_ids(cls, instance): """Validate and update lookData relationships""" invalid = set() @@ -76,41 +71,9 @@ class ValidateLookContents(pyblish.api.InstancePlugin): relationships = instance.data["lookData"]["relationships"] for relationship in relationships: look_name = relationship["name"] - for key, value in relationship.items(): - if value is None: - cls.errors.append("{} has invalid attribute " - "'{}'".format(look_name, key)) - - invalid.add(look_name) - - return invalid - - @classmethod - def validate_non_defaults(cls, instance): - """Check if instance content items are part of the default nodes""" - - invalid = [] - cams = ["perspShape", "topShape", "frontShape", "sideShape"] - cameras = cmds.ls(cams, long=True) - references = cmds.ls(referencedNodes=True) - default_nodes = cmds.ls(defaultNodes=True, long=True) - - defaults = list(set(cameras + references + default_nodes)) - - for node in cmds.ls(instance[:], long=True): - # might be a transform of a default item listed - if cmds.nodeType(node) == "transform": - children = cmds.listRelatives(node, - children=True, - fullPath=True) - if children: - node = children - else: - continue - - if node in defaults: - invalid.append(node) - cls.errors.append("'{}' is part of Maya default " - "nodes".format(node)) + uuid = relationship["uuid"] + if not uuid: + cls.errors.append("{} has invalid ID ") + invalid.add(look_name) return invalid diff --git a/colorbleed/plugins/maya/publish/validate_look_members_node_ids.py b/colorbleed/plugins/maya/publish/validate_look_members_node_ids.py index 942dbd996f..f168ba3b39 100644 --- a/colorbleed/plugins/maya/publish/validate_look_members_node_ids.py +++ b/colorbleed/plugins/maya/publish/validate_look_members_node_ids.py @@ -1,9 +1,11 @@ +import maya.cmds as cmds + import pyblish.api import colorbleed.api import colorbleed.maya.lib as lib -class ValidateLookMembersHaveId(pyblish.api.InstancePlugin): +class ValidateLookMembers(pyblish.api.InstancePlugin): """Validate look members have colorbleed id attributes Looks up the contents of the look to see if all its members have @@ -18,28 +20,28 @@ class ValidateLookMembersHaveId(pyblish.api.InstancePlugin): order = colorbleed.api.ValidatePipelineOrder families = ['colorbleed.lookdev'] hosts = ['maya'] - label = 'Look Members Have ID Attribute' + label = 'Look Members' actions = [colorbleed.api.SelectInvalidAction, colorbleed.api.GenerateUUIDsOnInvalidAction] def process(self, instance): """Process all meshes""" - invalid = self.get_invalid(instance) - if invalid: + invalid_ids = self.get_invalid(instance) + if invalid_ids: raise RuntimeError("Members found without " - "asset IDs: {0}".format(invalid)) + "asset IDs: {0}".format(invalid_ids)) @classmethod def get_invalid(cls, instance): - # Get all members from the sets members = set() - relations = instance.data["lookData"]["relationships"] - for relation in relations: + relationships = instance.data["lookData"]["relationships"] + for relation in relationships: members.update([member['name'] for member in relation['members']]) - # Ensure all nodes have a cbId invalid = [m for m in members if not lib.get_id(m)] + if invalid: + raise RuntimeError("Found invalid nodes.\nNo ID : " + "{}".format(invalid)) - return invalid diff --git a/colorbleed/plugins/maya/publish/validate_look_no_default_shaders.py b/colorbleed/plugins/maya/publish/validate_look_no_default_shaders.py index 4f33e15b1c..5042d01796 100644 --- a/colorbleed/plugins/maya/publish/validate_look_no_default_shaders.py +++ b/colorbleed/plugins/maya/publish/validate_look_no_default_shaders.py @@ -37,16 +37,15 @@ class ValidateLookNoDefaultShaders(pyblish.api.InstancePlugin): "initialParticleSE", "particleCloud1"] - setmembers = instance.data["setMembers"] - members = cmds.listRelatives(setmembers, + members = cmds.listRelatives(instance, allDescendents=True, - type="shape") - + shapes=True, + noIntermediate=True) or [] for member in members: # get connection # listConnections returns a list or None - shading_engine = cmds.listConnections(member, type="shadingEngine") + shading_engine = cmds.listConnections(member, type="objectSet") if not shading_engine: cls.log.error("Detected shape without shading engine : " "'{}'".format(member)) @@ -58,6 +57,7 @@ class ValidateLookNoDefaultShaders(pyblish.api.InstancePlugin): if shading_engine in disallowed: cls.log.error("Member connected to a disallows objectSet: " "'{}'".format(member)) + invalid.append(member) else: continue @@ -66,7 +66,6 @@ class ValidateLookNoDefaultShaders(pyblish.api.InstancePlugin): def process(self, instance): """Process all the nodes in the instance""" - # sets = self.get_invalid_sets(instance) - sets = self.get_invalid(instance) - if sets: - raise RuntimeError("Invalid shaders found: {0}".format(sets)) + invalid = self.get_invalid(instance) + if invalid: + raise RuntimeError("Invalid shaders found: {0}".format(invalid)) diff --git a/colorbleed/plugins/maya/publish/validate_look_single_shader.py b/colorbleed/plugins/maya/publish/validate_look_single_shader.py index fabdfb1a6d..1d780bc302 100644 --- a/colorbleed/plugins/maya/publish/validate_look_single_shader.py +++ b/colorbleed/plugins/maya/publish/validate_look_single_shader.py @@ -54,7 +54,7 @@ class ValidateSingleShader(pyblish.api.InstancePlugin): for shape in shapes: shading_engines = cmds.listConnections(shape, destination=True, - type="shadingEngine") + type="shadingEngine") or [] if len(shading_engines) > 1: invalid.append(shape) diff --git a/colorbleed/plugins/maya/publish/validate_node_ids.py b/colorbleed/plugins/maya/publish/validate_node_ids.py index 2a9d9ea25f..a5d8ce2d83 100644 --- a/colorbleed/plugins/maya/publish/validate_node_ids.py +++ b/colorbleed/plugins/maya/publish/validate_node_ids.py @@ -36,18 +36,10 @@ class ValidateNodeIDs(pyblish.api.InstancePlugin): # We do want to check the referenced nodes as it might be # part of the end product - nodes = lib.filter_out_nodes(set(instance[:]), defaults=True) - invalid = [n for n in nodes if not lib.get_id(n) - and not cls.validate_children(n)] + id_nodes = lib.get_id_required_nodes(defaults=True, + referenced_nodes=False) + + nodes = instance[:] + invalid = [n for n in nodes if n in id_nodes and not lib.get_id(n)] return invalid - - @staticmethod - def validate_children(node): - """Validate the children of the node if the ID is not present""" - - children = cmds.listRelatives(node, children=True) - for child in children: - if lib.get_id(child): - return True - return False