Skip to content

Experimental UniMMCore#

pymmcore_plus.experimental.unicore #

CameraDevice #

STANDARD_PROPERTIES: ClassVar = MappingProxyType({Keyword.ActualInterval_ms: ('actual_interval_ms', float), Keyword.Binning: ('binning', int), Keyword.CameraID: ('camera_id', str), Keyword.CameraName: ('camera_name', str), Keyword.CCDTemperature: ('ccd_temperature', float), Keyword.CCDTemperatureSetPoint: ('ccd_temperature_set_point', float), Keyword.EMGain: ('em_gain', float), Keyword.Exposure: ('exposure', float), Keyword.Gain: ('gain', float), Keyword.Interval_ms: ('interval_ms', float), Keyword.Offset: ('offset', float), 'PixelFormat': ('pixel_format', PixelFormat), Keyword.ReadoutMode: ('readout_mode', str), Keyword.ReadoutTime: ('readout_time', float), Keyword.Metadata_ROI_X: ('roi_x', int), Keyword.Metadata_ROI_Y: ('roi_y', int)}) class-attribute #

dtype() -> DTypeLike abstractmethod #

Return the data type of the image buffer.

get_binning() -> int #

Get the binning factor for the camera.

get_exposure() -> float abstractmethod #

Get the current exposure time in milliseconds.

register_standard_properties() -> None #

Inspect the class for standard properties and register them.

set_exposure(exposure: float) -> None abstractmethod #

Set the exposure time in milliseconds.

shape() -> tuple[int, ...] abstractmethod #

Return the shape of the image buffer.

This is used when querying Width, Height, and number of components. If the camera is grayscale, it should return (width, height). If the camera is color, it should return (width, height, n_channels).

start_sequence(n: int | None, get_buffer: Callable[[Sequence[int], DTypeLike], np.ndarray]) -> Iterator[Mapping] abstractmethod #

Start a sequence acquisition.

This method should be implemented by the camera device adapter and should yield metadata for each acquired image. The implementation should call get_buffer() to get a buffer, fill it with image data, then yield the metadata for that image.

The core will handle threading and synchronization. This function may block.

Parameters:

Name Type Description Default
n int | None

If an integer, this is the number of images to acquire. If None, the camera should acquire images indefinitely until stopped.

required
get_buffer Callable[[Sequence[int], DTypeLike], np.ndarray]

A callable that returns a buffer for the camera to fill with image data. You should call this with the shape of the image and the dtype of the image data. The core will produce a buffer of the requested shape and dtype, and you should fill it (in place) with the image data.

required

Yields:

Type Description
Mapping

Metadata for each acquired image. This should be yielded after the corresponding buffer has been filled with image data.

Device #

ABC for all Devices.

busy() -> bool #

Return True if the device is busy.

core() -> CMMCoreProxy property #

The device may use this to access a restricted subset of the Core API.

description() -> str #

Return a description of the device.

get_label() -> str #

get_property_info(prop_name: str) -> PropertyInfo #

Return the property controller for a property.

get_property_names() -> KeysView[str] #

Return the names of the properties.

get_property_value(prop_name: str) -> Any #

Return the value of a property.

has_property(prop_name: str) -> bool #

Return True if the device has a property with the given name.

initialize() -> None #

Initialize the device.

is_property_read_only(prop_name: str) -> bool #

Return True if the property is read-only.

is_property_sequenceable(prop_name: str) -> bool #

Return True if the property is sequenceable.

load_property_sequence(prop_name: str, sequence: Sequence[Any]) -> None #

Load a sequence into a property.

name() -> str classmethod #

Return the name of the device.

register_property(name: str, *, default_value: TProp | None = None, getter: Callable[[TDev], TProp] | None = None, setter: Callable[[TDev, TProp], None] | None = None, limits: tuple[int | float, int | float] | None = None, sequence_max_length: int = 0, allowed_values: Sequence[TProp] | None = None, is_read_only: bool = False, is_pre_init: bool = False, property_type: PropArg = None, sequence_loader: Callable[[TDev, Sequence[TProp]], None] | None = None, sequence_starter: Callable[[TDev], None] | None = None, sequence_stopper: Callable[[TDev], None] | None = None) -> None #

Manually register a property.

This is an alternative to using the @pymm_property decorator. It can be used to register properties that are not defined in the class body. This is useful for pure "user-side" properties that are not used by the adapter, but which the adapter may want to access (such as a preference or a configuration setting that doesn't affect the device's behavior, but which the adapter may want to read).

Properties defined this way are not accessible as class attributes.

set_property_allowed_values(prop_name: str, allowed_values: Sequence[Any]) -> None #

Set the allowed values of a property.

set_property_limits(prop_name: str, limits: tuple[float, float] | None) -> None #

Set the limits of a property.

set_property_sequence_max_length(prop_name: str, max_length: int) -> None #

Set the sequence max length of a property.

set_property_value(prop_name: str, value: Any) -> None #

Set the value of a property.

shutdown() -> None #

Shutdown the device.

start_property_sequence(prop_name: str) -> None #

Start a sequence of a property.

stop_property_sequence(prop_name: str) -> None #

Stop a sequence of a property.

type() -> DeviceType classmethod #

Return the type of the device.

GenericDevice #

Generic device API, e.g. for devices that don't fit into other categories.

Generic Devices generally only use the device property interface.

PropertyInfo dataclass #

State of a property of a device.

Attributes:

Name Type Description
name str

The name of the property.

default_value TProp, optional

The default value of the property, by default None.

last_value TProp, optional

The last value seen from the device, by default None.

limits tuple[int | float, int | float], optional

The minimum and maximum values of the property, by default None.

sequence_max_length int

The maximum length of a sequence of property values.

description str, optional

A description of the property, by default None.

type PropertyType

The type of the property.

allowed_values Sequence[TProp], optional

The allowed values of the property, by default None.

is_read_only bool

Whether the property is read-only.

is_pre_init bool

Whether the property must be set before initialization.

allowed_values: Sequence[TProp] | None = None class-attribute #

default_value: TProp | None = None class-attribute #

description: str | None = None class-attribute #

is_pre_init: bool = False class-attribute #

is_read_only: bool | None = None class-attribute #

last_value: TProp | None = None class-attribute #

limits: tuple[int | float, int | float] | None = None class-attribute #

name: str class-attribute #

sequence_max_length: int = 0 class-attribute #

type: PropertyType = PropertyType.Undef class-attribute #

is_sequenceable() -> bool property #

Return True if the property is sequenceable.

number_of_allowed_values() -> int property #

Return the number of allowed values.

SLMDevice #

ABC for Spatial Light Modulator (SLM) devices.

SLM devices are capable of displaying images. They are expected to represent a rectangular grid of pixels that can be either 8-bit or 32-bit. Illumination (light source on or off) is logically independent of displaying the image.

display_image() -> None abstractmethod #

Command the SLM to display the loaded image.

dtype() -> DTypeLike abstractmethod #

Return the data type of the image buffer.

get_exposure() -> float abstractmethod #

Find out the exposure interval of an SLM.

get_image() -> np.ndarray #

Get the current image from the SLM device adapter.

This is useful for verifying that the image was set correctly.

get_sequence_max_length() -> int #

Return the maximum length of an image sequence that can be uploaded.

send_sequence(sequence: Sequence[np.ndarray]) -> None #

Load a sequence of images to the SLM.

set_exposure(interval_ms: float) -> None abstractmethod #

Command the SLM to turn off after a specified interval.

set_image(pixels: np.ndarray) -> None abstractmethod #

Load the image into the SLM device adapter.

shape() -> tuple[int, ...] abstractmethod #

Return the shape of the SLM image buffer.

This is used when querying Width, Height, and number of components. If the SLM is grayscale, it should return (width, height). If the SLM is color, it should return (width, height, n_channels).

start_sequence() -> None #

Start a sequence of images on the SLM.

stop_sequence() -> None #

Stop a sequence of images on the SLM.

ShutterDevice #

Shutter device API, e.g. for physical shutters or electronic shutter control.

Or any 2-state device that can be either open or closed.

get_open() -> bool abstractmethod #

Return True if the shutter is open, False if it is closed.

set_open(open: bool) -> None abstractmethod #

Set the shutter to open or closed.

Parameters:

Name Type Description Default
open bool

True to open the shutter, False to close it.

required

StageDevice #

ABC for Stage devices.

get_position_um() -> float abstractmethod #

Returns the current position of the stage in microns.

set_position_um(val: float) -> None abstractmethod #

Set the position of the stage in microns.

StateDevice #

State device API, e.g. filter wheel, objective turret, etc.

A state device is a device that at any point in time is in a single state out of a list of possible states, like a filter wheel, an objective turret, etc. The interface contains functions to get and set the state, to give states human readable labels, and functions to make it possible to treat the state device as a shutter.

In terms of implementation, this base class provides the basic functionality by presenting state and label as properties, which it keeps in sync with the underlying device.

Parameters:

Name Type Description Default
state_labels Mapping[int, str] | Iterable[tuple[int, str]]

A mapping (or iterable of 2-tuples) of integer state indices to string labels.

required

assign_label_to_position(pos: int, label: str) -> None #

Assign a User-defined label to a position.

from_count(count: int) -> Self classmethod #

Simplified constructor with just a number of states.

get_position_for_label(label: str) -> int #

Return the position corresponding to the provided label.

get_state() -> int abstractmethod #

Get the current state of the device (integer index).

register_standard_properties() -> None #

Inspect the class for standard properties and register them.

set_position_or_label(pos_or_label: int | str) -> None #

Set the position of the device by index or label.

set_state(position: int) -> None abstractmethod #

Set the state of the device (integer index).

UniMMCore #

Unified Core object that first checks for python, then C++ devices.

load_py_device = loadPyDevice class-attribute #

clearCircularBuffer() -> None #

Clear all images from the circular buffer.

clearROI() -> None #

Clear the current region of interest (ROI) for the camera.

defineStateLabel(stateDeviceLabel: DeviceLabel | str, state: int, label: str) -> None #

Define a label for the specific state.

deviceBusy(label: DeviceLabel | str) -> bool #

deviceTypeBusy(devType: int) -> bool #

displaySLMImage(slmLabel: DeviceLabel | str | None = None) -> None #

Command the SLM to display the loaded image.

getAllowedPropertyValues(label: DeviceLabel | str, propName: PropertyName | str) -> tuple[str, ...] #

getBufferFreeCapacity() -> int #

Get the number of free slots in the circular buffer.

getBufferTotalCapacity() -> int #

Get the total capacity of the circular buffer.

getBytesPerPixel() -> int #

getCameraChannelName(channelNr: int) -> str #

Get the name of the camera channel.

getCameraDevice() -> DeviceLabel | Literal[''] #

Returns the label of the currently selected camera device.

Returns empty string if no camera device is selected.

getCircularBufferMemoryFootprint() -> int #

Get the circular buffer memory footprint in MB.

getDeviceDelayMs(label: DeviceLabel | str) -> float #

getDeviceDescription(label: DeviceLabel | str) -> str #

getDeviceInitializationState(label: str) -> DeviceInitializationState #

getDeviceLibrary(label: DeviceLabel | str) -> AdapterName #

getDeviceName(label: DeviceLabel | str) -> DeviceName #

getDevicePropertyNames(label: DeviceLabel | str) -> tuple[PropertyName, ...] #

getDeviceType(label: str) -> DeviceType #

getExposure(cameraLabel: DeviceLabel | str | None = None) -> float #

Get the exposure time in milliseconds.

getExposureSequenceMaxLength(cameraLabel: DeviceLabel | str) -> int #

Get the maximum length of the exposure sequence.

getImage(numChannel: int | None = None, *, fix: bool = True) -> np.ndarray #

getImageBitDepth() -> int #

getImageBufferSize() -> int #

getImageHeight() -> int #

getImageWidth() -> int #

getLastImage(*, out: np.ndarray | None = None) -> np.ndarray #

getLastImageMD(*args: Any, out: np.ndarray | None = None) -> np.ndarray #

getLoadedDevices() -> tuple[DeviceLabel, ...] #

getLoadedDevicesOfType(devType: int) -> tuple[DeviceLabel, ...] #

getNBeforeLastImageMD(n: int, md: pymmcore.Metadata, /, *, out: np.ndarray | None = None) -> np.ndarray #

getNumberOfCameraChannels() -> int #

getNumberOfComponents() -> int #

getNumberOfStates(stateDeviceLabel: DeviceLabel | str) -> int #

Return the total number of available positions (states).

getPixelSizeAffine(cached: bool = False) -> AffineTuple #

Get the pixel size affine transformation matrix.

getPixelSizeUm(cached: bool = False) -> float #

Get the pixel size in micrometers.

getProperty(label: DeviceLabel | str, propName: PropertyName | str) -> Any #

getPropertyFromCache(deviceLabel: DeviceLabel | str, propName: PropertyName | str) -> Any #

getPropertyLowerLimit(label: DeviceLabel | str, propName: PropertyName | str) -> float #

getPropertySequenceMaxLength(label: DeviceLabel | str, propName: PropertyName | str) -> int #

getPropertyType(label: str, propName: str) -> PropertyType #

getPropertyUpperLimit(label: DeviceLabel | str, propName: PropertyName | str) -> float #

getROI(label: DeviceLabel | str = '') -> list[int] #

Get the current region of interest (ROI) for the camera.

getRemainingImageCount() -> int #

getSLMBytesPerPixel(slmLabel: DeviceLabel | str | None = None) -> int #

Returns the number of bytes per pixel for the SLM.

getSLMDevice() -> DeviceLabel | Literal[''] #

Returns the label of the currently selected SLM device.

Returns empty string if no SLM device is selected.

getSLMExposure(slmLabel: DeviceLabel | str | None = None) -> float #

Find out the exposure interval of an SLM.

getSLMHeight(slmLabel: DeviceLabel | str | None = None) -> int #

Returns the height of the SLM in pixels.

getSLMImage(slmLabel: DeviceLabel | str | None = None) -> np.ndarray #

Get the current image from the SLM device.

getSLMNumberOfComponents(slmLabel: DeviceLabel | str | None = None) -> int #

Returns the number of color components (channels) in the SLM.

getSLMSequenceMaxLength(slmLabel: DeviceLabel | str) -> int #

Get the maximum length of an image sequence that can be uploaded.

getSLMWidth(slmLabel: DeviceLabel | str | None = None) -> int #

Returns the width of the SLM in pixels.

getShutterDevice() -> DeviceLabel | Literal[''] #

Returns the label of the currently selected Shutter device.

Returns empty string if no Shutter device is selected.

getShutterOpen(shutterLabel: DeviceLabel | str | None = None) -> bool #

getState(stateDeviceLabel: DeviceLabel | str) -> int #

Return the current state (position) on the specific device.

getStateFromLabel(stateDeviceLabel: DeviceLabel | str, stateLabel: str) -> int #

Obtain the state for a given label.

getStateLabel(stateDeviceLabel: DeviceLabel | str) -> StateLabel #

Return the current state as the label (string).

getStateLabels(stateDeviceLabel: DeviceLabel | str) -> tuple[StateLabel, ...] #

Return labels for all states.

getXPosition(xyStageLabel: DeviceLabel | str = '') -> float #

Obtains the current position of the X axis of the XY stage in microns.

getXYPosition(xyStageLabel: DeviceLabel | str = '') -> tuple[float, float] #

Obtains the current position of the XY stage in microns.

getXYStageDevice() -> DeviceLabel | Literal[''] #

Returns the label of the currently selected XYStage device.

Returns empty string if no XYStage device is selected.

getXYStageSequenceMaxLength(xyStageLabel: DeviceLabel | str) -> int #

Gets the maximum length of an XY stage's position sequence.

getYPosition(xyStageLabel: DeviceLabel | str = '') -> float #

Obtains the current position of the Y axis of the XY stage in microns.

hasProperty(label: DeviceLabel | str, propName: PropertyName | str) -> bool #

hasPropertyLimits(label: DeviceLabel | str, propName: PropertyName | str) -> bool #

home(xyOrZStageLabel: DeviceLabel | str) -> None #

Perform a hardware homing operation for an XY or focus/Z stage.

initializeAllDevices() -> None #

initializeCircularBuffer() -> None #

Initialize the circular buffer.

initializeDevice(label: DeviceLabel | str) -> None #

isBufferOverflowed() -> bool #

Check if the circular buffer has overflowed.

isExposureSequenceable(cameraLabel: DeviceLabel | str) -> bool #

Check if the camera supports exposure sequences.

isPropertyPreInit(label: DeviceLabel | str, propName: PropertyName | str) -> bool #

isPropertyReadOnly(label: DeviceLabel | str, propName: PropertyName | str) -> bool #

isPropertySequenceable(label: DeviceLabel | str, propName: PropertyName | str) -> bool #

isSequenceRunning(cameraLabel: DeviceLabel | str | None = None) -> bool #

isXYStageSequenceable(xyStageLabel: DeviceLabel | str) -> bool #

Queries XY stage if it can be used in a sequence.

loadDevice(label: str, moduleName: AdapterName | str, deviceName: DeviceName | str) -> None #

Loads a device from the plugin library, or python module.

In the standard MM case, this will load a device from the plugin library:

core.loadDevice("cam", "DemoCamera", "DCam")

For python devices, this will load a device from a python module:

core.loadDevice("pydev", "package.module", "DeviceClass")

loadExposureSequence(cameraLabel: DeviceLabel | str, exposureSequence_ms: Sequence[float]) -> None #

Transfer a sequence of exposure times to the camera.

loadPropertySequence(label: DeviceLabel | str, propName: PropertyName | str, eventSequence: Sequence[Any]) -> None #

loadPyDevice(label: str, device: Device) -> None #

Load a unicore.Device as a python device.

This API allows you to create python-side Device objects that can be used in tandem with the C++ devices. Whenever a method is called that would normally interact with a C++ device, this class will first check if a python device with the same label exists, and if so, use that instead.

Parameters:

Name Type Description Default
label str

The label to assign to the device.

required
device unicore.Device

The device object to load. Use the appropriate subclass of Device for the type of device you are creating.

required

loadSLMSequence(slmLabel: DeviceLabel | str, imageSequence: Sequence[bytes | np.ndarray]) -> None #

Load a sequence of images to the SLM.

loadXYStageSequence(xyStageLabel: DeviceLabel | str, xSequence: Sequence[float], ySequence: Sequence[float]) -> None #

Transfer a sequence of stage positions to the xy stage.

xSequence and ySequence must have the same length. This should only be called for XY stages that are sequenceable

popNextImage(*, fix: bool = True) -> np.ndarray #

popNextImageMD(*args: Any) -> np.ndarray #

prepareSequenceAcquisition(cameraLabel: DeviceLabel | str) -> None #

Prepare the camera for sequence acquisition.

reset() -> None #

setAdapterOriginXY(*args: Any) -> None #

Enable software translation of coordinates for the current XY stage.

The current position of the stage becomes (newXUm, newYUm). It is recommended that setOriginXY() be used instead where available.

setCameraDevice(cameraLabel: DeviceLabel | str) -> None #

Set the camera device.

setCircularBufferMemoryFootprint(sizeMB: int) -> None #

Set the circular buffer memory footprint in MB.

setDeviceDelayMs(label: DeviceLabel | str, delayMs: float) -> None #

setExposure(*args: Any) -> None #

Set the exposure time in milliseconds.

setOriginX(xyStageLabel: DeviceLabel | str = '') -> None #

Zero the given XY stage's X coordinate at the current position.

setOriginXY(xyStageLabel: DeviceLabel | str = '') -> None #

Zero the given XY stage's coordinates at the current position.

setOriginY(xyStageLabel: DeviceLabel | str = '') -> None #

Zero the given XY stage's Y coordinate at the current position.

setProperty(label: str, propName: str, propValue: bool | float | int | str) -> None #

setRelativeXYPosition(*args: Any) -> None #

Sets the relative position of the XY stage in microns.

setSLMDevice(slmLabel: DeviceLabel | str) -> None #

Set the SLM device.

setSLMExposure(*args: Any) -> None #

Command the SLM to turn off after a specified interval.

setSLMImage(*args: Any) -> None #

Load the image into the SLM device adapter.

setSLMPixelsTo(*args: Any) -> None #

Set all pixels of the SLM to a uniform intensity or RGB values.

setShutterDevice(shutterLabel: DeviceLabel | str) -> None #

setState(stateDeviceLabel: DeviceLabel | str, state: int) -> None #

Set state (position) on the specific device.

setStateLabel(stateDeviceLabel: DeviceLabel | str, stateLabel: str) -> None #

Set device state using the previously assigned label (string).

setXYPosition(*args: Any) -> None #

Sets the position of the XY stage in microns.

setXYStageDevice(xyStageLabel: DeviceLabel | str) -> None #

startExposureSequence(cameraLabel: DeviceLabel | str) -> None #

Start a sequence of exposures.

startPropertySequence(label: DeviceLabel | str, propName: PropertyName | str) -> None #

startSLMSequence(slmLabel: DeviceLabel | str) -> None #

Start a sequence of images on the SLM.

startXYStageSequence(xyStageLabel: DeviceLabel | str) -> None #

Starts an ongoing sequence of triggered events in an XY stage.

This should only be called for stages that are sequenceable

stop(xyOrZStageLabel: DeviceLabel | str) -> None #

Stop the XY or focus/Z stage.

stopExposureSequence(cameraLabel: DeviceLabel | str) -> None #

Stop a sequence of exposures.

stopPropertySequence(label: DeviceLabel | str, propName: PropertyName | str) -> None #

stopSLMSequence(slmLabel: DeviceLabel | str) -> None #

Stop a sequence of images on the SLM.

stopXYStageSequence(xyStageLabel: DeviceLabel | str) -> None #

Stops an ongoing sequence of triggered events in an XY stage.

This should only be called for stages that are sequenceable

systemBusy() -> bool #

unloadAllDevices() -> None #

unloadDevice(label: DeviceLabel | str) -> None #

usesDeviceDelay(label: DeviceLabel | str) -> bool #

waitForDevice(label: DeviceLabel | str) -> None #

waitForDeviceType(devType: int) -> None #

waitForSystem() -> None #

XYStageDevice #

ABC for XYStage devices.

get_position_um() -> tuple[float, float] abstractmethod #

Returns the current position of the XY stage in microns.

set_adapter_origin_um(x: float, y: float) -> None #

Alter the software coordinate translation between micrometers and steps.

... such that the current position becomes the given coordinates.

set_origin() -> None #

Zero the stage's coordinates at the current position.

This is a convenience method that calls set_origin_x and set_origin_y. Can be overridden for more efficient implementations.

set_origin_x() -> None abstractmethod #

Zero the stage's X coordinates at the current position.

set_origin_y() -> None abstractmethod #

Zero the stage's Y coordinates at the current position.

set_position_um(x: float, y: float) -> None abstractmethod #

Set the position of the XY stage in microns.

set_relative_position_um(dx: float, dy: float) -> None #

Move the stage by a relative amount.

Can be overridden for more efficient implementations.

XYStepperStageDevice #

ABC for XYStage devices that support stepper motors.

In this variant, rather than providing set_position_um and get_position_um, you provide set_position_steps, get_position_steps, get_step_size_x_um, and get_step_size_y_um. A default implementation of set_position_um and get_position_um is then provided that uses these methods, taking into account the XY-mirroring properties of the device.

get_position_steps() -> tuple[int, int] abstractmethod #

Returns the current position of the XY stage in steps.

get_position_um() -> tuple[float, float] #

Get the position of the XY stage in microns.

get_step_size_x_um() -> float abstractmethod #

Returns the step size of the X axis in microns.

get_step_size_y_um() -> float abstractmethod #

Returns the step size of the Y axis in microns.

set_adapter_origin_um(x: float = 0.0, y: float = 0.0) -> None #

Alter the software coordinate translation between micrometers and steps.

... such that the current position becomes the given coordinates.

set_origin() -> None #

Zero the stage's coordinates at the current position.

set_origin_x() -> None #

Zero the stage's X coordinates at the current position.

set_origin_y() -> None #

Zero the stage's Y coordinates at the current position.

set_position_steps(x: int, y: int) -> None abstractmethod #

Set the position of the XY stage in steps.

set_position_um(x: float, y: float) -> None #

Set the position of the XY stage in microns.

set_relative_position_steps(dx: int, dy: int) -> None #

Move the stage by a relative amount.

Can be overridden for more efficient implementations.

set_relative_position_um(dx: float, dy: float) -> None #

Default implementation for relative motion.

Can be overridden for more efficient implementations.

pymm_property(fget: Callable[[TDev], TProp] | None = None, *, limits: tuple[TLim, TLim] | None = None, sequence_max_length: int = 0, allowed_values: Sequence[TProp] | None = None, is_read_only: bool | None = None, is_pre_init: bool = False, name: str | None = None, property_type: PropArg = None) -> PropertyController[TDev, TProp] | Callable[[Callable[[TDev], TProp]], PropertyController[TDev, TProp]] #

Decorates a (getter) method to create a device property.

The returned PropertyController instance can be additionally used (similar to @property) to decorate setter, sequence_loader, sequence_starter, and/or sequence_stopper methods.

Properties can have limits, allowed values, but may not have both.

Properties will only be considered "sequenceable" (i.e. they support hardware triggering) if they have a non-zero sequence_max_length AND have decorated sequence_loader and sequence_starter methods.

Parameters:

Name Type Description Default
fget Callable[[TDev], TProp], optional

The getter method for the property, by default None.

None
limits tuple[float, float], optional

The minimum and maximum values of the property, by default None. Cannot be combined with allowed_values.

None
sequence_max_length int, optional

The maximum length of a sequence of property values, by default 0.

0
allowed_values Sequence[TProp], optional

The allowed values of the property, by default None. Cannot be combined with limits.

None
is_read_only bool, optional

Whether the property is read-only, by default False.

None
is_pre_init bool, optional

Whether the property must be set before initialization, by default False.

False
name str, optional

The name of the property, by default, the name of the getter method is used.

None
prop_type PropArg, optional

The type of the property, by default the return annotation of the getter method is used (but must be one of float, int, or str).

required

Examples:

class MyDevice(Device):
    @pymm_property(limits=(0, 100), sequence_max_length=10)
    def position(self) -> float:
        # get position from device
        return 42.0

    @position.setter
    def position(self, value: float) -> None:
        print(f"Setting position to {value}")

    @position.sequence_loader
    def load_position_sequence(self, sequence: Sequence[float]) -> None:
        print(f"Loading position sequence: {sequence}")

    @position.sequence_starter
    def start_position_sequence(self) -> None:
        print("Starting position sequence")

    @pymm_property(is_read_only=True)
    def pressure(self) -> float:
        return 1.0

    @pymm_property(allowed_values=["low", "medium", "high"])
    def speed(self) -> str:
        # get speed from device
        return "medium"

    @speed.setter
    def speed(self, value: str) -> None:
        print(f"Setting speed to {value}")