m๒ ,แธEc@s<dZdklZdkZdklZy dkZWnej on/Xd„Zd„Z d„Z d„Z d„Z d „Z d „Zd „Zd efd „ƒYZd„Zdefd„ƒYZd„Zdefd„ƒYZdefd„ƒYZd„Zdefd„ƒYZd„Zd„Zd„ZdS(sxTest ExtensionClass support in Persistence.Persistent $Id: test_ExtensionClass.py 29896 2005-04-07 04:48:06Z tim_one $ (s DocTestSuiteN(s PersistentcCsdS(s) >>> from ExtensionClass import Base - Support for a class initialiser: >>> class C(Persistent): ... def __class_init__(self): ... print 'class init called' ... print self.__name__ ... def bar(self): ... return 'bar called' class init called C >>> c = C() >>> int(c.__class__ is C) 1 >>> int(c.__class__ is type(c)) 1 - Provide an inheritedAttribute method for looking up attributes in base classes: >>> class C2(C): ... def bar(*a): ... return C2.inheritedAttribute('bar')(*a), 42 class init called C2 >>> o = C2() >>> o.bar() ('bar called', 42) This is for compatability with old code. New code should use super instead. The base class, Base, exists mainly to support the __of__ protocol. The __of__ protocol is similar to __get__ except that __of__ is called when an implementor is retrieved from an instance as well as from a class: >>> class O(Base): ... def __of__(*a): ... return a >>> o1 = O() >>> o2 = O() >>> C.o1 = o1 >>> c.o2 = o2 >>> c.o1 == (o1, c) 1 >>> C.o1 == o1 1 >>> int(c.o2 == (o2, c)) 1 We accomplish this by making a class that implements __of__ a descriptor and treating all descriptor ExtensionClasses this way. That is, if an extension class is a descriptor, it's __get__ method will be called even when it is retrieved from an instance. >>> class O(Base): ... def __get__(*a): ... return a ... >>> o1 = O() >>> o2 = O() >>> C.o1 = o1 >>> c.o2 = o2 >>> int(c.o1 == (o1, c, type(c))) 1 >>> int(C.o1 == (o1, None, type(c))) 1 >>> int(c.o2 == (o2, c, type(c))) 1 N((((tD/data/zmath/zope/lib/python/Persistence/tests/test_ExtensionClass.pyt test_basic sKcCsdS(s˜Test working with a classic class >>> class Classic: ... def x(self): ... return 42 >>> class O(Persistent): ... def __of__(*a): ... return a >>> class O2(Classic, O): ... def __of__(*a): ... return (O2.inheritedAttribute('__of__')(*a), ... O2.inheritedAttribute('x')(a[0])) >>> class C(Persistent): ... def __class_init__(self): ... print 'class init called' ... print self.__name__ ... def bar(self): ... return 'bar called' class init called C >>> c = C() >>> o2 = O2() >>> c.o2 = o2 >>> int(c.o2 == ((o2, c), 42)) 1 Test working with a new style >>> class Modern(object): ... def x(self): ... return 42 >>> class O2(Modern, O): ... def __of__(*a): ... return (O2.inheritedAttribute('__of__')(*a), ... O2.inheritedAttribute('x')(a[0])) >>> o2 = O2() >>> c.o2 = o2 >>> int(c.o2 == ((o2, c), 42)) 1 N((((Rt test_mixingms/cCsdS(sˆ Florent Guillaume wrote: ... Excellent. Will it also fix this particularity of ExtensionClass: >>> class A(Persistent): ... def foo(self): ... self.gee ... def bar(self): ... del self.gee >>> a=A() >>> a.foo() Traceback (most recent call last): ... AttributeError: gee >>> a.bar() Traceback (most recent call last): ... AttributeError: 'A' object has no attribute 'gee' I.e., the fact that KeyError is raised whereas a normal class would raise AttributeError. N((((Rtproper_error_on_deleattržscCsdS(sQ >>> x = Simple.__basicnew__() >>> x.__dict__ {} N((((Rttest__basicnew__ฝscCsdS(sZ >>> for name in 'x', '_x', 'x_', '__x_y__', '___x__', '__x___', '_x_': ... setattr(Persistent, name, 1) ... print getattr(Persistent, name) ... delattr(Persistent, name) ... print getattr(Persistent, name, 0) 1 0 1 0 1 0 1 0 1 0 1 0 1 0 >>> Persistent.__foo__ = 1 Traceback (most recent call last): ... TypeError: can't set attributes of built-in/extension type 'Persistence.Persistent' if the attribute name begins and ends with __ and contains only 4 _ characters >>> Persistent.__foo__ Traceback (most recent call last): ... AttributeError: type object 'Persistence.Persistent' has no attribute '__foo__' >>> del Persistent.__foo__ Traceback (most recent call last): ... TypeError: can't set attributes of built-in/extension type 'Persistence.Persistent' if the attribute name begins and ends with __ and contains only 4 _ characters N((((Rttest_setattr_on_extension_typeฤscCsdS(s๏ >>> for i in range(100): ... class B(Persistent): ... print i, ... if i and i%20 == 0: ... print 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 >>> import gc >>> x = gc.collect() N((((Rt test_class_creation_under_stress๐scCsW|iƒ}|iƒddig}|D]\}}|d||fq*~ƒGHdS(Ns{%s}s, s%r: %r(tdtitemstsorttjoint_[1]tktv(RR R R ((Rt print_dicts  cGscx\|D]T}|d djoqntt||dƒt||dƒƒ}|o|SqqWdS(Nit_v_t_p_i(RR(tattrstattrtcmptgetattrtselftNonetothertc(RRRRR((Rtcmpattrs s' tSimplecBstZd„Zd„ZRS(NcKs/||_|ii|ƒd|_d|_dS(Ntbluetbar(tnameRt__name__t__dict__tupdatetkwt_v_favorite_colort_p_foo(RRR!((Rt__init__s  cCst||d|iiƒŒS(Nt __class__(RRRRtkeys(RR((Rt__cmp__s(Rt __module__R$R'(((RRs cCsdS(sn >>> x = Simple('x', aaa=1, bbb='foo') >>> print_dict(x.__getstate__()) {'__name__': 'x', 'aaa': 1, 'bbb': 'foo'} >>> f, (c,), state = x.__reduce__() >>> f.__name__ '__newobj__' >>> f.__module__ 'copy_reg' >>> c.__name__ 'Simple' >>> print_dict(state) {'__name__': 'x', 'aaa': 1, 'bbb': 'foo'} >>> pickle.loads(pickle.dumps(x)) == x 1 >>> pickle.loads(pickle.dumps(x, 0)) == x 1 >>> pickle.loads(pickle.dumps(x, 1)) == x 1 >>> pickle.loads(pickle.dumps(x, 2)) == x 1 >>> x.__setstate__({'z': 1}) >>> x.__dict__ {'z': 1} N((((Rttest_basic_picklingstCustomcBs5tZd„Zd„Zd„Zd„Zd„ZRS(NcCs&ti|ƒ}|||_|_|S(N(t Persistentt__new__tclstrtxty(R-R/R0R.((RR,?scCs d|_dS(Ni*(Rta(RR/R0((RR$DscCs|i|ifS(N(RR/R0(R((Rt__getnewargs__GscCs|iS(N(RR1(R((Rt __getstate__JscCs ||_dS(N(R1R(RR1((Rt __setstate__Ms(RR(R,R$R2R3R4(((RR*=s     cCsdS(sฝ >>> x = Custom('x', 'y') >>> x.a = 99 >>> (f, (c, ax, ay), a) = x.__reduce__() >>> f.__name__ '__newobj__' >>> f.__module__ 'copy_reg' >>> c.__name__ 'Custom' >>> ax, ay, a ('x', 'y', 99) >>> pickle.loads(pickle.dumps(x)) == x 1 >>> pickle.loads(pickle.dumps(x, 0)) == x 1 >>> pickle.loads(pickle.dumps(x, 1)) == x 1 >>> pickle.loads(pickle.dumps(x, 2)) == x 1 N((((Rttest_pickling_w_overridesQstSlottedcBstZdZd„ZRS(Nts1ts2t_p_splatt_v_eekcCs)|||_|_d|_d|_dS(Nii(R7R8RR:R9(RR7R8((RR$ms (ss1ss2s_p_splats_v_eek(RR(t __slots__R$(((RR6kst SubSlottedcBs tZdZd„Zd„ZRS(Nts3ts4cCs ti|||ƒ||_dS(N(R6R$RR7R8R=(RR7R8R=((RR$tscCst||dddddƒS(NR%R7R8R=R>(RRR(RR((RR'ys(ss3ss4(RR(R;R$R'(((RR<rs cCsdS(sป >>> x = SubSlotted('x', 'y', 'z') >>> d, s = x.__getstate__() >>> d >>> print_dict(s) {'s1': 'x', 's2': 'y', 's3': 'z'} >>> pickle.loads(pickle.dumps(x)) == x 1 >>> pickle.loads(pickle.dumps(x, 0)) == x 1 >>> pickle.loads(pickle.dumps(x, 1)) == x 1 >>> pickle.loads(pickle.dumps(x, 2)) == x 1 >>> x.s4 = 'spam' >>> d, s = x.__getstate__() >>> d >>> print_dict(s) {'s1': 'x', 's2': 'y', 's3': 'z', 's4': 'spam'} >>> pickle.loads(pickle.dumps(x)) == x 1 >>> pickle.loads(pickle.dumps(x, 0)) == x 1 >>> pickle.loads(pickle.dumps(x, 1)) == x 1 >>> pickle.loads(pickle.dumps(x, 2)) == x 1 N((((Rttest_pickling_w_slots_only}s"t SubSubSlottedcBstZd„Zd„ZRS(NcKs<ti||||ƒ|ii|ƒd|_ d|_ dS(NRR( R<R$RR7R8R=RR R!R"R#(RR7R8R=R!((RR$ฃs c Cs(t||ddddd|iiƒŒS(NR%R7R8R=R>(RRRRR&(RR((RR'ฉs (RR(R$R'(((RR@กs cCsdS(s" >>> x = SubSubSlotted('x', 'y', 'z', aaa=1, bbb='foo') >>> d, s = x.__getstate__() >>> print_dict(d) {'aaa': 1, 'bbb': 'foo'} >>> print_dict(s) {'s1': 'x', 's2': 'y', 's3': 'z'} >>> pickle.loads(pickle.dumps(x)) == x 1 >>> pickle.loads(pickle.dumps(x, 0)) == x 1 >>> pickle.loads(pickle.dumps(x, 1)) == x 1 >>> pickle.loads(pickle.dumps(x, 2)) == x 1 >>> x.s4 = 'spam' >>> d, s = x.__getstate__() >>> print_dict(d) {'aaa': 1, 'bbb': 'foo'} >>> print_dict(s) {'s1': 'x', 's2': 'y', 's3': 'z', 's4': 'spam'} >>> pickle.loads(pickle.dumps(x)) == x 1 >>> pickle.loads(pickle.dumps(x, 0)) == x 1 >>> pickle.loads(pickle.dumps(x, 1)) == x 1 >>> pickle.loads(pickle.dumps(x, 2)) == x 1 N((((Rttest_pickling_w_slotsฎs$cCsdS(sไ >>> x = SubSubSlotted('x', 'y', 'z') >>> d, s = x.__getstate__() >>> print_dict(d) {} >>> print_dict(s) {'s1': 'x', 's2': 'y', 's3': 'z'} >>> pickle.loads(pickle.dumps(x)) == x 1 >>> pickle.loads(pickle.dumps(x, 0)) == x 1 >>> pickle.loads(pickle.dumps(x, 1)) == x 1 >>> pickle.loads(pickle.dumps(x, 2)) == x 1 >>> x.s4 = 'spam' >>> d, s = x.__getstate__() >>> print_dict(d) {} >>> print_dict(s) {'s1': 'x', 's2': 'y', 's3': 'z', 's4': 'spam'} >>> pickle.loads(pickle.dumps(x)) == x 1 >>> pickle.loads(pickle.dumps(x, 0)) == x 1 >>> pickle.loads(pickle.dumps(x, 1)) == x 1 >>> pickle.loads(pickle.dumps(x, 2)) == x 1 N((((Rt"test_pickling_w_slots_w_empty_dictิs$cCstƒS(N(t DocTestSuite(((Rt test_suite๚s(t__doc__tzope.testing.doctestRCtpicklet PersistenceR+tPersistence._Persistencet ImportErrorRRRRRRRRRR)R*R5R6R<R?R@RARBRD(R6R<RR@R*RRRRHR5R?R)RRCR+RRRARRDRBRRG((Rt?s4     M 1   ,    !  $ & &