I have a File Field in my Plone product that I want to allow the user to "Turn Off" blob storage. The file will be stored elsewhere. I can't seem to do it.
Below is my attempt. I can't get Products.Archetypes.Field.ObjectField.setStorage()
to recognize that this 'noStorage' instance "provides" IStorage
.
Much inconsequential code has been removed for brevity, but the complete source can be found at https://github.com/flipmcf/rfa.kaltura
The Archetype schema includes "ATBlob.schema" to pull in the "File" field, then:
class KalturaVideo(ATBlob, KalturaBase.KalturaContentMixin):
nostorage = NoStorage()
directlyProvides(nostorage, INoStorage)
def __init__(self, oid, **kwargs):
if settings.storageMethod == u"No Local Storage":
import pdb; pdb.set_trace() #
#(Pdb) IStorage.providedBy(self.nostorage)
#True
self.getField('file').setStorage(self, self.nostorage)
My Storage class and interface is really boring:
from zope.interface import implements
from ZODB.interfaces import IStorage
from zope.component.zcml import interface
from zope.interface import Interface
class INoStorage(IStorage):
pass
class NoStorage(object):
"""Completely skip storage on Plone."""
implements(INoStorage)
def __init__(self):
pass
def close():
pass
def getName():
return "NoStorage - Blackhole"
#etc... lots of implemented methods that do nothing.
configure.zcml
in the 'storage' package also:
<adapter
factory=".storage.NoStorage"
provides=".storage.INoStorage"
for="Products.Archetypes.interfaces.field.IObjectField"
/>
<adapter
factory=".storage.NoStorage"
provides=".storage.IStorage"
for="Products.Archetypes.interfaces.field.IObjectField"
/>
Now, within the setStorage()
method of Products.Archetypes.Field.ObjectField
:
def setStorage(self, instance, storage):
import pdb; pdb.set_trace()
#(Pdb) IStorage.providedBy(storage)
#False
#HeadDesk
if not IStorage.providedBy(storage):
raise ObjectFieldException, "Not a valid Storage method"
And when I debug, IStorage.providedBy(storage)
returns False
Why would it return False in setStorage
and True
in the calling code? Am I not registering the interface correctly?
Note that in the module Products.Archetypes.Field
, the IStorage
instance there is actually sourced from this:
from Products.Archetypes.interfaces.storage import IStorage
Comparing the interface resolution order (via __iro__
) we get
>>> from pprint import pprint as pp
>>> pp(ZODB.interfaces.IStorage.__iro__)
(<InterfaceClass ZODB.interfaces.IStorage>,
<InterfaceClass zope.interface.Interface>)
>>> pp(Products.Archetypes.interfaces.storage.IStorage.__iro__)
(<InterfaceClass Products.Archetypes.interfaces.storage.IStorage>,
<InterfaceClass zope.interface.Interface>)
As the INoStorage
was subclassed from ZODB.interfaces.IStorage
, and that interface class isn't the parent of Products.Archetypes.interfaces.storage.IStorage
which the setStorage
calls providedBy
on, the NoStorage
class as define will not satisfy that check. To solve this, just have INoStorage
simply inherit from the Archetype version of the IStorage
and implement all its methods and it should work as intend.
That said, you could simply your code somewhat further with regards to the way you provide the interfaces, see this example:
>>> class INoStorage(Products.Archetypes.interfaces.storage.IStorage):
... pass
...
>>> class NoStorage(object):
... zope.interface.implements(INoStorage)
...
>>> nostorage = NoStorage()
>>> Products.Archetypes.interfaces.storage.IStorage.providedBy(nostorage)
True
Inheritances of the Interface
subclasses will persist correctly through without extra directlyProvides
definitions, so you can just drop that extra call inside the KalturaVideo
class definition. Naturally, you can just do from ... import IStorage
and simply that to class INoStorage(IStorage)
. The example was done so to make things more explicitly visible.