<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv=Content-Type content="text/html; charset=us-ascii">
<META content="MSHTML 6.00.2900.3243" name=GENERATOR></HEAD>
<BODY 
style="WORD-WRAP: break-word; webkit-nbsp-mode: space; webkit-line-break: after-white-space">
<DIV dir=ltr align=left><FONT face=Arial color=#0000ff size=2><SPAN 
class=884500616-17012008>Thanks David, you are correct.&nbsp; I now am testing 
in the correct order, and everything works as expected for a simple 
attribute.&nbsp; Where I have been runing awry is when the the attribute is a 
class.&nbsp; I have assembled another example below.&nbsp; Thanks also to Tres 
Sever who suggested the following with the first example I 
sent:</SPAN></FONT></DIV>
<DIV dir=ltr align=left><FONT><SPAN class=884500616-17012008><FONT face=Arial 
color=#0000ff size=2></FONT></SPAN></FONT>&nbsp;</DIV>
<DIV dir=ltr align=left><FONT><SPAN class=884500616-17012008><FONT face=Arial 
color=#0000ff size=2>You are mutating the object *inside* your __setstate__: the 
ZODB persistence machinery clears the '_p_changed' flag after you *exit* 
from<SPAN class=884500616-17012008> </SPAN>'__setstate__': the protocol is not 
intended to support a persistent "write-on-read".</FONT></SPAN></FONT></DIV>
<DIV dir=ltr align=left><FONT><SPAN class=884500616-17012008><FONT face=Arial 
color=#0000ff size=2></FONT></SPAN></FONT>&nbsp;</DIV>
<DIV dir=ltr align=left><FONT><SPAN class=884500616-17012008><FONT face=Arial 
color=#0000ff size=2>I can accept this, but after returning from the 
__setstate__, I further modify the object and commit the transaction (see 
test_2_setstate).&nbsp; This should persist as I understand it.&nbsp; Why does 
it not?&nbsp; The reason I am persisting with this is the __setstate__ offers an 
elegant way to upgrade existing objects--something I find myself doing 
often.</FONT></SPAN></FONT></DIV>
<DIV dir=ltr align=left><FONT><SPAN class=884500616-17012008><FONT face=Arial 
color=#0000ff size=2></FONT></SPAN></FONT>&nbsp;</DIV>
<DIV dir=ltr align=left><FONT><SPAN class=884500616-17012008><FONT face=Arial 
color=#0000ff size=2>---------------------------------------------</DIV>
<DIV></FONT></SPAN></FONT><FONT face=Arial color=#0000ff size=2>import 
transaction<BR>import unittest<BR>from persistent import Persistent<BR>from ZODB 
import FileStorage, DB</FONT></DIV>
<DIV><FONT face=Arial color=#0000ff size=2></FONT>&nbsp;</DIV>
<DIV><FONT face=Arial color=#0000ff size=2>TMP_DB = 
'zodb-test-filestorage.fs'</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Arial color=#0000ff size=2>class 
Color(Persistent):<BR>&nbsp;&nbsp;&nbsp; def 
__init__(self):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.color = 
'blue'<BR>&nbsp;&nbsp;&nbsp; def setColor(self, 
color):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.color = 
color</FONT></DIV>
<DIV><SPAN class=884500616-17012008></SPAN><FONT face=Arial color=#0000ff 
size=2>&nbsp;<SPAN 
class=884500616-17012008>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;transaction.commit()</SPAN><BR>&nbsp;&nbsp;&nbsp; 
def getColor(self):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 
self.color</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Arial color=#0000ff size=2>class 
User(Persistent):<BR>&nbsp;&nbsp;&nbsp; def 
__init__(self):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
pass<BR>&nbsp;&nbsp;&nbsp; def __setstate__(self, 
state):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
Persistent.__setstate__(self, 
state)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not hasattr(self, 
'color'):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
print 'adding 
color'<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
self.color = Color()<BR>&nbsp;&nbsp;&nbsp; def 
getColor(self):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 
self.color.getColor()<BR>&nbsp;&nbsp;&nbsp; def setColor(self, 
color):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
self.color.setColor(color)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
transaction.commit()</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Arial color=#0000ff size=2>class 
ZODB_TestCase(unittest.TestCase):<BR>&nbsp;&nbsp;&nbsp; def 
setUp(self):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; storage = 
FileStorage.FileStorage(TMP_DB)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
self.db = DB(storage)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn = 
self.db.open()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbroot = 
conn.root()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Ensure that a 
'userdb' key is present<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # in the 
root<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not 
dbroot.has_key('userdb'):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
from BTrees.OOBTree import 
OOBTree<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
dbroot['userdb'] = OOBTree()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
self.userdb = dbroot['userdb']</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Arial color=#0000ff 
size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.id = 'amk'</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Arial color=#0000ff size=2>&nbsp;&nbsp;&nbsp; def 
tearDown(self):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
self.db.close()</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Arial color=#0000ff size=2>&nbsp;&nbsp;&nbsp; def 
test_1_AddUser(self):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print 'in 
test1'<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newuser = 
User()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newuser.first_name = 
'Andrew'; newuser.last_name = 
'Kuchling'<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Add object to the 
BTree, keyed on the ID<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
self.userdb[self.id] = newuser<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 
Commit the change<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
transaction.commit()</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Arial color=#0000ff 
size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # setstate is not called after 
the constructor<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assert not 
hasattr(newuser, 'color')</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Arial color=#0000ff size=2>&nbsp;&nbsp;&nbsp; def 
test_2_setstate(self):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print 'in 
test2'<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newuser = 
self.userdb[self.id]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # setstate is 
called subsequently<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assert 
hasattr(newuser, 'color')<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assert 
newuser.getColor() == 'blue'<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
newuser.setColor('red')<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assert 
newuser.getColor() == 'red'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Arial color=#0000ff size=2>&nbsp;&nbsp;&nbsp; def 
test_3_persistence(self):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print 
'in test3'<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newuser = 
self.userdb[self.id]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assert 
newuser.getColor() == 'red'</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Arial color=#0000ff size=2>if __name__ == 
'__main__':<BR>&nbsp;&nbsp;&nbsp; import os<BR>&nbsp;&nbsp;&nbsp; if 
os.path.exists(TMP_DB):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
os.unlink(TMP_DB)<BR>&nbsp;&nbsp;&nbsp; unittest.main()</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><SPAN class=884500616-17012008></SPAN><FONT face=Arial><FONT 
color=#0000ff><FONT size=2>-<SPAN 
class=884500616-17012008>------------------------------------------------------</SPAN></FONT></FONT></FONT><BR></DIV>
<DIV class=OutlookMessageHeader lang=en-us dir=ltr align=left>
<HR tabIndex=-1>
</DIV>
<DIV></DIV>
<DIV>Hi David,</DIV>
<DIV><FONT face=Arial color=#0000ff size=2></FONT><BR 
class=webkit-block-placeholder></DIV>
<DIV>It&nbsp;looks&nbsp;like&nbsp;you&nbsp;might&nbsp;be&nbsp;assuming&nbsp;that&nbsp;the&nbsp;tests&nbsp;run&nbsp;in&nbsp;the&nbsp;order</DIV>
<DIV>you&nbsp;wrote&nbsp;them.&nbsp;&nbsp;The&nbsp;test_persistence()&nbsp;function&nbsp;actually&nbsp;gets&nbsp;called</DIV>
<DIV>before&nbsp;the&nbsp;test_setstate(), so there is no chance for the color 
to be 'red'.</DIV>
<DIV><FONT face=Arial color=#0000ff size=2></FONT><BR></DIV>
<DIV>I don't think the failure of this particular test has anything to do 
with&nbsp;</DIV>
<DIV>your __setstate__() method. &nbsp;When I write __setstate__() 
methods,</DIV>
<DIV>though, &nbsp;I modify the state dictionary and then call 
Persistent.__setstate__. &nbsp;</DIV>
<DIV>This&nbsp;avoids triggering the persistent attribute machinery at 
all.</DIV>
<DIV><FONT face=Arial color=#0000ff size=2></FONT><BR></DIV>
<DIV>David Binger</DIV>
<DIV><FONT face=Arial color=#0000ff size=2></FONT><BR></DIV>
<DIV>
<DIV><FONT face=Arial color=#0000ff 
size=2></FONT>&nbsp;</DIV></DIV></BODY></HTML>