def test_state_device_widget(qtbot, global_mmcore: CMMCorePlus):
    for label in global_mmcore.getLoadedDevicesOfType(DeviceType.StateDevice):
        wdg: StateDeviceWidget = DeviceWidget.for_device(label)
        qtbot.addWidget(wdg)
        wdg.show()
        assert wdg.deviceLabel() == label
        # assert wdg.deviceName() == "DObjective"
        assert global_mmcore.getStateLabel(label) == wdg._combo.currentText()
        assert global_mmcore.getState(label) == wdg._combo.currentIndex()
        start_state = wdg.state()

        next_state = (wdg.state() + 1) % len(wdg.stateLabels())
        with qtbot.waitSignal(global_mmcore.events.propertyChanged):
            global_mmcore.setState(label, next_state)

        assert wdg.state() != start_state
        assert wdg.state() == global_mmcore.getState(
            label) == wdg._combo.currentIndex()
        assert (wdg.stateLabel() == global_mmcore.getStateLabel(label) ==
                wdg._combo.currentText())

        wdg._disconnect()
        # once disconnected, core changes shouldn't call out to the widget
        global_mmcore.setState(label, start_state)
        assert global_mmcore.getStateLabel(label) != wdg._combo.currentText()
Exemple #2
0
def test_search_paths(core: CMMCorePlus):
    """Make sure search paths get added to path"""
    core.setDeviceAdapterSearchPaths(["test_path"])
    assert "test_path" in os.getenv("PATH")

    with pytest.raises(TypeError):
        core.setDeviceAdapterSearchPaths("test_path")
Exemple #3
0
def test_metadata(core: CMMCorePlus):
    core.startContinuousSequenceAcquisition(10)
    core.stopSequenceAcquisition()
    image, md = core.getLastImageMD()
    assert isinstance(md, Metadata)
    assert md["Height"] == "512"
    assert "ImageNumber" in md.keys()
    assert ("Binning", "1") in md.items()
    assert "GRAY16" in md.values()

    assert "Camera" in md
    md["Camera"] = "new"
    assert md["Camera"] == "new" == md.get("Camera")

    cpy = md.copy()
    assert cpy == md

    del md["Camera"]
    assert "Camera" not in md

    assert "Camera" in cpy
    assert md.get("", 1) == 1  # default

    md.clear()
    assert not md

    assert isinstance(md.json(), str)
def test_prop_browser(qtbot):
    from pymmcore_plus import CMMCorePlus

    mmcore = CMMCorePlus()
    cfg = Path(__file__).parent / "test_config.cfg"
    mmcore.loadSystemConfiguration(str(cfg))
    pb = PropBrowser(mmcore)
    qtbot.addWidget(pb)
    pb.show()
Exemple #5
0
def _creat_prop_widget(core: CMMCorePlus, dev: str,
                       prop: str) -> PPropValueWidget:
    """The type -> widget selection part used in the above function."""

    if core.isPropertyReadOnly(dev, prop):
        return ReadOnlyWidget()

    ptype = core.getPropertyType(dev, prop)
    if allowed := core.getAllowedPropertyValues(dev, prop):
        if ptype is PropertyType.Integer and set(allowed) == {"0", "1"}:
            return IntBoolWidget()
        return ChoiceWidget(core, dev, prop)
Exemple #6
0
def test_mda(core: CMMCorePlus, qtbot: "QtBot"):
    """Test signal emission during MDA"""
    mda = MDASequence(
        time_plan={
            "interval": 0.1,
            "loops": 2
        },
        stage_positions=[(1, 1, 1)],
        z_plan={
            "range": 3,
            "step": 1
        },
        channels=[{
            "config": "DAPI",
            "exposure": 1
        }],
    )
    fr_mock = MagicMock()
    ss_mock = MagicMock()
    sf_mock = MagicMock()
    xystage_mock = MagicMock()
    stage_mock = MagicMock()
    exp_mock = MagicMock()

    core.mda._events.frameReady.connect(fr_mock)
    core.mda._events.sequenceStarted.connect(ss_mock)
    core.mda._events.sequenceFinished.connect(sf_mock)
    core.events.XYStagePositionChanged.connect(xystage_mock)
    core.events.stagePositionChanged.connect(stage_mock)
    core.events.exposureChanged.connect(exp_mock)

    with qtbot.waitSignal(core.mda._events.sequenceFinished):
        core.run_mda(mda)
    assert fr_mock.call_count == len(list(mda))
    for event, _call in zip(mda, fr_mock.call_args_list):
        assert isinstance(_call.args[0], np.ndarray)
        assert _call.args[1] == event

    ss_mock.assert_called_once_with(mda)
    sf_mock.assert_called_once_with(mda)
    xystage_mock.assert_called_with("XY", 1.0, 1.0)
    exp_mock.assert_called_with("Camera", 1.0)
    stage_mock.assert_has_calls([
        call("Z", -0.5),
        call("Z", 0.5),
        call("Z", 1.5),
        call("Z", 2.5),
        call("Z", -0.5),
        call("Z", 0.5),
        call("Z", 1.5),
        call("Z", 2.5),
    ])
Exemple #7
0
def test_lock_and_callbacks(core: CMMCorePlus, qtbot):
    if not isinstance(core.events, QObject):
        pytest.skip(
            reason="Skip lock tests on psygnal until we can remove qtbot.")

    # when a function with a lock triggers a callback
    # that callback should be able to call locked functions
    # without hanging.

    # do some threading silliness here so we don't accidentally hang our
    # test if things go wrong have to use *got_lock* to check because we
    # can't assert in the function as theads don't throw their exceptions
    # back into the calling thread.
    got_lock = False

    def cb(*args, **kwargs):
        nonlocal got_lock
        got_lock = core.lock.acquire(timeout=0.1)
        if got_lock:
            core.lock.release()

    core.events.XYStagePositionChanged.connect(cb)

    def trigger_cb():
        core.setXYPosition(4, 5)

    th = Thread(target=trigger_cb)
    with qtbot.waitSignal(core.events.XYStagePositionChanged):
        th.start()
    assert got_lock
    got_lock = False

    core.mda._events.frameReady.connect(cb)
    mda = MDASequence(
        time_plan={
            "interval": 0.1,
            "loops": 2
        },
        stage_positions=[(1, 1, 1)],
        z_plan={
            "range": 3,
            "step": 1
        },
        channels=[{
            "config": "DAPI",
            "exposure": 1
        }],
    )

    with qtbot.waitSignal(core.mda._events.sequenceFinished):
        core.run_mda(mda)
    assert got_lock
Exemple #8
0
def test_guess_channel_group(core: CMMCorePlus):

    chan_group = core.getChannelGroup()
    assert chan_group == "Channel"

    assert core.getOrGuessChannelGroup() == ["Channel"]

    with patch.object(core, "getChannelGroup", return_value=""):
        assert core.getOrGuessChannelGroup() == ["Channel"]

        with pytest.raises(TypeError):
            core.channelGroup_pattern = 4

        # assign a new regex that won't match Channel using a str
        # this will return all the mm groups, but that's because this a bad regex
        # to use
        core.channelGroup_pattern = "^((?!(Channel)).)*$"
        assert core.getOrGuessChannelGroup() == [
            "Camera",
            "LightPath",
            "Objective",
            "System",
        ]

        # assign new using a pre-compile pattern
        core.channelGroup_pattern = re.compile("Channel")
        chan_group = core.getOrGuessChannelGroup()
        assert chan_group == ["Channel"]
Exemple #9
0
def test_mda_pause_cancel(core: CMMCorePlus, qtbot: "QtBot"):
    """Test signal emission during MDA with cancelation"""
    mda = MDASequence(
        time_plan={
            "interval": 0.25,
            "loops": 10
        },
        stage_positions=[(1, 1, 1)],
        z_plan={
            "range": 3,
            "step": 1
        },
        channels=[{
            "config": "DAPI",
            "exposure": 1
        }],
    )

    pause_mock = MagicMock()
    cancel_mock = MagicMock()
    sf_mock = MagicMock()
    ss_mock = MagicMock()

    core.mda._events.sequenceStarted.connect(ss_mock)
    core.mda._events.sequencePauseToggled.connect(pause_mock)
    core.mda._events.sequenceCanceled.connect(cancel_mock)
    core.mda._events.sequenceFinished.connect(sf_mock)

    _fcount = 0

    @core.mda._events.frameReady.connect
    def _onframe(frame, event):
        nonlocal _fcount
        _fcount += 1
        if _fcount == 1:
            core.mda.toggle_pause()
            pause_mock.assert_called_with(True)
            core.mda.toggle_pause()
            pause_mock.assert_called_with(False)
        elif _fcount == 2:
            core.mda.cancel()

    with qtbot.waitSignal(core.mda._events.sequenceFinished):
        core.run_mda(mda)

    ss_mock.assert_called_once_with(mda)
    cancel_mock.assert_called_once_with(mda)
    assert _fcount < len(list(mda))
    sf_mock.assert_called_once_with(mda)
Exemple #10
0
def test_core(core: CMMCorePlus):
    assert isinstance(core, CMMCorePlus)
    assert isinstance(core, CMMCore)
    # because the fixture tries to find micromanager, this should be populated
    assert core.getDeviceAdapterSearchPaths()
    assert isinstance(core.events.propertyChanged,
                      (psygnal.SignalInstance, QSignalInstance))
    assert isinstance(core.mda.events.frameReady,
                      (psygnal.SignalInstance, QSignalInstance))
    assert not core.mda._canceled
    assert not core.mda._paused

    # because the fixture loadsSystemConfig 'demo'
    assert len(core.getLoadedDevices()) == 12

    assert "CMMCorePlus" in repr(core)
Exemple #11
0
def test_device_type_overrides(core: CMMCorePlus):
    dt = core.getDeviceType("Camera")
    assert isinstance(dt, DeviceType)
    assert str(dt) == "Camera"
    assert int(dt) == 2
    assert dt == DeviceType["Camera"]
    assert dt == DeviceType["CameraDevice"]
    assert dt == DeviceType(2)
def test_mmproperty(core: CMMCorePlus):
    for prop in core.iterProperties(as_object=True):
        assert prop.isValid()
        assert prop.dict()

        if prop.isReadOnly():
            with pytest.warns(UserWarning):
                prop.value = "asdf"
Exemple #13
0
def test_load_system_config(core: CMMCorePlus):
    with pytest.raises(FileNotFoundError):
        core.loadSystemConfiguration("nonexistent")

    config_path = Path(__file__).parent / "local_config.cfg"
    core.loadSystemConfiguration(str(config_path))
    assert core.getLoadedDevices() == (
        "DHub",
        "Camera",
        "Dichroic",
        "Emission",
        "Excitation",
        "Objective",
        "Z",
        "Path",
        "XY",
        "Shutter",
        "Autofocus",
        "Core",
    )
Exemple #14
0
def test_setContext(core: CMMCorePlus):
    # should work with either leading capitalization
    with core.setContext(shutterOpen=False):
        assert not core.getShutterOpen()
    with core.setContext(ShutterOpen=False):
        assert not core.getShutterOpen()

    # if we set an invalid value make sure initial state is still restored
    with pytest.raises(TypeError):
        with core.setContext(autoShutter=False, shutterOpen="sadfsd"):
            assert not core.getAutoShutter()
    assert core.getAutoShutter()

    with pytest.raises(ValueError):
        with core.setContext(autoShutter=False):
            raise ValueError
    assert core.getAutoShutter()
Exemple #15
0
def test_configuration(core: CMMCorePlus):
    state = core.getSystemState()
    assert isinstance(state, Configuration)
    assert not isinstance(core.getSystemState(native=True), Configuration)

    assert str(state)

    tup = tuple(state)
    assert isinstance(tup, tuple)
    assert all(isinstance(x, tuple) and len(x) == 3 for x in tup)

    with pytest.raises(TypeError):
        assert state["Camera"] == 1
    with pytest.raises(TypeError):
        assert "Camera" in state

    assert state["Camera", "Binning"] == "1"
    assert PropertySetting("Camera", "Binning", "1") in state
    assert state in state

    assert ("Camera", "Binning") in state
Exemple #16
0
def global_mmcore(request):
    _core._SESSION_CORE = CMMCorePlus()  # refresh singleton
    if request.param == "remote":
        from pymmcore_plus import server

        server.try_kill_server()

    mmc = _core.get_core_singleton(remote=request.param == "remote")
    if len(mmc.getLoadedDevices()) < 2:
        mmc.loadSystemConfiguration(
            str(Path(__file__).parent / "test_config.cfg"))
    return mmc
Exemple #17
0
def test_prop_browser_core_reset(global_mmcore: CMMCorePlus, qtbot):
    """test that loading and resetting doesn't cause errors."""
    global_mmcore.unloadAllDevices()
    pb = PropertyBrowser(mmcore=global_mmcore)
    qtbot.addWidget(pb)
    global_mmcore.loadSystemConfiguration()
    global_mmcore.reset()
Exemple #18
0
def test_objective_widget_changes_objective(global_mmcore: CMMCorePlus, qtbot):
    obj_wdg = MMObjectivesWidget()
    qtbot.addWidget(obj_wdg)

    start_z = 100.0
    global_mmcore.setPosition("Z", start_z)
    stage_mock = Mock()
    obj_wdg._mmc.events.stagePositionChanged.connect(stage_mock)

    assert obj_wdg._combo.currentText() == "Nikon 10X S Fluor"
    with pytest.raises(ValueError):
        obj_wdg._combo.setCurrentText("10asdfdsX")

    assert global_mmcore.getCurrentPixelSizeConfig() == "Res10x"

    new_val = "Nikon 40X Plan Fluor ELWD"
    with qtbot.waitSignal(global_mmcore.events.propertyChanged):
        obj_wdg._combo.setCurrentText(new_val)

    stage_mock.assert_has_calls([call("Z", 0), call("Z", start_z)])
    assert obj_wdg._combo.currentText() == new_val
    assert global_mmcore.getStateLabel(obj_wdg._objective_device) == new_val
    assert global_mmcore.getCurrentPixelSizeConfig() == "Res40x"

    assert global_mmcore.getPosition("Z") == start_z
Exemple #19
0
def test_register_mda_engine(core: CMMCorePlus, qtbot: "QtBot"):
    orig_engine = core.mda

    registered_mock = MagicMock()
    core.events.mdaEngineRegistered.connect(registered_mock)

    # fake that mda is running
    # with an actual mda the threading and timing is
    # such that this ends up being a flaky test if we
    # use `core.run_mda`
    core.mda._running = True
    new_engine = MDAEngine(core)
    with pytest.raises(ValueError):
        core.register_mda_engine(new_engine)
    core.mda._running = False

    with qtbot.waitSignal(core.events.mdaEngineRegistered):
        core.register_mda_engine(new_engine)
    assert core._mda_engine is new_engine

    # invalid engine
    class nonconforming_engine:
        pass

    with pytest.raises(TypeError):
        core.register_mda_engine(nonconforming_engine())
    registered_mock.assert_called_once_with(new_engine, orig_engine)
def test_device_callbacks(core: CMMCorePlus):
    dev = Device("Camera", core)
    mock = Mock()
    mock2 = Mock()

    # regular connection
    dev.propertyChanged.connect(mock)
    dev.propertyChanged("Gain").connect(mock2)
    core.setProperty("Camera", "Gain", "6")
    mock.assert_called_once_with("Gain", "6")
    mock2.assert_called_once_with("6")
    mock.reset_mock()
    mock2.reset_mock()
    core.setProperty("Camera", "Binning", "2")
    mock.assert_called_once_with("Binning", "2")
    mock2.assert_not_called()

    # regular disconnection
    mock.reset_mock()
    mock2.reset_mock()
    dev.propertyChanged.disconnect(mock)
    dev.propertyChanged("Gain").disconnect(mock2)
    core.setProperty("Camera", "Gain", "4")
    mock.assert_not_called()
    mock2.assert_not_called()
Exemple #21
0
def test_md_overrides(core: CMMCorePlus):
    core.startContinuousSequenceAcquisition(10)
    core.stopSequenceAcquisition()

    image, md = core.getNBeforeLastImageMD(0)
    assert isinstance(md, Metadata)

    image, md = core.popNextImageMD()
    assert isinstance(md, Metadata)
Exemple #22
0
def get_core_singleton(remote=False) -> CMMCorePlus:
    """Retrieve the MMCore singleton for this session.

    The first call to this function determines whether we're running remote or not.
    perhaps a temporary function for now...
    """
    global _SESSION_CORE
    if _SESSION_CORE is None:
        if remote:
            from pymmcore_plus import RemoteMMCore

            _SESSION_CORE = RemoteMMCore()  # type: ignore  # it has the same interface.
        else:
            _SESSION_CORE = CMMCorePlus.instance()
    return _SESSION_CORE
Exemple #23
0
def test_new_position_methods(core: CMMCorePlus):
    x1, y1 = core.getXYPosition()
    z1 = core.getZPosition()

    core.setRelativeXYZPosition(1, 1, 1)

    x2, y2 = core.getXYPosition()
    z2 = core.getZPosition()

    assert round(x2, 2) == x1 + 1
    assert round(y2, 2) == y1 + 1
    assert round(z2, 2) == z1 + 1
def test_device_object(core: CMMCorePlus):
    for device in core.iterDevices(as_object=True):
        device.wait()
        assert not device.isBusy()
        assert device.schema()
        assert device.description()
        lib = device.library()
        assert lib if device.type() is not DeviceType.Core else not lib
        assert device.name()
        assert repr(device)
        assert device.core is core
        assert device.isLoaded()

        if device.supportsDetection():
            assert device.detect() is not DeviceDetectionStatus.Unimplemented
        else:
            assert device.detect() is DeviceDetectionStatus.Unimplemented

        if device.type() is not DeviceType.Core:
            device.unload()
            assert not device.isLoaded()
            assert "NOT LOADED" in repr(device)
Exemple #25
0
def test_get_objectives(core: CMMCorePlus):
    devices = core.guessObjectiveDevices()
    assert len(devices) == 1
    assert devices[0] == "Objective"

    with pytest.raises(TypeError):
        core.objective_device_pattern = 4

    # assign a new regex that won't match Objective using a str
    core.objective_device_pattern = "^((?!Objective).)*$"
    assert "Objective" not in core.guessObjectiveDevices()

    # assign new using a pre-compile pattern
    core.objective_device_pattern = re.compile("Objective")
    devices = core.guessObjectiveDevices()
    assert len(devices) == 1
    assert devices[0] == "Objective"
Exemple #26
0
from pymmcore_plus import CMMCorePlus

# see https://github.com/tlambert03/useq-schema
sequence = MDASequence(
    channels=["DAPI", {
        "config": "FITC",
        "exposure": 50
    }],
    time_plan={
        "interval": 2,
        "loops": 5
    },
    z_plan={
        "range": 4,
        "step": 0.5
    },
    axis_order="tpcz",
)

mmc = CMMCorePlus.instance()
mmc.loadSystemConfiguration()


@mmc.mda.events.frameReady.connect
def new_frame(img, event):
    print(img.shape)


mda_thread = mmc.run_mda(sequence)
Exemple #27
0
import pytest
from pymmcore_plus import CMMCorePlus, PropertyType

from micromanager_gui._core_widgets import PropertyWidget

# not sure how else to parametrize the test without instantiating here at import ...
CORE = CMMCorePlus()
CORE.loadSystemConfiguration()
dev_props = [(dev, prop) for dev in CORE.getLoadedDevices()
             for prop in CORE.getDevicePropertyNames(dev)]


def _assert_equal(a, b):
    try:
        assert float(a) == float(b)
    except ValueError:
        assert str(a) == str(b)


@pytest.mark.parametrize("dev, prop", dev_props)
def test_property_widget(dev, prop, qtbot):
    wdg = PropertyWidget(dev, prop, core=CORE)
    qtbot.addWidget(wdg)
    if CORE.isPropertyReadOnly(dev, prop) or prop in (
            "SimulateCrash",
            "Trigger",
            "AsyncPropertyLeader",
    ):
        return

    start_val = CORE.getProperty(dev, prop)
            Whether to force a change away from tracking the default camera.
        """
        if not force:
            raise RuntimeError(
                "Setting the camera on a DefaultCameraExposureWidget "
                "may cause it to malfunction. Either use *force=True* "
                " or create an ExposureWidget"
            )
        return super().setCamera(camera)

    def _camera_updated(self, value: str):
        # This will not always fire
        # see https://github.com/micro-manager/mmCoreAndDevices/issues/181
        self._camera = value
        # this will result in a double call of _on_load if this callback
        # was triggered by a configuration load. But I don't see an easy way around that
        # fortunately _on_load should be low cost
        self._on_load()


if __name__ == "__main__":  # pragma: no cover
    import sys

    from pymmcore_plus import CMMCorePlus  # noqa

    CMMCorePlus.instance().loadSystemConfiguration()
    app = QtW.QApplication(sys.argv)
    win = DefaultCameraExposureWidget()
    win.show()
    sys.exit(app.exec_())
Exemple #29
0
def iter_dev_props(mmc: CMMCorePlus) -> Iterator[Tuple[str, str]]:
    for dev in mmc.getLoadedDevices():
        for prop in mmc.getDevicePropertyNames(dev):
            yield dev, prop
from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING

import pytest
from pymmcore_plus import CMMCorePlus

from micromanager_gui._core_widgets import DefaultCameraExposureWidget

if TYPE_CHECKING:
    from pytestqt.qtbot import QtBot

# not sure how else to parametrize the test without instantiating here at import ...
CORE = CMMCorePlus()
CORE.loadSystemConfiguration(Path(__file__).parent.parent / "test_config.cfg")


def test_exposure_widget(qtbot: QtBot):
    CORE.setExposure(15)
    wdg = DefaultCameraExposureWidget(core=CORE)
    qtbot.addWidget(wdg)

    # check that it get's whatever core is set to.
    assert wdg.spinBox.value() == 15
    with qtbot.waitSignal(CORE.events.exposureChanged):
        CORE.setExposure(30)
    assert wdg.spinBox.value() == 30

    with qtbot.wait_signal(CORE.events.exposureChanged):
        wdg.spinBox.setValue(45)