def testLessArgs(self) -> None: class C: def foo(self, _x, _y, **_kwargs): pass def after_2(x, y, *args, **kwargs): self.after_2_res = x, y def after_1(x, *args, **kwargs): self.after_1_res = x def after_0(*args, **kwargs): self.after_0_res = 0 self.after_2_res = None self.after_1_res = None self.after_0_res = None c = C() After(c.foo, after_2) After(c.foo, after_1) After(c.foo, after_0) c.foo(10, 20, foo=1) assert self.after_2_res == (10, 20) assert self.after_1_res == 10 assert self.after_0_res == 0
def testDeadCallbackCleared(self) -> None: my_object = _MyClass() my_object.SetAlpha(0) my_object.SetBravo(0) self._value = [] class B: def event(s, value): # @NoSelf self._b_value = value class A: def event(s, obj, value): # @NoSelf self._a_value = value a = A() b = B() self._a_value = None self._b_value = None # Test After/Remove with a callback and sender_as_parameter After(my_object.SetAlpha, a.event, sender_as_parameter=True) After(my_object.SetAlpha, b.event, sender_as_parameter=False) w = weakref.ref(a) my_object.SetAlpha(3) assert 3 == self._a_value assert 3 == self._b_value del a my_object.SetAlpha(4) assert 3 == self._a_value assert 4 == self._b_value assert w() is None
def testOnClassMethod(self) -> None: class A: @classmethod def foo(cls): pass self.after_exec_class_method = 0 def FooAfterClassMethod(): self.after_exec_class_method += 1 self.after_exec_self_method = 0 def FooAfterSelfMethod(): self.after_exec_self_method += 1 After(A.foo, FooAfterClassMethod) a = A() After(a.foo, FooAfterSelfMethod) a.foo() assert 1 == self.after_exec_class_method assert 1 == self.after_exec_self_method Remove(A.foo, FooAfterClassMethod) a.foo() assert 1 == self.after_exec_class_method assert 2 == self.after_exec_self_method
def testOnClassAndOnInstance1(self) -> None: vals = [] def OnCall1(instance, val): vals.append(("call_instance", val)) def OnCall2(val): vals.append(("call_class", val)) After(Stub.call, OnCall1) s = Stub() After(s.call, OnCall2) s.call(True) assert [("call_instance", True), ("call_class", True)] == vals
def testClassOverride(self) -> None: Before(C.foo, self.before) After(C.foo, self.after) self.a.foo(1) assert self.foo_called == (self.a, 1) assert self.after_called == (self.a, 1) assert self.after_count == 1 assert self.before_called == (self.a, 1) assert self.before_count == 1 self.b.foo(2) assert self.foo_called == (self.b, 2) assert self.after_called == (self.b, 2) assert self.after_count == 2 assert self.before_called == (self.b, 2) assert self.before_count == 2 assert Remove(C.foo, self.before) self.a.foo(3) assert self.foo_called == (self.a, 3) assert self.after_called == (self.a, 3) assert self.after_count == 3 assert self.before_called == (self.b, 2) assert self.before_count == 2
def testInstanceOverride(self) -> None: Before(self.a.foo, self.before) After(self.a.foo, self.after) self.a.foo(1) assert self.foo_called == (self.a, 1) assert self.after_called == (1, ) assert self.before_called == (1, ) assert self.after_count == 1 assert self.before_count == 1 self.b.foo(2) assert self.foo_called == (self.b, 2) assert self.after_called == (1, ) assert self.before_called == (1, ) assert self.after_count == 1 assert self.before_count == 1 assert Remove(self.a.foo, self.before) == True self.a.foo(2) assert self.foo_called == (self.a, 2) assert self.after_called == (2, ) assert self.before_called == (1, ) assert self.after_count == 2 assert self.before_count == 1 Before(self.a.foo, self.before) Before(self.a.foo, self.before) # Registering twice has no effect the 2nd time self.a.foo(5) assert self.before_called == (5, ) assert self.before_count == 2
def testActionMethodDies(self) -> None: class A: def foo(self): pass def FooAfter(): self.after_exec += 1 self.after_exec = 0 a = A() weak_a = weakref.ref(a) After(a.foo, FooAfter) a.foo() assert self.after_exec == 1 del a # IMPORTANT: behaviour change. The description below is for the previous # behaviour. That is not true anymore (the circular reference is not kept anymore) # callback creates a circular reference; that's ok, because we want # to still be able to do "x = a.foo" and keep a strong reference to it assert weak_a() is None
def testAfterBeforeHandleError(self) -> None: class C: def Method(self, x): return x * 2 def AfterMethod(*args): self.after_called += 1 raise RuntimeError def BeforeMethod(*args): self.before_called += 1 raise RuntimeError self.before_called = 0 self.after_called = 0 c = C() Before(c.Method, BeforeMethod) After(c.Method, AfterMethod) # Now behavior changed and it will fail on first callback error with pytest.raises(RuntimeError): assert c.Method(10) == 20 assert self.before_called == 1 assert self.after_called == 0
def testBoundMethodsRight(self) -> None: foo = self.a.foo foo = Before(foo, self.before) foo = After(foo, self.after) foo(10) assert self.before_count == 1 assert self.after_count == 1
def testBoundMethodsWrong(self) -> None: foo = self.a.foo Before(foo, self.before) After(foo, self.after) foo(10) assert 0 == self.before_count assert 0 == self.after_count
def testSenderDies2(self) -> None: After(self.a.foo, self.after, True) self.a.foo(1) assert (self.a, 1) == self.after_called a = weakref.ref(self.a) self.after_called = None self.foo_called = None del self.a assert a() is None
def testOnNullClass(self) -> None: class _MyNullSubClass(Null): def GetIstodraw(self): return True s = _MyNullSubClass() def AfterSetIstodraw(): pass After(s.SetIstodraw, AfterSetIstodraw)
def testOnClassAndOnInstance2(self) -> None: vals = [] def OnCall1(instance, val): vals.append(("call_class", val)) def OnCall2(val): vals.append(("call_instance", val)) s = Stub() After(s.call, OnCall2) After(Stub.call, OnCall1) # Tricky thing here: because we added the callback in the class after we added it to the # instance, the callback on the instance cannot be rebound, thus, calling it on the instance # won't really trigger the callback on the class (not really what would be expected of the # after method, but I couldn't find a reasonable way to overcome that). # A solution could be keeping track of all callbacks and rebinding all existent ones in the # instances to the one in the class, but it seems overkill for such an odd situation. s.call(True) assert [("call_instance", True)] == vals
def testAfterRegisterMultipleAndUnregisterOnce(self) -> None: class A: def foo(self): pass a = A() def FooAfter1(): Remove(a.foo, FooAfter1) self.after_exec += 1 def FooAfter2(): self.after_exec += 1 self.after_exec = 0 After(a.foo, FooAfter1) After(a.foo, FooAfter2) a.foo() # it was iterating in the original after, so, this case # was only giving 1 result and not 2 as it should assert 2 == self.after_exec a.foo() assert 3 == self.after_exec a.foo() assert 4 == self.after_exec After(a.foo, FooAfter2) After(a.foo, FooAfter2) After(a.foo, FooAfter2) a.foo() assert 5 == self.after_exec Remove(a.foo, FooAfter2) a.foo() assert 5 == self.after_exec
def testAfterRemove(self) -> None: my_object = _MyClass() my_object.SetAlpha(0) my_object.SetBravo(0) After(my_object.SetAlpha, my_object.SetBravo) my_object.SetAlpha(1) assert my_object.bravo == 1 Remove(my_object.SetAlpha, my_object.SetBravo) my_object.SetAlpha(2) assert my_object.bravo == 1
def test_sender_as_parameter_after_and_before(self) -> None: self.zulu_calls = [] def zulu_one(*args): self.zulu_calls.append((1, args)) def zulu_too(*args): self.zulu_calls.append((2, args)) Before(self.a.foo, zulu_one, sender_as_parameter=True) After(self.a.foo, zulu_too) assert self.zulu_calls == [] self.a.foo(0) assert self.zulu_calls == [(1, (self.a, 0)), (2, (0, ))]
def testWithCallable(self) -> None: class Stub: def call(self, _b): pass class Aux: def __call__(self, _b): self.called = True s = Stub() a = Aux() After(s.call, a) s.call(True) assert a.called
def testAfterRemoveCallback(self) -> None: my_object = _MyClass() my_object.SetAlpha(0) my_object.SetBravo(0) # Test After/Remove with a callback event = Callback() After(my_object.SetAlpha, event) event.Register(my_object.SetBravo) my_object.SetAlpha(3) assert my_object.bravo == 3 Remove(my_object.SetAlpha, event) my_object.SetAlpha(4) assert my_object.bravo == 3
def testListMethodAsCallback(self, mocker) -> None: """ This was based on a failure on souring20.core.model.multiple_simulation_runs._tests.test_multiple_simulation_runs.testNormalExecution which failed with "TypeError: cannot create weak reference to 'list' object" """ vals: List[str] = [] class Stub: def call(self, *args, **kwargs): pass s = Stub() After(s.call, vals.append) s.call("call_append") assert ["call_append"] == vals
def testAfterRemoveCallbackAndSenderAsParameter(self) -> None: my_object = _MyClass() my_object.SetAlpha(0) my_object.SetBravo(0) def event(obj_or_value, value): self._value = value # Test After/Remove with a callback and sender_as_parameter After(my_object.SetAlpha, event, sender_as_parameter=True) my_object.SetAlpha(3) assert 3 == self._value Remove(my_object.SetAlpha, event) my_object.SetAlpha(4) assert 3 == self._value
def testSingletonOptimization() -> None: class MySingleton(Singleton): pass class MockClass: called = False def ObtainStack(self, *args, **kwargs): self.called = True obj = MockClass() After(MySingleton._ObtainStack, obj.ObtainStack) obj.called = False MySingleton.GetSingleton() assert obj.called obj.called = False MySingleton.GetSingleton() assert not obj.called
def testCallbackAndInterfaces() -> None: """ Tests if the interface "AssertImplements" works with "callbacked" methods. """ @ImplementsInterface(_InterfM1) class My: def m1(self): "" def MyCallback(): "" from oop_ext.foundation.callback import After o = My() AssertImplements(o, _InterfM1) After(o.m1, MyCallback) AssertImplements(o, _InterfM1) AssertImplements(o, _InterfM1) # Not raises BadImplementationError
def __init__(self): Before(self.SetFilename, GetWeakProxy(self._BeforeSetFilename)) After(self.SetFilename, GetWeakProxy(self._AfterSetFilename)) self.before = False self.after = False