Ticket #10318 (closed Bug: fixed)
ExtensionClass change causes "Attempt to set attribute on empty acquisition wrapper"
| Reported by: | newbery | Owned by: | hannosch |
|---|---|---|---|
| Priority: | blocker | Milestone: | 4.0 |
| Component: | Infrastructure | Version: | |
| Keywords: | Cc: | frisi, esteele |
Description
Using 4.0b1,
It seems that any TTW view customization via /portal_view_customizations causes later views to throw the following error:
2010-03-10 23:10:40 ERROR ZODB.Connection Couldn't load state for 0x1c44
Traceback (most recent call last):
File ".../ZODB3-3.9.4-py2.6-macosx-10.3-i386.egg/ZODB/Connection.py", line 838, in setstate
self._setstate(obj)
File ".../ZODB3-3.9.4-py2.6-macosx-10.3-i386.egg/ZODB/Connection.py", line 906, in _setstate
self._reader.setGhostState(obj, p)
File ".../ZODB3-3.9.4-py2.6-macosx-10.3-i386.egg/ZODB/serialize.py", line 616, in setGhostState
state = self.getState(pickle)
File ".../ZODB3-3.9.4-py2.6-macosx-10.3-i386.egg/ZODB/serialize.py", line 609, in getState
return unpickler.load()
File ".../ZODB3-3.9.4-py2.6-macosx-10.3-i386.egg/ZODB/serialize.py", line 477, in _persistent_load
return self.load_persistent(*reference)
File ".../ZODB3-3.9.4-py2.6-macosx-10.3-i386.egg/ZODB/serialize.py", line 514, in load_persistent
obj._p_oid = oid
AttributeError: Attempt to set attribute on empty acquisition wrapper
2010-03-10 23:10:40 ERROR Zope.SiteErrorLog 1268291440.780.276724844509 http://localhost:8888/Plone2
Traceback (innermost last):
Module ZPublisher.Publish, line 116, in publish
Module ZPublisher.BaseRequest, line 434, in traverse
Module ZPublisher.BeforeTraverse, line 99, in __call__
Module Products.CMFCore.PortalObject, line 81, in __before_publishing_traverse__
Module Products.CMFCore.DynamicType, line 142, in __before_publishing_traverse__
Module zope.publisher.defaultview, line 88, in queryDefaultViewName
Module ZODB.Connection, line 838, in setstate
Module ZODB.Connection, line 906, in _setstate
Module ZODB.serialize, line 616, in setGhostState
Module ZODB.serialize, line 609, in getState
Module ZODB.serialize, line 477, in _persistent_load
Module ZODB.serialize, line 514, in load_persistent
AttributeError: Attempt to set attribute on empty acquisition wrapper
Similar tb's actually show up multiple times but I'm guessing that's just some error cascading artifact.
Restarting the instance does not eliminate the error.
Patching line 514 in ZODB.serialize.py like so:
try:
obj._p_oid = oid
except AttributeError:
return self._conn.get(oid)
seems to fix the issue for now but I have no idea if this solution is robust enough for the long term.
Change History
comment:2 Changed 2 years ago by hannosch
- Owner set to hannosch
I have seen the same issue in a Plone 3.x site after upgrading to the new Acquisition/ExtensionClass releases. In that case it only happened with the singing&dancing signup portlet. I haven't debugged this yet.
comment:3 Changed 2 years ago by frisi
- Cc frisi added
got the same error when adding a p4a.subtype for collective.lineage (see http://plone.org/products/collective-lineage/issues/15) the patch above works around the problem
comment:4 Changed 23 months ago by hannosch
- Summary changed from TTW view customization throws error to Attempt to set attribute on empty acquisition wrapper
I debugged this a bit more. What happens is that some persistent references end up being of the form ('0x001', 'Acquisition.ImplicitAcquisitionWrapper')
This causes the _persistent_load method to try to load the oid, with the ImplicitAcquisitionWrapper as the class. Loading the actual object and ignoring the class from the reference works fine. So at least there's no unrecoverable data loss caused by this.
My workaround for this looks like this for now:
def _persistent_load(self, reference):
if isinstance(reference, tuple):
# Ignore broken AQ wrapper hint
if reference[1] == ImplicitAcquisitionWrapper:
return self.load_oid(reference[0])
return self.load_persistent(*reference)
elif isinstance(reference, str):
return self.load_oid(reference)
...
Of course the real bug is the presence of the ImplicitAcquisitionWrapper in the reference tuple. This shouldn't be there in the first place. Instead the actual class should be stored there.
comment:5 Changed 23 months ago by frisi
maybe this helps in tracking down where the real problem occures:
i got the "Attempt to set attribute on empty acquisition wrapper" error when marking a folder with p4a.subtyper (see this lineage issue)
using a version of plone.app.folder that does not contain the change made in r34308 made the error go away.
comment:6 Changed 23 months ago by davisagli
The storage of that <ImplicitAcquisitionWrapper> reference in the persistent reference is a side effect of the change in ExtensionClass to no longer provide a getnewargs method.
From ObjectWriter.persistent_id in ZODB/serialize.py:
klass = type(obj)
if hasattr(klass, '__getnewargs__'):
# We don't want to save newargs in object refs.
# It's possible that __getnewargs__ is degenerate and
# returns (), but we don't want to have to deghostify
# the object to find out.
# Note that this has the odd effect that, if the class has
# __getnewargs__ of its own, we'll lose the optimization
# of caching the class info.
if database_name is not None:
return ['n', (database_name, oid)]
return oid
# Note that we never get here for persistent classes.
# We'll use direct refs for normal classes.
if database_name is not None:
return ['m', (database_name, oid, klass)]
return oid, klass
comment:7 Changed 23 months ago by frisi
pinning ExtensionClass = 2.12.0 in my buildout works around this error for new objects.
an object stored using 2.13 that produced the AttributeError can't be fixed with that. for these cases one needs the fix proposed in comment 4
is ist wiser/safer to pin ExtensionClass, or to patch serialize.py? will i lose the performance gain for objects created with 2.12?
comment:8 follow-up: ↓ 10 Changed 23 months ago by davisagli
- Priority changed from major to blocker
- Cc esteele added
- Summary changed from Attempt to set attribute on empty acquisition wrapper to ExtensionClass change causes "Attempt to set attribute on empty acquisition wrapper"
This is a blocker for 4.0b2, IMO.
I think the change in ExtensionClass is also the culprit for the PicklingErrors some people have been seeing during upgrading, if there are items whose class can't be imported -- see e.g. http://n2.nabble.com/Upgrade-to-Plone-4-td4758292.html
frisi, presumably if you re-pickled all your objects you could then remove the serialize.py patch again. Yes, you will lose the performance gain from the ExtensionClass change.
comment:9 Changed 23 months ago by hannosch
- Status changed from new to closed
- Resolution set to fixed
comment:10 in reply to: ↑ 8 Changed 22 months ago by frisi
Replying to davisagli:
frisi, presumably if you re-pickled all your objects you could then remove the serialize.py patch again. Yes, you will lose the performance gain from the ExtensionClass change.
thx for your answer. what is the easiest way to re-pickle objects to get rid of this patch in an existing instance? is there some utility script or method i can call in pdbdebugmode or zopepy?
