[Checkins] SVN: Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/ various changes to provide an IIndexableObject marker interface. Wrapping is applied to objects not providing this interface. Adjust tests to reflect this and provide a fixture for the PortalFolder tests instead of using a full-blown Catalog
Miles Waller
miles at jamkit.com
Tue Mar 17 10:35:43 EDT 2009
Log message for revision 98183:
various changes to provide an IIndexableObject marker interface. Wrapping is applied to objects not providing this interface. Adjust tests to reflect this and provide a fixture for the PortalFolder tests instead of using a full-blown Catalog
Changed:
U Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/CHANGES.txt
U Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/CatalogTool.py
U Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/configure.zcml
U Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/content.zcml
D Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/implements.zcml
U Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/interfaces/_tools.py
U Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/testing.py
U Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/tests/test_CatalogTool.py
U Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/tests/test_PortalFolder.py
-=-
Modified: Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/CHANGES.txt
===================================================================
--- Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/CHANGES.txt 2009-03-17 14:11:53 UTC (rev 98182)
+++ Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/CHANGES.txt 2009-03-17 14:35:42 UTC (rev 98183)
@@ -4,8 +4,9 @@
2.2.0 (unreleased)
------------------
-- PortalCatalog: Changed to use a multi-adaptor to allow pluggable
- IndexableObjectWrapper class. The change will assist in integrating with
+- PortalCatalog: Changed to use a multi-adaptor to allow a pluggable
+ IndexableObjectWrapper class. Objects that implement IIndexableObject
+ are not wrapped. The change will assist in integrating with
other indexing strategies from third-party packages.
- Events: Changed 'handleContentishEvent' behavior for IObjectCopiedEvent.
Modified: Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/CatalogTool.py
===================================================================
--- Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/CatalogTool.py 2009-03-17 14:11:53 UTC (rev 98182)
+++ Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/CatalogTool.py 2009-03-17 14:35:42 UTC (rev 98183)
@@ -34,7 +34,8 @@
from Products.CMFCore.ActionProviderBase import ActionProviderBase
from Products.CMFCore.interfaces import ICatalogTool
from Products.CMFCore.interfaces import IIndexableObjectWrapper
-from Products.CMFCore.interfaces import IContentish
+from Products.CMFCore.interfaces import IIndexableObject
+from Products.CMFCore.interfaces import ICatalogAware
from Products.CMFCore.permissions import AccessInactivePortalContent
from Products.CMFCore.permissions import ManagePortal
from Products.CMFCore.permissions import View
@@ -45,8 +46,6 @@
from Products.CMFCore.utils import getToolByName
from Products.CMFCore.utils import UniqueObject
-from zope.component import getMultiAdapter
-
class IndexableObjectSpecification(ObjectSpecificationDescriptor):
# This class makes the wrapper transparent, adapter lookup is
@@ -63,8 +62,8 @@
class IndexableObjectWrapper(object):
- implements(IIndexableObjectWrapper)
- adapts(IContentish, ICatalogTool)
+ implements(IIndexableObjectWrapper, IIndexableObject)
+ adapts(ICatalogAware, ICatalogTool)
__providedBy__ = IndexableObjectSpecification()
def __init__(self, ob, catalog):
@@ -258,7 +257,10 @@
# information just before cataloging.
# XXX: this method violates the rules for tools/utilities:
# it depends on a non-utility tool
- w = getMultiAdapter((obj, self), IIndexableObjectWrapper)
+ if not IIndexableObject.providedBy(obj):
+ w = IIndexableObject((obj, self))
+ else:
+ w = obj
ZCatalog.catalog_object(self, w, uid, idxs, update_metadata,
pghandler)
Modified: Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/configure.zcml
===================================================================
--- Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/configure.zcml 2009-03-17 14:11:53 UTC (rev 98182)
+++ Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/configure.zcml 2009-03-17 14:35:42 UTC (rev 98183)
@@ -13,6 +13,4 @@
<include file="tool.zcml"/>
- <include file="implements.zcml"/>
-
</configure>
Modified: Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/content.zcml
===================================================================
--- Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/content.zcml 2009-03-17 14:11:53 UTC (rev 98182)
+++ Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/content.zcml 2009-03-17 14:35:42 UTC (rev 98183)
@@ -29,4 +29,11 @@
name="cmf.folder.btree"
/>
+ <!-- Default wrapper for indexing IContentish objects -->
+ <adapter
+ for=".interfaces.ICatalogAware
+ .interfaces.ICatalogTool"
+ provides=".interfaces.IIndexableObject"
+ factory=".CatalogTool.IndexableObjectWrapper" />
+
</configure>
Deleted: Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/implements.zcml
===================================================================
--- Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/implements.zcml 2009-03-17 14:11:53 UTC (rev 98182)
+++ Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/implements.zcml 2009-03-17 14:35:42 UTC (rev 98183)
@@ -1,11 +0,0 @@
-<configure
- xmlns="http://namespaces.zope.org/zope">
-
- <!-- Default wrapper for indexing IContentish objects -->
- <adapter
- for="Products.CMFCore.interfaces.IContentish
- Products.CMFCore.interfaces.ICatalogTool"
- provides="Products.CMFCore.interfaces.IIndexableObjectWrapper"
- factory="Products.CMFCore.CatalogTool.IndexableObjectWrapper" />
-
-</configure>
Modified: Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/interfaces/_tools.py
===================================================================
--- Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/interfaces/_tools.py 2009-03-17 14:11:53 UTC (rev 98182)
+++ Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/interfaces/_tools.py 2009-03-17 14:35:42 UTC (rev 98183)
@@ -406,7 +406,12 @@
a user is not allowed to see.
"""
+class IIndexableObject(Interface):
+ """ Marker interface for objects that can be indexed in
+ the portal catalog
+ """
+
#
# PUT factory handler interfaces
#
Modified: Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/testing.py
===================================================================
--- Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/testing.py 2009-03-17 14:11:53 UTC (rev 98182)
+++ Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/testing.py 2009-03-17 14:35:42 UTC (rev 98183)
@@ -131,7 +131,6 @@
zcml.load_config('traversing.zcml', Products.Five)
zcml.load_config('event.zcml', Products.Five)
zcml.load_config('event.zcml', Products.CMFCore)
- zcml.load_config('implements.zcml', Products.CMFCore)
setHooks()
@classmethod
Modified: Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/tests/test_CatalogTool.py
===================================================================
--- Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/tests/test_CatalogTool.py 2009-03-17 14:11:53 UTC (rev 98182)
+++ Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/tests/test_CatalogTool.py 2009-03-17 14:35:42 UTC (rev 98183)
@@ -21,6 +21,10 @@
from zope.interface import implements
from zope.component import getMultiAdapter
from Products.CMFCore.interfaces import ICatalogTool
+from Products.CMFCore.tests.base.dummy import DummyContent
+from Products.CMFCore.interfaces import IIndexableObject
+from Products.CMFCore.interfaces import ICatalogAware
+
from Products.CMFCore.tests.base.testcase import SecurityTest
class FakeFolder(Implicit):
@@ -39,6 +43,22 @@
def getCatalogVariablesFor(self, ob):
return self._vars
+class CatalogDummyContent(DummyContent):
+
+ """ Dummy content that already provides IIndexableObject
+ and therefore does not need a wrapper to be registered
+ """
+
+ implements(IIndexableObject, ICatalogAware)
+ allowedRolesAndUsers = ['Manager'] # default value
+
+class CatalogDummyContent2(DummyContent):
+
+ """ Dummy content that needs a wrapper to be registered
+ """
+
+ implements(ICatalogAware)
+
class IndexableObjectWrapperTests(unittest.TestCase):
def _getTargetClass(self):
@@ -101,12 +121,12 @@
def test_adapts(self):
from zope.component import adaptedBy
- from Products.CMFCore.interfaces import IContentish
+ from Products.CMFCore.interfaces import ICatalogAware
from Products.CMFCore.interfaces import ICatalogTool
w = self._getTargetClass()
adapts = adaptedBy(w)
- self.assertEqual(adapts, (IContentish, ICatalogTool))
+ self.assertEqual(adapts, (ICatalogAware, ICatalogTool))
class CatalogToolTests(SecurityTest):
@@ -119,18 +139,8 @@
return self._getTargetClass()(*args, **kw)
def _makeContent(self, *args, **kw):
- from Products.CMFCore.tests.base.dummy import DummyContent
- from Products.CMFCore.interfaces import ICatalogTool
- from Products.CMFCore.interfaces import IContentish
- from Products.CMFCore.interfaces import IIndexableObjectWrapper
- from Products.CMFCore.CatalogTool import IndexableObjectWrapper
+ return CatalogDummyContent(*args, **kw)
- from zope.component import getSiteManager
- self.sm = getSiteManager()
- self.sm.registerAdapter(IndexableObjectWrapper, (IContentish, ICatalogTool), IIndexableObjectWrapper)
-
- return DummyContent(*args, **kw)
-
def test_interfaces(self):
from zope.interface.verify import verifyClass
from Products.CMFCore.interfaces import IActionProvider
@@ -185,7 +195,7 @@
catalog = self._makeOne()
catalog.addIndex('allowedRolesAndUsers', 'KeywordIndex')
dummy = self._makeContent(catalog=1)
- dummy._View_Permission = ('Blob',)
+ dummy.allowedRolesAndUsers = ('Blob',)
catalog.catalog_object(dummy, '/dummy')
self.loginWithRoles('Blob')
@@ -197,7 +207,7 @@
catalog = self._makeOne()
catalog.addIndex('allowedRolesAndUsers', 'KeywordIndex')
dummy = self._makeContent(catalog=1)
- dummy._View_Permission = ('Blob',)
+ dummy.allowedRolesAndUsers = ('Blob',)
catalog.catalog_object(dummy, '/dummy')
self.loginWithRoles('Blob')
@@ -210,7 +220,7 @@
catalog = self._makeOne()
catalog.addIndex('allowedRolesAndUsers', 'KeywordIndex')
dummy = self._makeContent(catalog=1)
- dummy._View_Permission = ('Blob',)
+ dummy.allowedRoleAndUsers = ('Blob',)
catalog.catalog_object(dummy, '/dummy')
self.loginWithRoles('Waggle')
@@ -222,7 +232,7 @@
catalog = self._makeOne()
catalog.addIndex('allowedRolesAndUsers', 'KeywordIndex')
dummy = self._makeContent(catalog=1)
- dummy._View_Permission = ('Blob',)
+ dummy.allowedRolesAndUsers = ('Blob',)
catalog.catalog_object(dummy, '/dummy')
self.loginWithRoles('Waggle')
@@ -239,7 +249,7 @@
catalog.addIndex('expires', 'DateIndex')
now = DateTime()
dummy = self._makeContent(catalog=1)
- dummy._View_Permission = ('Blob',)
+ dummy.allowedRolesAndUsers = ('Blob',)
self.loginWithRoles('Blob')
@@ -300,7 +310,7 @@
catalog.addIndex('expires', 'DateIndex')
now = DateTime()
dummy = self._makeContent(catalog=1)
- dummy._View_Permission = ('Blob',)
+ dummy.allowedRolesAndUsers = ('Blob',)
self.loginWithRoles('Blob')
@@ -334,7 +344,7 @@
catalog.addIndex('expires', 'DateIndex')
now = DateTime()
dummy = self._makeContent(catalog=1)
- dummy._View_Permission = ('Blob',)
+ dummy.allowedRolesAndUsers = ('Blob',)
self.loginWithRoles('Blob')
@@ -480,7 +490,40 @@
self.failUnless('Blob' in arus)
self.failUnless('user:%s' % user.getId() in arus)
+ def test_wrapping1(self):
+ # DummyContent implements IIndexableObject
+ # so should be indexed
+ dummy = self._makeContent(catalog=1)
+ ctool = self._makeOne()
+ ctool.catalog_object(dummy, '/dummy')
+ self.assertEqual(1, len(ctool._catalog.searchResults()))
+ def test_wrapping2(self):
+ # DummyContent does not implement IIndexableObject
+ # no wrapper registered - should create an error
+ dummy = DummyContent(catalog=1)
+ ctool = self._makeOne()
+ self.assertRaises(TypeError, ctool.catalog_object,
+ dummy, '/dummy')
+
+ def test_wrapping3(self):
+ # DummyContent does not implement IIndexableObject
+ # wrapper registered - should look this up
+
+ def FakeWrapper(object, catalog):
+ return object
+
+ from zope.component import getSiteManager
+ self.sm = getSiteManager()
+ self.sm.registerAdapter( FakeWrapper
+ , (ICatalogAware, ICatalogTool)
+ , IIndexableObject )
+
+ dummy = CatalogDummyContent2(catalog=1)
+ ctool = self._makeOne()
+ ctool.catalog_object(dummy, '/dummy')
+ self.assertEqual(1, len(ctool._catalog.searchResults()))
+
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(IndexableObjectWrapperTests),
Modified: Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/tests/test_PortalFolder.py
===================================================================
--- Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/tests/test_PortalFolder.py 2009-03-17 14:11:53 UTC (rev 98182)
+++ Products.CMFCore/branches/miwa-catalog-adapter/Products/CMFCore/tests/test_PortalFolder.py 2009-03-17 14:35:42 UTC (rev 98183)
@@ -31,7 +31,7 @@
from zope.interface import implements
from zope.interface.verify import verifyClass
-from Products.CMFCore.CatalogTool import CatalogTool
+from Products.CMFCore.interfaces import ICatalogTool
from Products.CMFCore.exceptions import BadRequest
from Products.CMFCore.interfaces import ITypesTool
from Products.CMFCore.testing import ConformsToFolder
@@ -45,17 +45,44 @@
from Products.CMFCore.tests.base.testcase import SecurityTest
from Products.CMFCore.tests.base.tidata import FTIDATA_CMF15
from Products.CMFCore.tests.base.tidata import FTIDATA_DUMMY
-from Products.CMFCore.tests.base.utils import has_path
from Products.CMFCore.TypesTool import FactoryTypeInformation as FTI
from Products.CMFCore.TypesTool import TypesTool
from Products.CMFCore.WorkflowTool import WorkflowTool
+from types import TupleType
-
def extra_meta_types():
return [{'name': 'Dummy', 'action': 'manage_addFolder',
'permission': 'View'}]
+class DummyCatalogTool:
+ implements(ICatalogTool)
+ def __init__(self):
+ self.paths = []
+ self.ids = []
+
+ def indexObject(self, object):
+ self.paths.append( '/'.join(object.getPhysicalPath()) )
+ self.ids.append( object.getId() )
+
+ def unindexObject(self, object):
+ self.paths.remove( '/'.join(object.getPhysicalPath()) )
+ self.ids.append( object.getId() )
+
+ def reindexObject(self, object):
+ pass
+
+ def __len__(self):
+ return len(self.paths)
+
+def has_path(catalog, path):
+ if type(path) is TupleType:
+ path = '/'.join(path)
+ return path in catalog.paths
+
+def has_id(catalog, id):
+ return id in catalog.ids
+
class PortalFolderFactoryTests(SecurityTest):
layer = TraversingEventZCMLLayer
@@ -211,7 +238,7 @@
#
test = self._makeOne('test')
ttool = self.site._setObject( 'portal_types', TypesTool() )
- ctool = self.site._setObject( 'portal_catalog', CatalogTool() )
+ ctool = self.site._setObject( 'portal_catalog', DummyCatalogTool() )
self.assertEqual( len(ctool), 0 )
test._setObject( 'foo', DummyContent( 'foo' , catalog=1 ) )
@@ -232,7 +259,7 @@
# instantiation (Tracker issue 309)
#
ttool = self.site._setObject( 'portal_types', TypesTool() )
- ctool = self.site._setObject( 'portal_catalog', CatalogTool() )
+ ctool = self.site._setObject( 'portal_catalog', DummyCatalogTool() )
wftool = self.site._setObject( 'portal_workflow', WorkflowTool() )
test = self._makeOne('test')
wftool.notifyCreated(test)
@@ -248,7 +275,7 @@
test = self._makeOne('test')
ttool = self.site._setObject( 'portal_types', TypesTool() )
- ctool = self.site._setObject( 'portal_catalog', CatalogTool() )
+ ctool = self.site._setObject( 'portal_catalog', DummyCatalogTool() )
self.assertEqual( len(ctool), 0 )
test._setObject( 'sub', PortalFolder( 'sub', '' ) )
@@ -436,29 +463,28 @@
from Products.CMFCore.PortalFolder import PortalFolder
ttool = self.site._setObject( 'portal_types', TypesTool() )
- ctool = self.site._setObject( 'portal_catalog', CatalogTool() )
- ctool.addIndex('getId', 'FieldIndex')
+ ctool = self.site._setObject( 'portal_catalog', DummyCatalogTool() )
self.assertEqual( len(ctool), 0 )
folder = self._makeOne('folder')
folder._setObject( 'sub', PortalFolder( 'sub', '' ) )
folder.sub._setObject( 'foo', DummyContent( 'foo', catalog=1 ) )
self.assertEqual( len(ctool), 1 )
- self.failUnless( 'foo' in ctool.uniqueValuesFor('getId') )
- self.failUnless( has_path(ctool._catalog,
+ self.failUnless( has_id(ctool, 'foo') )
+ self.failUnless( has_path(ctool,
'/bar/site/folder/sub/foo') )
transaction.savepoint(optimistic=True)
folder.manage_renameObject(id='sub', new_id='new_sub')
self.assertEqual( len(ctool), 1 )
- self.failUnless( 'foo' in ctool.uniqueValuesFor('getId') )
- self.failUnless( has_path(ctool._catalog,
+ self.failUnless( has_id(ctool, 'foo') )
+ self.failUnless( has_path(ctool,
'/bar/site/folder/new_sub/foo') )
folder._setObject( 'bar', DummyContent( 'bar', catalog=1 ) )
self.assertEqual( len(ctool), 2 )
- self.failUnless( 'bar' in ctool.uniqueValuesFor('getId') )
- self.failUnless( has_path(ctool._catalog, '/bar/site/folder/bar') )
+ self.failUnless( has_id(ctool, 'bar') )
+ self.failUnless( has_path(ctool, '/bar/site/folder/bar') )
folder._setObject( 'sub2', PortalFolder( 'sub2', '' ) )
sub2 = folder.sub2
@@ -471,17 +497,17 @@
cookie = folder.manage_cutObjects(ids=['bar'])
sub2.manage_pasteObjects(cookie)
- self.failUnless( 'foo' in ctool.uniqueValuesFor('getId') )
- self.failUnless( 'bar' in ctool.uniqueValuesFor('getId') )
+ self.failUnless( has_id( ctool, 'foo' ) )
+ self.failUnless( has_id( ctool, 'bar' ) )
self.assertEqual( len(ctool), 2 )
- self.failUnless( has_path(ctool._catalog,
+ self.failUnless( has_path(ctool,
'/bar/site/folder/sub2/bar') )
def test_contentPaste(self):
#
# Does copy / paste work?
#
- ctool = self.site._setObject( 'portal_catalog', CatalogTool() )
+ ctool = self.site._setObject( 'portal_catalog', DummyCatalogTool() )
ttool = self.site._setObject( 'portal_types', TypesTool() )
fti = FTIDATA_DUMMY[0].copy()
ttool._setObject( 'Dummy Content', FTI(**fti) )
@@ -497,9 +523,9 @@
self.failIf( 'dummy' in sub2.contentIds() )
self.failIf( 'dummy' in sub3.objectIds() )
self.failIf( 'dummy' in sub3.contentIds() )
- self.failUnless( has_path(ctool._catalog, '/bar/site/sub1/dummy') )
- self.failIf( has_path(ctool._catalog, '/bar/site/sub2/dummy') )
- self.failIf( has_path(ctool._catalog, '/bar/site/sub3/dummy') )
+ self.failUnless( has_path(ctool, '/bar/site/sub1/dummy') )
+ self.failIf( has_path(ctool, '/bar/site/sub2/dummy') )
+ self.failIf( has_path(ctool, '/bar/site/sub3/dummy') )
cookie = sub1.manage_copyObjects( ids = ( 'dummy', ) )
# Waaa! force sub2 to allow paste of Dummy object.
@@ -513,9 +539,9 @@
self.failUnless( 'dummy' in sub2.contentIds() )
self.failIf( 'dummy' in sub3.objectIds() )
self.failIf( 'dummy' in sub3.contentIds() )
- self.failUnless( has_path(ctool._catalog, '/bar/site/sub1/dummy') )
- self.failUnless( has_path(ctool._catalog, '/bar/site/sub2/dummy') )
- self.failIf( has_path(ctool._catalog, '/bar/site/sub3/dummy') )
+ self.failUnless( has_path(ctool, '/bar/site/sub1/dummy') )
+ self.failUnless( has_path(ctool, '/bar/site/sub2/dummy') )
+ self.failIf( has_path(ctool, '/bar/site/sub3/dummy') )
transaction.savepoint(optimistic=True)
cookie = sub1.manage_cutObjects( ids = ('dummy',) )
@@ -530,9 +556,9 @@
self.failUnless( 'dummy' in sub2.contentIds() )
self.failUnless( 'dummy' in sub3.objectIds() )
self.failUnless( 'dummy' in sub3.contentIds() )
- self.failIf( has_path(ctool._catalog, '/bar/site/sub1/dummy') )
- self.failUnless( has_path(ctool._catalog, '/bar/site/sub2/dummy') )
- self.failUnless( has_path(ctool._catalog, '/bar/site/sub3/dummy') )
+ self.failIf( has_path(ctool, '/bar/site/sub1/dummy') )
+ self.failUnless( has_path(ctool, '/bar/site/sub2/dummy') )
+ self.failUnless( has_path(ctool, '/bar/site/sub3/dummy') )
class ContentFilterTests(unittest.TestCase):
More information about the Checkins
mailing list