[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