ophyd_async.tango.testing#

Package Contents#

Classes#

ExampleStrEnum

All members should exist in the Backend, and there will be no extras.

TangoTestDevice

Declarative ophyd-async Device pairing 1:1 with OneOfEverythingTangoDevice.

Functions#

generate_random_trl_prefix

Generate a random Tango domain/family prefix for use in test devices.

start_tango_device_servers

Start a Tango device servers subprocess by running script with args.

trl

Build the TRL a device server subprocess serves device_name at.

Data#

API#

ophyd_async.tango.testing.DEVICE_SERVERS#

None

class ophyd_async.tango.testing.ExampleStrEnum[source]#

Bases: ophyd_async.core.StrictEnum

All members should exist in the Backend, and there will be no extras.

A#

‘AAA’

B#

‘BBB’

C#

‘CCC’

class ophyd_async.tango.testing.TangoTestDevice(trl: str = '', name: str = '')[source]#

Bases: ophyd_async.tango.core.TangoDevice, ophyd_async.core.StandardReadable

Declarative ophyd-async Device pairing 1:1 with OneOfEverythingTangoDevice.

Constructed with auto_fill_signals=False, so only these Annotated fields are created — a purely declarative Device, unlike TangoDevice(trl) used on its own (the default auto_fill_signals=True procedural/dynamic flavour, which discovers every attribute/command on the live proxy with no annotations at all). Both flavours connect to the exact same running OneOfEverythingTangoDevice server instance and see identical values — see tests/system_tests/tango/core/test_tango_declarative_device.py.

Field names must equal the server’s real Tango attribute/command names (Tango has no PvSuffix-equivalent indirection). A curated subset, not every datatype OneOfEverythingTangoDevice serves (that full matrix is OneOfEverythingTangoDevice itself plus the fully-dynamic TangoDevice(trl) procedural flavour) — enough to demonstrate: scalar RW (a_str, a_bool), a StrictEnum field (strenum), a DevState-backed enum (my_state), a numeric scalar with change-detect polling params (float64), a spectrum/array field (int32_spectrum), an image field (float64_image), a zero-arg TriggerableCommand (void_cmd), and a typed Command[P, T] with mismatched in/out types (float_to_bool_cmd).

int32_spectrum is typed np.int_ (platform-native width, not np.int32) to match what get_python_type (ophyd_async.tango.core) actually reports for Tango SPECTRUM attributes - it maps every signed integer Tango type to plain int regardless of width (unlike its own command return-type mapping, which is width-specific), so a width-specific annotation here would fail the connector’s datatype check even though nothing is wrong. np.int_/np.float64 are used rather than bare int/float only because Array1D/np.dtype need an np.generic subclass, not because the precision matters - np.dtype(np.int_) == np.dtype(int) and np.dtype(np.float64) == np.dtype(float) are both True.

TangoPolling is given on every field even though OneOfEverythingTangoDevice itself pushes Tango change events for all its attributes, because TangoDevice’s default support_events=False means the connector polls unless told otherwise — this mirrors ophyd_async.tango.demo.DemoMotor’s convention so copied-and-pasted reference code keeps working against servers that don’t push events.

a_str: Annotated[SignalRW[str], TangoPolling(0.1)]#

None

a_bool: Annotated[SignalRW[bool], TangoPolling(0.1)]#

None

strenum: Annotated[SignalRW[ExampleStrEnum], TangoPolling(0.1)]#

None

my_state: Annotated[SignalRW[DevStateEnum], TangoPolling(0.1)]#

None

float64: Annotated[SignalRW[float], TangoPolling(0.1, 0.001, 0.001)]#

None

int32_spectrum: Annotated[SignalRW[Array1D[int_]], TangoPolling(0.1)]#

None

float64_image: Annotated[SignalRW[ndarray[Any, dtype[float64]]], TangoPolling(0.1)]#

None

void_cmd: TriggerableCommand#

None

float_to_bool_cmd: Command[[float], bool]#

None

ophyd_async.tango.testing.generate_random_trl_prefix() str[source]#

Generate a random Tango domain/family prefix for use in test devices.

ophyd_async.tango.testing.start_tango_device_servers(script: Path, *args: str) ManagedSubprocess[source]#

Start a Tango device servers subprocess by running script with args.

Generic: doesn’t know or care which catalog script is - e.g. ophyd_async.tango.testing.DEVICE_SERVERS (this package’s fixed basic/everything catalog) or ophyd_async.tango.demo.DEVICE_SERVERS (motor/channel/detector). Invoked with the current interpreter, not -m ophyd_async..., so the exact same argv works verbatim from a venv that doesn’t have ophyd_async installed at all. If you need a different Tango install/version, run script with that venv’s python directly instead of going through this function - same as any other standalone script.

Parameters:
  • script – The script implementing the device server catalog to host.

  • args – Positional args for that script’s __main__, e.g. (prefix, str(port)) or (prefix, str(port), str(num_channels)) - whatever that particular catalog’s script expects. You choose port yourself, e.g. via ophyd_async.testing.find_free_port, and need to hang onto it to build TRLs afterwards (see trl below).

ophyd_async.tango.testing.trl(prefix: str, port: int, device_name: str) str[source]#

Build the TRL a device server subprocess serves device_name at.