Deadline Pype 3 - modify Pype Plugin

Use copy of modified DL Python plugin as base
This commit is contained in:
Petr Kalis 2021-03-02 17:11:37 +01:00
parent d2dba8c4a9
commit d08947269f
3 changed files with 111 additions and 112 deletions

View file

@ -100,7 +100,6 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
icon = "tractor"
deadline_plugin = "Pype"
hosts = ["fusion", "maya", "nuke", "celaction", "aftereffects", "harmony"]
families = ["render.farm", "prerender",
@ -150,7 +149,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
# list of family names to transfer to new family if present
families_transfer = ["render3d", "render2d", "ftrack", "slate"]
plugin_python_version = "3.7"
plugin_pype_version = "3.0"
# script path for publish_filesequence.py
publishing_script = None
@ -186,7 +185,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
).format(output_dir))
roothless_mtdt_p = metadata_path
return (metadata_path, roothless_mtdt_p)
return metadata_path, roothless_mtdt_p
def _submit_deadline_post_job(self, instance, job, instances):
"""Submit publish job to Deadline.
@ -220,7 +219,6 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
self._create_metadata_path(instance)
environment = job["Props"].get("Env", {})
environment["PYPE_METADATA_FILE"] = roothless_metadata_path
environment["AVALON_PROJECT"] = io.Session["AVALON_PROJECT"]
environment["AVALON_ASSET"] = io.Session["AVALON_ASSET"]
environment["AVALON_TASK"] = io.Session["AVALON_TASK"]
@ -230,6 +228,11 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
environment["PYPE_PUBLISH_JOB"] = "1"
environment["PYPE_RENDER_JOB"] = "0"
args = [
'publish',
roothless_metadata_path
]
# Generate the payload for Deadline submission
payload = {
"JobInfo": {
@ -250,7 +253,8 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
"OutputDirectory0": output_dir
},
"PluginInfo": {
"Version": self.plugin_python_version,
"Version": self.plugin_pype_version,
"Arguments": " ".join(args),
"SingleFrameOnly": "True",
},
# Mandatory for Deadline, may be empty
@ -1069,6 +1073,6 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
self.log.info("interpreter::{}".format(interpreter))
executable_path = os.path.join(*interpreter)
assert executable_path is not None, ("Cannot determine path")
assert executable_path is not None, "Cannot determine path"
return str(executable_path)

View file

@ -1,37 +1,27 @@
[State]
Type=Enum
Items=Global Enabled;Opt-In;Disabled
Category=Options
CategoryOrder=0
CategoryIndex=0
Label=State
Default=Global Enabled
Description=How this event plug-in should respond to events. If Global, all jobs and slaves will trigger the events for this plugin. If Opt-In, jobs and slaves can choose to trigger the events for this plugin. If Disabled, no events are triggered for this plugin.
[About]
Type=label
Label=About
Category=About Plugin
CategoryOrder=-1
Index=0
Default=Pype Plugin for Deadline
Description=Not configurable
[PythonSearchPaths]
Type=MultiLineMultiFolder
Label=Additional Python Search Paths
Category=Options
[ConcurrentTasks]
Type=label
Label=ConcurrentTasks
Category=About Plugin
CategoryOrder=-1
Index=0
Default=True
Description=Not configurable
[Pype_Executable_3_0]
Type=multilinemultifilename
Label=Pype 3.0 Executable
Category=Pype Executables
CategoryOrder=0
CategoryIndex=1
Index=0
Default=
Description=The list of paths to append to the PYTHONPATH environment variable. This allows the Python job to find custom modules in non-standard locations.
Description=The path to the Pype executable. Enter alternative paths on separate lines.
[LoggingLevel]
Type=Enum
Label=Logging Level
Category=Options
CategoryOrder=0
CategoryIndex=2
Items=DEBUG;INFO;WARNING;ERROR
Default=DEBUG
Description=Logging level where printing will start.
[PypeExecutable]
Type=MultiLineMultiFolder
Label=Path to Pype executable dir
Category=Job Plugins
CategoryOrder=1
CategoryIndex=1
Default=
Description=

View file

@ -1,9 +1,10 @@
import sys
import subprocess
import platform
import os
from System.IO import *
from System.Text.RegularExpressions import *
from Deadline.Plugins import DeadlinePlugin, PluginType
from Deadline.Plugins import *
from Deadline.Scripting import *
import re
######################################################################
@ -28,84 +29,88 @@ class PypeDeadlinePlugin(DeadlinePlugin):
for publish process.
"""
def __init__(self):
self.StartJobCallback += self.StartJob
self.InitializeProcessCallback += self.InitializeProcess
self.RenderTasksCallback += self.RenderTasks
self.RenderExecutableCallback += self.RenderExecutable
self.RenderArgumentCallback += self.RenderArgument
def Cleanup(self):
del self.StartJobCallback
for stdoutHandler in self.StdoutHandlers:
del stdoutHandler.HandleCallback
del self.InitializeProcessCallback
del self.RenderTasksCallback
del self.RenderExecutableCallback
del self.RenderArgumentCallback
def StartJob(self):
# adding python search paths
paths = self.GetConfigEntryWithDefault("PythonSearchPaths", "").strip()
paths = paths.split(";")
for path in paths:
self.LogInfo("Extending sys.path with: " + str(path))
sys.path.append(path)
self.LogInfo("PypeDeadlinePlugin start")
try:
metadata_file = \
self.GetProcessEnvironmentVariable("PYPE_METADATA_FILE")
if not metadata_file:
raise RuntimeError("Env var PYPE_METADATA_FILE value missing")
pype_app = self.get_pype_executable_path()
args = [
pype_app,
'publish',
metadata_file
]
env = {}
env = dict(os.environ)
job = self.GetJob()
for key in job.GetJobEnvironmentKeys():
env[str(key)] = str(job.GetJobEnvironmentKeyValue(key))
exit_code = subprocess.call(args, shell=True, env=env)
if exit_code != 0:
raise RuntimeError("Publishing failed, check worker's log")
self.LogInfo("PypeDeadlinePlugin end")
except Exception:
import traceback
self.LogInfo(traceback.format_exc())
self.LogInfo("PypeDeadlinePlugin failed")
raise
# Called by Deadline to initialize the process.
def InitializeProcess(self):
# Set the plugin specific settings.
self.PluginType = PluginType.Simple
self.StdoutHandling = True
def RenderTasks(self):
# do nothing, no render, just publishing, still must be here
pass
self.SingleFramesOnly = self.GetBooleanPluginInfoEntryWithDefault(
"SingleFramesOnly", False)
self.LogInfo("Single Frames Only: %s" % self.SingleFramesOnly)
def get_pype_executable_path(self):
"""
Returns calculated path based on settings and platform
self.AddStdoutHandlerCallback(
".*Progress: (\d+)%.*").HandleCallback += self.HandleProgress
Uses 'pype_console' executable
"""
pype_command = "pype_console"
if platform.system().lower() == "linux":
pype_command = "pype_console.sh"
if platform.system().lower() == "windows":
pype_command = "pype_console.exe"
def RenderExecutable(self):
version = self.GetPluginInfoEntry("Version")
pype_root = self.GetConfigEntryWithDefault("PypeExecutable", "")
exeList = self.GetConfigEntry(
"Pype_Executable_" + version.replace(".", "_"))
exe = FileUtils.SearchFileList(exeList)
if exe == "":
self.FailRender(
"Pype " + version + " executable was not found " +
"in the semicolon separated list \"" + exeList + "\". " +
"The path to the render executable can be configured " +
"from the Plugin Configuration in the Deadline Monitor.")
return exe
pype_app = os.path.join(pype_root.strip(), pype_command)
if not os.path.exists(pype_app):
raise RuntimeError("App '{}' doesn't exist. " +
"Fix it in Tools > Configure Events > " +
"pype".format(pype_app))
def RenderArgument(self):
arguments = str(self.GetPluginInfoEntryWithDefault("Arguments", ""))
arguments = RepositoryUtils.CheckPathMapping(arguments)
return pype_app
arguments = re.sub(r"<(?i)STARTFRAME>", str(self.GetStartFrame()),
arguments)
arguments = re.sub(r"<(?i)ENDFRAME>", str(self.GetEndFrame()),
arguments)
arguments = re.sub(r"<(?i)QUOTE>", "\"", arguments)
arguments = self.ReplacePaddedFrame(arguments,
"<(?i)STARTFRAME%([0-9]+)>",
self.GetStartFrame())
arguments = self.ReplacePaddedFrame(arguments,
"<(?i)ENDFRAME%([0-9]+)>",
self.GetEndFrame())
count = 0
for filename in self.GetAuxiliaryFilenames():
localAuxFile = Path.Combine(self.GetJobsDataDirectory(), filename)
arguments = re.sub(r"<(?i)AUXFILE" + str(count) + r">",
localAuxFile.replace("\\", "/"), arguments)
count += 1
return arguments
def ReplacePaddedFrame(self, arguments, pattern, frame):
frameRegex = Regex(pattern)
while True:
frameMatch = frameRegex.Match(arguments)
if frameMatch.Success:
paddingSize = int(frameMatch.Groups[1].Value)
if paddingSize > 0:
padding = StringUtils.ToZeroPaddedString(frame,
paddingSize,
False)
else:
padding = str(frame)
arguments = arguments.replace(frameMatch.Groups[0].Value,
padding)
else:
break
return arguments
def HandleProgress(self):
progress = float(self.GetRegexMatch(1))
self.SetProgress(progress)