Skip to content

validate_render_relative_paths

ValidateRenderRelativePaths

Bases: InstancePlugin, OptionalPyblishPluginMixin

Validates render scene does not use relative paths.

Because the scene will be rendered from the published folder if it renders to a relative path then the output will end up in the publish folder instead of the expected location.

Source code in client/ayon_cinema4d/plugins/publish/validate_render_relative_paths.py
 19
 20
 21
 22
 23
 24
 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
class ValidateRenderRelativePaths(
    pyblish.api.InstancePlugin, OptionalPyblishPluginMixin
):
    """Validates render scene does not use relative paths.

    Because the scene will be rendered from the published folder if it renders
    to a relative path then the output will end up in the publish folder
    instead of the expected location.

    """

    label = "Validate Render Relative Paths"
    order = pyblish.api.ValidatorOrder
    families = ["render"]
    optional = False
    actions = [RepairAction]

    settings_category = "cinema4d"

    def process(self, instance: pyblish.api.Instance):
        if not self.is_active(instance.data):
            return

        doc: c4d.documents.BaseDocument = instance.context.data["doc"]
        take_data = doc.GetTakeData()
        take: c4d.modules.takesystem.BaseTake = instance.data["transientData"][
            "take"
        ]
        render_data, base_take = take.GetEffectiveRenderData(take_data)
        invalid: bool = False

        # Regular image
        save_image: bool = render_data[c4d.RDATA_SAVEIMAGE]
        if save_image:
            token_path: str = render_data[c4d.RDATA_PATH]
            if not os.path.isabs(token_path):
                self.log.error(
                    "Regular image Render output path is relative:\n"
                    f"{token_path}"
                )
                invalid = True

        # Multi-Pass image
        save_multipass_image: bool = render_data[c4d.RDATA_MULTIPASS_SAVEIMAGE]
        if save_multipass_image:
            token_path: str = render_data[c4d.RDATA_MULTIPASS_FILENAME]
            if not os.path.isabs(token_path):
                self.log.error(
                    "Multi-Pass Image render output path is relative:\n"
                    f"{token_path}",
                )
                invalid = True

        if invalid:
            raise PublishValidationError(
                "Please use an absolute path for render output.",
                description=self.get_description(),
            )

    @classmethod
    def repair(cls, instance: pyblish.api.Instance):
        current_file = instance.context.data["currentFile"]
        if not current_file:
            raise RuntimeError(
                "Cannot repair relative paths because the current "
                "file path is unknown. Please save the Cinema 4D "
                "project and try again."
            )
        current_folder = os.path.dirname(current_file)

        doc: c4d.documents.BaseDocument = instance.context.data["doc"]
        take_data = doc.GetTakeData()
        take: c4d.modules.takesystem.BaseTake = instance.data["transientData"][
            "take"
        ]
        render_data, base_take = take.GetEffectiveRenderData(take_data)

        for key, label in RENDER_DATA_KEYS.items():
            token_path: str = render_data[key]

            # Strip leading dot from ./ or .\ start if present
            if token_path.startswith(("./", ".\\")):
                token_path = token_path[2:]

            if not os.path.isabs(token_path):
                render_data[key] = os.path.join(current_folder, token_path)

        c4d.EventAdd()

    @classmethod
    def get_description(cls) -> str:
        return inspect.cleandoc(
            """### Render paths are relative

            The render output paths must be absolute paths.

            Relative paths can lead to renders being saved in unexpected
            locations due to the render possibly occurring from a published
            workfile.

            Use the 'Repair' action to convert relative paths to
            absolute paths based on the current Cinema4D project folder.
        """
        )