def test_or_then_chained(self): observer1 = 1 observer2 = 2 observer3 = 3 observer4 = 4 expr1 = create_expression(observer1) expr2 = create_expression(observer2) expr3 = create_expression(observer3) expr4 = create_expression(observer4) expr = (expr1 | expr2).then(expr3 | expr4) expected = [ ObserverGraph( node=observer1, children=[ create_graph(observer3), create_graph(observer4), ], ), ObserverGraph( node=observer2, children=[ create_graph(observer3), create_graph(observer4), ], ), ] actual = expr._as_graphs() self.assertEqual(actual, expected)
def test_add_notifiers_for_children_graphs(self): # Test adding notifiers using children graphs observable1 = DummyObservable() child_observer1 = DummyObserver(observables=[observable1], ) observable2 = DummyObservable() child_observer2 = DummyObserver(observables=[observable2], ) parent_observer = DummyObserver(next_objects=[mock.Mock()], ) graph = ObserverGraph( node=parent_observer, children=[ ObserverGraph(node=child_observer1, ), ObserverGraph(node=child_observer2, ) ], ) # when call_add_or_remove_notifiers( graph=graph, remove=False, ) # then self.assertCountEqual( observable1.notifiers, [ # For child1 observer child_observer1.notifier, ]) self.assertCountEqual( observable2.notifiers, [ # For child2 observer child_observer2.notifier, ])
def test_add_maintainers(self): # Test adding maintainers for children graphs observable = DummyObservable() maintainer = DummyNotifier() root_observer = DummyObserver( notify=False, observables=[observable], maintainer=maintainer, ) # two children, each will have a maintainer graph = ObserverGraph( node=root_observer, children=[ ObserverGraph(node=DummyObserver()), ObserverGraph(node=DummyObserver()), ], ) # when call_add_or_remove_notifiers( graph=graph, remove=False, ) # then # the dummy observer always return the same maintainer object. self.assertEqual(observable.notifiers, [maintainer, maintainer])
def test_remove_maintainers(self): observable = DummyObservable() maintainer = DummyNotifier() observable.notifiers = [maintainer, maintainer] root_observer = DummyObserver( notify=False, observables=[observable], maintainer=maintainer, ) # for there are two children graphs # two maintainers will be removed. graph = ObserverGraph( node=root_observer, children=[ ObserverGraph(node=DummyObserver()), ObserverGraph(node=DummyObserver()), ], ) # when call_add_or_remove_notifiers( graph=graph, remove=True, ) # then self.assertEqual(observable.notifiers, [])
def test_children_ordered(self): child_graph = ObserverGraph(node=2) graph = ObserverGraph( node=1, children=[ child_graph, ObserverGraph(node=3), ], ) self.assertIs(graph.children[0], child_graph)
def test_children_unique(self): child_graph = ObserverGraph(node=2) with self.assertRaises(ValueError) as exception_cm: ObserverGraph( node=1, children=[ child_graph, ObserverGraph(node=2), ], ) self.assertEqual(str(exception_cm.exception), "Not all children are unique.")
def test_equality_different_length_children(self): graph1 = ObserverGraph( node=1, children=[ ObserverGraph(node=2), ObserverGraph(node=3), ], ) graph2 = ObserverGraph( node=1, children=[ ObserverGraph(node=2), ], ) self.assertNotEqual(graph1, graph2)
def create_graph(*nodes): """ Create an ObserverGraph with the given nodes joined one after another. Parameters ---------- *nodes : hashable Items to be attached as nodes Returns ------- ObserverGraph """ node = nodes[-1] graph = ObserverGraph(node=node) for node in nodes[:-1][::-1]: graph = ObserverGraph(node=node, children=[graph]) return graph
def observer_change_handler(event, graph, handler, target, dispatcher): """ Handler for maintaining observers. Parameters ---------- event : TraitChangeEvent Event triggered by add_trait. graph : ObserverGraph Description for the *downstream* observers, i.e. excluding self. handler : callable User handler. target : object Object seen by the user as the owner of the observer. dispatcher : callable Callable for dispatching the handler. """ new_graph = ObserverGraph(node=_RestrictedNamedTraitObserver( name=event.new, wrapped_observer=graph.node, ), children=graph.children) add_or_remove_notifiers( object=event.object, graph=new_graph, handler=handler, target=target, dispatcher=dispatcher, remove=False, )
def test_observer_graph_hash_with_named_listener(self): # Test equality + hashing using set passes. path1 = ObserverGraph( node=create_observer(name="foo"), children=[ ObserverGraph(node=create_observer(name="bar")), ], ) path2 = ObserverGraph( node=create_observer(name="foo"), children=[ ObserverGraph(node=create_observer(name="bar")), ], ) # This tests __eq__ and __hash__ self.assertEqual(path1, path2)
def test_add_notifiers_for_extra_graph(self): observable = DummyObservable() extra_notifier = DummyNotifier() extra_observer = DummyObserver( observables=[observable], notifier=extra_notifier, ) extra_graph = ObserverGraph(node=extra_observer, ) observer = DummyObserver(extra_graphs=[extra_graph], ) graph = ObserverGraph(node=observer) # when call_add_or_remove_notifiers( graph=graph, remove=False, ) # then self.assertEqual(observable.notifiers, [extra_notifier])
def test_remove_notifiers_for_extra_graph(self): observable = DummyObservable() extra_notifier = DummyNotifier() extra_observer = DummyObserver( observables=[observable], notifier=extra_notifier, ) extra_graph = ObserverGraph(node=extra_observer, ) observer = DummyObserver(extra_graphs=[extra_graph], ) graph = ObserverGraph(node=observer) # suppose the notifier was added before observable.notifiers = [extra_notifier] # when call_add_or_remove_notifiers( graph=graph, remove=True, ) # then self.assertEqual(observable.notifiers, [])
def test_remove_notifier_raises_let_error_propagate(self): # Test if the notifier remove_from raises, the error will # be propagated. # DummyNotifier.remove_from raises if the notifier is not found. observer = DummyObserver( observables=[DummyObservable()], notifier=DummyNotifier(), ) with self.assertRaises(NotifierNotFound): call_add_or_remove_notifiers( graph=ObserverGraph(node=observer), remove=True, )
def test_remove_notifiers_for_children_graphs(self): observable1 = DummyObservable() notifier1 = DummyNotifier() child_observer1 = DummyObserver( observables=[observable1], notifier=notifier1, ) observable2 = DummyObservable() notifier2 = DummyNotifier() child_observer2 = DummyObserver( observables=[observable2], notifier=notifier2, ) parent_observer = DummyObserver(next_objects=[mock.Mock()], ) graph = ObserverGraph( node=parent_observer, children=[ ObserverGraph(node=child_observer1, ), ObserverGraph(node=child_observer2, ) ], ) # suppose notifiers were added observable1.notifiers = [notifier1] observable2.notifiers = [notifier2] # when call_add_or_remove_notifiers( graph=graph, remove=True, ) # then self.assertEqual(observable1.notifiers, []) self.assertEqual(observable2.notifiers, [])
def test_add_trait_notifiers(self): observable = DummyObservable() notifier = DummyNotifier() observer = DummyObserver( notify=True, observables=[observable], notifier=notifier, ) graph = ObserverGraph(node=observer) # when call_add_or_remove_notifiers( graph=graph, remove=False, ) # then self.assertEqual(observable.notifiers, [notifier])
def iter_extra_graphs(self, graph): """ Yield new ObserverGraph to be contributed by this observer. Parameters ---------- graph : ObserverGraph The graph this observer is part of. Yields ------ ObserverGraph """ yield ObserverGraph( node=TraitAddedObserver( match_func=self.filter, optional=False, ), children=[graph], )
def call_add_or_remove_notifiers(**kwargs): """ Convenience function for calling add_or_remove_notifiers with default values. Parameters ---------- **kwargs New argument values to use instead. """ values = dict( object=mock.Mock(), graph=ObserverGraph(node=None), handler=mock.Mock(), target=_DEFAULT_TARGET, dispatcher=dispatch_same, remove=False, ) values.update(kwargs) add_or_remove_notifiers(**values)
def iter_extra_graphs(self, graph): """ Yield additional ObserverGraph for adding/removing notifiers when this observer is encountered in a given ObserverGraph. Parameters ---------- graph : ObserverGraph The graph where this observer is the root node. Yields ------ graph : ObserverGraph """ yield ObserverGraph( node=TraitAddedObserver( match_func=lambda name, trait: name == self.name, optional=self.optional, ), children=[graph], )
def test_add_trait_notifiers_notify_flag_is_false(self): # Test when the notify flag is false, the notifier is not # added. observable = DummyObservable() notifier = DummyNotifier() observer = DummyObserver( notify=False, observables=[observable], notifier=notifier, ) graph = ObserverGraph(node=observer) # when call_add_or_remove_notifiers( graph=graph, remove=False, ) # then self.assertEqual(observable.notifiers, [])
def test_remove_notifiers_skip_if_notify_flag_is_false(self): observable = DummyObservable() notifier = DummyNotifier() observable.notifiers = [notifier] observer = DummyObserver( notify=False, observables=[observable], notifier=notifier, ) graph = ObserverGraph(node=observer, ) # when call_add_or_remove_notifiers( graph=graph, remove=True, ) # then # notify is false, remove does nothing. self.assertEqual(observable.notifiers, [notifier])
def test_equality_order_of_children(self): # The order of items in children does not matter graph1 = ObserverGraph( node=1, children=[ ObserverGraph(node=2), ObserverGraph(node=3), ], ) graph2 = ObserverGraph( node=1, children=[ ObserverGraph(node=3), ObserverGraph(node=2), ], ) self.assertEqual(graph1, graph2) self.assertEqual(hash(graph1), hash(graph2))
def graph_from_nodes(*nodes): nodes = nodes[::-1] graph = ObserverGraph(node=nodes[0]) for node in nodes[1:]: graph = ObserverGraph(node=node, children=[graph]) return graph
def _create_graphs(self, branches): return [ ObserverGraph(node=self.observer, children=branches), ]
def test_basic_instance_change(self): class Bar(HasTraits): value = Int() class Foo(HasTraits): bar = Instance(Bar) on_bar_value_changed = self.handler bar = Bar() foo1 = Foo(bar=bar) foo2 = Foo(bar=bar) def observer_handler(event, graph, handler, target, dispatcher): # Very stupid handler for maintaining notifiers. old_notifiers = event.old._trait("value", 2)._notifiers(True) old_notifiers.remove(handler) new_notifiers = event.new._trait("value", 2)._notifiers(True) new_notifiers.append(handler) # Ignore graph, which would have been used for propagating # notifiers in nested objects. # Ignore target, which would have been used as the context # for the user handler. # Ignore dispatcher, which would otherwise wrap the user handler. # Two notifiers are added to bar # One "belongs" to foo1, the second one "belongs" to foo2 bar._trait("value", 2)._notifiers(True).extend([ on_bar_value_changed, on_bar_value_changed, ]) # this is for maintaining notifiers that belong to foo1 notifier_foo1 = create_notifier( observer_handler=observer_handler, event_factory=self.event_factory, graph=ObserverGraph(node=None), handler=on_bar_value_changed, target=foo1, dispatcher=dispatch_here, ) notifier_foo1.add_to(foo1._trait("bar", 2)) # this is for maintaining notifiers that belong to foo2 notifier_foo2 = create_notifier( observer_handler=observer_handler, event_factory=self.event_factory, graph=ObserverGraph(node=None), handler=on_bar_value_changed, target=foo2, dispatcher=dispatch_here, ) notifier_foo2.add_to(foo2._trait("bar", 2)) # when # the bar is changed, the ObserverChangeNotifier is fired so that # user handler on Bar.value is maintained. self.event_args_list.clear() new_bar = Bar(value=1) foo1.bar = new_bar foo2.bar = new_bar new_bar.value += 1 # then self.assertEqual(len(self.event_args_list), 2) # when # changes on the old bar will not be captured self.event_args_list.clear() bar.value += 1 # then self.assertEqual(len(self.event_args_list), 0)