diff --git a/src/ophyd_async/core/_signal_backend.py b/src/ophyd_async/core/_signal_backend.py index e1bef64d77..7d0a35a895 100644 --- a/src/ophyd_async/core/_signal_backend.py +++ b/src/ophyd_async/core/_signal_backend.py @@ -13,7 +13,10 @@ # To be a 1D array shape should really be tuple[int], but np.array() # currently produces tuple[int, ...] even when it has 1D input args # https://github.com/numpy/numpy/issues/28077#issuecomment-2566485178 + Array1D = np.ndarray[tuple[int, ...], np.dtype[DTypeScalar_co]] +"""A type alias for a 1D numpy array with a specific scalar data type.""" + Primitive = bool | int | float | str SignalDatatype = ( Primitive diff --git a/src/ophyd_async/epics/adandor/_andor_controller.py b/src/ophyd_async/epics/adandor/_andor_controller.py index b0b5756fe1..d1d60a2bf2 100644 --- a/src/ophyd_async/epics/adandor/_andor_controller.py +++ b/src/ophyd_async/epics/adandor/_andor_controller.py @@ -13,6 +13,8 @@ class Andor2Controller(adcore.ADBaseController[Andor2DriverIO]): + """For controlling the Andor 2 detector.""" + def __init__( self, driver: Andor2DriverIO, diff --git a/src/ophyd_async/epics/adkinetix/_kinetix_controller.py b/src/ophyd_async/epics/adkinetix/_kinetix_controller.py index 91ade01dc2..9f86690bd1 100644 --- a/src/ophyd_async/epics/adkinetix/_kinetix_controller.py +++ b/src/ophyd_async/epics/adkinetix/_kinetix_controller.py @@ -17,6 +17,8 @@ class KinetixController(adcore.ADBaseController[KinetixDriverIO]): + """Controller for adkinetix detector.""" + def __init__( self, driver: KinetixDriverIO, diff --git a/src/ophyd_async/epics/adkinetix/_kinetix_io.py b/src/ophyd_async/epics/adkinetix/_kinetix_io.py index 78556e5631..3eb0d3bb20 100644 --- a/src/ophyd_async/epics/adkinetix/_kinetix_io.py +++ b/src/ophyd_async/epics/adkinetix/_kinetix_io.py @@ -4,6 +4,8 @@ class KinetixTriggerMode(StrictEnum): + """Trigger mode for ADKinetix detector.""" + INTERNAL = "Internal" EDGE = "Rising Edge" GATE = "Exp. Gate" diff --git a/src/ophyd_async/epics/adpilatus/_pilatus_controller.py b/src/ophyd_async/epics/adpilatus/_pilatus_controller.py index 87bda8fd63..a30397de8a 100644 --- a/src/ophyd_async/epics/adpilatus/_pilatus_controller.py +++ b/src/ophyd_async/epics/adpilatus/_pilatus_controller.py @@ -31,6 +31,8 @@ class PilatusReadoutTime(float, Enum): class PilatusController(adcore.ADBaseController[PilatusDriverIO]): + """Controller for ADPilatus detector.""" + _supported_trigger_types = { DetectorTrigger.INTERNAL: PilatusTriggerMode.INTERNAL, DetectorTrigger.CONSTANT_GATE: PilatusTriggerMode.EXT_ENABLE, diff --git a/src/ophyd_async/epics/adpilatus/_pilatus_io.py b/src/ophyd_async/epics/adpilatus/_pilatus_io.py index a04791163d..720721108d 100644 --- a/src/ophyd_async/epics/adpilatus/_pilatus_io.py +++ b/src/ophyd_async/epics/adpilatus/_pilatus_io.py @@ -4,6 +4,8 @@ class PilatusTriggerMode(StrictEnum): + """Trigger modes for ADPilatus detector.""" + INTERNAL = "Internal" EXT_ENABLE = "Ext. Enable" EXT_TRIGGER = "Ext. Trigger" diff --git a/src/ophyd_async/epics/adsimdetector/_sim.py b/src/ophyd_async/epics/adsimdetector/_sim.py index b4b354da5c..3d2b8f338e 100644 --- a/src/ophyd_async/epics/adsimdetector/_sim.py +++ b/src/ophyd_async/epics/adsimdetector/_sim.py @@ -4,10 +4,15 @@ from ophyd_async.epics import adcore -class SimDriverIO(adcore.ADBaseIO): ... +class SimDriverIO(adcore.ADBaseIO): + """Base class for driving simulated Areadetector IO.""" + + pass class SimController(adcore.ADBaseController[SimDriverIO]): + """Controller for simulated Areadetector.""" + def __init__( self, driver: SimDriverIO, @@ -20,6 +25,8 @@ def get_deadtime(self, exposure: float | None) -> float: class SimDetector(adcore.AreaDetector[SimController]): + """Detector for simulated Areadetector.""" + def __init__( self, prefix: str, diff --git a/src/ophyd_async/epics/advimba/_vimba_controller.py b/src/ophyd_async/epics/advimba/_vimba_controller.py index 065b633aa8..85ffaf6ad8 100644 --- a/src/ophyd_async/epics/advimba/_vimba_controller.py +++ b/src/ophyd_async/epics/advimba/_vimba_controller.py @@ -24,6 +24,8 @@ class VimbaController(adcore.ADBaseController[VimbaDriverIO]): + """Controller for the Vimba detector.""" + def __init__( self, driver: VimbaDriverIO, diff --git a/src/ophyd_async/epics/advimba/_vimba_io.py b/src/ophyd_async/epics/advimba/_vimba_io.py index 3f0293ffac..3c223becf6 100644 --- a/src/ophyd_async/epics/advimba/_vimba_io.py +++ b/src/ophyd_async/epics/advimba/_vimba_io.py @@ -20,6 +20,8 @@ class VimbaConvertFormat(StrictEnum): class VimbaTriggerSource(StrictEnum): + """Mode for the source of triggers on the Vimbda.""" + FREERUN = "Freerun" LINE1 = "Line1" LINE2 = "Line2" @@ -35,11 +37,15 @@ class VimbaOverlap(StrictEnum): class VimbaOnOff(StrictEnum): + """On/Off modes on the Vimba detector.""" + ON = "On" OFF = "Off" class VimbaExposeOutMode(StrictEnum): + """Modes for exposure on the Vimba detector.""" + TIMED = "Timed" # Use ExposureTime PV TRIGGER_WIDTH = "TriggerWidth" # Expose for length of high signal diff --git a/src/ophyd_async/epics/core/_aioca.py b/src/ophyd_async/epics/core/_aioca.py index d064fa1ad6..f0e165220e 100644 --- a/src/ophyd_async/epics/core/_aioca.py +++ b/src/ophyd_async/epics/core/_aioca.py @@ -240,6 +240,8 @@ def _use_pyepics_context_if_imported(): class CaSignalBackend(EpicsSignalBackend[SignalDatatypeT]): + """Backend for a signal to interact with PVs over channel access.""" + def __init__( self, datatype: type[SignalDatatypeT] | None, diff --git a/src/ophyd_async/epics/core/_epics_connector.py b/src/ophyd_async/epics/core/_epics_connector.py index 8649469626..f701405e1a 100644 --- a/src/ophyd_async/epics/core/_epics_connector.py +++ b/src/ophyd_async/epics/core/_epics_connector.py @@ -38,6 +38,8 @@ def fill_backend_with_prefix( class EpicsDeviceConnector(DeviceConnector): + """Used for connecting signals to static EPICS pvs.""" + def __init__(self, prefix: str) -> None: self.prefix = prefix diff --git a/src/ophyd_async/epics/core/_p4p.py b/src/ophyd_async/epics/core/_p4p.py index 816beda335..0e2673981c 100644 --- a/src/ophyd_async/epics/core/_p4p.py +++ b/src/ophyd_async/epics/core/_p4p.py @@ -335,6 +335,8 @@ def _pva_request_string(fields: Sequence[str]) -> str: class PvaSignalBackend(EpicsSignalBackend[SignalDatatypeT]): + """Backend for a signal to interact with PVs over pva.""" + def __init__( self, datatype: type[SignalDatatypeT] | None, diff --git a/src/ophyd_async/epics/core/_pvi_connector.py b/src/ophyd_async/epics/core/_pvi_connector.py index 712b58d2e9..685a5fd1a7 100644 --- a/src/ophyd_async/epics/core/_pvi_connector.py +++ b/src/ophyd_async/epics/core/_pvi_connector.py @@ -32,6 +32,11 @@ def _get_signal_details(entry: Entry) -> tuple[type[Signal], str, str]: class PviDeviceConnector(DeviceConnector): + """ + Used for connecting to PVI devices, where signals are be dynamically + defined at introspection. + """ + def __init__(self, prefix: str = "", error_hint: str = "") -> None: # TODO: what happens if we get a leading "pva://" here? self.prefix = prefix diff --git a/src/ophyd_async/epics/eiger/_eiger_controller.py b/src/ophyd_async/epics/eiger/_eiger_controller.py index 2b5049eac2..7f4a1608c7 100644 --- a/src/ophyd_async/epics/eiger/_eiger_controller.py +++ b/src/ophyd_async/epics/eiger/_eiger_controller.py @@ -19,6 +19,8 @@ class EigerController(DetectorController): + """Controller for the Eiger detector.""" + def __init__( self, driver: EigerDriverIO, diff --git a/src/ophyd_async/epics/eiger/_eiger_io.py b/src/ophyd_async/epics/eiger/_eiger_io.py index 484843ed30..c01ad2914e 100644 --- a/src/ophyd_async/epics/eiger/_eiger_io.py +++ b/src/ophyd_async/epics/eiger/_eiger_io.py @@ -9,6 +9,8 @@ class EigerTriggerMode(StrictEnum): class EigerDriverIO(Device): + """Contains signals for handling IO on the Eiger detector.""" + def __init__(self, prefix: str, name: str = "") -> None: self.bit_depth = epics_signal_r(int, f"{prefix}BitDepthReadout") self.stale_parameters = epics_signal_r(bool, f"{prefix}StaleParameters") diff --git a/src/ophyd_async/epics/motor.py b/src/ophyd_async/epics/motor.py index da27df8e08..412c9ff538 100644 --- a/src/ophyd_async/epics/motor.py +++ b/src/ophyd_async/epics/motor.py @@ -24,10 +24,14 @@ class MotorLimitsException(Exception): + """Exception for invalid motor limits.""" + pass class InvalidFlyMotorException(Exception): + """Exception for invalid motor.""" + pass diff --git a/src/ophyd_async/epics/testing/_example_ioc.py b/src/ophyd_async/epics/testing/_example_ioc.py index 5ae8880881..383c311fb7 100644 --- a/src/ophyd_async/epics/testing/_example_ioc.py +++ b/src/ophyd_async/epics/testing/_example_ioc.py @@ -15,12 +15,16 @@ class EpicsTestEnum(StrictEnum): + """For testing strict enum values in test IOCs.""" + A = "Aaa" B = "Bbb" C = "Ccc" class EpicsTestSubsetEnum(SubsetEnum): + """For testing subset enum values in test IOCs.""" + A = "Aaa" B = "Bbb" @@ -34,6 +38,8 @@ class EpicsTestTable(Table): class EpicsTestCaDevice(EpicsDevice): + """Device for use in a channel access test IOC.""" + my_int: A[SignalRW[int], PvSuffix("int")] my_float: A[SignalRW[float], PvSuffix("float")] float_prec_0: A[SignalRW[int], PvSuffix("float_prec_0")] @@ -57,6 +63,8 @@ class EpicsTestCaDevice(EpicsDevice): class EpicsTestPvaDevice(EpicsTestCaDevice): + """Device for use in a pv access test IOC.""" + # pva can support all signal types that ca can int8a: A[SignalRW[Array1D[np.int8]], PvSuffix("int8a")] uint16a: A[SignalRW[Array1D[np.uint16]], PvSuffix("uint16a")] @@ -68,6 +76,8 @@ class EpicsTestPvaDevice(EpicsTestCaDevice): class EpicsTestIocAndDevices: + """Test IOC with ca and pva devices.""" + def __init__(self): self.prefix = generate_random_pv_prefix() self.ioc = TestingIOC() diff --git a/src/ophyd_async/epics/testing/_utils.py b/src/ophyd_async/epics/testing/_utils.py index f66fa016c0..50c69a88ff 100644 --- a/src/ophyd_async/epics/testing/_utils.py +++ b/src/ophyd_async/epics/testing/_utils.py @@ -7,10 +7,13 @@ 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)) + ":" class TestingIOC: + """For initialising an IOC in tests.""" + def __init__(self): self._db_macros: list[tuple[Path, dict[str, str]]] = [] self.output = "" diff --git a/src/ophyd_async/fastcs/core.py b/src/ophyd_async/fastcs/core.py index 07e6581164..5021c0dd09 100644 --- a/src/ophyd_async/fastcs/core.py +++ b/src/ophyd_async/fastcs/core.py @@ -3,6 +3,7 @@ def fastcs_connector(device: Device, uri: str, error_hint: str = "") -> DeviceConnector: + """Used to create devices and connections on pvi device `Device`.""" # TODO: add Tango support based on uri scheme connector = PviDeviceConnector(uri, error_hint) connector.create_children_from_annotations(device) diff --git a/src/ophyd_async/fastcs/panda/_block.py b/src/ophyd_async/fastcs/panda/_block.py index 45943a491f..6044a1fcb2 100644 --- a/src/ophyd_async/fastcs/panda/_block.py +++ b/src/ophyd_async/fastcs/panda/_block.py @@ -11,12 +11,16 @@ class CaptureMode(StrictEnum): + """Capture mode for the `DataBlock` on the PandA.""" + FIRST_N = "FIRST_N" LAST_N = "LAST_N" FOREVER = "FOREVER" class DataBlock(Device): + """Data block for the PandA. Used for writing data through the IOC.""" + # In future we may decide to make hdf_* optional hdf_directory: SignalRW[str] hdf_file_name: SignalRW[str] @@ -31,22 +35,30 @@ class DataBlock(Device): class PulseBlock(Device): + """Used for configuring pulses in the PandA.""" + delay: SignalRW[float] width: SignalRW[float] class PcompDirection(StrictEnum): + """Direction options for position compare in the PandA.""" + POSITIVE = "Positive" NEGATIVE = "Negative" EITHER = "Either" class BitMux(SubsetEnum): + """Bit input with configurable delay in the PandA.""" + ZERO = "ZERO" ONE = "ONE" class PcompBlock(Device): + """Position compare block in the PandA.""" + active: SignalR[bool] dir: SignalRW[PcompDirection] enable: SignalRW[BitMux] @@ -57,6 +69,8 @@ class PcompBlock(Device): class TimeUnits(StrictEnum): + """Options for units of time in the PandA.""" + MIN = "min" S = "s" MS = "ms" @@ -64,6 +78,8 @@ class TimeUnits(StrictEnum): class SeqBlock(Device): + """Sequencer block in the PandA.""" + table: SignalRW[SeqTable] active: SignalR[bool] repeats: SignalRW[int] @@ -73,11 +89,15 @@ class SeqBlock(Device): class PcapBlock(Device): + """Position capture block in the PandA.""" + active: SignalR[bool] arm: SignalRW[bool] class CommonPandaBlocks(Device): + """Pandablocks device with blocks which are common and required on introspection.""" + pulse: DeviceVector[PulseBlock] seq: DeviceVector[SeqBlock] pcomp: DeviceVector[PcompBlock] diff --git a/src/ophyd_async/fastcs/panda/_control.py b/src/ophyd_async/fastcs/panda/_control.py index be79c41e71..1c60353c4c 100644 --- a/src/ophyd_async/fastcs/panda/_control.py +++ b/src/ophyd_async/fastcs/panda/_control.py @@ -10,6 +10,8 @@ class PandaPcapController(DetectorController): + """For controlling a PCAP capture on the PandA.""" + def __init__(self, pcap: PcapBlock) -> None: self.pcap = pcap self._arm_status: AsyncStatus | None = None diff --git a/src/ophyd_async/fastcs/panda/_hdf_panda.py b/src/ophyd_async/fastcs/panda/_hdf_panda.py index 29e8cd0e5b..8c1bce1b65 100644 --- a/src/ophyd_async/fastcs/panda/_hdf_panda.py +++ b/src/ophyd_async/fastcs/panda/_hdf_panda.py @@ -15,6 +15,8 @@ class HDFPanda( CommonPandaBlocks, StandardDetector[PandaPcapController, PandaHDFWriter] ): + """PandA with common blocks for standard HDF writing.""" + def __init__( self, prefix: str, diff --git a/src/ophyd_async/fastcs/panda/_table.py b/src/ophyd_async/fastcs/panda/_table.py index 78b445409f..6087c8a413 100644 --- a/src/ophyd_async/fastcs/panda/_table.py +++ b/src/ophyd_async/fastcs/panda/_table.py @@ -7,6 +7,8 @@ class PandaHdf5DatasetType(StrictEnum): + """Dataset options for HDF capture.""" + FLOAT_64 = "float64" UINT_32 = "uint32" @@ -17,6 +19,8 @@ class DatasetTable(Table): class SeqTrigger(StrictEnum): + """Trigger options for the SeqTable.""" + IMMEDIATE = "Immediate" BITA_0 = "BITA=0" BITA_1 = "BITA=1" @@ -33,6 +37,8 @@ class SeqTrigger(StrictEnum): class SeqTable(Table): + """Data type for the panda seq table.""" + repeats: Array1D[np.uint16] trigger: Sequence[SeqTrigger] position: Array1D[np.int32] diff --git a/src/ophyd_async/fastcs/panda/_trigger.py b/src/ophyd_async/fastcs/panda/_trigger.py index 05702a0b14..a3af08c315 100644 --- a/src/ophyd_async/fastcs/panda/_trigger.py +++ b/src/ophyd_async/fastcs/panda/_trigger.py @@ -15,6 +15,8 @@ class SeqTableInfo(BaseModel): class StaticSeqTableTriggerLogic(FlyerController[SeqTableInfo]): + """For controlling the PandA `SeqTable` when flyscanning.""" + def __init__(self, seq: SeqBlock) -> None: self.seq = seq @@ -64,6 +66,8 @@ class PcompInfo(BaseModel): class StaticPcompTriggerLogic(FlyerController[PcompInfo]): + """For controlling the PandA `PcompBlock` when flyscanning.""" + def __init__(self, pcomp: PcompBlock) -> None: self.pcomp = pcomp diff --git a/src/ophyd_async/fastcs/panda/_writer.py b/src/ophyd_async/fastcs/panda/_writer.py index e10613ec55..3ff758d848 100644 --- a/src/ophyd_async/fastcs/panda/_writer.py +++ b/src/ophyd_async/fastcs/panda/_writer.py @@ -21,6 +21,8 @@ class PandaHDFWriter(DetectorWriter): + """For writing for PandA data from the `DataBlock`.""" + _ctxt: Context | None = None def __init__( diff --git a/src/ophyd_async/sim/_motor.py b/src/ophyd_async/sim/_motor.py index 1c07b2b613..ebcd149945 100644 --- a/src/ophyd_async/sim/_motor.py +++ b/src/ophyd_async/sim/_motor.py @@ -68,6 +68,7 @@ async def set(self, value: float): """ Asynchronously move the motor to a new position. """ + start = time.time() new_position = value # Make sure any existing move tasks are stopped await self.stop() @@ -96,6 +97,7 @@ async def set(self, value: float): name=self.name, unit=units, ) + print("Move took", time.time() - start) if not self._set_success: raise RuntimeError("Motor was stopped") diff --git a/src/ophyd_async/sim/_point_detector.py b/src/ophyd_async/sim/_point_detector.py index 68c5bca3c8..0e37e52a27 100644 --- a/src/ophyd_async/sim/_point_detector.py +++ b/src/ophyd_async/sim/_point_detector.py @@ -78,6 +78,8 @@ async def _update_values(self, acquire_time: float): @AsyncStatus.wrap async def trigger(self): + start = time.time() for setter in self._value_signals.values(): setter(0) await self._update_values(await self.acquire_time.get_value()) + print("Trigger took", time.time() - start)