def testUnbound(self): ''' We don't accept unbound methods as callback listeners. ''' output = [] class MyClass(object): def MyMethod(self): output.append('MyMethod') class MyListener(object): def Listen(self): output.append('Listen') a = MyClass() a.MyMethod() assert output == ['MyMethod'] # Registering bound method, OK b = MyListener() After(a.MyMethod, b.Listen) a.MyMethod() assert output == ['MyMethod', 'MyMethod', 'Listen'] # Registering unbound method, FAIL with pytest.raises(AssertionError): After(a.MyMethod, MyListener.Listen) assert output == ['MyMethod', 'MyMethod', 'Listen']
def testOnNullClass(self): ''' On Null classes, After/Before has no effect. ''' class MyNullSubClass(Null): '' count = [0] def AfterSetIt(): count[0] += 1 AfterSetIt() assert count == [1] s = Null() After(s.SetIt, AfterSetIt) s.SetIt() assert count == [1] s = MyNullSubClass() After(s.SetIt, AfterSetIt) s.SetIt() assert count == [1]
def _FTPOpenFile(filename_url): ''' Opens a file (FTP only) and sets things up to close ftp connection when the file is closed. :param filename_url: .. see:: OpenFile ''' ftp_host = FTPHost(filename_url) try: # Open remote file in binary mode to maintain the original encoding and end of line. open_file = ftp_host.open(filename_url.path, 'rb') # Set it up so when open_file is closed, ftp_host closes too def FTPClose(): # Before closing, remove callback to avoid recursion, since ftputil closes all files # it has from ben10.foundation.callback import Remove Remove(open_file.close, FTPClose) ftp_host.close() from ben10.foundation.callback import After After(open_file.close, FTPClose) return open_file except: ftp_host.close() raise
def testBeforeAfter(self): callback_args = [] def AfterCallback(): callback_args.append('after') def BeforeCallback(): callback_args.append('before') class MyClass: def Hooked(self): callback_args.append('hooked') my_obj = MyClass() callback_args = [] my_obj.Hooked() assert callback_args == ['hooked'] callback_args = [] After(my_obj.Hooked, AfterCallback) my_obj.Hooked() assert callback_args == ['hooked', 'after'] callback_args = [] Before(my_obj.Hooked, BeforeCallback) my_obj.Hooked() assert callback_args == ['before', 'hooked', 'after']
def testOnClassAndOnInstance(self): vals = [] class Stub(object): def call(self, *args, **kwargs): 'Never called!' 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 vals == [('call_instance', True), ('call_class', True)]
def testOnClassAndOnInstance2(self): class Stub(object): def Method(self, *args, **kwargs): pass def OnCallClass(instance, val): vals.append(('call_class', val)) def OnCallInstance(val): vals.append(('call_instance', val)) # Tricky thing here: because we added the callback in the class (2) after we added it to the # instance (1), 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. vals = [] s = Stub() After(s.Method, OnCallInstance) # (1) After(Stub.Method, OnCallClass) # (2) s.Method(1) assert vals == [('call_instance', 1), ] assert Remove(s.Method, OnCallInstance) == True assert Remove(Stub.Method, OnCallClass) == True vals = [] s = Stub() s.Method(2) assert vals == [] vals = [] s = Stub() After(Stub.Method, OnCallClass) # (2) After(s.Method, OnCallInstance) # (1) s.Method(3) assert vals == [('call_class', 3), ('call_instance', 3) ]
def testSingletonOptimization(self): class MySingleton(Singleton): pass def _ObtainStack(*args, **kwargs): self._called = True After(MySingleton._ObtainStack, _ObtainStack) self._called = False MySingleton.GetSingleton() assert self._called self._called = False MySingleton.GetSingleton() assert not self._called
def testCallbackAndInterfaces(self): ''' Tests if the interface "AssertImplements" works with "callbacked" methods. ''' class My(object): ImplementsInterface(_InterfM1) def m1(self): '' def MyCallback(): '' from ben10.foundation.callback import After o = My() AssertImplements(o, _InterfM1) After(o.m1, MyCallback) AssertImplements(o, _InterfM1) AssertImplements(o, _InterfM1) # Not raises BadImplementationError