mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-26 13:52:15 +01:00
added base of tvpaint worker implementation
This commit is contained in:
parent
9f68ee1aac
commit
6973584ca2
3 changed files with 269 additions and 2 deletions
14
openpype/hosts/tvpaint/worker/__init__.py
Normal file
14
openpype/hosts/tvpaint/worker/__init__.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
from .worker_job import (
|
||||
ExecuteSimpleGeorgeScript,
|
||||
ExecuteGeorgeScript,
|
||||
ExecuteGeorgeScriptWithResult,
|
||||
TVPaintCommands
|
||||
)
|
||||
|
||||
|
||||
__all__ = (
|
||||
"ExecuteSimpleGeorgeScript",
|
||||
"ExecuteGeorgeScript",
|
||||
"ExecuteGeorgeScriptWithResult",
|
||||
"TVPaintCommands"
|
||||
)
|
||||
242
openpype/hosts/tvpaint/worker/worker_job.py
Normal file
242
openpype/hosts/tvpaint/worker/worker_job.py
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
import os
|
||||
import tempfile
|
||||
import inspect
|
||||
import copy
|
||||
from uuid import uuid4
|
||||
from abc import ABCMeta, abstractmethod, abstractproperty
|
||||
|
||||
import six
|
||||
|
||||
|
||||
TMP_FILE_PREFIX = "opw_tvp_"
|
||||
|
||||
|
||||
@six.add_metaclass(ABCMeta)
|
||||
class BaseCommand:
|
||||
@abstractproperty
|
||||
def name(self):
|
||||
"""Command name (must be unique)."""
|
||||
pass
|
||||
|
||||
def __init__(self, parent, data):
|
||||
if data is None:
|
||||
data = {}
|
||||
else:
|
||||
data = copy.deepcopy(data)
|
||||
|
||||
command_id = data.get("id")
|
||||
if command_id is None:
|
||||
command_id = str(uuid4())
|
||||
data["id"] = command_id
|
||||
data["command"] = self.name
|
||||
|
||||
self._parent = parent
|
||||
self._result = None
|
||||
self._command_data = data
|
||||
self._done = False
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
return self._command_data["id"]
|
||||
|
||||
@property
|
||||
def parent(self):
|
||||
return self._parent
|
||||
|
||||
@property
|
||||
def done(self):
|
||||
return self._done
|
||||
|
||||
def set_done(self):
|
||||
self._done = True
|
||||
|
||||
def set_result(self, result):
|
||||
self._result = result
|
||||
|
||||
def result(self):
|
||||
return {
|
||||
"id": self.id,
|
||||
"result": self._result,
|
||||
"done": self._done
|
||||
}
|
||||
|
||||
def command_data(self):
|
||||
return copy.deepcopy(self._command_data)
|
||||
|
||||
@abstractmethod
|
||||
def execute(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def from_existing(cls, data):
|
||||
pass
|
||||
|
||||
def execute_george(self, george_script):
|
||||
return self.parent.execute_george(george_script)
|
||||
|
||||
def execute_george_through_file(self, george_script):
|
||||
return self.parent.execute_george_through_file(george_script)
|
||||
|
||||
|
||||
class ExecuteSimpleGeorgeScript(BaseCommand):
|
||||
name = "execute_george_simple"
|
||||
|
||||
def __init__(self, parent, script, data=None):
|
||||
data = data or {}
|
||||
data["script"] = script
|
||||
self._script = script
|
||||
super().__init__(parent, data)
|
||||
|
||||
def execute(self):
|
||||
self._result = self.execute_george(self._script)
|
||||
|
||||
@classmethod
|
||||
def from_existing(cls, parent, data):
|
||||
script = data.pop("script")
|
||||
return cls(parent, script, data)
|
||||
|
||||
|
||||
class ExecuteGeorgeScript(BaseCommand):
|
||||
name = "execute_george_through_file"
|
||||
|
||||
def __init__(self, parent, script, data=None):
|
||||
data = data or {}
|
||||
data["script"] = script
|
||||
self._script = script
|
||||
super().__init__(parent, data)
|
||||
|
||||
def execute(self):
|
||||
self.execute_george_through_file(self._script)
|
||||
|
||||
@classmethod
|
||||
def from_existing(cls, parent, data):
|
||||
script = data.pop("script")
|
||||
return cls(parent, script, data)
|
||||
|
||||
|
||||
class ExecuteGeorgeScriptWithResult(BaseCommand):
|
||||
name = "execute_george_through_file_result"
|
||||
|
||||
def __init__(self, parent, script, tmp_file_keys, data=None):
|
||||
data = data or {}
|
||||
data["script"] = script
|
||||
data["tmp_file_keys"] = tmp_file_keys
|
||||
self._script = script
|
||||
self._tmp_file_keys = tmp_file_keys
|
||||
super().__init__(parent, data)
|
||||
|
||||
def execute(self):
|
||||
filepath_by_key = {}
|
||||
for key in self._tmp_file_keys:
|
||||
output_file = tempfile.NamedTemporaryFile(
|
||||
mode="w", prefix=TMP_FILE_PREFIX, suffix=".txt", delete=False
|
||||
)
|
||||
output_file.close()
|
||||
filepath_by_key[key] = output_file.name.replace("\\", "/")
|
||||
|
||||
formatted_script = self._script.format(**filepath_by_key)
|
||||
self.execute_george_through_file(formatted_script)
|
||||
|
||||
result = {}
|
||||
for key, filepath in filepath_by_key.items():
|
||||
with open(filepath, "r") as stream:
|
||||
data = stream.read()
|
||||
result[key] = data
|
||||
os.remove(filepath)
|
||||
|
||||
self._result = result
|
||||
|
||||
@classmethod
|
||||
def from_existing(cls, parent, data):
|
||||
script = data.pop("script")
|
||||
tmp_file_keys = data.pop("tmp_file_keys")
|
||||
return cls(parent, script, tmp_file_keys, data)
|
||||
|
||||
|
||||
class TVPaintCommands:
|
||||
def __init__(self, workfile, commands=None, communicator=None):
|
||||
if not commands:
|
||||
commands = []
|
||||
|
||||
self._workfile = workfile
|
||||
self._commands = []
|
||||
self._communicator = communicator
|
||||
self._command_classes_by_name = None
|
||||
|
||||
self.commands_from_data(commands)
|
||||
|
||||
@property
|
||||
def communicator(self):
|
||||
return self._communicator
|
||||
|
||||
@property
|
||||
def classes_by_name(self):
|
||||
if self._command_classes_by_name is None:
|
||||
command_classes_by_name = {}
|
||||
for attr in globals().values():
|
||||
if (
|
||||
not inspect.isclass(attr)
|
||||
or not issubclass(attr, BaseCommand)
|
||||
or attr is BaseCommand
|
||||
):
|
||||
continue
|
||||
|
||||
if inspect.isabstract(attr):
|
||||
print("Skipping abstract class {}".format(attr.__name__))
|
||||
command_classes_by_name[attr.name] = attr
|
||||
self._command_classes_by_name = command_classes_by_name
|
||||
|
||||
return self._command_classes_by_name
|
||||
|
||||
def commands_from_data(self, commands_data):
|
||||
for command_data in commands_data:
|
||||
command_name = command_data["command"]
|
||||
|
||||
klass = self.classes_by_name[command_name]
|
||||
command = klass.from_existing(command_data)
|
||||
self.add_command(command)
|
||||
|
||||
def add_command(self, command):
|
||||
self._commands.append(command)
|
||||
|
||||
def _open_workfile(self):
|
||||
george_script = "tv_LoadProject '\"'\"{}\"'\"'".format(
|
||||
self._workfile.replace("\\", "/")
|
||||
)
|
||||
self.execute_george_through_file(george_script)
|
||||
|
||||
def _close_workfile(self):
|
||||
pass
|
||||
|
||||
def execute(self):
|
||||
self._open_workfile()
|
||||
for command in self._commands:
|
||||
command.execute()
|
||||
command.set_done()
|
||||
self._close_workfile()
|
||||
|
||||
def commands_data(self):
|
||||
return [
|
||||
command.command_data()
|
||||
for command in self._commands
|
||||
]
|
||||
|
||||
def result(self):
|
||||
return [
|
||||
command.result()
|
||||
for command in self._commands
|
||||
]
|
||||
|
||||
def execute_george(self, george_script):
|
||||
return self.communicator.execute_george(george_script)
|
||||
|
||||
def execute_george_through_file(self, george_script):
|
||||
temporary_file = tempfile.NamedTemporaryFile(
|
||||
mode="w", prefix=TMP_FILE_PREFIX, suffix=".grg", delete=False
|
||||
)
|
||||
temporary_file.write(george_script)
|
||||
temporary_file.close()
|
||||
temp_file_path = temporary_file.name.replace("\\", "/")
|
||||
self.execute_george("tv_runscript {}".format(temp_file_path))
|
||||
os.remove(temp_file_path)
|
||||
|
|
@ -2,6 +2,7 @@ import signal
|
|||
import time
|
||||
import asyncio
|
||||
|
||||
from openpype.hosts.tvpaint.worker import TVPaintCommands
|
||||
from avalon.tvpaint.communication_server import (
|
||||
BaseCommunicator,
|
||||
CommunicationWrapper
|
||||
|
|
@ -55,8 +56,18 @@ class WorkerCommunicator(BaseCommunicator):
|
|||
if job is None:
|
||||
return
|
||||
|
||||
print(job)
|
||||
self._worker_connection.finish_job()
|
||||
success = False
|
||||
message = "Unknown function"
|
||||
data = None
|
||||
workfile = job["workfile"]
|
||||
if job.data.get("function") == "commands":
|
||||
commands = TVPaintCommands(workfile, job.data["commands"])
|
||||
commands.execute()
|
||||
success = True
|
||||
message = "Executed"
|
||||
data = commands.result()
|
||||
|
||||
self._worker_connection.finish_job(success, message, data)
|
||||
|
||||
def main_loop(self):
|
||||
while self.server_is_running:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue