Source code for schrodinger.test.fakejob

import os
from typing import Optional

from schrodinger.infra import mmjob
from schrodinger.job import jobcontrol
from schrodinger.Qt import QtCore

from . import mmshare_testfile

job_record_scalars = {
    "JobId",
    "ParentJobId",
    "Name",
    "Program",
    "Processors",
    "OrigLaunchHost",
    "OrigLaunchDir",
    "Host",
    "User",
    "Dir",
    "HostEntry",
    "Commandline",
    "QueueHost",
    "BatchId",
    "JobHost",
    "JobSchrodinger",
    "JobDir",
    "JobProgress",
    "Status",
    "ExitStatus",
    "ExitCode",
    "Timezone",
    "LaunchTime",
    "StartTime",
    "StatusTime",
    "StopTime",
    "StructureOutputFile",
    "Debug",
    "Project",
    "Disposition",
    "ViewName",
    "TmpLaunchDir",
    "DisplayStatus",
    "StatusChangeReason",
    "DownloadableFiles",
}

job_record_lists = {
    "InputFiles",
    "OutputFiles",
    "LogFiles",
    # "Licenses", # ignored because it doesn't appear to be used in jobcontrol.Job
    "Envs",
    "SubJobs",
    "Errors",
}


[docs]def create_fake_job(JobId: str, **kwargs) -> jobcontrol.Job: """ Returns a jobcontrol.Job created a from a job record with the given kwargs dict. """ cpp_job = _get_cpp_job(JobId=JobId, **kwargs) return jobcontrol.Job(JobId, cpp_job)
def _get_cpp_job(**kwargs) -> mmjob.Job: """ Returns an mmjob.Job created from a job record with the given kwargs dict. The values in the kwargs dict will NOT be escaped. """ job_record_lines = [] for field, value in kwargs.items(): if field in job_record_scalars: if value is None or value == "": continue job_record_lines.append(f"{field}: {value}") elif field in job_record_lists: if len(value) == 0: continue # list items are 1-indexed. for i in range(1, len(value) + 1): line = f"{field}[{i}]: {value[i-1]}" job_record_lines.append(line) else: raise ValueError( f"Unexpected keyword argument: {field} is not a valid job record field." ) job_record_text = '\n'.join(job_record_lines) cpp_job = mmjob.job_from_job_record_text(job_record_text) return cpp_job
[docs]def get_legacy_completed_job() -> jobcontrol.Job: """ Returns a completed job with an ExitStatus of finished. """ legacy_job_id = "isabel-0-42f280f5" return create_fake_job(legacy_job_id, Status="completed", ExitStatus="finished")
[docs]def get_legacy_died_job() -> jobcontrol.Job: """ Returns a completed job with legacy jobcontrol JobId and an ExitStatus of "died". """ return get_job(mmshare_testfile("job_test_files/isabel-0-42f280f5"))
[docs]def get_legacy_running_job() -> jobcontrol.Job: """ Returns a running job with a legacy job id. """ return get_job(mmshare_testfile("job_test_files/isabel-0-42f280f6"))
[docs]def get_job(filename) -> jobcontrol.Job: """ Return a job object from a text file. """ with open(filename) as fh: cpp_job = mmjob.job_from_job_record_text(fh.read()) # No need to patch jobcontrol.Job.readAgain here, it won't be called # because we're already initializing with a cpp_job. job = jobcontrol.Job(job_id=os.path.basename(filename), cpp_job=cpp_job) return job
[docs]class FakeJobDownloader(QtCore.QObject): """ Drop-in replacement for the JobDownloader class, immediately emits a signal indicating a successful download. """ downloadFinished = QtCore.pyqtSignal(str)
[docs] def __init__(self, jobid): super().__init__() self.output = ''
[docs] def download(self): self.downloadFinished.emit(self.output)
[docs]class FakeFailedJobDownloader(FakeJobDownloader): """ Like FakeJobDownloader, but emits its signal with a non-empty string, indicating a download failure. """ FAKE_OUTPUT = 'fake download failed'
[docs] def __init__(self, jobid): super().__init__(jobid) self.output = FakeFailedJobDownloader.FAKE_OUTPUT
[docs]class FakeJobLauncher(QtCore.QObject): """ Drop-in replacement for the JobLauncher class, immediately emits a signal indicating a successful download. """ # hack to provide class var to show last value last_job_cmd = None jobStarted = QtCore.pyqtSignal(jobcontrol.Job) jobLaunchFailed = QtCore.pyqtSignal(str)
[docs] def __init__(self, job_cmd, job: Optional[jobcontrol.Job] = None): # set cls variable FakeJobLauncher.last_job_cmd = job_cmd super().__init__() # The job to emit from launch. if job is None: job = get_legacy_died_job() self._job = job
[docs] def launch(self): QtCore.QTimer.singleShot(0, self._launchFinished)
def _launchFinished(self): self.jobStarted.emit(self._job)