I was using plone.directives.form version 1.0 with Plone 4.2.5 and after upgrading to 4.2.6 I started seeing the following traceback and I guess its due to plone.
In case someone runs into this type of problem and cannot bring the old package back, here's another approach:
import transaction
from AccessControl.SecurityManagement import newSecurityManager
from AccessControl.User import system
from Testing.makerequest import makerequest
from zope.component.hooks import setSite
from zope.globalrequest import setRequest
from zc.relation.interfaces import ICatalog
from z3c.relationfield.event import _relations
from z3c.relationfield.event import _setRelation
from zope.component import getUtility
app = makerequest(app)
newSecurityManager(None, system)
portal = app.Plone
setSite(portal)
portal.REQUEST['PARENTS'] = [portal]
portal.REQUEST.setVirtualRoot('/')
setRequest(portal.REQUEST)
THRESHOLD = 100
relations_catalog = getUtility(ICatalog)
paths = ['/'.join(r.from_object.getPhysicalPath())
for r in relations_catalog.findRelations() if r.from_object]
relations_catalog.clear()
counter = 0
for path in paths:
obj = app.unrestrictedTraverse(path)
for name, relation in _relations(obj):
_setRelation(obj, name, relation)
counter += 1
if counter % THRESHOLD == 0:
transaction.savepoint()
transaction.commit()
One more option, I developed a package called collective.diversion that is designed to ease the pain of pickling errors when moving a class. Neither of the above scripts worked for me, however using collective.diversion did.
Adding the package to the buildout and including the following ZCML caused the items to be loaded, and they'll be persisted back in the correct place on write, so reindexing the catalogue should be sufficient.
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:diversion="http://namespaces.plone.org/diversion">
<diversion:class
old="plone.directives.form.schema.Schema"
new="plone.supermodel.model.Schema"
/>
</configure>
Just for reference that's how I fixed it:
While still on plone.directives.form
1.0 update your objects so that they do no longer provide the plone.directives.form.schema.Schema
interface.
Then re-create the relations:
from z3c.relationfield import RelationValue
from zc.relation.interfaces import ICatalog
from zope.app.intid.interfaces import IIntIds
from zope.component import getUtility
from zope.event import notify
from zope.lifecycleevent import ObjectModifiedEvent
logger = logging.getLogger(LOGGER)
relations_catalog = getUtility(ICatalog)
intids = getUtility(IIntIds)
relations = [rel for rel in relations_catalog.findRelations()]
len_relations = len(relations)
logger.info('Relations needed to update: {0}'.format(len_relations))
for relation in relations:
# get the object link and the object linked
object_with_link = relation.from_object
object_linked_to = relation.to_object
# remove the broken relation
object_with_link.reference = None
# let the catalog remove the old relation
notify(ObjectModifiedEvent(object_with_link))
# create a new relation
object_linked_to_intid = intids.getId(object_linked_to)
new_relation = RelationValue(object_linked_to_intid)
object_with_link.reference = new_relation
# let the catalog know about this new relation
notify(ObjectModifiedEvent(object_with_link))
After this, stop the instance, run buildout again to update plone.directives.form
to version 1.1 and voilà!
The Schema class is now in plone.supermodel.model, not plone.directives.form.schema.
However, the real problem you should try to fix is that the code is for some reason trying to store a schema in the ZODB. Pickling/unpickling Zope interfaces is not supported.