Source code for ophyd_async.epics.testing._utils

import random
import string
import subprocess
import sys
import time
from pathlib import Path


[docs] def generate_random_pv_prefix() -> str: """For generating random PV names in test devices.""" return "".join(random.choice(string.ascii_lowercase) for _ in range(12)) + ":"
[docs] class TestingIOC: """For initialising an IOC in tests.""" def __init__(self): self._db_macros: list[tuple[Path, dict[str, str]]] = [] self.output = ""
[docs] def add_database(self, db: Path | str, /, **macros: str): self._db_macros.append((Path(db), macros))
[docs] def start(self): ioc_args = [ sys.executable, "-m", "epicscorelibs.ioc", ] for db, macros in self._db_macros: macro_str = ",".join(f"{k}={v}" for k, v in macros.items()) ioc_args += ["-m", macro_str, "-d", str(db)] self._process = subprocess.Popen( ioc_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, ) assert self._process.stdout # noqa: S101 # this is to make Pylance happy start_time = time.monotonic() while "iocRun: All initialization complete" not in self.output: if time.monotonic() - start_time > 10: self.stop() raise TimeoutError(f"IOC did not start in time:\n{self.output}") self.output += self._process.stdout.readline()
[docs] def stop(self): try: self.output += self._process.communicate("exit()")[0] except ValueError: # Someone else already called communicate pass