Bases: InstancePlugin
Validates if locally pre rendered files are all as expected.
Artists might render manually with AERender
button and want only to publish these files after visually checking them. This validator checks that there exists files with same names as were expected to be rendered.
Applies only on instances created with 'Use existing frames'.
Source code in client/ayon_aftereffects/plugins/publish/validate_rendered_files.py
13
14
15
16
17
18
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
123
124
125
126
127
128
129 | class ValidateRenderedFiles(pyblish.api.InstancePlugin):
"""Validates if locally pre rendered files are all as expected.
Artists might render manually with AE`Render` button and want only to
publish these files after visually checking them.
This validator checks that there exists files with same names as were
expected to be rendered.
Applies only on instances created with 'Use existing frames'.
"""
order = pyblish.api.ValidatorOrder
label = "Validate Rendered Files"
families = ["render"]
hosts = ["aftereffects"]
actions = [RepairAction]
optional = True
def process(self, instance):
"""Plugin entry point."""
use_existing_frames = (
instance.data["creator_attributes"]
["render_target"] == "frames"
)
if not use_existing_frames:
self.log.debug("Not using existing frames, skipping")
return
expected_files = {os.path.basename(file_path)
for file_path in instance.data["expectedFiles"]}
collected_files = self._get_collected_files(instance)
# prepared for multiple outputs per render queue, now it will be only
# single folder
checked_folders = self._get_checked_folders(instance)
missing = expected_files - collected_files
if missing:
raise PublishValidationError(
"<b>Checked:</b> {}<br/><br/>"
"<b>Missing expected files:</b> {}<br/><br/>"
"Expected files: {}<br/>"
"Existing files: {}".format(
sorted(checked_folders),
sorted(missing),
sorted(expected_files),
sorted(collected_files)
)
)
else:
self.log.debug("Matching expected and found files")
collections, remainders = (
self._get_collections_and_remainders(collected_files))
if remainders:
raise PublishValidationError(
f"Folders {checked_folders} contain out of sequence files "
f"{remainders}. <br/><br/>"
f"This will cause issue when integrating.<br/><br/>"
"Please remove these files manually or use `Repair` action to "
"delete them."
)
if len(collections) > 1:
raise PublishValidationError(
f"Folders {checked_folders} contain multiple collections "
f"{collections}. <br/><br/>"
f"This will cause issue during extraction of review.<br/><br/>"
"Please remove one of the collections manually!"
)
@classmethod
def _get_checked_folders(cls, instance):
"""Parses physical output dirs from Render Queue Output Module(s)"""
checked_folders = {os.path.dirname(file_path)
for file_path in instance.data["expectedFiles"]}
return checked_folders
@classmethod
def _get_collections_and_remainders(cls, collected_files):
"""Looks for similarly named files outside of collected sequence.
Could cause an issue in ExtractReview or Integrate.
"""
return clique.assemble(collected_files)
@classmethod
def _get_collected_files(cls, instance):
"""Returns all physically found frames for output dir(s)"""
collected_files = []
for repre in instance.data["representations"]:
repre_files = repre["files"]
if isinstance(repre_files, str):
repre_files = [repre_files]
collected_files.extend(repre_files)
collected_files = set(collected_files)
return collected_files
@classmethod
def repair(cls, instance):
"""Deletes out of sequence files from output dir(s)."""
collected_files = cls._get_collected_files(instance)
checked_folders = cls._get_checked_folders(instance)
_, remainders = cls._get_collections_and_remainders(collected_files)
for remainder_file_name in remainders:
for checked_folder in checked_folders:
file_path = os.path.join(checked_folder, remainder_file_name)
if os.path.exists(file_path):
cls.log.warning(f"Removing {file_path}")
os.remove(file_path)
continue
|
process(instance)
Plugin entry point.
Source code in client/ayon_aftereffects/plugins/publish/validate_rendered_files.py
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 | def process(self, instance):
"""Plugin entry point."""
use_existing_frames = (
instance.data["creator_attributes"]
["render_target"] == "frames"
)
if not use_existing_frames:
self.log.debug("Not using existing frames, skipping")
return
expected_files = {os.path.basename(file_path)
for file_path in instance.data["expectedFiles"]}
collected_files = self._get_collected_files(instance)
# prepared for multiple outputs per render queue, now it will be only
# single folder
checked_folders = self._get_checked_folders(instance)
missing = expected_files - collected_files
if missing:
raise PublishValidationError(
"<b>Checked:</b> {}<br/><br/>"
"<b>Missing expected files:</b> {}<br/><br/>"
"Expected files: {}<br/>"
"Existing files: {}".format(
sorted(checked_folders),
sorted(missing),
sorted(expected_files),
sorted(collected_files)
)
)
else:
self.log.debug("Matching expected and found files")
collections, remainders = (
self._get_collections_and_remainders(collected_files))
if remainders:
raise PublishValidationError(
f"Folders {checked_folders} contain out of sequence files "
f"{remainders}. <br/><br/>"
f"This will cause issue when integrating.<br/><br/>"
"Please remove these files manually or use `Repair` action to "
"delete them."
)
if len(collections) > 1:
raise PublishValidationError(
f"Folders {checked_folders} contain multiple collections "
f"{collections}. <br/><br/>"
f"This will cause issue during extraction of review.<br/><br/>"
"Please remove one of the collections manually!"
)
|
repair(instance)
classmethod
Deletes out of sequence files from output dir(s).
Source code in client/ayon_aftereffects/plugins/publish/validate_rendered_files.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 | @classmethod
def repair(cls, instance):
"""Deletes out of sequence files from output dir(s)."""
collected_files = cls._get_collected_files(instance)
checked_folders = cls._get_checked_folders(instance)
_, remainders = cls._get_collections_and_remainders(collected_files)
for remainder_file_name in remainders:
for checked_folder in checked_folders:
file_path = os.path.join(checked_folder, remainder_file_name)
if os.path.exists(file_path):
cls.log.warning(f"Removing {file_path}")
os.remove(file_path)
continue
|