mς TγΈEc@s‹dZdkZdkZhZdefd„ƒYZeed„Zd„Zde fd„ƒYZ deei fd „ƒYZ d „Z dS( sKBroken object support $Id: broken.py 29446 2005-03-11 22:07:51Z tim_one $ NtBrokencBsTtZdZeZZdZd„Zd„Zd„Zd„Z d„Z d„Z RS(s Broken object base class Broken objects are placeholders for objects that can no longer be created because their class has gone away. Broken objects don't really do much of anything, except hold their state. The Broken class is used as a base class for creating classes in leu of missing classes:: >>> Atall = type('Atall', (Broken, ), {'__module__': 'not.there'}) The only thing the class can be used for is to create new objects:: >>> Atall() >>> Atall().__Broken_newargs__ () >>> Atall().__Broken_initargs__ () >>> Atall(1, 2).__Broken_newargs__ (1, 2) >>> Atall(1, 2).__Broken_initargs__ (1, 2) >>> a = Atall.__new__(Atall, 1, 2) >>> a >>> a.__Broken_newargs__ (1, 2) >>> a.__Broken_initargs__ You can't modify broken objects:: >>> a.x = 1 Traceback (most recent call last): ... BrokenModified: Can't change broken objects But you can set their state:: >>> a.__setstate__({'x': 1, }) You can pickle broken objects:: >>> r = a.__reduce__() >>> len(r) 3 >>> r[0] is rebuild True >>> r[1] ('not.there', 'Atall', 1, 2) >>> r[2] {'x': 1} >>> import cPickle >>> a2 = cPickle.loads(cPickle.dumps(a, 1)) >>> a2 >>> a2.__Broken_newargs__ (1, 2) >>> a2.__Broken_initargs__ >>> a2.__Broken_state__ {'x': 1} Cleanup:: >>> broken_cache.clear() s broken objectcGs ti|ƒ}||id<|S(Nt__Broken_newargs__(tobjectt__new__tclass_tresulttargst__dict__(RRR((t*/data/zmath/zope/lib/python/ZODB/broken.pyRcs cGs||id(R R RR(R ((Rt__repr__wscCstdƒ‚dS(NsCan't change broken objects(tBrokenModified(R tnametvalue((Rt __setattr__{s( RRt__doc__tNoneRR RR RRRR(((RRs E     cCs²yt|ƒWntj on6Xti|}yt||ƒSWntj onXyt ||fSWnt j onX|||fhd|<ƒ}|t ||f<|S(sτFind a global object, returning a broken class if it can't be found. This function looks up global variable in modules:: >>> import sys >>> find_global('sys', 'path') is sys.path True If an object can't be found, a broken class is returned:: >>> broken = find_global('ZODB.not.there', 'atall') >>> issubclass(broken, Broken) True >>> broken.__module__ 'ZODB.not.there' >>> broken.__name__ 'atall' Broken classes are cached:: >>> find_global('ZODB.not.there', 'atall') is broken True If we "repair" a missing global:: >>> class ZODBnotthere: ... atall = [] >>> sys.modules['ZODB.not'] = ZODBnotthere >>> sys.modules['ZODB.not.there'] = ZODBnotthere we can then get the repaired value:: >>> find_global('ZODB.not.there', 'atall') is ZODBnotthere.atall True Of course, if we beak it again:: >>> del sys.modules['ZODB.not'] >>> del sys.modules['ZODB.not.there'] we get the broken value:: >>> find_global('ZODB.not.there', 'atall') is broken True Cleanup:: >>> broken_cache.clear() RN(t __import__t modulenamet ImportErrortsystmodulestmoduletgetattrt globalnametAttributeErrort broken_cachetKeyErrorttypeRR(RR"RR&RR ((Rt find_global~s"5 cGst||ƒ}|i||ŒS(s©Recreate a broken object, possibly recreating the missing class This functions unpickles broken objects:: >>> broken = rebuild('ZODB.notthere', 'atall', 1, 2) >>> broken >>> broken.__Broken_newargs__ (1, 2) If we "repair" the brokenness:: >>> class notthere: # fake notthere module ... class atall(object): ... def __new__(self, *args): ... ob = object.__new__(self) ... ob.args = args ... return ob ... def __repr__(self): ... return 'atall %s %s' % self.args >>> sys.modules['ZODB.notthere'] = notthere >>> rebuild('ZODB.notthere', 'atall', 1, 2) atall 1 2 >>> del sys.modules['ZODB.notthere'] Cleanup:: >>> broken_cache.clear() N(R'RR"RRR(RR"RR((RR Θs!RcBstZdZRS(s&Attempt to modify a broken object (RRR(((RRνs tPersistentBrokencBsDtZdZd„Zd„Zd„Zd„Zd„Zd„ZRS(sΰPersistent broken objects Persistent broken objects are used for broken objects that are also persistent. In addition to having to track the original object data, they need to handle persistent meta data. Persistent broken classes are created from existing broken classes using the persistentBroken, function:: >>> Atall = type('Atall', (Broken, ), {'__module__': 'not.there'}) >>> PAtall = persistentBroken(Atall) (Note that we always get the *same* persistent broken class for a given broken class:: >>> persistentBroken(Atall) is PAtall True ) Persistent broken classes work a lot like broken classes:: >>> a = PAtall.__new__(PAtall, 1, 2) >>> a >>> a.__Broken_newargs__ (1, 2) >>> a.__Broken_initargs__ >>> a.x = 1 Traceback (most recent call last): ... BrokenModified: Can't change broken objects Unlike regular broken objects, persistent broken objects keep track of persistence meta data: >>> a._p_oid = '\0\0\0\0****' >>> a and persistent broken objects aren't directly picklable: >>> a.__reduce__() Traceback (most recent call last): ... BrokenModified: but you can get their state: >>> a.__setstate__({'y': 2}) >>> a.__getstate__() {'y': 2} Cleanup:: >>> broken_cache.clear() cGs#tii|ƒ}||id<|S(NR(t persistentt PersistentRRRRR(RRR((RR.s cGst|ƒ‚dS(N(RR (R R((RR3scCs|iS(N(R R(R ((Rt __getstate__6scCs:|idƒotii|||ƒn tdƒ‚dS(Nt_p_sCan't change broken objects(Rt startswithR)R*RR RR(R RR((RR9scCs d|ii|ii|ifS(Ns%(R R RRt_p_oid(R ((RR?scCs|iS(N(R R(R ((Rt__getnewargs__Ds( RRRRRR+RRR/(((RR(ρs .     cCs^y|idSWnHtj o<t|it|fhd|i<ƒ|_|idSnXdS(Nt__Broken_Persistent__R(RRR%R&RR(RR0(R((RtpersistentBrokenGs  (RRR)R$RRR&R'R t TypeErrorRR*R(R1( R(R1R R)RRR$R'R((Rt?s  fJ %V