Skip to content

validate_node_ids_related

ValidateNodeIDsRelated

Bases: MayaInstancePlugin, OptionalPyblishPluginMixin

Validate nodes have a related cbId to the instance.data[folderPath]

Source code in client/ayon_maya/plugins/publish/validate_node_ids_related.py
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
class ValidateNodeIDsRelated(plugin.MayaInstancePlugin,
                             OptionalPyblishPluginMixin):
    """Validate nodes have a related `cbId` to the instance.data[folderPath]"""

    order = ValidatePipelineOrder
    label = 'Node Ids Related (ID)'
    families = ["model",
                "look",
                "rig"]
    optional = True

    actions = [ayon_maya.api.action.SelectInvalidAction,
               ayon_maya.api.action.GenerateUUIDsOnInvalidAction]

    @classmethod
    def apply_settings(cls, project_settings):
        # Disable plug-in if cbId workflow is disabled
        if not project_settings["maya"].get("use_cbid_workflow", True):
            cls.enabled = False
            return

    def process(self, instance):
        """Process all nodes in instance (including hierarchy)"""
        if not self.is_active(instance.data):
            return

        # Ensure all nodes have a cbId
        invalid = self.get_invalid(instance)
        if invalid:

            invalid_list = "\n".join(f"- {node}" for node in sorted(invalid))

            raise PublishValidationError((
                "Nodes IDs found that are not related to folder '{}':\n{}"
                ).format(instance.data["folderPath"], invalid_list),
                description=self.get_description()
            )

    @classmethod
    def get_invalid(cls, instance):
        """Return the member nodes that are invalid"""
        folder_id = instance.data["folderEntity"]["id"]

        # We do want to check the referenced nodes as it might be
        # part of the end product
        invalid = list()
        nodes_by_other_folder_ids = defaultdict(set)
        for node in instance:
            _id = lib.get_id(node)
            if not _id:
                continue

            node_folder_id = _id.split(":", 1)[0]
            if node_folder_id != folder_id:
                invalid.append(node)
                nodes_by_other_folder_ids[node_folder_id].add(node)

        # Log what other assets were found.
        if nodes_by_other_folder_ids:
            project_name = instance.context.data["projectName"]
            other_folder_ids = set(nodes_by_other_folder_ids.keys())

            # Remove folder ids that are not valid UUID identifiers, these
            # may be legacy OpenPype ids
            other_folder_ids = {folder_id for folder_id in other_folder_ids
                                if is_valid_uuid(folder_id)}
            if not other_folder_ids:
                return invalid

            folder_entities = get_folders(project_name=project_name,
                                          folder_ids=other_folder_ids,
                                          fields=["path"])
            if folder_entities:
                # Log names of other assets detected
                # We disregard logging nodes/ids for asset ids where no asset
                # was found in the database because ValidateNodeIdsInDatabase
                # takes care of that.
                folder_paths = {entity["path"] for entity in folder_entities}
                cls.log.error(
                    "Found nodes related to other folders:\n{}".format(
                        "\n".join(f"- {path}" for path in sorted(folder_paths))
                    )
                )

        return invalid

    @staticmethod
    def get_description():
        return inspect.cleandoc("""### Node IDs must match folder id

        The node ids must match the folder entity id you are publishing to.

        Usually these mismatch occurs if you are re-using nodes from another
        folder or project.

        #### How to repair?

        The repair action will regenerate new ids for
        the invalid nodes to match the instance's folder.
        """)

get_invalid(instance) classmethod

Return the member nodes that are invalid

Source code in client/ayon_maya/plugins/publish/validate_node_ids_related.py
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
@classmethod
def get_invalid(cls, instance):
    """Return the member nodes that are invalid"""
    folder_id = instance.data["folderEntity"]["id"]

    # We do want to check the referenced nodes as it might be
    # part of the end product
    invalid = list()
    nodes_by_other_folder_ids = defaultdict(set)
    for node in instance:
        _id = lib.get_id(node)
        if not _id:
            continue

        node_folder_id = _id.split(":", 1)[0]
        if node_folder_id != folder_id:
            invalid.append(node)
            nodes_by_other_folder_ids[node_folder_id].add(node)

    # Log what other assets were found.
    if nodes_by_other_folder_ids:
        project_name = instance.context.data["projectName"]
        other_folder_ids = set(nodes_by_other_folder_ids.keys())

        # Remove folder ids that are not valid UUID identifiers, these
        # may be legacy OpenPype ids
        other_folder_ids = {folder_id for folder_id in other_folder_ids
                            if is_valid_uuid(folder_id)}
        if not other_folder_ids:
            return invalid

        folder_entities = get_folders(project_name=project_name,
                                      folder_ids=other_folder_ids,
                                      fields=["path"])
        if folder_entities:
            # Log names of other assets detected
            # We disregard logging nodes/ids for asset ids where no asset
            # was found in the database because ValidateNodeIdsInDatabase
            # takes care of that.
            folder_paths = {entity["path"] for entity in folder_entities}
            cls.log.error(
                "Found nodes related to other folders:\n{}".format(
                    "\n".join(f"- {path}" for path in sorted(folder_paths))
                )
            )

    return invalid

process(instance)

Process all nodes in instance (including hierarchy)

Source code in client/ayon_maya/plugins/publish/validate_node_ids_related.py
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
def process(self, instance):
    """Process all nodes in instance (including hierarchy)"""
    if not self.is_active(instance.data):
        return

    # Ensure all nodes have a cbId
    invalid = self.get_invalid(instance)
    if invalid:

        invalid_list = "\n".join(f"- {node}" for node in sorted(invalid))

        raise PublishValidationError((
            "Nodes IDs found that are not related to folder '{}':\n{}"
            ).format(instance.data["folderPath"], invalid_list),
            description=self.get_description()
        )

is_valid_uuid(value)

Return whether value is a valid UUID

Source code in client/ayon_maya/plugins/publish/validate_node_ids_related.py
16
17
18
19
20
21
22
def is_valid_uuid(value) -> bool:
    """Return whether value is a valid UUID"""
    try:
        uuid.UUID(value)
    except ValueError:
        return False
    return True