Пример #1
0
def test_chained_emitters():
    """Chained emitters"""

    source = type("Source", (), {})()

    em1 = EventEmitter(source=None, type="test_event1")
    em2 = EventEmitter(source=source, type="test_event2")
    em1.connect(em2)
    em1.connect(record_event)
    record_event.result = None
    ev = em1()
    record_event.assert_result(event=ev,
                               event_class=Event,
                               source=None,
                               type="test_event1",
                               sources=[None])

    # sources look different from second emitter, but type is the same.
    em1.disconnect(record_event)
    em2.connect(record_event)
    record_event.result = None
    ev = em1()
    record_event.assert_result(
        event=ev,
        event_class=Event,
        source=source,
        type="test_event1",
        sources=[None, source],
    )
Пример #2
0
def test_event_connect_order():
    """Test event connection order"""
    def a(e):
        return

    def b(e):
        return

    def c(e):
        return

    def d(e):
        return

    def e(e):
        return

    def f(e):
        return

    em = EventEmitter(type="test_event")
    assert_raises(ValueError, em.connect, c, before=["c", "foo"])
    assert_raises(ValueError, em.connect, c, position="foo")
    assert_raises(TypeError, em.connect, c, ref=dict())
    em.connect(c, ref=True)
    assert_equal((c, ), tuple(em.callbacks))
    em.connect(c)
    assert_equal((c, ), tuple(em.callbacks))
    em.connect(d, ref=True, position="last")
    assert_equal((c, d), tuple(em.callbacks))
    em.connect(b, ref=True)  # position='first'
    assert_equal((b, c, d), tuple(em.callbacks))
    assert_raises(RuntimeError, em.connect, a, before="c", after="d")  # can't
    em.connect(a, ref=True, before=["c", "d"])  # first possible pos == 0
    assert_equal((a, b, c, d), tuple(em.callbacks))
    em.connect(f, ref=True, after=["c", "d"])
    assert_equal((a, b, c, d, f), tuple(em.callbacks))
    em.connect(e, ref=True, after="d", before="f")
    assert_equal(("a", "b", "c", "d", "e", "f"), tuple(em.callback_refs))
    em.disconnect(e)
    em.connect(e, ref=True, after="a", before="f", position="last")
    assert_equal(("a", "b", "c", "d", "e", "f"), tuple(em.callback_refs))
    em.disconnect(e)
    em.connect(e, ref="e", after="d", before="f", position="last")
    assert_equal(("a", "b", "c", "d", "e", "f"), tuple(em.callback_refs))
    em.disconnect(e)
    em.connect(e, after="d", before="f", position="first")  # no name
    assert_equal(("a", "b", "c", "d", None, "f"), tuple(em.callback_refs))
    em.disconnect(e)
    assert_raises(ValueError, em.connect, e, ref="d")  # duplicate name
    em.connect(e, ref=True, after=[], before="f", position="last")
    assert_equal(("a", "b", "c", "d", "e", "f"), tuple(em.callback_refs))
    assert_equal((a, b, c, d, e, f), tuple(em.callbacks))

    old_e = e

    def e():  # type: ignore
        return

    assert_raises(ValueError, em.connect, e, ref=True)  # duplicate name
    em.connect(e)
    assert_equal((None, "a", "b", "c", "d", "e", "f"), tuple(em.callback_refs))
    assert_equal((e, a, b, c, d, old_e, f), tuple(em.callbacks))
Пример #3
0
def test_disconnect():
    """Emitter disconnection"""
    em = EventEmitter(type="test_event")

    def cb1(ev):
        record_event.result = 1

    def cb2(ev):
        record_event.result = 2

    em.connect((record_event, "__call__"))  # type: ignore
    em.connect(cb1)
    em.connect(cb2)
    record_event.result = None
    em.disconnect(cb2)
    em.disconnect(cb2)  # should pass silently
    ev = em()
    record_event.assert_result(event=ev)

    record_event.result = None
    em.disconnect((record_event, "__call__"))  # type: ignore
    ev = em()
    assert record_event.result == 1

    record_event.result = None
    em.connect(cb1)
    em.connect(cb2)
    em.connect((record_event, "__call__"))  # type: ignore
    em.disconnect()
    em()
    assert record_event.result is None
Пример #4
0
    def __init__(
        self,
        function: Callable[..., _R],
        call_button: bool | str | None = None,
        layout: str = "vertical",
        labels: bool = True,
        tooltips: bool = True,
        app: AppRef = None,
        visible: bool = None,
        auto_call: bool = False,
        result_widget: bool = False,
        param_options: dict[str, dict] | None = None,
        name: str = None,
        persist: bool = False,
        **kwargs,
    ):
        if not callable(function):
            raise TypeError(
                "'function' argument to FunctionGui must be callable.")

        # consume extra Widget keywords
        extra = set(kwargs) - {"annotation", "gui_only"}
        if extra:
            s = "s" if len(extra) > 1 else ""
            raise TypeError(
                f"FunctionGui got unexpected keyword argument{s}: {extra}")
        if param_options is None:
            param_options = {}
        elif not isinstance(param_options, dict):
            raise TypeError("'param_options' must be a dict of dicts")

        sig = magic_signature(function, gui_options=param_options)
        self.return_annotation = sig.return_annotation
        if tooltips:
            _inject_tooltips_from_docstrings(function.__doc__, sig)

        self.persist = persist
        self._function = function
        self.__wrapped__ = function
        # it's conceivable that function is not actually an instance of FunctionType
        # we can still support any generic callable, but we need to be careful not to
        # access attributes (like `__name__` that only function objects have).
        # Mypy doesn't seem catch this at this point:
        # https://github.com/python/mypy/issues/9934
        self._callable_name = (getattr(function, "__name__", None) or
                               f"{function.__module__}.{function.__class__}")
        super().__init__(
            layout=layout,
            labels=labels,
            visible=visible,
            widgets=list(sig.widgets(app).values()),
            name=name or self._callable_name,
        )
        self._param_options = param_options
        self.called = EventEmitter(self, type="called")
        self._result_name = ""
        self._call_count: int = 0

        # a deque of Progressbars to be created by (possibly nested) tqdm_mgui iterators
        self._tqdm_pbars: Deque[ProgressBar] = deque()
        # the nesting level of tqdm_mgui iterators in a given __call__
        self._tqdm_depth: int = 0

        if call_button is None:
            call_button = not auto_call
        self._call_button: PushButton | None = None
        if call_button:
            text = call_button if isinstance(call_button, str) else "Run"
            self._call_button = PushButton(gui_only=True,
                                           text=text,
                                           name="call_button")
            if not auto_call:  # (otherwise it already gets called)

                def _disable_button_and_call(val):
                    # disable the call button until the function has finished
                    self._call_button = cast(PushButton, self._call_button)
                    self._call_button.enabled = False
                    try:
                        self.__call__()
                    finally:
                        self._call_button.enabled = True

                self._call_button.changed.connect(_disable_button_and_call)
            self.append(self._call_button)

        self._result_widget: LineEdit | None = None
        if result_widget:
            self._result_widget = LineEdit(gui_only=True, name="result")
            self._result_widget.enabled = False
            self.append(self._result_widget)

        if persist:
            self._load(quiet=True)

        self._auto_call = auto_call
        self.changed.connect(self._on_change)
Пример #5
0
def test_emitter_block2():
    state = [False, False]

    def a(ev):
        state[0] = True

    def b(ev):
        state[1] = True

    e = EventEmitter(source=None, type="event")
    e.connect(a)
    e.connect(b)

    def assert_state(a, b):
        assert state == [a, b]
        state[0] = False
        state[1] = False

    e()
    assert_state(True, True)

    # test global blocking
    e.block()
    e()
    assert_state(False, False)
    e.block()
    e()
    assert_state(False, False)

    # test global unlock, multiple depth
    e.unblock()
    e()
    assert_state(False, False)
    e.unblock()
    e()
    assert_state(True, True)

    # test unblock failure
    try:
        e.unblock()
        raise Exception("Expected RuntimeError")
    except RuntimeError:
        pass

    # test single block
    e.block(a)
    e()
    assert_state(False, True)

    e.block(b)
    e()
    assert_state(False, False)

    e.block(b)
    e()
    assert_state(False, False)

    # test single unblock
    e.unblock(a)
    e()
    assert_state(True, False)

    e.unblock(b)
    e()
    assert_state(True, False)

    e.unblock(b)
    e()
    assert_state(True, True)

    # Test single unblock failure
    try:
        e.unblock(a)
        raise Exception("Expected RuntimeError")
    except RuntimeError:
        pass

    # test global blocker
    with e.blocker():
        e()
        assert_state(False, False)

        # test nested blocker
        with e.blocker():
            e()
            assert_state(False, False)

        e()
        assert_state(False, False)

    e()
    assert_state(True, True)

    # test single blocker
    with e.blocker(a):
        e()
        assert_state(False, True)

        # test nested gloabel blocker
        with e.blocker():
            e()
            assert_state(False, False)

        e()
        assert_state(False, True)

        # test nested single blocker
        with e.blocker(a):
            e()
            assert_state(False, True)

        with e.blocker(b):
            e()
            assert_state(False, False)

        e()
        assert_state(False, True)

    e()
    assert_state(True, True)
Пример #6
0
 def _post_init(self):
     super()._post_init()
     self.changed = EventEmitter(source=self, type="changed")
     self._widget._mgui_bind_change_callback(self._on_value_change)
Пример #7
0
    def _post_init(self):
        from magicgui.events import EventEmitter

        self.changed = EventEmitter(source=self, type="changed")
        self._widget._mgui_bind_change_callback(
            lambda *x: self.changed(value=self.value))