Source code for ophyd_async.epics.testing._launch
"""Launch this repo's EPICS IOC subprocesses.
Kept separate from the `_ioc.py` files (`ophyd_async.epics.testing`'s and
`ophyd_async.epics.demo`'s) deliberately: those are genuinely standalone
(zero `ophyd_async` imports - can be copied into or run from a bare
EPICS-only venv), and importing `ophyd_async.testing` here would break that
if this lived in the same file.
`start_ioc` mirrors `ophyd_async.tango.testing.start_tango_device_servers`'s
shape exactly - generic, doesn't know or care which IOC topology it's
launching.
"""
import random
import string
import sys
from pathlib import Path
from ophyd_async.testing import ManagedSubprocess, start_subprocess
_READY_MARKER = "iocRun: All initialization complete"
_STOP_INPUT = "exit()"
[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]
def start_ioc(script: Path, *args: str) -> ManagedSubprocess:
"""Start an EPICS IOC subprocess by running `script` with `args`.
Mirrors `ophyd_async.tango.testing.start_tango_device_servers`'s shape and
subprocess handling: rather than building the IOC's full argv inline,
this always launches a real, independently-runnable file - the exact
command a human would type by hand, so there's no separate "does this
even work standalone" code path to keep correct.
:param script: The script implementing the IOC topology to host, e.g.
`ophyd_async.epics.demo.IOC` or `ophyd_async.epics.testing.IOC`.
:param args: Positional args for that script's `__main__`, e.g. `prefix`
or `prefix, str(num_channels)` - whatever it expects. Overriding
which executable actually hosts the IOC (defaulting to the bundled
`epicscorelibs.ioc`) is a command-line-only concern of that script
itself - pass `--softioc ...` as one of `args` if you need that (see
the script's own `--help`); this function doesn't thread it through.
"""
subprocess_args = [sys.executable, str(script), *args]
return start_subprocess(subprocess_args, _READY_MARKER, stop_input=_STOP_INPUT)