1*90c8c64dSAndroid Build Coastguard Worker""" 2*90c8c64dSAndroid Build Coastguard WorkerA Python Singleton mixin class that makes use of some of the ideas 3*90c8c64dSAndroid Build Coastguard Workerfound at http://c2.com/cgi/wiki?PythonSingleton. Just inherit 4*90c8c64dSAndroid Build Coastguard Workerfrom it and you have a singleton. No code is required in 5*90c8c64dSAndroid Build Coastguard Workersubclasses to create singleton behavior -- inheritance from 6*90c8c64dSAndroid Build Coastguard WorkerSingleton is all that is needed. 7*90c8c64dSAndroid Build Coastguard Worker 8*90c8c64dSAndroid Build Coastguard WorkerAssume S is a class that inherits from Singleton. Useful behaviors 9*90c8c64dSAndroid Build Coastguard Workerare: 10*90c8c64dSAndroid Build Coastguard Worker 11*90c8c64dSAndroid Build Coastguard Worker1) Getting the singleton: 12*90c8c64dSAndroid Build Coastguard Worker 13*90c8c64dSAndroid Build Coastguard Worker S.getInstance() 14*90c8c64dSAndroid Build Coastguard Worker 15*90c8c64dSAndroid Build Coastguard Workerreturns the instance of S. If none exists, it is created. 16*90c8c64dSAndroid Build Coastguard Worker 17*90c8c64dSAndroid Build Coastguard Worker2) The usual idiom to construct an instance by calling the class, i.e. 18*90c8c64dSAndroid Build Coastguard Worker 19*90c8c64dSAndroid Build Coastguard Worker S() 20*90c8c64dSAndroid Build Coastguard Worker 21*90c8c64dSAndroid Build Coastguard Workeris disabled for the sake of clarity. If it were allowed, a programmer 22*90c8c64dSAndroid Build Coastguard Workerwho didn't happen notice the inheritance from Singleton might think he 23*90c8c64dSAndroid Build Coastguard Workerwas creating a new instance. So it is felt that it is better to 24*90c8c64dSAndroid Build Coastguard Workermake that clearer by requiring the call of a class method that is defined in 25*90c8c64dSAndroid Build Coastguard WorkerSingleton. An attempt to instantiate via S() will restult in an SingletonException 26*90c8c64dSAndroid Build Coastguard Workerbeing raised. 27*90c8c64dSAndroid Build Coastguard Worker 28*90c8c64dSAndroid Build Coastguard Worker3) If S.__init__(.) requires parameters, include them in the 29*90c8c64dSAndroid Build Coastguard Workerfirst call to S.getInstance(.). If subsequent calls have parameters, 30*90c8c64dSAndroid Build Coastguard Workera SingletonException is raised. 31*90c8c64dSAndroid Build Coastguard Worker 32*90c8c64dSAndroid Build Coastguard Worker4) As an implementation detail, classes that inherit 33*90c8c64dSAndroid Build Coastguard Workerfrom Singleton may not have their own __new__ 34*90c8c64dSAndroid Build Coastguard Workermethods. To make sure this requirement is followed, 35*90c8c64dSAndroid Build Coastguard Workeran exception is raised if a Singleton subclass includ 36*90c8c64dSAndroid Build Coastguard Workeres __new__. This happens at subclass instantiation 37*90c8c64dSAndroid Build Coastguard Workertime (by means of the MetaSingleton metaclass. 38*90c8c64dSAndroid Build Coastguard Worker 39*90c8c64dSAndroid Build Coastguard WorkerBy Gary Robinson, [email protected]. No rights reserved -- 40*90c8c64dSAndroid Build Coastguard Workerplaced in the public domain -- which is only reasonable considering 41*90c8c64dSAndroid Build Coastguard Workerhow much it owes to other people's version which are in the 42*90c8c64dSAndroid Build Coastguard Workerpublic domain. The idea of using a metaclass came from 43*90c8c64dSAndroid Build Coastguard Workera comment on Gary's blog (see 44*90c8c64dSAndroid Build Coastguard Workerhttp://www.garyrobinson.net/2004/03/python_singleto.html#comments). 45*90c8c64dSAndroid Build Coastguard WorkerNot guaranteed to be fit for any particular purpose. 46*90c8c64dSAndroid Build Coastguard Worker""" 47*90c8c64dSAndroid Build Coastguard Worker 48*90c8c64dSAndroid Build Coastguard Workerclass SingletonException(Exception): 49*90c8c64dSAndroid Build Coastguard Worker pass 50*90c8c64dSAndroid Build Coastguard Worker 51*90c8c64dSAndroid Build Coastguard Workerclass MetaSingleton(type): 52*90c8c64dSAndroid Build Coastguard Worker def __new__(metaclass, strName, tupBases, dict): 53*90c8c64dSAndroid Build Coastguard Worker if '__new__' in dict: 54*90c8c64dSAndroid Build Coastguard Worker raise SingletonException, 'Can not override __new__ in a Singleton' 55*90c8c64dSAndroid Build Coastguard Worker return super(MetaSingleton,metaclass).__new__(metaclass, strName, tupBases, dict) 56*90c8c64dSAndroid Build Coastguard Worker 57*90c8c64dSAndroid Build Coastguard Worker def __call__(cls, *lstArgs, **dictArgs): 58*90c8c64dSAndroid Build Coastguard Worker raise SingletonException, 'Singletons may only be instantiated through getInstance()' 59*90c8c64dSAndroid Build Coastguard Worker 60*90c8c64dSAndroid Build Coastguard Workerclass Singleton(object): 61*90c8c64dSAndroid Build Coastguard Worker __metaclass__ = MetaSingleton 62*90c8c64dSAndroid Build Coastguard Worker 63*90c8c64dSAndroid Build Coastguard Worker def getInstance(cls, *lstArgs): 64*90c8c64dSAndroid Build Coastguard Worker """ 65*90c8c64dSAndroid Build Coastguard Worker Call this to instantiate an instance or retrieve the existing instance. 66*90c8c64dSAndroid Build Coastguard Worker If the singleton requires args to be instantiated, include them the first 67*90c8c64dSAndroid Build Coastguard Worker time you call getInstance. 68*90c8c64dSAndroid Build Coastguard Worker """ 69*90c8c64dSAndroid Build Coastguard Worker if cls._isInstantiated(): 70*90c8c64dSAndroid Build Coastguard Worker if len(lstArgs) != 0: 71*90c8c64dSAndroid Build Coastguard Worker raise SingletonException, 'If no supplied args, singleton must already be instantiated, or __init__ must require no args' 72*90c8c64dSAndroid Build Coastguard Worker else: 73*90c8c64dSAndroid Build Coastguard Worker if len(lstArgs) != cls._getConstructionArgCountNotCountingSelf(): 74*90c8c64dSAndroid Build Coastguard Worker raise SingletonException, 'If the singleton requires __init__ args, supply them on first instantiation' 75*90c8c64dSAndroid Build Coastguard Worker instance = cls.__new__(cls) 76*90c8c64dSAndroid Build Coastguard Worker instance.__init__(*lstArgs) 77*90c8c64dSAndroid Build Coastguard Worker cls.cInstance = instance 78*90c8c64dSAndroid Build Coastguard Worker return cls.cInstance 79*90c8c64dSAndroid Build Coastguard Worker getInstance = classmethod(getInstance) 80*90c8c64dSAndroid Build Coastguard Worker 81*90c8c64dSAndroid Build Coastguard Worker def _isInstantiated(cls): 82*90c8c64dSAndroid Build Coastguard Worker return hasattr(cls, 'cInstance') 83*90c8c64dSAndroid Build Coastguard Worker _isInstantiated = classmethod(_isInstantiated) 84*90c8c64dSAndroid Build Coastguard Worker 85*90c8c64dSAndroid Build Coastguard Worker def _getConstructionArgCountNotCountingSelf(cls): 86*90c8c64dSAndroid Build Coastguard Worker return cls.__init__.im_func.func_code.co_argcount - 1 87*90c8c64dSAndroid Build Coastguard Worker _getConstructionArgCountNotCountingSelf = classmethod(_getConstructionArgCountNotCountingSelf) 88*90c8c64dSAndroid Build Coastguard Worker 89*90c8c64dSAndroid Build Coastguard Worker def _forgetClassInstanceReferenceForTesting(cls): 90*90c8c64dSAndroid Build Coastguard Worker """ 91*90c8c64dSAndroid Build Coastguard Worker This is designed for convenience in testing -- sometimes you 92*90c8c64dSAndroid Build Coastguard Worker want to get rid of a singleton during test code to see what 93*90c8c64dSAndroid Build Coastguard Worker happens when you call getInstance() under a new situation. 94*90c8c64dSAndroid Build Coastguard Worker 95*90c8c64dSAndroid Build Coastguard Worker To really delete the object, all external references to it 96*90c8c64dSAndroid Build Coastguard Worker also need to be deleted. 97*90c8c64dSAndroid Build Coastguard Worker """ 98*90c8c64dSAndroid Build Coastguard Worker try: 99*90c8c64dSAndroid Build Coastguard Worker delattr(cls,'cInstance') 100*90c8c64dSAndroid Build Coastguard Worker except AttributeError: 101*90c8c64dSAndroid Build Coastguard Worker # run up the chain of base classes until we find the one that has the instance 102*90c8c64dSAndroid Build Coastguard Worker # and then delete it there 103*90c8c64dSAndroid Build Coastguard Worker for baseClass in cls.__bases__: 104*90c8c64dSAndroid Build Coastguard Worker if issubclass(baseClass, Singleton): 105*90c8c64dSAndroid Build Coastguard Worker baseClass._forgetClassInstanceReferenceForTesting() 106*90c8c64dSAndroid Build Coastguard Worker _forgetClassInstanceReferenceForTesting = classmethod(_forgetClassInstanceReferenceForTesting) 107*90c8c64dSAndroid Build Coastguard Worker 108*90c8c64dSAndroid Build Coastguard Worker 109*90c8c64dSAndroid Build Coastguard Workerif __name__ == '__main__': 110*90c8c64dSAndroid Build Coastguard Worker import unittest 111*90c8c64dSAndroid Build Coastguard Worker 112*90c8c64dSAndroid Build Coastguard Worker class PublicInterfaceTest(unittest.TestCase): 113*90c8c64dSAndroid Build Coastguard Worker def testReturnsSameObject(self): 114*90c8c64dSAndroid Build Coastguard Worker """ 115*90c8c64dSAndroid Build Coastguard Worker Demonstrates normal use -- just call getInstance and it returns a singleton instance 116*90c8c64dSAndroid Build Coastguard Worker """ 117*90c8c64dSAndroid Build Coastguard Worker 118*90c8c64dSAndroid Build Coastguard Worker class A(Singleton): 119*90c8c64dSAndroid Build Coastguard Worker def __init__(self): 120*90c8c64dSAndroid Build Coastguard Worker super(A, self).__init__() 121*90c8c64dSAndroid Build Coastguard Worker 122*90c8c64dSAndroid Build Coastguard Worker a1 = A.getInstance() 123*90c8c64dSAndroid Build Coastguard Worker a2 = A.getInstance() 124*90c8c64dSAndroid Build Coastguard Worker self.assertEquals(id(a1), id(a2)) 125*90c8c64dSAndroid Build Coastguard Worker 126*90c8c64dSAndroid Build Coastguard Worker def testInstantiateWithMultiArgConstructor(self): 127*90c8c64dSAndroid Build Coastguard Worker """ 128*90c8c64dSAndroid Build Coastguard Worker If the singleton needs args to construct, include them in the first 129*90c8c64dSAndroid Build Coastguard Worker call to get instances. 130*90c8c64dSAndroid Build Coastguard Worker """ 131*90c8c64dSAndroid Build Coastguard Worker 132*90c8c64dSAndroid Build Coastguard Worker class B(Singleton): 133*90c8c64dSAndroid Build Coastguard Worker 134*90c8c64dSAndroid Build Coastguard Worker def __init__(self, arg1, arg2): 135*90c8c64dSAndroid Build Coastguard Worker super(B, self).__init__() 136*90c8c64dSAndroid Build Coastguard Worker self.arg1 = arg1 137*90c8c64dSAndroid Build Coastguard Worker self.arg2 = arg2 138*90c8c64dSAndroid Build Coastguard Worker 139*90c8c64dSAndroid Build Coastguard Worker b1 = B.getInstance('arg1 value', 'arg2 value') 140*90c8c64dSAndroid Build Coastguard Worker b2 = B.getInstance() 141*90c8c64dSAndroid Build Coastguard Worker self.assertEquals(b1.arg1, 'arg1 value') 142*90c8c64dSAndroid Build Coastguard Worker self.assertEquals(b1.arg2, 'arg2 value') 143*90c8c64dSAndroid Build Coastguard Worker self.assertEquals(id(b1), id(b2)) 144*90c8c64dSAndroid Build Coastguard Worker 145*90c8c64dSAndroid Build Coastguard Worker 146*90c8c64dSAndroid Build Coastguard Worker def testTryToInstantiateWithoutNeededArgs(self): 147*90c8c64dSAndroid Build Coastguard Worker 148*90c8c64dSAndroid Build Coastguard Worker class B(Singleton): 149*90c8c64dSAndroid Build Coastguard Worker 150*90c8c64dSAndroid Build Coastguard Worker def __init__(self, arg1, arg2): 151*90c8c64dSAndroid Build Coastguard Worker super(B, self).__init__() 152*90c8c64dSAndroid Build Coastguard Worker self.arg1 = arg1 153*90c8c64dSAndroid Build Coastguard Worker self.arg2 = arg2 154*90c8c64dSAndroid Build Coastguard Worker 155*90c8c64dSAndroid Build Coastguard Worker self.assertRaises(SingletonException, B.getInstance) 156*90c8c64dSAndroid Build Coastguard Worker 157*90c8c64dSAndroid Build Coastguard Worker def testTryToInstantiateWithoutGetInstance(self): 158*90c8c64dSAndroid Build Coastguard Worker """ 159*90c8c64dSAndroid Build Coastguard Worker Demonstrates that singletons can ONLY be instantiated through 160*90c8c64dSAndroid Build Coastguard Worker getInstance, as long as they call Singleton.__init__ during construction. 161*90c8c64dSAndroid Build Coastguard Worker 162*90c8c64dSAndroid Build Coastguard Worker If this check is not required, you don't need to call Singleton.__init__(). 163*90c8c64dSAndroid Build Coastguard Worker """ 164*90c8c64dSAndroid Build Coastguard Worker 165*90c8c64dSAndroid Build Coastguard Worker class A(Singleton): 166*90c8c64dSAndroid Build Coastguard Worker def __init__(self): 167*90c8c64dSAndroid Build Coastguard Worker super(A, self).__init__() 168*90c8c64dSAndroid Build Coastguard Worker 169*90c8c64dSAndroid Build Coastguard Worker self.assertRaises(SingletonException, A) 170*90c8c64dSAndroid Build Coastguard Worker 171*90c8c64dSAndroid Build Coastguard Worker def testDontAllowNew(self): 172*90c8c64dSAndroid Build Coastguard Worker 173*90c8c64dSAndroid Build Coastguard Worker def instantiatedAnIllegalClass(): 174*90c8c64dSAndroid Build Coastguard Worker class A(Singleton): 175*90c8c64dSAndroid Build Coastguard Worker def __init__(self): 176*90c8c64dSAndroid Build Coastguard Worker super(A, self).__init__() 177*90c8c64dSAndroid Build Coastguard Worker 178*90c8c64dSAndroid Build Coastguard Worker def __new__(metaclass, strName, tupBases, dict): 179*90c8c64dSAndroid Build Coastguard Worker return super(MetaSingleton,metaclass).__new__(metaclass, strName, tupBases, dict) 180*90c8c64dSAndroid Build Coastguard Worker 181*90c8c64dSAndroid Build Coastguard Worker self.assertRaises(SingletonException, instantiatedAnIllegalClass) 182*90c8c64dSAndroid Build Coastguard Worker 183*90c8c64dSAndroid Build Coastguard Worker 184*90c8c64dSAndroid Build Coastguard Worker def testDontAllowArgsAfterConstruction(self): 185*90c8c64dSAndroid Build Coastguard Worker class B(Singleton): 186*90c8c64dSAndroid Build Coastguard Worker 187*90c8c64dSAndroid Build Coastguard Worker def __init__(self, arg1, arg2): 188*90c8c64dSAndroid Build Coastguard Worker super(B, self).__init__() 189*90c8c64dSAndroid Build Coastguard Worker self.arg1 = arg1 190*90c8c64dSAndroid Build Coastguard Worker self.arg2 = arg2 191*90c8c64dSAndroid Build Coastguard Worker 192*90c8c64dSAndroid Build Coastguard Worker b1 = B.getInstance('arg1 value', 'arg2 value') 193*90c8c64dSAndroid Build Coastguard Worker self.assertRaises(SingletonException, B, 'arg1 value', 'arg2 value') 194*90c8c64dSAndroid Build Coastguard Worker 195*90c8c64dSAndroid Build Coastguard Worker def test_forgetClassInstanceReferenceForTesting(self): 196*90c8c64dSAndroid Build Coastguard Worker class A(Singleton): 197*90c8c64dSAndroid Build Coastguard Worker def __init__(self): 198*90c8c64dSAndroid Build Coastguard Worker super(A, self).__init__() 199*90c8c64dSAndroid Build Coastguard Worker class B(A): 200*90c8c64dSAndroid Build Coastguard Worker def __init__(self): 201*90c8c64dSAndroid Build Coastguard Worker super(B, self).__init__() 202*90c8c64dSAndroid Build Coastguard Worker 203*90c8c64dSAndroid Build Coastguard Worker # check that changing the class after forgetting the instance produces 204*90c8c64dSAndroid Build Coastguard Worker # an instance of the new class 205*90c8c64dSAndroid Build Coastguard Worker a = A.getInstance() 206*90c8c64dSAndroid Build Coastguard Worker assert a.__class__.__name__ == 'A' 207*90c8c64dSAndroid Build Coastguard Worker A._forgetClassInstanceReferenceForTesting() 208*90c8c64dSAndroid Build Coastguard Worker b = B.getInstance() 209*90c8c64dSAndroid Build Coastguard Worker assert b.__class__.__name__ == 'B' 210*90c8c64dSAndroid Build Coastguard Worker 211*90c8c64dSAndroid Build Coastguard Worker # check that invoking the 'forget' on a subclass still deletes the instance 212*90c8c64dSAndroid Build Coastguard Worker B._forgetClassInstanceReferenceForTesting() 213*90c8c64dSAndroid Build Coastguard Worker a = A.getInstance() 214*90c8c64dSAndroid Build Coastguard Worker B._forgetClassInstanceReferenceForTesting() 215*90c8c64dSAndroid Build Coastguard Worker b = B.getInstance() 216*90c8c64dSAndroid Build Coastguard Worker assert b.__class__.__name__ == 'B' 217*90c8c64dSAndroid Build Coastguard Worker 218*90c8c64dSAndroid Build Coastguard Worker unittest.main() 219*90c8c64dSAndroid Build Coastguard Worker 220*90c8c64dSAndroid Build Coastguard Worker 221