def run(self, keep: bool, upload: bool, assume_clean: bool, sensor_plot: bool, plot_audio: bool) -> None: submission_hash = str(config["sauron.test_submission_hash"]) output_dir = config.get_output_dir(submission_hash) args = SubmissionRunnerArgs( dark=None, local=not upload, overwrite=True, keep_frames=False, store_to=None, assume_clean=assume_clean, sensor_plot=sensor_plot, plot_audio=plot_audio, halt_after_acquisition=False, ignore_prior=True, ) with Valar() as db: SauronxLock().lock(None) try: # these will get shut down afterward audio = SauronxAudio() audio.start() b = Board() b.init() ss = SubmissionRunner(args, db, audio, b) ss.run(submission_hash, True) if not keep: shutil.rmtree(output_dir, ignore_errors=True) finally: SauronxLock().unlock(ignore_warning=True)
def log(self) -> None: parser = argparse.ArgumentParser( description="Show the recent history of submissions on this Sauron." ) self._parse_args(parser) lookup = LookupTools() with Valar(): lookup.history()
def lookup(self) -> None: parser = argparse.ArgumentParser( description="List something in Valar", usage= "sauronx lookup [users|experiments|submissions|history|batteries|assays|templates|configs|stimuli|audio_files|sensors|plates|runs|plate_types|saurons|locations]", ) parser.add_argument("what", help="What to list") args = self._parse_args(parser) with Valar(): getattr(LookupTools(), args.what)()
def update( self, text: str, when: datetime.datetime = datetime.datetime.now()) -> None: with Valar() as valar: import valarpy.model as model conf = model.SauronConfigs( datetime_changed=when, description=text, sauron=config.sauron_id, created=datetime.datetime.now(), ) conf.save() print(Fore.BLUE + "Created new sauron_config {}".format(conf.id))
def run( self, hashes: List[str], dark: Optional[int], local: bool, overwrite: bool, keep_frames: bool, store_to: Optional[str], assume_clean: bool, sensor_plot: bool, plot_audio: bool, halt_after_acquisition: bool, ignore_prior: bool, keep_lock: bool, ) -> None: args = SubmissionRunnerArgs( dark=dark, local=local, overwrite=overwrite, keep_frames=keep_frames, store_to=store_to, assume_clean=assume_clean, sensor_plot=sensor_plot, plot_audio=plot_audio, halt_after_acquisition=halt_after_acquisition, ignore_prior=ignore_prior, ) SauronxLock().lock(None) try: b = Board() b.init() audio = SauronxAudio() audio.start() with Valar() as db: ss = SubmissionRunner(args, db, audio, b) for i, h in enumerate(hashes): # TODO datetime_started only applies to the first hash. Is this really what we want? self._log_start(args.local, h) # we don't need a new process for the last run ss.run(h, i == len(hashes) - 1) self._log_finish(args.local, h, halt_after_acquisition) finally: if not keep_lock: SauronxLock().unlock(ignore_warning=True)
def __init__( self, submission_hash: Optional[str], db: Optional[Valar] = None, acquisition_start: bool = False, ignore_warnings: bool = False, ) -> None: """If submission_hash is None, don't try to access submission_obj or status_obj or call update_status.""" self.db = None # type: Valar self._internal_db = None # type: bool self.submission_hash = None # type: Optional[str] self.submission_obj = None # type: Submissions self.sauron_obj = None # type: Saurons self.status_obj = None # type: Optional[SubmissionRecords] self._internal_db = db is None # don't close if it was built outside self.ignore_warnings = ignore_warnings self.acquisition_start = acquisition_start self.submission_hash = submission_hash if self.submission_hash is not None: processing_list = ProcessingList.now() if self.submission_hash in processing_list: warn_user( "Refusing to touch {}:".format(submission_hash), "Another SauronX process appears to be handling it.", "If this is wrong, run 'sauronx clear {}' to continue.". format(submission_hash), ) raise LockedError( "Refusing to touch {}: Another SauronX process appears to be handling it." .format(submission_hash)) if db is None: self.db = Valar() else: self.db = db try: if "connection.notification.slack_info_file" in config: with open( str(config["connection.notification.slack_info_file"]), "r") as file: self._slack_hook = file.readline() self._slack_user_dict = json.loads(file.readline()) except Exception: warn_user("Failed to call notification") logger.error("Failed to call notification", exc_info=True)
def clean(self) -> None: parser = argparse.ArgumentParser( description= "List SauronX output on this machine and decide whether to delete it" ) parser.add_argument( "--auto", action="store_true", help="Auto-accept each recommendation without prompting") parser.add_argument( "--skip-ignores", action="store_true", help="Don’t prompt when the recommendation is to ignore.", ) args, restrictions, options, base_dir = self._data_args(parser) with Valar() as db: if args.auto: DataManager(db).auto_clean(restrictions, options, base_dir) else: DataManager(db).clean(restrictions, options, base_dir, args.skip_ignores)
def connect(self) -> None: """Hidden connection test.""" with Valar(): pass
def data(self) -> None: parser = argparse.ArgumentParser( description="List SauronX output on this machine") args, restrictions, options, base_dir = self._data_args(parser) with Valar() as db: DataManager(db).data(restrictions, options, base_dir)
def print_info(self, extended: bool = False) -> None: with Valar() as valar: print() self._bannered( Style.BRIGHT + "Version information...", "Version ".ljust(20, ".") + " " + sauronx_version, "Hash ".ljust(20, ".") + " " + git_commit_hash(sauronx_home), ) obj = config.get_sauron_config() self._bannered( Style.BRIGHT + "Hardware config information...", "Date/time changed ".ljust(20, ".") + " " + "{}Z".format( config.sauron_number, obj.datetime_changed.strftime("%Y-%m-%d_%H-%M-%S")), "Description ".ljust(20, ".") + " " + obj.description, ) self._bannered( Style.BRIGHT + "Video information...", "QP ".ljust(20, ".") + " " + str(config["sauron.data.video.qp"]), "Keyframe interval ".ljust(20, ".") + " " + str(config["sauron.data.video.keyframe_interval"]), "Preset ".ljust(20, ".") + " " + config.get_str("sauron.data.video.preset"), "Custom params ".ljust(20, ".") + " " + "; ".join([ str(k) + "=" + str(v) for k, v in config["sauron.data.video.extra_x265_params"].items() ]), ) self._bannered( Style.BRIGHT + "Hardware information...", "FPS ".ljust(20, ".") + " " + str(config["sauron.hardware.camera.frames_per_second"]), "Exposure ".ljust(20, ".") + " " + str(config["sauron.hardware.camera.exposure"]), "Gain ".ljust(20, ".") + " " + str(config["sauron.hardware.camera.gain"]), "Gamma ".ljust(20, ".") + " " + str(config["sauron.hardware.camera.gamma"]), "Black level ".ljust(20, ".") + " " + str(config["sauron.hardware.camera.black_level"]), "Pre-padding ".ljust(20, ".") + " " + str(config[ "sauron.hardware.camera.padding_before_milliseconds"]), "Post-padding ".ljust(20, ".") + " " + str(config["sauron.hardware.camera.padding_after_milliseconds"] ), "Arduino chipset ".ljust(20, ".") + " " + config.get_str("sauron.hardware.arduino.chipset"), "Sample rate (ms) ".ljust(20, ".") + " " + str(config[ "sauron.hardware.sensors.sampling_interval_milliseconds"]), "Audio floor (dB) ".ljust(20, ".") + " " + str(config["sauron.hardware.stimuli.audio.audio_floor"]), "Registered sensors ".ljust(20, ".") + " " + "; ".join(config["sauron.hardware.sensors.registry"]), ) self._bannered( Style.BRIGHT + "Sauronx config information...", "Sauron ".ljust(20, ".") + " " + str(config.sauron_name), "Raw frames dir ".ljust(20, ".") + " " + config.raw_frames_root, "Output dir ".ljust(20, ".") + " " + config.output_dir_root, "Trash dir ".ljust(20, ".") + " " + config.trash_dir(), "Temp dir ".ljust(20, ".") + " " + config.temp_dir(), "Incubation dir ".ljust(20, ".") + " " + config.get_incubation_dir(), "Prototyping dir ".ljust(20, ".") + " " + config.get_prototyping_dir(), "Plate types ".ljust(20, ".") + " " + "; ".join(config.list_plate_types()), ) if extended: self._bannered( Style.BRIGHT + "Environment information...", *[((key + " ").ljust(40, ".") + " " + escape_for_properties(value)) for key, value in config.environment_info.items()], )
import datetime import json import logging from enum import Enum from typing import List, Optional from pocketutils.full import Tools from valarpy.Valar import Valar from pocketutils.core.exceptions import LockedError, RefusingRequestError from pocketutils.misc.fancy_console import ColorMessages from loguru import logger Valar().open() from valarpy.model import * from sauronx import datetime_started_raw from .configuration import config from .locks import ProcessingList, ProcessingSubmission, SauronxLock class InterceptHandler(logging.Handler): """ Redirects standard logging to loguru. """ def emit(self, record): # Get corresponding Loguru level if it exists try: level = logger.level(record.levelname).name except ValueError: