Skip to content

Commit

Permalink
Transformed CelAction to AbstractSubmitDeadline
Browse files Browse the repository at this point in the history
Untested!
  • Loading branch information
kalisp committed Nov 6, 2024
1 parent 73b3400 commit 19639fb
Showing 1 changed file with 40 additions and 204 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import os
import re
import json
import getpass
import pyblish.api
import attr

from ayon_deadline.abstract_submit_deadline import requests_post
from ayon_deadline import abstract_submit_deadline


class CelactionSubmitDeadline(pyblish.api.InstancePlugin):
@attr.s
class CelactionPluginInfo():
SceneFile = attr.ib(default=None)
OutputFilePath = attr.ib(default=None)
Output = attr.ib(default=None)
StartupDirectory = attr.ib(default=None)
Arguments = attr.ib(default=None)
ProjectPath = attr.ib(default=None)
AWSAssetFile0 = attr.ib(default=None)


class CelactionSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline):
"""Submit CelAction2D scene to Deadline
Renders are submitted to a Deadline Web Service.
Expand All @@ -18,99 +28,37 @@ class CelactionSubmitDeadline(pyblish.api.InstancePlugin):
order = pyblish.api.IntegratorOrder + 0.1
hosts = ["celaction"]
families = ["render.farm"]
settings_category = "deadline"

deadline_department = ""
deadline_priority = 50
deadline_pool = ""
deadline_pool_secondary = ""
deadline_group = ""
deadline_chunk_size = 1
deadline_job_delay = "00:00:08:00"

def process(self, instance):
def get_job_info(self, job_info=None):
job_info.Plugin = "CelAction"

context = instance.context
# already collected explicit values for rendered Frames
if not job_info.Frames:
# Deadline requires integers in frame range
frame_range = "{}-{}".format(
int(round(self._instance.data["frameStart"])),
int(round(self._instance.data["frameEnd"])))
job_info.Frames = frame_range

deadline_url = instance.data["deadline"]["url"]
assert deadline_url, "Requires Deadline Webservice URL"
return job_info

self.deadline_url = "{}/api/jobs".format(deadline_url)
self._comment = instance.data["comment"]
self._deadline_user = context.data.get(
"deadlineUser", getpass.getuser())
self._frame_start = int(instance.data["frameStart"])
self._frame_end = int(instance.data["frameEnd"])
def get_plugin_info(self):
plugin_info = CelactionPluginInfo()
instance = self._instance

# get output path
render_path = instance.data['path']
script_path = context.data["currentFile"]
render_path = instance.data["path"]
render_dir = os.path.dirname(render_path)

response = self.payload_submit(instance,
script_path,
render_path
)
# Store output dir for unified publisher (filesequence)
instance.data["deadlineSubmissionJob"] = response.json()
self._expected_files(instance, render_path)

instance.data["outputDir"] = os.path.dirname(
render_path).replace("\\", "/")

instance.data["publishJobState"] = "Suspended"

# adding 2d render specific family for version identification in Loader
instance.data["families"] = ["render2d"]
script_path = self.scene_path
plugin_info.SceneFile = script_path
plugin_info.ProjectPath = script_path
plugin_info.OutputFilePath = render_dir.replace("\\", "/")
plugin_info.StartupDirectory = ""

def payload_submit(self,
instance,
script_path,
render_path
):
resolution_width = instance.data["resolutionWidth"]
resolution_height = instance.data["resolutionHeight"]
render_dir = os.path.normpath(os.path.dirname(render_path))
render_path = os.path.normpath(render_path)
script_name = os.path.basename(script_path)

anatomy = instance.context.data["anatomy"]
publish_template = anatomy.get_template_item(
"publish", "default", "path"
)
for item in instance.context:
if "workfile" in item.data["productType"]:
msg = "Workfile (scene) must be published along"
assert item.data["publish"] is True, msg

template_data = item.data.get("anatomyData")
rep = item.data.get("representations")[0].get("name")
template_data["representation"] = rep
template_data["ext"] = rep
template_data["comment"] = None
template_filled = publish_template.format_strict(
template_data
)
script_path = os.path.normpath(template_filled)

self.log.info(
"Using published scene for render {}".format(script_path)
)

jobname = "%s - %s" % (script_name, instance.name)

output_filename_0 = self.preview_fname(render_path)

try:
# Ensure render folder exists
os.makedirs(render_dir)
except OSError:
pass

# define chunk and priority
chunk_size = instance.context.data.get("chunk")
if not chunk_size:
chunk_size = self.deadline_chunk_size

# search for %02d pattern in name, and padding number
search_results = re.search(r"(%0)(\d)(d)[._]", render_path).groups()
split_patern = "".join(search_results)
padding_number = int(search_results[1])
Expand All @@ -128,126 +76,14 @@ def payload_submit(self,
f"-= AbsoluteFrameNumber=on -= PadDigits={padding_number}",
"-= ClearAttachment=on",
]
plugin_info.Arguments = " ".join(args)

payload = {
"JobInfo": {
# Job name, as seen in Monitor
"Name": jobname,

# plugin definition
"Plugin": "CelAction",

# Top-level group name
"BatchName": script_name,

# Arbitrary username, for visualisation in Monitor
"UserName": self._deadline_user,

"Department": self.deadline_department,
"Priority": self.deadline_priority,

"Group": self.deadline_group,
"Pool": self.deadline_pool,
"SecondaryPool": self.deadline_pool_secondary,
"ChunkSize": chunk_size,

"Frames": f"{self._frame_start}-{self._frame_end}",
"Comment": self._comment,

# Optional, enable double-click to preview rendered
# frames from Deadline Monitor
"OutputFilename0": output_filename_0.replace("\\", "/"),

# # Asset dependency to wait for at least
# the scene file to sync.
# "AssetDependency0": script_path
"ScheduledType": "Once",
"JobDelay": self.deadline_job_delay
},
"PluginInfo": {
# Input
"SceneFile": script_path,

# Output directory
"OutputFilePath": render_dir.replace("\\", "/"),

# Plugin attributes
"StartupDirectory": "",
"Arguments": " ".join(args),

# Resolve relative references
"ProjectPath": script_path,
"AWSAssetFile0": render_path,
},

# Mandatory for Deadline, may be empty
"AuxFiles": []
}

plugin = payload["JobInfo"]["Plugin"]
self.log.debug("using render plugin : {}".format(plugin))

self.log.debug("Submitting..")
self.log.debug(json.dumps(payload, indent=4, sort_keys=True))

# adding expectied files to instance.data
self.expected_files(instance, render_path)
self.log.debug("__ expectedFiles: `{}`".format(
instance.data["expectedFiles"]))
auth = instance.data["deadline"]["auth"]
verify = instance.data["deadline"]["verify"]
response = requests_post(self.deadline_url, json=payload,
auth=auth,
verify=verify)

if not response.ok:
self.log.error(
"Submission failed! [{}] {}".format(
response.status_code, response.content))
self.log.debug(payload)
raise SystemExit(response.text)

return response

def preflight_check(self, instance):
"""Ensure the startFrame, endFrame and byFrameStep are integers"""

for key in ("frameStart", "frameEnd"):
value = instance.data[key]

if int(value) == value:
continue

self.log.warning(
"%f=%d was rounded off to nearest integer"
% (value, int(value))
)

def preview_fname(self, path):
"""Return output file path with #### for padding.
Deadline requires the path to be formatted with # in place of numbers.
For example `/path/to/render.####.png`
Args:
path (str): path to rendered images
Returns:
str
"""
self.log.debug("_ path: `{}`".format(path))
if "%" in path:
search_results = re.search(r"[._](%0)(\d)(d)[._]", path).groups()
split_patern = "".join(search_results)
split_path = path.split(split_patern)
hashes = "#" * int(search_results[1])
return "".join([split_path[0], hashes, split_path[-1]])
# adding 2d render specific family for version identification in Loader
instance.data["families"] = ["render2d"]

self.log.debug("_ path: `{}`".format(path))
return path
return attr.asdict(plugin_info)

def expected_files(self, instance, filepath):
def _expected_files(self, instance, filepath):
""" Create expected files in instance data
"""
if not instance.data.get("expectedFiles"):
Expand Down

0 comments on commit 19639fb

Please sign in to comment.