[docs]deflist_scripts(self):"""Returns a list of script names."""return[ff.name.replace(ff.suffix,"")forffinself.path.glob("*.inp")]
[docs]defget_steps(self,name:str)->list[tuple[str,str,float|None]]:"""Returns the list of steps of the script."""ifnamenotinself.list_scripts():raiseValueError(f"Cannot find script {name}.")lines=(self.path/(name+".inp")).read_text().splitlines()steps=[]forlineinlines:ifline.strip().startswith("#"):continueparts=line.strip().split()try:timeout=float(parts[0])actor=parts[1]command_string=" ".join(parts[2:])exceptValueError:actor=parts[0]command_string=" ".join(parts[1:])timeout=Nonesteps.append((actor,command_string,timeout))returnsteps
[docs]asyncdefrun(self,name:str,command:Command[HALActor]|None=None)->bool:"""Runs a script. This coroutine creates a task with all the steps to execute and adds it to the ``running`` dictionary. The execution can be cancelled by calling `.stop`, at which point the task will be cancelled and `.run` will handle the cancellation. """asyncdefrun_steps(steps):forn,stepinenumerate(steps):actor,command_string,timeout=stepifcommand:step_message=f"{actor}{command_string}"iftimeout:step_message=f"{timeout}{step_message}"command.warning(text=f"Script {name}: {step_message}")runner=self.actorifcommandisNoneelsecommandifcommand:command.debug(script_step=[name,f"{actor}{command_string}",n+1,len(steps),])ifactor=="sleep":awaitasyncio.sleep(float(command_string))else:awaitasyncio.wait_for(runner.send_command(actor,command_string),timeout,)ifnameinself.running:raiseRuntimeError(f"Script {name} is already running.")steps=self.get_steps(name)task=asyncio.create_task(run_steps(steps))self.running[name]=taskself._emit_running()# Now actually await the task, but be sure to handle cancellation.# If there is another kind of error (e.g. a timeout), raise it.try:awaittaskexceptasyncio.CancelledError:returnFalseexceptasyncio.TimeoutError:ifcommand:command.error(error=f"Script {name}: one of the steps timedout out.")returnFalseexceptException:raisefinally:self.running.pop(name)self._emit_running()returnTrue
[docs]asyncdefcancel(self,name:str):"""Cancels a running script."""ifnamenotinself.running:raiseRuntimeError(f"Script {name} is not running.")task=self.running[name]task.cancel()
def_emit_running(self,command:HALCommandType|None=None):"""Emits the ``running_scripts`` keyword."""running_scripts=list(self.running.keys())ifcommand:command.info(running_scripts=running_scripts)else:self.actor.write("i",running_scripts=running_scripts)