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.
"""
)
|