[ZODB-Dev] Why does this useage of __setstate__ fail?

Mika, David P (GE, Research) mika at crd.ge.com
Thu Jan 17 11:21:30 EST 2008


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


 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.zope.org/pipermail/zodb-dev/attachments/20080117/92ceb059/attachment-0001.htm


More information about the ZODB-Dev mailing list