def test_watch_immediate(): a = observe({ "foo": 5, "bar": [6, 7, 8], "quux": 10, "quuz": { "a": 1, "b": 2 } }) called = 0 def _callback(old_value, new_value): nonlocal called called += 1 watcher = watch(lambda: a["quuz"], _callback, deep=True, immediate=True) assert not watcher.dirty assert watcher.value == a["quuz"] assert len(watcher._deps) > 1 assert called == 1 a["quuz"]["b"] = 3 assert not watcher.dirty assert called == 2
def test_deps_delete(): # test that dep objects are removed on delete state = observe({"foo": 5, "bar": 6}) state["baz"] = 5 assert len(state.__keydeps__) == 3 del state["baz"] assert len(state.__keydeps__) == 2 state.popitem() assert len(state.__keydeps__) == 1 state.clear() assert len(state.__keydeps__) == 0
def test_observe_new_coll(): # this test proves that even tho we have redundant deps # we don't redundantly recompute state = observe({"foo": 5, "bar": 6}) @computed def prop(): return state["bar"] * 3 assert prop() == 3 * 6 # this adds a new collection into the scene # it should automatically also become observable state["bar"] = [1, 2, 3] assert prop() == [1, 2, 3, 1, 2, 3, 1, 2, 3] # this will only trigger re-evaluation # if the list became observable state["bar"][0] = 4 assert prop() == [4, 2, 3, 4, 2, 3, 4, 2, 3]
def test_deps_copy(): # this test proves that even tho we have redundant deps # we don't redundantly recompute state = observe({"foo": 5, "bar": 6}) call_count = 0 @computed def prop(): nonlocal call_count call_count += 1 return state.copy() assert prop() == {"foo": 5, "bar": 6} assert prop() is not state assert len(prop.__watcher__._deps) == 3 assert call_count == 1 state["foo"] = 3 assert prop() == {"foo": 3, "bar": 6} assert prop() is not state assert len(prop.__watcher__._deps) == 3 assert call_count == 2
def test_observe_changed(): # this test proves that we only fire if a value actually # changed state = observe({"foo": 5, "bar": 6}) call_count = 0 @computed def prop(): nonlocal call_count call_count += 1 return state["bar"] * 3 for _ in range(2): assert prop() == 3 * 6 assert call_count == 1 # no change state["bar"] = state["bar"] for _ in range(2): assert prop() == 3 * 6 assert call_count == 1
def test_usage_deep_vs_non_deep(): a = observe({"foo": [0, 1]}) non_deep_called = 0 def _non_deep_callback(old_value, new_value): nonlocal non_deep_called non_deep_called += 1 deep_called = 0 def _deep_callback(old_value, new_value): nonlocal deep_called deep_called += 1 watcher = watch(lambda: a["foo"], _non_deep_callback) deep_watcher = watch(lambda: a["foo"], _deep_callback, deep=True) assert not watcher.dirty assert not deep_watcher.dirty assert non_deep_called == 0 a["foo"].append(1) assert non_deep_called == 0 assert deep_called == 1
self.setLayout(layout) self.button.clicked.connect(self.on_button_clicked) self.reset.clicked.connect(self.on_reset_clicked) def on_button_clicked(self): self.state["clicked"] += 1 def on_reset_clicked(self): self.state["clicked"] = 0 if __name__ == "__main__": # Define some state state = observe({"clicked": 0}) app = QApplication([]) # Create layout and pass state to widgets layout = QVBoxLayout() layout.addWidget(Display(state)) layout.addWidget(Controls(state)) widget = QWidget() widget.setLayout(layout) widget.show() widget.setWindowTitle("Clicked?") app.exec_()
def test_usage(): a = observe({ "foo": 5, "bar": [6, 7, 8], "quux": 10, "quuz": { "a": 1, "b": 2 } }) execute_count = 0 def bla(): nonlocal execute_count execute_count += 1 multi = 0 if a["quux"] == 10: multi = a["foo"] * 5 else: multi = a["bar"][-1] * 5 return multi * a["quuz"]["b"] computed_bla = computed(bla) assert computed_bla() == 50 assert computed_bla() == 50 assert execute_count == 1 a["quux"] = 25 assert computed_bla() == 80 assert computed_bla() == 80 assert execute_count == 2 a["quuz"]["b"] = 3 assert computed_bla() == 120 assert computed_bla() == 120 assert execute_count == 3 @computed def bla2(): nonlocal execute_count execute_count += 1 return a["foo"] * computed_bla() assert bla2() == 600 assert bla2() == 600 assert execute_count == 4 a["quuz"]["b"] = 4 assert bla2() == 800 assert bla2() == 800 assert execute_count == 6 called = 0 def _callback(old_value, new_value): nonlocal called called += 1 watcher = watch(lambda: a["quuz"], _callback, deep=True, immediate=False) assert not watcher.dirty assert watcher.value == a["quuz"] assert len(watcher._deps) > 1 assert called == 0 a["quuz"]["b"] = 3 assert not watcher.dirty assert called == 1 assert computed_bla() == 120 assert execute_count == 7 assert not computed_bla.__watcher__.dirty a["bar"].extend([9, 10]) assert computed_bla.__watcher__.dirty assert computed_bla() == 150 assert execute_count == 8