from __future__ import print_function import unittest import wrapt @wrapt.synchronized def function(): print('function') class C1(object): @wrapt.synchronized def function1(self): print('function1') @wrapt.synchronized @classmethod def function2(cls): print('function2') @wrapt.synchronized @staticmethod def function3(): print('function3') c1 = C1() @wrapt.synchronized class C2(object): pass @wrapt.synchronized class C3: pass class C4(object): # XXX This yields undesirable results due to how class method is # implemented. The classmethod doesn't bind the method to the class # before calling. As a consequence, the decorator wrapper function # sees the instance as None with the class being explicitly passed # as the first argument. It isn't possible to detect and correct # this. @classmethod @wrapt.synchronized def function2(cls): print('function2') @staticmethod @wrapt.synchronized def function3(): print('function3') c4 = C4() class TestSynchronized(unittest.TestCase): def test_synchronized_function(self): _lock0 = getattr(function, '_synchronized_lock', None) self.assertEqual(_lock0, None) function() _lock1 = getattr(function, '_synchronized_lock', None) self.assertNotEqual(_lock1, None) function() _lock2 = getattr(function, '_synchronized_lock', None) self.assertNotEqual(_lock2, None) self.assertEqual(_lock2, _lock1) function() _lock3 = getattr(function, '_synchronized_lock', None) self.assertNotEqual(_lock3, None) self.assertEqual(_lock3, _lock2) def test_synchronized_inner_staticmethod(self): _lock0 = getattr(C1.function3, '_synchronized_lock', None) self.assertEqual(_lock0, None) c1.function3() _lock1 = getattr(C1.function3, '_synchronized_lock', None) self.assertNotEqual(_lock1, None) C1.function3() _lock2 = getattr(C1.function3, '_synchronized_lock', None) self.assertNotEqual(_lock2, None) self.assertEqual(_lock2, _lock1) C1.function3() _lock3 = getattr(C1.function3, '_synchronized_lock', None) self.assertNotEqual(_lock3, None) self.assertEqual(_lock3, _lock2) def test_synchronized_outer_staticmethod(self): _lock0 = getattr(C4.function3, '_synchronized_lock', None) self.assertEqual(_lock0, None) c4.function3() _lock1 = getattr(C4.function3, '_synchronized_lock', None) self.assertNotEqual(_lock1, None) C4.function3() _lock2 = getattr(C4.function3, '_synchronized_lock', None) self.assertNotEqual(_lock2, None) self.assertEqual(_lock2, _lock1) C4.function3() _lock3 = getattr(C4.function3, '_synchronized_lock', None) self.assertNotEqual(_lock3, None) self.assertEqual(_lock3, _lock2) def test_synchronized_inner_classmethod(self): if hasattr(C1, '_synchronized_lock'): del C1._synchronized_lock _lock0 = getattr(C1, '_synchronized_lock', None) self.assertEqual(_lock0, None) c1.function2() _lock1 = getattr(C1, '_synchronized_lock', None) self.assertNotEqual(_lock1, None) C1.function2() _lock2 = getattr(C1, '_synchronized_lock', None) self.assertNotEqual(_lock2, None) self.assertEqual(_lock2, _lock1) C1.function2() _lock3 = getattr(C1, '_synchronized_lock', None) self.assertNotEqual(_lock3, None) self.assertEqual(_lock3, _lock2) def test_synchronized_outer_classmethod(self): # XXX If all was good, this would be detected as a class # method call, but the classmethod decorator doesn't bind # the wrapped function to the class before calling and # just calls it direct, explicitly passing the class as # first argument. This screws things up. Would be nice if # Python were fixed, but that isn't likely to happen. #_lock0 = getattr(C4, '_synchronized_lock', None) _lock0 = getattr(C4.function2, '_synchronized_lock', None) self.assertEqual(_lock0, None) c4.function2() #_lock1 = getattr(C4, '_synchronized_lock', None) _lock1 = getattr(C4.function2, '_synchronized_lock', None) self.assertNotEqual(_lock1, None) C4.function2() #_lock2 = getattr(C4, '_synchronized_lock', None) _lock2 = getattr(C4.function2, '_synchronized_lock', None) self.assertNotEqual(_lock2, None) self.assertEqual(_lock2, _lock1) C4.function2() #_lock3 = getattr(C4, '_synchronized_lock', None) _lock3 = getattr(C4.function2, '_synchronized_lock', None) self.assertNotEqual(_lock3, None) self.assertEqual(_lock3, _lock2) def test_synchronized_instancemethod(self): if hasattr(C1, '_synchronized_lock'): del C1._synchronized_lock _lock0 = getattr(c1, '_synchronized_lock', None) self.assertEqual(_lock0, None) C1.function1(c1) _lock1 = getattr(c1, '_synchronized_lock', None) self.assertNotEqual(_lock1, None) c1.function1() _lock2 = getattr(c1, '_synchronized_lock', None) self.assertNotEqual(_lock2, None) self.assertEqual(_lock2, _lock1) c1.function1() _lock3 = getattr(c1, '_synchronized_lock', None) self.assertNotEqual(_lock3, None) self.assertEqual(_lock3, _lock2) del c1._synchronized_lock C1.function2() _lock4 = getattr(C1, '_synchronized_lock', None) self.assertNotEqual(_lock4, None) c1.function1() _lock5 = getattr(c1, '_synchronized_lock', None) self.assertNotEqual(_lock5, None) self.assertNotEqual(_lock5, _lock4) def test_synchronized_type_new_style(self): if hasattr(C2, '_synchronized_lock'): del C2._synchronized_lock _lock0 = getattr(C2, '_synchronized_lock', None) self.assertEqual(_lock0, None) c2 = C2() _lock1 = getattr(C2, '_synchronized_lock', None) self.assertNotEqual(_lock1, None) c2 = C2() _lock2 = getattr(C2, '_synchronized_lock', None) self.assertNotEqual(_lock2, None) self.assertEqual(_lock2, _lock1) c2 = C2() _lock3 = getattr(C2, '_synchronized_lock', None) self.assertNotEqual(_lock3, None) self.assertEqual(_lock3, _lock2) def test_synchronized_type_old_style(self): if hasattr(C3, '_synchronized_lock'): del C3._synchronized_lock _lock0 = getattr(C3, '_synchronized_lock', None) self.assertEqual(_lock0, None) c2 = C3() _lock1 = getattr(C3, '_synchronized_lock', None) self.assertNotEqual(_lock1, None) c2 = C3() _lock2 = getattr(C3, '_synchronized_lock', None) self.assertNotEqual(_lock2, None) self.assertEqual(_lock2, _lock1) c2 = C3() _lock3 = getattr(C3, '_synchronized_lock', None) self.assertNotEqual(_lock3, None) self.assertEqual(_lock3, _lock2) if __name__ == '__main__': unittest.main()