Re: [Zope3-Users] Re: Evolution of ZoDB after changing python modules structure (moving content classes to another module)
On Sun, Jun 10, 2007 at 09:14:24AM +0200, Aleksander Kowalczyk wrote: > On 6/8/07, Alek Kowalczyk <[EMAIL PROTECTED]> wrote: > > > >Alek Kowalczyk <[EMAIL PROTECTED]> 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: (( >mypackage.mymodule.MyContentClass > >> instance '\x00\x00\x00\x00\x00\x00\x02q'>, > >> > > 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 Note that findObjectMatching will not return all the persistent objects, but only those that are directly placed in containers. Other objects (e.g. ones stored in annotations) refer to your old classes, you'll need to do more. Stephan Richter once figured out how to do that for SchoolTool, IIRC it involved looping through all OIDs in the database and marking them as _p_changed. Marius Gedminas -- Whom the gods would destroy, they first teach BASIC. signature.asc Description: Digital signature ___ Zope3-users mailing list Zope3-users@zope.org http://mail.zope.org/mailman/listinfo/zope3-users
Re: [Zope3-Users] Re: Evolution of ZoDB after changing python modules structure (moving content classes to another module)
On 6/12/07, Rupert Redington <[EMAIL PROTECTED]> wrote: Aleksander Kowalczyk wrote: > On 6/8/07, Alek Kowalczyk <[EMAIL PROTECTED]> wrote: >> >> Alek Kowalczyk <[EMAIL PROTECTED]> 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: ((> mypackage.mymodule.MyContentClass >> > instance '\x00\x00\x00\x00\x00\x00\x02q'>, >> > > > I found a quite well working solution on >> http://mail.zope.org/pipermail/zodb-dev/2006-September/010382.html >> [...] > 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... :) > 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 Yes, I've tried this already - it doesn't work too :( I have removed this because I believe Zope.generations do the commit for me after calling my evolve function. Thanks! Alek Kowalczyk ___ Zope3-users mailing list Zope3-users@zope.org http://mail.zope.org/mailman/listinfo/zope3-users
Re: [Zope3-Users] Re: Evolution of ZoDB after changing python modules structure (moving content classes to another module)
Aleksander Kowalczyk wrote: > On 6/8/07, Alek Kowalczyk <[EMAIL PROTECTED]> wrote: >> >> Alek Kowalczyk <[EMAIL PROTECTED]> 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: ((> mypackage.mymodule.MyContentClass >> > instance '\x00\x00\x00\x00\x00\x00\x02q'>, >> > > > 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 ___ Zope3-users mailing list Zope3-users@zope.org http://mail.zope.org/mailman/listinfo/zope3-users
Re: [Zope3-Users] Re: Evolution of ZoDB after changing python modules structure (moving content classes to another module)
On 6/8/07, Alek Kowalczyk <[EMAIL PROTECTED]> wrote: Alek Kowalczyk <[EMAIL PROTECTED]> 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: (( instance '\x00\x00\x00\x00\x00\x00\x02q'>, > 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 ___ Zope3-users mailing list Zope3-users@zope.org http://mail.zope.org/mailman/listinfo/zope3-users