durusmail: durus-users: Mutating __class__ of persistent classes
Mutating __class__ of persistent classes
2006-02-08
2006-02-08
2006-02-08
2006-02-09
Mutating __class__ of persistent classes
A.M. Kuchling
2006-02-08
For a database update script, I want to change the __class__ attribute
of certain objects from class A to class B.  (Not *all* class A
instances need to be changed, so I can't just rename the classes.)

The obvious way of doing this, assigning to __class__, doesn't seem to
work, but I don't see why.  The change takes effect in the process,
and even seems to be committed properly (the .durus file grows and the
record that's written does seem to contain the string '__main__.B'),
but the object stubbornly remains an instance of A.

A test script is below.  If you run it twice, you get this output:

root@bona:~/.ace# python t.py
Existing  '\x00\x00\x00\x00\x00\x00C\x18' 1
Creating new object
After commit:  '\x00\x00\x00\x00\x00\x00C\x19' 3


root@bona:~/.ace# python t.py
Existing  '\x00\x00\x00\x00\x00\x00C\x19' 3
Creating new object
After commit:  '\x00\x00\x00\x00\x00\x00C\x1a' 3
root@bona:~/.ace#

Note that the object with the same OID 'C\x19' has a different
__class__ at the end of the first and the start of the second
execution, but an attribute value (the '3') matches.  Is __class__
treated specially in some way?

I can't shake the feeling I'm missing something stupid and obvious
here.  Is there something bogus in my test program?

--amk


from durus.connection import Connection
from durus.client_storage import ClientStorage
from durus.persistent import Persistent

class A (Persistent):
     pass

class B (Persistent):
     pass

class Dummy (Persistent):
     pass

# Change this to your server.
hostname = 'bona'
connection = Connection(ClientStorage(host=hostname), cache_size=12000)

root = connection.get_root()
#del root['a']
if root.has_key('a'):
    base = root['a']
else:
    base = Dummy()
    root['a'] = base
    base.obj = A()
    base.obj.a = 1
    connection.commit()

# Print class of existing object
base = root['a']
obj = base.obj
print 'Existing', obj.__class__, repr(obj._p_oid), obj.a

print 'Creating new object'
base.obj = A()
base.obj.a = 2
connection.commit()

# Change object's __class__ to B
root = connection.get_root()
base = root['a']
obj = base.obj
##print 'is ghost?', obj._p_is_ghost()
obj.__class__ = B
obj.a = obj.a + 1
obj._p_note_change()
connection.commit()

# Print class, OID after commit
root = connection.get_root()
base = root['a']
obj = base.obj
print 'After commit:', obj.__class__, repr(obj._p_oid), obj.a
reply