Skip to content

exe

AbstractExecutable

Bases: ABC

Abstract base class of an Executable

Source code in chmpy/exe/exe.py
class AbstractExecutable(ABC):
    """ Abstract base class of an Executable"""

    _name = "job"
    _has_dependencies = False
    _working_directory = None
    _stdout = ""
    _stderr = ""
    _timeout = 86400.0  # timeout in seconds
    _result = None
    _output_file = None
    _executable_location = None

    @property
    def executable(self):
        return self._executable_location

    @executable.setter
    def executable(self, value):
        os.access(value)
        self._executable_location = os.path.abspath(value)

    @property
    def working_directory(self):
        """Return the current working directory for this job"""
        return self._working_directory

    @working_directory.setter
    def working_directory(self, dirname):
        """"Set the working directory for this job"""
        assert dir_exists_or_is_creatable(
            dirname
        ), f"{dirname} either cannot be found or is not createable"
        self._working_directory = dirname

    @abc.abstractmethod
    def result(self):
        """Return the result of this calculation"""
        raise NotImplementedError

    @property
    def stdout(self):
        """Return the output to stdout for this job"""
        return self._stdout

    @property
    def has_dependencies(self):
        """Does this job require some work before it
        can be run?"""
        return self._has_dependencies

    @abc.abstractmethod
    def resolve_dependencies(self):
        """Do whatever needs to be done before running
        the job (e.g. write input file etc.)"""
        raise NotImplementedError

    @abc.abstractmethod
    def post_process(self):
        """ Do whatever needs to be done after the job."""
        raise NotImplementedError

    @property
    def name(self):
        """ The name of the job as a string."""
        return self._name

    @name.setter
    def name(self, name):
        """ Change the name of the job. """
        self._name = name

    @property
    def timeout(self):
        return self._timeout

    @timeout.setter
    def timeout(self, value):
        self._timeout = float(value)

    @property
    def output_file(self):
        if not self._output_file:
            self._output_file = tempfile.mkstemp(prefix="cspy-", suffix=".txt")
        return self._output_file

    @output_file.setter
    def output_file(self, value):
        if value:
            assert path_exists_or_is_creatable(value)
            self._output_file = value

    def _run_raw(self, *args, **kwargs):
        """Run the calculation, may throw exceptions"""
        self.resolve_dependencies()
        self.returncode = 130
        with Path(self.output_file).open("w+") as of:
            cmd_list = [self.executable] + [x for x in args]
            command = run_subprocess(
                cmd_list,
                stdout=of,
                timeout=self.timeout,
                cwd=self.working_directory,
                **kwargs,
            )
        self.returncode = command.returncode
        self._check_returncode(cmd_list)
        self.post_process()

    def _run_raw_stdin(self, *args, **kwargs):
        """Run the calculation, may throw exceptions"""
        self.resolve_dependencies()
        self.returncode = 130
        with Path(self.input_file).open() as inp:
            with Path(self.output_file).open("w+") as of:
                cmd_list = [self.executable] + [x for x in args]
                command = run_subprocess(
                    cmd_list,
                    stdout=of,
                    stdin=inp,
                    timeout=self.timeout,
                    cwd=self.working_directory,
                    **kwargs,
                )
        self.returncode = command.returncode
        self._check_returncode(cmd_list)
        self.post_process()

    def _check_returncode(self, cmd_list):
        if self.returncode != 0:
            raise ReturnCodeError(
                "Command '{}' exited with return code {}".format(
                    " ".join(str(x) for x in cmd_list), self.returncode
                )
            )

    @abc.abstractmethod
    def run(self, *args, **kwargs):
        raise NotImplementedError

    def __str__(self):
        return "{}: {}".format(self.__class__.__name__, self.name)

    def __repr__(self):
        return str(self)

has_dependencies property

Does this job require some work before it can be run?

name property writable

The name of the job as a string.

stdout property

Return the output to stdout for this job

working_directory property writable

Return the current working directory for this job

post_process() abstractmethod

Do whatever needs to be done after the job.

Source code in chmpy/exe/exe.py
@abc.abstractmethod
def post_process(self):
    """ Do whatever needs to be done after the job."""
    raise NotImplementedError

resolve_dependencies() abstractmethod

Do whatever needs to be done before running the job (e.g. write input file etc.)

Source code in chmpy/exe/exe.py
@abc.abstractmethod
def resolve_dependencies(self):
    """Do whatever needs to be done before running
    the job (e.g. write input file etc.)"""
    raise NotImplementedError

result() abstractmethod

Return the result of this calculation

Source code in chmpy/exe/exe.py
@abc.abstractmethod
def result(self):
    """Return the result of this calculation"""
    raise NotImplementedError