BaseRenderWorker split into BaseRenderWorker & BaseRenderEngine

This commit is contained in:
Brett Williams
2023-05-22 18:53:19 -05:00
parent ef5ecf335d
commit c73b6d1da7

View File

@@ -30,27 +30,24 @@ def string_to_status(string):
class BaseRenderWorker(object): class BaseRenderWorker(object):
renderer = 'BaseRenderWorker' engine = None
render_engine = None
render_engine_version = None
supported_extensions = []
install_paths = []
supported_export_formats = []
def __init__(self, input_path, output_path, args=None, ignore_extensions=True): def __init__(self, input_path, output_path, args=None, ignore_extensions=True):
if not ignore_extensions: if not ignore_extensions:
if not any(ext in input_path for ext in self.supported_extensions): if not any(ext in input_path for ext in self.engine.supported_extensions):
err_meg = f'Cannot find valid project with supported file extension for {self.renderer} renderer' err_meg = f'Cannot find valid project with supported file extension for {self.engine.name} renderer'
logger.error(err_meg) logger.error(err_meg)
raise ValueError(err_meg) raise ValueError(err_meg)
if not self.engine:
raise NotImplementedError("Engine not defined")
# Essential Info # Essential Info
self.input_path = input_path self.input_path = input_path
self.output_path = output_path self.output_path = output_path
self.args = args or {} self.args = args or {}
self.date_created = datetime.now() self.date_created = datetime.now()
self.renderer_version = self.version() self.renderer_version = self.engine.version()
# Frame Ranges # Frame Ranges
self.total_frames = 0 self.total_frames = 0
@@ -75,23 +72,6 @@ class BaseRenderWorker(object):
self.is_finished = False self.is_finished = False
self.last_output = None self.last_output = None
@classmethod
def version(cls):
raise NotImplementedError("Unknown version")
@classmethod
def renderer_path(cls):
path = None
try:
path = subprocess.check_output(['which', cls.render_engine]).decode('utf-8').strip()
except subprocess.CalledProcessError:
for p in cls.install_paths:
if os.path.exists(p):
path = p
except Exception as e:
logging.exception(e)
return path
def validate(self): def validate(self):
if not os.path.exists(self.input_path): if not os.path.exists(self.input_path):
raise FileNotFoundError(f"Cannot find input path: {self.input_path}") raise FileNotFoundError(f"Cannot find input path: {self.input_path}")
@@ -128,9 +108,9 @@ class BaseRenderWorker(object):
self.errors.append(msg) self.errors.append(msg)
return return
if not self.renderer_path(): if not self.engine.renderer_path():
self.status = RenderStatus.ERROR self.status = RenderStatus.ERROR
msg = 'Cannot find render engine path for {}'.format(self.render_engine) msg = 'Cannot find render engine path for {}'.format(self.engine.name())
logger.error(msg) logger.error(msg)
self.errors.append(msg) self.errors.append(msg)
return return
@@ -166,12 +146,12 @@ class BaseRenderWorker(object):
with open(self.log_path, "a") as f: with open(self.log_path, "a") as f:
f.write("{3} - Starting {0} {1} Render for {2}\n".format(self.renderer, self.version(), self.input_path, f.write(f"{self.start_time.isoformat()} - Starting {self.engine.name()} {self.engine.version()} "
self.start_time.isoformat())) f"Render for {self.input_path}")
f.write(f"Running command: {' '.join(subprocess_cmds)}\n") f.write(f"Running command: {' '.join(subprocess_cmds)}\n")
for c in io.TextIOWrapper(self.__process.stdout, encoding="utf-8"): # or another encoding for c in io.TextIOWrapper(self.__process.stdout, encoding="utf-8"): # or another encoding
f.write(c) f.write(c)
logger.debug(f"{self.renderer}Worker: {c.strip()}") logger.debug(f"{self.engine.name()}Worker: {c.strip()}")
self.last_output = c.strip() self.last_output = c.strip()
self._parse_stdout(c.strip()) self._parse_stdout(c.strip())
f.write('\n') f.write('\n')
@@ -187,18 +167,19 @@ class BaseRenderWorker(object):
duration = self.end_time - self.start_time duration = self.end_time - self.start_time
if return_code: if return_code:
message = f"{self.renderer} render failed with return_code {return_code} after {duration}" message = f"{self.engine.name()} render failed with return_code {return_code} after {duration}"
logger.error(message) logger.error(message)
self.failed_attempts = self.failed_attempts + 1 self.failed_attempts = self.failed_attempts + 1
else: else:
message = f"{self.renderer} render completed successfully in {duration}" message = f"{self.engine.name()} render completed successfully in {duration}"
logger.info(message) logger.info(message)
self.status = RenderStatus.COMPLETED self.status = RenderStatus.COMPLETED
f.write(message) f.write(message)
if self.failed_attempts >= self.maximum_attempts and self.status is not RenderStatus.CANCELLED: if self.failed_attempts >= self.maximum_attempts and self.status is not RenderStatus.CANCELLED:
logger.error('{} Render of {} failed after {} attempts'.format(self.renderer, self.input_path, self.failed_attempts)) logger.error('{} Render of {} failed after {} attempts'.format(self.engine.name(), self.input_path,
self.failed_attempts))
self.status = RenderStatus.ERROR self.status = RenderStatus.ERROR
if not self.errors: if not self.errors:
self.errors = [self.last_output] self.errors = [self.last_output]
@@ -237,6 +218,45 @@ class BaseRenderWorker(object):
return elapsed return elapsed
class BaseRenderEngine(object):
install_paths = []
supported_extensions = []
@classmethod
def name(cls):
return cls.__name__.lower()
@classmethod
def renderer_path(cls):
path = None
try:
path = subprocess.check_output(['which', cls.name()]).decode('utf-8').strip()
except subprocess.CalledProcessError:
for p in cls.install_paths:
if os.path.exists(p):
path = p
except Exception as e:
logging.exception(e)
return path
@classmethod
def version(cls):
raise NotImplementedError("version not implemented")
@classmethod
def get_help(cls):
path = cls.renderer_path()
if not path:
raise FileNotFoundError("renderer path not found")
help_doc = subprocess.check_output([path, '-h'], stderr=subprocess.STDOUT).decode('utf-8')
return help_doc
@classmethod
def get_formats(cls):
raise NotImplementedError("get_formats not implemented")
class RenderWorkerFactory: class RenderWorkerFactory:
@staticmethod @staticmethod
@@ -255,15 +275,14 @@ class RenderWorkerFactory:
@staticmethod @staticmethod
def supported_renderers(): def supported_renderers():
return [x.render_engine for x in RenderWorkerFactory.supported_classes()] return [x.engine.name() for x in RenderWorkerFactory.supported_classes()]
@staticmethod @staticmethod
def class_for_name(name): def class_for_name(name):
name = name.lower() name = name.lower()
for render_class in RenderWorkerFactory.supported_classes(): for render_class in RenderWorkerFactory.supported_classes():
if render_class.render_engine == name: if render_class.engine.name() == name:
return render_class return render_class
raise LookupError(f'Cannot find class for name: {name}') raise LookupError(f'Cannot find class for name: {name}')