One of our sites has a broken relations catalog and I don't know how to fix it.
This is what I see in the log:
2015-11-20T09:27:43 ERROR Zope.SiteErrorLog 1448018863.240.913599974037 http://www.example.com/folder/news-item/##edit
Traceback (innermost last):
Module ZPublisher.Publish, line 138, in publish
Module ZPublisher.mapply, line 77, in mapply
Module ZPublisher.Publish, line 48, in call_object
Module z3c.form.form, line 218, in __call__
Module collective.nitf.browser, line 64, in update
Module plone.dexterity.browser.edit, line 62, in update
Module plone.z3cform.fieldsets.extensible, line 59, in update
Module plone.z3cform.patch, line 30, in GroupForm_update
Module z3c.form.group, line 145, in update
Module plone.app.z3cform.csrf, line 21, in execute
Module z3c.form.action, line 98, in execute
Module z3c.form.button, line 315, in __call__
Module z3c.form.button, line 170, in __call__
Module plone.dexterity.browser.edit, line 26, in handleApply
Module z3c.form.group, line 126, in applyChanges
Module zope.event, line 31, in notify
Module zope.component.event, line 24, in dispatch
Module zope.component._api, line 136, in subscribers
Module zope.component.registry, line 321, in subscribers
Module zope.interface.adapter, line 585, in subscribers
Module zope.component.event, line 32, in objectEventNotify
Module zope.component._api, line 136, in subscribers
Module zope.component.registry, line 321, in subscribers
Module zope.interface.adapter, line 585, in subscribers
Module z3c.relationfield.event, line 76, in updateRelations
Module zc.relation.catalog, line 546, in unindex
Module zc.relation.catalog, line 556, in unindex_doc
Module zc.relation.catalog, line 622, in _remove
KeyError: 304600783
I already tried the code in The dreaded plone.relations IntId KeyError, written by #martijn-pieters some years ago, but seems is no longer valid as I can't find any interfaces named IComplexRelationshipContainer.
Any hints?
Verify if plone.relations are installed.
See here http://davidjb.com/blog/2010/10/bad-relationships-relationchoice-relationcatalog-and-removed-dexterity-content-in-plone, may be the solution for this problem.
Eg.
from zope.component.hooks import setSite
from AccessControl.SecurityManagement import newSecurityManager
from AccessControl.SecurityManager import setSecurityPolicy
from Testing.makerequest import makerequest
from Products.CMFCore.tests.base.security import PermissiveSecurityPolicy, OmnipotentUser
from zope.component import getUtility
from zope.intid.interfaces import IIntIds
from zc.relation.interfaces import ICatalog
_policy=PermissiveSecurityPolicy()
_oldpolicy=setSecurityPolicy(_policy)
newSecurityManager(None, OmnipotentUser().__of__(app.acl_users))
portal = makerequest(app['Plone'])
setSite(portal)
intids = getUtility(IIntIds)
catalog = getUtility(ICatalog)
print [x.from_object for x in sorted(catalog.findRelations({}))]
I think some years ago I stumpled upon something similar.
I launched this and everything worked fine later:
from Products.Five.browser import BrowserView
from Products.CMFCore.utils import getToolByName
from z3c.relationfield.event import updateRelations
from z3c.relationfield.interfaces import IHasRelations
from zc.relation.interfaces import ICatalog
from zope.component import getUtility
class View(BrowserView):
def __call__(self):
rcatalog = getUtility(ICatalog)
# Clear the relation catalog to fix issues with interfaces that don't exist anymore.
# This actually fixes the from_interfaces_flattened and to_interfaces_flattened indexes.
rcatalog.clear()
pc = getToolByName(self.context, 'portal_catalog')
brains = pc.searchResults(object_provides=IHasRelations.__identifier__)
for brain in brains:
obj = brain.getObject()
updateRelations(obj, None)
return "Catalog rebuilt for %s objects" % len(brains)
Related
I have a dexterity content type and I'd like to have a Select-Field which is not required and which values came from a vocabulary.
This is the vocabulary:
#grok.provider(IContextSourceBinder)
def voc_test(context):
values = range(10, 21)
terms = map(lambda x: SimpleTerm(value=str(x),
title=str(x)), values)
return SimpleVocabulary(terms)
And this the definition of the field:
from plone.directives import dexterity, form
from plone.namedfile.field import NamedImage
from zope import schema
class IMyType(form.Schema):
...
form.widget('test', SelectFieldWidget)
test = schema.List(
title=_(u"Test"),
value_type=schema.Choice(source=vocabularies.voc_test),
description=_(u"desc_test"),
required=False,
)
What I get is a select field with my values from the vocabulary and the first value is 'No Value'. That is fine. But when I hit save and have 'No Value' selected a error message is shown:
Traceback (innermost last):
Module ZPublisher.Publish, line 138, in publish
Module ZPublisher.mapply, line 77, in mapply
Module ZPublisher.Publish, line 48, in call_object
Module plone.z3cform.layout, line 66, in __call__
Module plone.z3cform.layout, line 50, in update
Module plone.dexterity.browser.edit, line 52, in update
Module plone.z3cform.fieldsets.extensible, line 59, in update
Module plone.z3cform.patch, line 30, in GroupForm_update
Module z3c.form.group, line 145, in update
Module plone.app.z3cform.csrf, line 21, in execute
Module z3c.form.action, line 98, in execute
Module z3c.form.button, line 315, in __call__
Module z3c.form.button, line 170, in __call__
Module plone.dexterity.browser.edit, line 23, in handleApply
Module z3c.form.group, line 98, in extractData
Module z3c.form.form, line 147, in extractData
Module z3c.form.field, line 303, in extract
Module z3c.form.converter, line 316, in toFieldValue
Module z3c.form.term, line 41, in getValue
Module z3c.form.term, line 38, in getTermByToken
Module zope.schema.vocabulary, line 133, in getTermByToken
LookupError: --NOVALUE--
If I change:
required=False,
to
required=True
saving works.
Hopefully someone can help. Thanks.
Set a default that is within your vocabulary and make the field required so that "--NOVALUE--" is not in the options.
If, for some reason, you want to use "-- NOVALUE --" for that default, then add it to the vocabulary. If the field is set required, it will not be duplicated.
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.directives.form being upgraded to version 1.1.
How can I avoid this error? The only line of code that is not from default Plone on the traceback is on der.freitag.handlers where it does a transaction.commit() and the content type is just a regular dexterity content type.
1385740390.020.496977141203 http://10.100.0.207:8081/website/front-page/atomkraft/++add++der.freitag.customizablearticlelink
Traceback (innermost last):
Module ZPublisher.Publish, line 138, in publish
Module ZPublisher.mapply, line 77, in mapply
Module ZPublisher.Publish, line 48, in call_object
Module plone.z3cform.layout, line 70, in __call__
Module plone.z3cform.layout, line 54, in update
Module plone.dexterity.browser.add, line 112, in update
Module plone.z3cform.fieldsets.extensible, line 59, in update
Module plone.z3cform.patch, line 30, in GroupForm_update
Module z3c.form.group, line 138, in update
Module z3c.form.action, line 99, in execute
Module z3c.form.button, line 315, in __call__
Module z3c.form.button, line 170, in __call__
Module plone.dexterity.browser.add, line 99, in handleAdd
Module z3c.form.form, line 247, in createAndAdd
Module plone.dexterity.browser.add, line 78, in add
Module plone.dexterity.utils, line 152, in addContentToContainer
Module Products.BTreeFolder2.BTreeFolder2, line 455, in _setObject
Module zope.event, line 31, in notify
Module zope.component.event, line 24, in dispatch
Module zope.component._api, line 136, in subscribers
Module zope.component.registry, line 321, in subscribers
Module zope.interface.adapter, line 585, in subscribers
Module zope.component.event, line 32, in objectEventNotify
Module zope.component._api, line 136, in subscribers
Module zope.component.registry, line 321, in subscribers
Module zope.interface.adapter, line 585, in subscribers
Module der.freitag.handlers, line 126, in set_customizable_article_link_id
Module transaction._manager, line 89, in commit
Module transaction._transaction, line 329, in commit
Module transaction._transaction, line 443, in _commitResources
Module ZODB.Connection, line 567, in commit
Module ZODB.Connection, line 623, in _commit
Module ZODB.Connection, line 658, in _store_objects
Module ZODB.serialize, line 422, in serialize
Module ZODB.serialize, line 431, in _dump
PicklingError: Can't pickle <class 'plone.directives.form.schema.Schema'>: attribute lookup plone.directives.form.schema.Schema failed
EDIT: the object that is being created has a relation field (a z3c.relationfield.schema.RelationChoice) and it turns out that zc.relation keeps a list of all interfaces provided by each member of any relation. Thus, after upgrading from plone.directives.form version 1.0 to version 1.1 the interfaces on plone.directives.form can no longer be resolved.
From z3c.relationfield documentation I don't see any option to update relations, so the only solution would be to get all relations and recreate them?
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.
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>
I'm working on a content type that uses datagridfield.
Within the subobject, I have a choice field with a custom vocabulary.
The vocabulary work outside the datagrid (If I use it directly in the content type's schema). But when I add it to the subobject, it doesn't work anymore.
Looking at the debug note, I see the vocabluary's context is NO_VALUE.
Any hint/direction to make this works ?
This is the simplest schema that won't work (I think):
# Import
from zope import schema
from zope.interface import Interface
from plone.directives import form
from collective.z3cform.datagridfield import DataGridFieldFactory, DictRow
# The container
class IMenu(Interface):
dishes = schema.List(value_type=schema.TextLine())
# The vocabulary
#grok.provider(IContextSourceBinder)
def getDishes(context):
terms = [SimpleVocabulary.createTerm(dish, dish, dish) for dish in context.dishes]
return SimpleVocabulary(terms)
# The object line
class IOrderLine(Interface):
dish = schema.Choice(source=getDishes)
quantity = schema.Int()
# The object
class IOrder(Interface):
form.widget(dishes=DataGridFieldFactory)
dishes = schema.List(value_type=DictRow(schema=IOrderLine))
Now I register Menu, Order as dexterity content type, add a menu and tried to add an order within it, I got an error on Order add view and this is the traceback:
Traceback (innermost last):
Module ZPublisher.Publish, line 126, in publish
Module ZPublisher.mapply, line 77, in mapply
Module Products.PDBDebugMode.runcall, line 70, in pdb_runcall
Module ZPublisher.Publish, line 46, in call_object
Module plone.z3cform.layout, line 66, in __call__
Module plone.z3cform.layout, line 50, in update
Module plone.dexterity.browser.add, line 112, in update
Module plone.z3cform.fieldsets.extensible, line 59, in update
Module plone.z3cform.patch, line 30, in GroupForm_update
Module z3c.form.group, line 128, in update
Module z3c.form.form, line 134, in updateWidgets
Module z3c.form.field, line 277, in update
Module z3c.form.browser.multi, line 63, in update
Module z3c.form.browser.widget, line 171, in update
Module z3c.form.widget, line 477, in update
Module collective.z3cform.datagridfield.datagridfield, line 107, in updateWidgets
Module collective.z3cform.datagridfield.datagridfield, line 91, in getWidget
Module z3c.form.browser.widget, line 171, in update
Module z3c.form.object, line 217, in update
Module z3c.form.object, line 208, in updateWidgets
Module z3c.form.object, line 87, in update
Module plone.z3cform.patch, line 21, in BaseForm_update
Module z3c.form.form, line 150, in update
Module z3c.form.form, line 134, in updateWidgets
Module z3c.form.field, line 277, in update
Module z3c.form.browser.select, line 51, in update
Module z3c.form.browser.widget, line 171, in update
Module z3c.form.widget, line 220, in update
Module z3c.form.widget, line 214, in updateTerms
Module zope.component._api, line 107, in getMultiAdapter
Module zope.component._api, line 120, in queryMultiAdapter
Module zope.component.registry, line 238, in queryMultiAdapter
Module zope.interface.adapter, line 532, in queryMultiAdapter
Module z3c.form.term, line 96, in ChoiceTerms
Module zope.schema._field, line 349, in bind
Module waga.game.core.content.interfaces, line 202, in getDishes
AttributeError: 'NO_VALUE' object has no attribute 'dishes'
> /home/quyetnd/Projects/waga.game.core/src/waga/game/core/content/interfaces.py(202)getDishes()
-> terms = [SimpleVocabulary.createTerm(dish, dish, dish) for dish in context.dishes]
The context object is an instance.
This is limitation in z3c.form (at least some versions, I think it has been fixed in the newer ones).
My ugly workaround in vocab source function:
if not context:
context = getSite()
if not context:
# Form is rendered from console without HTTP request traversing, etc.
# and thread local site variable is not set
raise RuntimeError("Oh snap. Beer time.")
...
http://developer.plone.org/serving/traversing.html#using-getsite
I have a persistent tile that has a choice field:
subjects = schema.List(
title=_(u"Subjects"),
value_type=schema.Choice(
vocabulary='my.subjects'
),
)
but this is failing on edit view rendering like this:
2013-05-22 18:37:56 ERROR Zope.SiteErrorLog 1369240676.330.546121806344 http://localhost:8082/plumi/##edit-tile/tagcloud.tile/home-cloud
Traceback (innermost last):
Module ZPublisher.Publish, line 126, in publish
Module ZPublisher.mapply, line 77, in mapply
Module ZPublisher.Publish, line 46, in call_object
Module plone.z3cform.layout, line 70, in __call__
Module plone.z3cform.layout, line 54, in update
Module plone.app.tiles.browser.edit, line 48, in update
Module plone.app.tiles.browser.base, line 55, in update
Module plone.z3cform.fieldsets.extensible, line 59, in update
Module plone.z3cform.patch, line 30, in GroupForm_update
Module z3c.form.group, line 125, in update
Module plone.app.tiles.browser.base, line 71, in updateWidgets
Module z3c.form.field, line 275, in update
Module z3c.form.browser.orderedselect, line 50, in update
Module z3c.form.browser.widget, line 70, in update
Module z3c.form.widget, line 199, in update
Module z3c.form.widget, line 193, in updateTerms
Module zope.component._api, line 107, in getMultiAdapter
Module zope.component._api, line 120, in queryMultiAdapter
Module zope.component.registry, line 238, in queryMultiAdapter
Module zope.interface.adapter, line 532, in queryMultiAdapter
Module z3c.form.term, line 174, in CollectionTerms
Module zope.schema._field, line 352, in bind
Module Zope2.App.schema, line 33, in get
Module my.vocabularies, line 22, in __call__
Module Products.CMFCore.utils, line 10, in check_getToolByName
Module Products.CMFCore.utils, line 120, in getToolByName
AttributeError: portal_catalog
This happen because the context passed to the vocabulary call is the data dictionary of the tile. It happens also when using SearchableTextSourceBinder in another field:
source=SearchableTextSourceBinder(
{'is_folderish': True},
default_query='path:'
)
that makes plone.app.vocabularies.catalog fail:
Module plone.app.vocabularies.catalog, line 237, in __call__
Module plone.app.vocabularies.catalog, line 144, in __init__
Module Products.CMFCore.utils, line 10, in check_getToolByName
Module Products.CMFCore.utils, line 120, in getToolByName
AttributeError: portal_catalog
I don't know, if it's by design, but when a persistent tile is edited, context sensitive vocabulary will get its context (persistent tile data dictionary) without any acquisition wrapping. Therefore all lookups which rely on acquisition will fail.
You could try fixing your vocabulary to use portal root as its context for getToolByName-looksup using either plone.api.portal.get() or zope.component.hooks.getSite().
If you really need the current context, an ugly way would be to get zope.globalrequest.getRequest().get("PUBLISHED") which should be the current publishable context found by ZPublisher. It's usually a view, but you can get your context object from its acquisition chain. Of course, you should be very defensive with that approach.
I'm having problem with FS controller page template. I had this Plone2 base product which i have eggified while doing Plone 4.2 migration. I have pasted traceback below.
Traceback (innermost last):
Module ZPublisher.Publish, line 126, in publish
Module ZPublisher.mapply, line 77, in mapply
Module ZPublisher.Publish, line 46, in call_object
Module Products.CMFFormController.FSControllerPageTemplate, line 91, in __call__
Module Products.CMFFormController.BaseControllerPageTemplate, line 26, in _call
Module Products.CMFFormController.FormController, line 384, in validate
Module ZPublisher.mapply, line 77, in mapply
Module ZPublisher.Publish, line 46, in call_object
Module Products.CMFFormController.FSControllerValidator, line 58, in __call__
Module Products.CMFFormController.Script, line 145, in __call__
Module Products.CMFCore.FSPythonScript, line 130, in __call__
Module Shared.DC.Scripts.Bindings, line 322, in __call__
Module Shared.DC.Scripts.Bindings, line 359, in _bindAndExec
Module Products.PythonScripts.PythonScript, line 344, in _exec
Module script, line 32, in exams_list
- <FSControllerValidator at /dev/exam/online/booking/validators/exams_list>
- Line 32
Module AccessControl.ZopeGuards, line 299, in guarded_import
Unauthorized: Using import with a level specification isn't supported by AccessControl: _warnings
line 32 on exams_list validators is wrap with astric
if event and not state.getErrors():
try:
context.script.validateEvent()
except ValueError,exc:
state.setError('SIMSError',str(exc))
**except 'dryrun':**
state.setStatus('dryrun')
Any help or pointer always helpful.
Support for string exceptions was removed from Python 2.6; you'll need to use a proper exception class for 'dryrun' instead.
You'll need to mark that exception as importable by restricted code before you can then import it into your Controller Script.
Here is an example definition for such an exception:
from AccessControl.SecurityInfo import ModuleSecurityInfo
security = ModuleSecurityInfo('My.Product.exceptions')
security.declarePublic('DryRunException')
class DryRunException(Exception):
'''The process was not committed, this was only a dry run'''
With the ModuleSecurityInfo information in place you can now import this exception into your script:
from My.Product.exceptions import DryRunException
and catch that instead in your except block; the code that throws this exception will need to be updated too, of course.