The first call of the accessor of the image field of a BlobWrapper
returns None and the second call returns a BlobWrapper
. Some hint?
In [1]: id = app.Plone.invokeFactory('Image', 'myimage', title='MyImage')
In [2]: image=app.Plone[id]
In [3]: blobWrapper=image.getBlobWrapper()
In [4]: accessor=blobWrapper.getField('image').getAccessor(blobWrapper)
In [5]: accessor()
In [6]: accessor()
Out[6]: <plone.app.blob.field.BlobWrapper at 0xa35a194>
The getAccessor
method of the field takes the object in this case your ATImage instance
as parameter not a blobWrapper instance
>>> accessor = image.getField('image').getAccessor(image)
>>> accessor()
<plone.app.blob.field.BlobWrapper object at 0x1050446e0>
Check this github link
security.declarePublic('getAccessor')
def getAccessor(self, instance):
"""Return the accessor method for getting data out of this
field"""
if self.accessor:
return getattr(instance, self.accessor, None)
return None
UPDATE:
Explenation why the first call of the accessor is None
and second not.
I has something to do with the magic's of Products.Archetypes. If you pass the BlobWrapper instance instead of a ATImage instance, the following happens:
First call:
At some point the get
method of Archetypes ObjectField gets called, See https://github.com/plone/Products.Archetypes/blob/master/Products/Archetypes/Field.py#L785
It catches the AttributeError (AttributeError: Attribut...'image'
), which btw. usually happens if you add a new Field to a ContentType, because the BlobWrapper instance has no Attribute image
(The ATImage would have this attribute).
Then it initializes your BlobWrapper like a new field on the ATImage.
This persists some crap on your Blobwrapper instance, which you don't want :-)
The return value is None
, see https://github.com/plone/Products.Archetypes/blob/master/Products/Archetypes/Field.py#L803
Second call: Since the first call did some modifications to your BlobWrapper instance, the second call works and returns the correct value. https://github.com/plone/Products.Archetypes/blob/master/Products/Archetypes/Field.py#L785
Technically the first call initializes an AnnotationStorage
on your BlobWrapper instance.
> /Users/maethu/.buildout/eggs-cache/Products.Archetypes-1.9.4-py2.7.egg/Products/Archetypes/Storage/annotation.py(62)get()
-> def get(self, name, instance, **kwargs):
(Pdb) l
57 """Clean up data in set method
58 """
59 raise NotImplementedError
60
61 security.declarePrivate('get')
62 -> def get(self, name, instance, **kwargs):
63 ann = getAnnotation(instance)
64 value = ann.getSubkey(self._key, subkey=name, default=_marker)
65 if value is _marker:
66 if self._migrate:
67 value = self._migration(name, instance, **kwargs)
(Pdb) name
'image'
(Pdb) instance
<plone.app.blob.field.BlobWrapper object at 0x10d4042a8>
(Pdb) getAnnotation(instance)
{'Archetypes.storage.AnnotationStorage-image': <plone.app.blob.field.BlobWrapper object at 0x10d430a28>}
I really think you should not do this :-)
If I got something wrong pls correct... it's kinda hard to understand this Archetypes behaviour.