[Zope3-Users] Re: Evolution of ZoDB after changing python modules structure (moving content classes to another module)

Rupert Redington rupert at neontribe.co.uk
Tue Jun 12 06:59:01 EDT 2007


Aleksander Kowalczyk wrote:
> On 6/8/07, Alek Kowalczyk <thealx at poczta.onet.pl> wrote:
>>
>> Alek Kowalczyk <thealx at ...> writes:
>>
>> >
>> > Hi,
>> > I moved my content class from mypackage.mymodule.MyContentClass into
>> > mypackage.mysubpackage.mymodule.MyContentClass.
>> > But when started Zope and went to visit an object I have previously
>> created (of
>> > MyContentClass), I get:
>> > ComponentLookupError: ((<persistent broken
>> mypackage.mymodule.MyContentClass
>> > instance '\x00\x00\x00\x00\x00\x00\x02q'>,
>> > <zope.publisher.browser.BrowserRequest instance
>>
> I found a quite well working solution on
>> http://mail.zope.org/pipermail/zodb-dev/2006-September/010382.html
>>
>> There was only one issue: this solution assumes that we have given a DB,
>> while
>> Zope evolve method receives already open connection. Unfortunately
>> classFactory
>> from DB is cached in Connection's private fields in constructor.
>> Because of that I could not assign my custom 'renaming' class factory
>> using:
>>
>> def evolve(context): #won't work!
>>     context.connection.db().classFactory = myClassFactory
>>
>> Instead I had to do some dirty private fields substitution in
>> Connection's
>> ObjectReader:
>>
>> def evolve(context): #this works nice
>>     context.connection._reader._factory = myClassFactory
> 
> 
> I shouldn't announce success too early. The solution works but only during
> first Zope run (i.e just after evolving the schema).
> Although classFactory returns proper class during evolve, the new class
> name
> is not saved in ZoDB, so after next unghosting object get old class names
> again.
> 
> Here is my evolve script. I really don't know what more should I do to make
> Zope/ZoDB write the new class name in ZoDB. Can someone help me a bit... :)
> ?
> 
> def convertingClassFactory(connection, moduleName, globalName):
>    #convert class name to new one and return the class object
> 
> def evolve(context):
>    #dirty hack to substitute classFactory
>    context.connection._reader._factory = convertingClassFactory
>    root = context.connection.root().get(ZopePublication.root_name, None)
>    for object in findObjectsMatching(root, lambda x: True):
>        if hasattr(object, '_p_activate'):
>            object._p_activate()
>            object._p_changed = True
> 

Somebody correct me if I'm wrong
I imagine you'd need to commit the transaction manually:


 def evolve(context):
    #dirty hack to substitute classFactory
    context.connection._reader._factory = convertingClassFactory
    root = context.connection.root().get(ZopePublication.root_name, None)
    for object in findObjectsMatching(root, lambda x: True):
         if hasattr(object, '_p_activate'):
            object._p_activate()
            object._p_changed = True
    import transaction
    transaction.commit()


Hope that helps,

Rupert


More information about the Zope3-users mailing list