import logging import os import subprocess logger = logging.getLogger() SUBPROCESS_TIMEOUT = 5 class BaseRenderEngine(object): install_paths = [] supported_extensions = [] def __init__(self, custom_path=None): self.custom_renderer_path = custom_path if not self.renderer_path(): raise FileNotFoundError(f"Cannot find path to renderer for {self.name()} instance") def renderer_path(self): return self.custom_renderer_path or self.default_renderer_path() @classmethod def name(cls): return str(cls.__name__).lower() @classmethod def default_renderer_path(cls): path = None try: # Linux and macOS path = subprocess.check_output(['which', cls.name()], timeout=SUBPROCESS_TIMEOUT).decode('utf-8').strip() except (subprocess.CalledProcessError, FileNotFoundError): for p in cls.install_paths: if os.path.exists(p): path = p except Exception as e: logger.exception(e) return path def version(self): raise NotImplementedError("version not implemented") @staticmethod def downloader(): # override when subclassing if using a downloader class return None @staticmethod def worker_class(): # override when subclassing to link worker class raise NotImplementedError("Worker class not implemented") def ui_options(self): # override to return options for ui return {} def get_help(self): # override if renderer uses different help flag path = self.renderer_path() if not path: raise FileNotFoundError("renderer path not found") help_doc = subprocess.check_output([path, '-h'], stderr=subprocess.STDOUT, timeout=SUBPROCESS_TIMEOUT).decode('utf-8') return help_doc def get_project_info(self, project_path, timeout=10): raise NotImplementedError(f"get_project_info not implemented for {self.__name__}") @classmethod def get_output_formats(cls): raise NotImplementedError(f"get_output_formats not implemented for {cls.__name__}") @classmethod def get_arguments(cls): pass def perform_presubmission_tasks(self, project_path): return project_path