gears/tests/test_signals.py
Sai Nane c5eaba88b7 Python type system experiments.
Push the envelope as far as you can!
...and then give up and use cast(), because we don't have applicative
functors or higher kinded types
2025-03-09 15:42:06 +13:00

122 lines
2.5 KiB
Python

from dataclasses import dataclass
from typing import NamedTuple
from unittest.mock import MagicMock
from gears import Gear
from gears.connections import connect
from gears.effect import effect_of
def test_get_set():
g = Gear(1)
assert g.get() == 1
assert g() == 1
g.set(3)
assert g.get() == 3
assert g() == 3
def test_basic_effect():
g = Gear("E")
last_arg: str | None = None
@effect_of(g)
def value_changed(v: str):
nonlocal last_arg
last_arg = v
assert last_arg == "E"
def test_effect_of_2():
g1 = Gear("E")
g2 = Gear(3)
last_arg: tuple[str, int] | None = None
@effect_of(g1, g2)
def value_changed(v1: str, v2: int):
nonlocal last_arg
last_arg = (v1, v2)
assert last_arg == ("E", 3)
g2.set(4)
assert last_arg == ("E", 4)
def test_connect():
my_str = Gear("123")
my_int = connect(my_str, lambda s: int(s), lambda _, i: str(i))
assert my_int() == 123
my_int.set(321)
assert my_str() == "321"
def test_connect_multiplication():
mul1 = Gear(10.0)
mul2 = connect(mul1, lambda x: x * 2.0, lambda _, y: y / 2.0)
mul3 = connect(mul1, lambda x: x * 3.0, lambda _, y: y / 3.0)
assert mul2() == 20
assert mul3() == 30
mul2.set(30)
assert mul1() == 15
assert mul3() == 45
def test_connect_property():
class Foo(NamedTuple):
bar: int
baz: int
foo = Gear(Foo(bar=1, baz=2))
bar = connect(
foo,
lambda foo: foo.bar,
lambda foo, bar: Foo(bar=bar, baz=foo.baz),
# TODO: look into dataclasses.replace
)
assert bar() == 1
bar.set(5)
assert bar() == 5
assert foo() == Foo(5, 2)
# class IntEntryOld:
# on_value_changed: Signal[int]
# _val: int
# def get_val(self, val: int): ...
# def set_val(self, val: int): ...
# class IntEntry:
# def __init__(self, value: Gear[int]): ...
# int_entry = IntEntry()
# effect_of(bar)(int_entry.set_val)
# int_entry.on_value_changed.connect(bar.set)
# @effect_of(bar)
# def update_ui(bar: int):
# int_entry.set_val(bar)
# def update_model(bar_val: int):
# bar.set(bar_val)
# int_entry.on_value_changed.connect(update_model)
def hello(my_callback):
my_callback(5)
def test_demonstrate_magicmock():
m = MagicMock()
# print(f"{m.foo(4).bar[0]=}")
# m.
hello(m)
# assert m.call_count == 1
m.assert_called_once_with(5)