1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
import pytest
from psygnal import EmitLoopError
from magicgui import magic_factory
from magicgui.type_map._magicgui import MagicFactory
from magicgui.widgets import ComboBox, FunctionGui, Slider
def test_magic_factory():
"""Test basic magic_factory behavior."""
@magic_factory(call_button=True)
def factory(x: int = 1):
return x
assert isinstance(factory, MagicFactory)
# factories make widgets that are FunctionGui instances
widget1 = factory()
assert isinstance(widget1, FunctionGui)
assert widget1.call_button
# You can call them repeatedly, and even override the initial kwargs
# given to magic_factory (just like with functools.partial)
widget2 = factory(call_button=False, x={"widget_type": "Slider"})
assert widget1 is not widget2
assert isinstance(widget2, FunctionGui)
assert not widget2.call_button
assert isinstance(widget2.x, Slider)
# the widget, (like all FunctionGuis) is still callable and accepts args
assert widget1() == 1
assert widget1(3) == 3
def test_magic_factory_reuse():
"""Test magic_factory can be reused."""
@magic_factory(x={"choices": ["a", "b"]})
def factory(x="a"):
return x
# there was an earlier bug that overrode widget parameters. this tests for that
widget_a = factory()
assert isinstance(widget_a.x, ComboBox)
widget_b = factory()
assert isinstance(widget_b.x, ComboBox)
def test_magic_factory_repr():
"""Test basic magic_factory behavior."""
@magic_factory(labels=False)
def factory(x: int = 1):
return x
rep = repr(factory)
assert rep.startswith("MagicFactory(function=<function test_magic_factory_repr")
assert rep.endswith("labels=False)")
@magic_factory(labels=False, x={"widget_type": "Slider"})
def factory2(x: int = 1):
return x
assert repr(factory2).endswith(
"labels=False, param_options={'x': {'widget_type': 'Slider'}})"
)
def test_magic_factory_only_takes_kwargs():
@magic_factory(labels=False)
def factory(x: int = 1):
return x
with pytest.raises(ValueError) as e:
factory("positional")
assert "only accept keyword arguments" in str(e)
@magic_factory
def self_referencing_factory(x: int = 1):
"""Function that refers to itself, and wants the FunctionGui instance."""
return self_referencing_factory
def test_magic_factory_self_reference():
"""Test that self-referential factories work in global scopes."""
widget = self_referencing_factory()
assert isinstance(widget(), FunctionGui)
def test_magic_local_factory_self_reference():
"""Test that self-referential factories work in local scopes."""
@magic_factory
def local_self_referencing_factory(x: int = 1):
return local_self_referencing_factory
widget = local_self_referencing_factory()
assert isinstance(widget(), FunctionGui)
def test_factory_init():
def bomb():
raise RuntimeError("boom")
def widget_init(widget):
widget.called.connect(bomb)
@magic_factory(widget_init=widget_init)
def factory(x: int = 1):
pass
widget = factory()
with pytest.raises(EmitLoopError):
widget()
def test_bad_value_factory_init():
def widget_init():
pass
with pytest.raises(TypeError):
@magic_factory(widget_init=widget_init) # type: ignore
def factory(x: int = 1):
pass
def test_bad_type_factory_init():
with pytest.raises(TypeError):
@magic_factory(widget_init=1) # type: ignore
def factory(x: int = 1):
pass
def test_none_defaults():
"""Make sure that an unannotated parameter with default=None is ok."""
@magic_factory
def factory(arg=None):
return 1
assert factory()() == 1
|