Thanks David, you are correct. I now am testing in the correct order, and everything works as expected for a simple attribute. Where I have been runing awry is when the the attribute is a class. I have assembled another example below. Thanks also to Tres Sever who suggested the following with the first example I sent: You are mutating the object *inside* your __setstate__: the ZODB persistence machinery clears the '_p_changed' flag after you *exit* from '__setstate__': the protocol is not intended to support a persistent "write-on-read". I can accept this, but after returning from the __setstate__, I further modify the object and commit the transaction (see test_2_setstate). This should persist as I understand it. Why does it not? The reason I am persisting with this is the __setstate__ offers an elegant way to upgrade existing objects--something I find myself doing often. --------------------------------------------- import transaction import unittest from persistent import Persistent from ZODB import FileStorage, DB TMP_DB = 'zodb-test-filestorage.fs' class Color(Persistent): def __init__(self): self.color = 'blue' def setColor(self, color): self.color = color transaction.commit() def getColor(self): return self.color class User(Persistent): def __init__(self): pass def __setstate__(self, state): Persistent.__setstate__(self, state) if not hasattr(self, 'color'): print 'adding color' self.color = Color() def getColor(self): return self.color.getColor() def setColor(self, color): self.color.setColor(color) transaction.commit() class ZODB_TestCase(unittest.TestCase): def setUp(self): storage = FileStorage.FileStorage(TMP_DB) self.db = DB(storage) conn = self.db.open() dbroot = conn.root() # Ensure that a 'userdb' key is present # in the root if not dbroot.has_key('userdb'): from BTrees.OOBTree import OOBTree dbroot['userdb'] = OOBTree() self.userdb = dbroot['userdb'] self.id = 'amk' def tearDown(self): self.db.close() def test_1_AddUser(self): print 'in test1' newuser = User() newuser.first_name = 'Andrew'; newuser.last_name = 'Kuchling' # Add object to the BTree, keyed on the ID self.userdb[self.id] = newuser # Commit the change transaction.commit() # setstate is not called after the constructor assert not hasattr(newuser, 'color') def test_2_setstate(self): print 'in test2' newuser = self.userdb[self.id] # setstate is called subsequently assert hasattr(newuser, 'color') assert newuser.getColor() == 'blue' newuser.setColor('red') assert newuser.getColor() == 'red' def test_3_persistence(self): print 'in test3' newuser = self.userdb[self.id] assert newuser.getColor() == 'red' if __name__ == '__main__': import os if os.path.exists(TMP_DB): os.unlink(TMP_DB) unittest.main() -------------------------------------------------------
________________________________ Hi David, It looks like you might be assuming that the tests run in the order you wrote them. The test_persistence() function actually gets called before the test_setstate(), so there is no chance for the color to be 'red'. I don't think the failure of this particular test has anything to do with your __setstate__() method. When I write __setstate__() methods, though, I modify the state dictionary and then call Persistent.__setstate__. This avoids triggering the persistent attribute machinery at all. David Binger
_______________________________________________ For more information about ZODB, see the ZODB Wiki: http://www.zope.org/Wikis/ZODB/ ZODB-Dev mailing list - ZODB-Dev@zope.org http://mail.zope.org/mailman/listinfo/zodb-dev