I'm not really sure this is a problem but I have a feeling that it will bite me later on. Anyway.. I have defined a class that's both a container and has properties of its own. The class (it's a CMF class) derives from SkinnedFolder, PortalContent and DefaultDublinCoreImpl. The problem is that many of the attributes are only meaningful for the object itself, not for the contained objects. This doesn't really bother me, but I would like to avoid indexing (and putting in the metadata) these attributes. So, I cannot use attributes starting with _ to stop acquisition since this would preclude putting them in the index/metadata. I cannot use Aquisition.explicit since I have no control on the contained objects (in fact the purpose of having a class deriving on SkinnedFolder is to use existing types as content). I've tried, with no success, the following: class MyClass(SkinnedFolder, PortalContent, DefaultDublinCoreImpl): .... .... def MyAttr(self): if not isinstance(aq_base(self),MyClass): return None .... .... No success because when the method gets called self is an instance of MyClass, so the method never returns None. Any hint? TIA -- Luca Olivetti Wetron Automatización S.A. http://www.wetron.es/ Tel. +34 93 5883004 Fax +34 93 5883007
Luca Olivetti wrote:
No success because when the method gets called self is an instance of MyClass, so the method never returns None.
I would index the actual attribute, I'd index something called index_yourattributename. Then define a method called 'index_yourattributename' as follows: return getattr(context.aq_explicit,'yourattributename') ...and if you're really paranoid, make 'index_yourattributename' an external method: from Acquisition import aq_base def index_yourattributename(self): return getattr(aq_base(self),'yourattributename') cheers, Chris
Chris Withers wrote: Thanks! you put me on the right track
I would index the actual attribute, I'd index something called
s/would/wouldn't/ I suppose ;-)
index_yourattributename. Then define a method called 'index_yourattributename' as follows:
return getattr(context.aq_explicit,'yourattributename')
Ok, the key is *not* to define the method inside the class. To wrap it up in case someone searches the list: 1) define a python script somewhere in the acquisition path where the catalog will pick it up. Since mine is a CMF Product I used the skin directory. Call it, e.g., index_yourattribute 2) the content of the script is attr=getattr(context.aq_explicit,'yourattributename') if callable(attr): attr=attr() return attr 3) define an index and/or metadata called like the python script (index_yourattribute) 4) enjoy :-) Bye -- Luca Olivetti Wetron Automatización S.A. http://www.wetron.es/ Tel. +34 93 5883004 Fax +34 93 5883007
Luca Olivetti wrote:
2) the content of the script is
attr=getattr(context.aq_explicit,'yourattributename')
hmmm, change that to attr=getattr(context.aq_explicit,'yourattributename',()) if it is to be picked up by a keyword index
if callable(attr): attr=attr() return attr
-- Luca Olivetti Wetron Automatización S.A. http://www.wetron.es/ Tel. +34 93 5883004 Fax +34 93 5883007
Luca Olivetti wrote:
Luca Olivetti wrote:
2) the content of the script is
attr=getattr(context.aq_explicit,'yourattributename')
hmmm, change that to
attr=getattr(context.aq_explicit,'yourattributename',())
if it is to be picked up by a keyword index
if callable(attr): attr=attr() return attr
I stumbled into another problem: the method is useable for indexes but not for metadata. I digged into the source of ZCatalog and I saw that's because Zcatalog first calls recordify (see Catalog.py) on the object which uses MV (from Missing) to indicate a missing attribute, while each plugin index uses a different method to identify a missing attribute (for example, UnIndex.py defines an internal _merker as []). So if my method uses attr=getattr(context.aq_explicit,'myattribute') it will tipically work in a plugin index because it's wrapped in a try except block, but will not work with metadata since there's no try/except there. I can use attr=getattr(context.aq_explicit,'myattribute',MV) (in an external method, a python script cannot use Missing) but that, while giving the correct result to recordify, will still index the object since the plugin index is expecting another value to indicate a missing attribute. If it were possible to import an attribute starting with _ doing from Products.PluginIndexes.common.Unindex import _merker attr=getattr(context.aq_explicit,'myattribute',_merker) will give the correct result for a fieldIndex but would use the wrong metadata for other indexes. I may be wrong but I think that the inconsistency between the value used by the catalog and the various plugin indexes to indicate a missing value should be fixed, for example they could all import MV from Missing like Catalog.py does. Should I file this into the collector or there is another reason I don't know for these inconsistencies? I can change it myself in my local zope (currently 2.6.1b1) but there's no point in doing it if the next release will overwrite my changes. For the time being, do you see another solution besides writing two methods (one for metadata and the other for indexes)? TIA -- Luca Olivetti Wetron Automatización S.A. http://www.wetron.es/ Tel. +34 93 5883004 Fax +34 93 5883007
Luca Olivetti wrote:
I stumbled into another problem: the method is useable for indexes but not for metadata. I digged into the source of ZCatalog and I saw that's because Zcatalog first calls recordify (see Catalog.py) on the object which uses MV (from Missing) to indicate a missing attribute, while each plugin index uses a different method to identify a missing attribute (for example, UnIndex.py defines an internal _merker as []).
Why would hypothesise that the real problem is that adding stuff to indexes ignores AttributeError's and KeyError's which storing it as metadata doesn't, which it should.
So if my method uses
attr=getattr(context.aq_explicit,'myattribute')
it will tipically work in a plugin index because it's wrapped in a try except block, but will not work with metadata since there's no try/except there.
So put one in yourself ;-) (well, something that works the same...) attr=getattr(context.aq_explicit,'myattribute',None) I think that's your best bet... cheers, Chris
Chris Withers wrote:
Luca Olivetti wrote:
I stumbled into another problem: the method is useable for indexes but not for metadata. I digged into the source of ZCatalog and I saw that's because Zcatalog first calls recordify (see Catalog.py) on the object which uses MV (from Missing) to indicate a missing attribute, while each plugin index uses a different method to identify a missing attribute (for example, UnIndex.py defines an internal _merker as []).
Why would hypothesise that the real problem is that adding stuff to indexes ignores AttributeError's and KeyError's which storing it as metadata doesn't, which it should.
Yes, this is the quick fix I finally adopted: --- Catalog.py.orig Tue Dec 31 10:25:44 2002 +++ Catalog.py Tue Dec 31 10:39:28 2002 @@ -400,8 +400,11 @@ record = [] # the unique id is allways the first element for x in self.names: - attr=getattr(object, x, MV) - if(attr is not MV and callable(attr)): attr=attr() + try: + attr=getattr(object, x, MV) + if(attr is not MV and callable(attr)): attr=attr() + except AttributeError: + attr=MV record.append(attr) return tuple(record)
So if my method uses
attr=getattr(context.aq_explicit,'myattribute')
it will tipically work in a plugin index because it's wrapped in a try except block, but will not work with metadata since there's no try/except there.
So put one in yourself ;-) (well, something that works the same...)
attr=getattr(context.aq_explicit,'myattribute',None)
That was the first thing I tried but it didn't (aesthetically) please me: *all* object would be catalogged (it not the same None than the missing value each plugin index and metadata uses). Bye -- Luca Olivetti Wetron Automatización S.A. http://www.wetron.es/ Tel. +34 93 5883004 Fax +34 93 5883007
participants (2)
-
Chris Withers -
Luca Olivetti