[Zope3-checkins] SVN: Zope3/trunk/ Restored the catalog and catalog-indexing code.

Jim Fulton jim at zope.com
Sun Aug 29 17:10:45 EDT 2004


Log message for revision 27347:
  Restored the catalog and catalog-indexing code.
  
  This code has been substantially refactored.  Catalogs are just
  utilities. The indexing code is derived from the code in zope.index
  for use just in catalogs (thus no zope.app.index package).  Various
  subscribers are provided to get catalogs and their indexes to be
  updated at appropriate times.
  
  The README.txt now gives a working (functional text) example of how to
  create and use catalogs.
  
  There are lots of issues, but the dificult wiring work is done.
  


Changed:
  A   Zope3/trunk/package-includes/zope.app.catalog-configure.zcml
  A   Zope3/trunk/src/zope/app/catalog/
  UU  Zope3/trunk/src/zope/app/catalog/README.txt
  _U  Zope3/trunk/src/zope/app/catalog/__init__.py
  _U  Zope3/trunk/src/zope/app/catalog/attribute.py
  _U  Zope3/trunk/src/zope/app/catalog/browser/__init__.py
  _U  Zope3/trunk/src/zope/app/catalog/browser/advanced.pt
  _U  Zope3/trunk/src/zope/app/catalog/browser/catalog.py
  _U  Zope3/trunk/src/zope/app/catalog/browser/catalog_icon.gif
  UU  Zope3/trunk/src/zope/app/catalog/browser/configure.zcml
  UU  Zope3/trunk/src/zope/app/catalog/catalog.py
  _U  Zope3/trunk/src/zope/app/catalog/configure.zcml
  _U  Zope3/trunk/src/zope/app/catalog/field.py
  A   Zope3/trunk/src/zope/app/catalog/ftests.py
  UU  Zope3/trunk/src/zope/app/catalog/interfaces.py
  _U  Zope3/trunk/src/zope/app/catalog/keyword.py
  UU  Zope3/trunk/src/zope/app/catalog/tests.py
  UU  Zope3/trunk/src/zope/app/catalog/text.py


-=-
Copied: Zope3/trunk/package-includes/zope.app.catalog-configure.zcml (from rev 27182, Zope3/branches/jim-index/package-includes/zope.app.catalog-configure.zcml)

Copied: Zope3/trunk/src/zope/app/catalog (from rev 27182, Zope3/branches/jim-index/src/zope/app/catalog)

Modified: Zope3/trunk/src/zope/app/catalog/README.txt
===================================================================
--- Zope3/branches/jim-index/src/zope/app/catalog/README.txt	2004-08-18 19:23:39 UTC (rev 27182)
+++ Zope3/trunk/src/zope/app/catalog/README.txt	2004-08-29 21:10:45 UTC (rev 27347)
@@ -1,76 +1,391 @@
-Adding a site catalog:
+Catalogs
+========
 
-This also presupposes a product called "blog", which allows you to create
-content objects - this should apply equally to any other content objects
-in your own zope install, presuming they have attributes with values ;)
+Catalogs are simple tools used to suppprt searching.  A catalog
+manages a collection of indexes, and aranges for objects to indexed
+with it's contained indexes.
 
-Add Utility Service to ++etc++site.  Make sure it's marked "Active".
+TODO: Filters
+      Catalogs should provide the option to filter the objects the
+      catalog. This would facilitate the use of separate catalogs for
+      separate purposes.  It should be possible to specify a a
+      collection of types (interfaces) to be cataloged and a filtering
+      expression.  Perhaps another option would be to be the ability
+      to spcify a names filter adapter.
 
-Add a new folder to ++etc++site to keep things clean, called 'searches'.
+Catalogs use a unique-id tool to assign short (integer) ids to
+objects.  Before creating a catalog, you must create a uniqueid tool:
 
-Go to /++etc++site/searches, the new folder
+  >>> print http(r"""
+  ... POST /++etc++site/default/AddUtility/action.html HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... Content-Length: 78
+  ... Content-Type: application/x-www-form-urlencoded
+  ... Referer: http://localhost:8081/++etc++site/default/AddUtility
+  ... 
+  ... type_name=zope.app.browser.add.zope.app.uniqueid.UniqueIdUtility&id=&add=+Add+""")
+  HTTP/1.1 303 ...
 
-Add a Catalog, called 'blogCatalog'.  This will take you to a "New Utility
-Registration" page.  Enter a name of 'blogCatalog' (this is the name you
-will use to find the utility via getUtility()), a provided interface of
-"ICatalogQuery" (the interface we implement for a queryable object), a
-permission of zope.View, and make it active.
+And register it:
 
-Now we have a utility that implements ICatalogQuery named 'blogCatalog'.
-Look in ++etc++site, Utility service, see that it's registered.
+  >>> print http(r"""
+  ... POST /++etc++site/default/UniqueIdUtility/addRegistration.html HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... Content-Length: 864
+  ... Content-Type: multipart/form-data; boundary=---------------------------68417209514430962931254091825
+  ... Referer: http://localhost:8081/++etc++site/default/UniqueIdUtility/addRegistration.html
+  ... 
+  ... -----------------------------68417209514430962931254091825
+  ... Content-Disposition: form-data; name="field.name"
+  ... 
+  ... 
+  ... -----------------------------68417209514430962931254091825
+  ... Content-Disposition: form-data; name="field.interface"
+  ... 
+  ... zope.app.uniqueid.interfaces.IUniqueIdUtility
+  ... -----------------------------68417209514430962931254091825
+  ... Content-Disposition: form-data; name="field.interface-empty-marker"
+  ... 
+  ... 1
+  ... -----------------------------68417209514430962931254091825
+  ... Content-Disposition: form-data; name="field.permission"
+  ... 
+  ... zope.Public
+  ... -----------------------------68417209514430962931254091825
+  ... Content-Disposition: form-data; name="field.permission-empty-marker"
+  ... 
+  ... 1
+  ... -----------------------------68417209514430962931254091825
+  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
+  ... 
+  ... Add
+  ... -----------------------------68417209514430962931254091825--
+  ... """)
+  HTTP/1.1 303 ...
 
-Make the blogCatalog have a fieldindex for 'author' - click on the blogCatalog
-object, select the "Indexes" tab, and add a Field Index.  Interface can be
-zope.interface.Interface, field name should be 'author'.
 
-Add a blog object with an author field to the content space.
+Moving short-id management outside of catalogs make it possible to
+join searches accross multiple catalogs and indexing tools
+(e.g. relationship indexes).
 
-Now we add a search interface:
+TODO: Filters?
+      Maybe unique-id tools should be filtered as well, however, this
+      would limit the value of unique id tools for providing
+      cross-catalog/cross-index merging.  At least the domain for a
+      unique id tool would be broader than the domain of a catalog.
+      The value of filtering in the unique id tool is that it limits
+      the amount of work that needs to be done by catalogs.
+      One obvious aplication is to provide separate domains for
+      ordinary and meta content. If we did this, then we'd need to be
+      able to select, and, perhaps, alter, the unique-id tool used by
+      a catalog.
+   
+Once we have a unique-id tool, you can add a catalog:
 
-Add the Views Service to ++etc++site.  Make sure it's marked "Active".
+  >>> print http(r"""
+  ... POST /++etc++site/default/AddUtility/action.html HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... Content-Length: 77
+  ... Content-Type: application/x-www-form-urlencoded
+  ... Referer: http://localhost:8081/++etc++site/default/AddUtility
+  ... 
+  ... type_name=zope.app.browser.add.zope.app.catalog.catalog.Catalog&id=&add=+Add+""")
+  HTTP/1.1 303 ...
 
-Add a module to ++etc++site/default called 'module'. Insert code:
+and register it:
 
-"""
-from zope.app import zapi 
-from zope.app.catalog.interfaces.catalog import ICatalogQuery
 
-class CatalogView: 
-    def search(self): 
-        request = self.request 
-        catalog = zapi.getUtility(
-            self.context,
-            ICatalogQuery, 
-            name='blogCatalog') 
-        terms = request['terms'] 
-        return catalog.searchResults(author=terms)
-"""
+  >>> print http(r"""
+  ... POST /++etc++site/default/Catalog/addRegistration.html HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... Content-Length: 855
+  ... Content-Type: multipart/form-data; boundary=---------------------------17974048709381505781405189947
+  ... Referer: http://localhost:8081/++etc++site/default/Catalog/addRegistration.html
+  ... 
+  ... -----------------------------17974048709381505781405189947
+  ... Content-Disposition: form-data; name="field.name"
+  ... 
+  ... 
+  ... -----------------------------17974048709381505781405189947
+  ... Content-Disposition: form-data; name="field.interface"
+  ... 
+  ... zope.app.catalog.interfaces.ICatalog
+  ... -----------------------------17974048709381505781405189947
+  ... Content-Disposition: form-data; name="field.interface-empty-marker"
+  ... 
+  ... 1
+  ... -----------------------------17974048709381505781405189947
+  ... Content-Disposition: form-data; name="field.permission"
+  ... 
+  ... zope.Public
+  ... -----------------------------17974048709381505781405189947
+  ... Content-Disposition: form-data; name="field.permission-empty-marker"
+  ... 
+  ... 1
+  ... -----------------------------17974048709381505781405189947
+  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
+  ... 
+  ... Add
+  ... -----------------------------17974048709381505781405189947--
+  ... """)
+  HTTP/1.1 303 ...
 
-The "name" in the getUtility call is the name you gave the catalog utility
-when you added it.
 
-Go to ++etc++site/searches, add a page folder, 'pageFolder', click on it and
-go to Default Registration tab. Specify the following properties:
+Once we have a catalog, we can add indexes to it.  Before we add an
+index, let's add a templated page.  When adding indexes, existing
+objects are indexed, so the document we add now will appear in the
+index:
 
-  For interface: zope.interface.Interface
-  Dotted name of factory: module.CatalogView
-  Permission: zope.View
+  >>> print http(r"""
+  ... POST /+/zope.app.zptpage.ZPTPage%3D HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... Content-Length: 780
+  ... Content-Type: multipart/form-data; boundary=---------------------------1425445234777458421417366789
+  ... Referer: http://localhost:8081/+/zope.app.zptpage.ZPTPage=
+  ... 
+  ... -----------------------------1425445234777458421417366789
+  ... Content-Disposition: form-data; name="field.source"
+  ... 
+  ... <html>
+  ... <body>
+  ... Now is the time, for all good dudes to come to the aid of their country.
+  ... </body>
+  ... </html>
+  ... -----------------------------1425445234777458421417366789
+  ... Content-Disposition: form-data; name="field.expand.used"
+  ... 
+  ... 
+  ... -----------------------------1425445234777458421417366789
+  ... Content-Disposition: form-data; name="field.evaluateInlineCode.used"
+  ... 
+  ... 
+  ... -----------------------------1425445234777458421417366789
+  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
+  ... 
+  ... Add
+  ... -----------------------------1425445234777458421417366789
+  ... Content-Disposition: form-data; name="add_input_name"
+  ... 
+  ... dudes
+  ... -----------------------------1425445234777458421417366789--
+  ... """)
+  HTTP/1.1 303 ...
 
-Add a page, 'search' to etc/searches/pageFolder:
+Perhaps the most common type of index to be added is a text index.
+Most indexes require the specification of an interface, an attribute,
+and an indication of whether the attribute must be called.
 
-"""
-<html>
-  <tal:block define="results view/search">
-    <b>Results:</b>
-    <div tal:repeat="result results">
-      <a tal:define="url result/@@absolute_url"
-         tal:attributes="href url"
-         tal:content="url" />
-    </div>
-  </tal:block>
-</html>
-"""
+TODO: Simplify the UI for selecting interfaces and attributes
+      There are a number of ways the UI for this could be made more
+      user friendly:
 
-You can now access http://$ZOPE:$PORT/search?terms=authorname
-Where search is the name of the page in the pageFolder, authorname is the
-author name you wish to search for.
+      - If the user selects an interface, we could then provide a
+        select list of possible attributes and we could determine the
+        callability.  Perhaps selection of an interface should be
+        required. 
+
+      - An index should have a way to specify default values. In
+        particular, text indexes usially use ISearchableText and
+        searchableText. 
+
+For text indexes, one generally uses
+`zope.index.interfaces.searchabletext.ISearchableText`,
+`getSearchableText` and True.
+
+  >>> print http(r"""
+  ... POST /++etc++site/default/Catalog/+/AddTextIndex%3D HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... Content-Length: 1003
+  ... Content-Type: multipart/form-data; boundary=---------------------------12609588153518590761493918424
+  ... Referer: http://localhost:8081/++etc++site/default/Catalog/+/AddTextIndex=
+  ... 
+  ... -----------------------------12609588153518590761493918424
+  ... Content-Disposition: form-data; name="field.interface"
+  ... 
+  ... zope.index.interfaces.searchabletext.ISearchableText
+  ... -----------------------------12609588153518590761493918424
+  ... Content-Disposition: form-data; name="field.interface-empty-marker"
+  ... 
+  ... 1
+  ... -----------------------------12609588153518590761493918424
+  ... Content-Disposition: form-data; name="field.field_name"
+  ... 
+  ... getSearchableText
+  ... -----------------------------12609588153518590761493918424
+  ... Content-Disposition: form-data; name="field.field_callable.used"
+  ... 
+  ... 
+  ... -----------------------------12609588153518590761493918424
+  ... Content-Disposition: form-data; name="field.field_callable"
+  ... 
+  ... on
+  ... -----------------------------12609588153518590761493918424
+  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
+  ... 
+  ... Add
+  ... -----------------------------12609588153518590761493918424
+  ... Content-Disposition: form-data; name="add_input_name"
+  ... 
+  ... 
+  ... -----------------------------12609588153518590761493918424--
+  ... """, handle_errors=False)
+  HTTP/1.1 303 ...
+
+
+We can visit the advanced tab of the catalog to get some index
+statistics.  Doing so, we see that we have a single document and that
+the total word count is 8. The word count is only 8 because ssome stop
+words have been eliminated.
+
+
+  >>> print http(r"""
+  ... GET /++etc++site/default/Catalog/@@advanced.html HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... Referer: http://localhost:8081/++etc++site/default/Catalog/@@contents.html
+  ... """)
+  HTTP/1.1 200 Ok
+  ...
+  <table border="0">
+     <tr><th>Index</th>
+         <th>Document Count</th>
+         <th>Word Count</th>
+     </tr>
+     <tr>
+         <td>TextIndex</td>
+         <td>1</td>
+         <td>8</td>
+      </tr>
+  </table>
+  ...
+
+Now lets add some more pages:
+
+  >>> print http(r"""
+  ... POST /+/zope.app.zptpage.ZPTPage%3D HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... Content-Length: 754
+  ... Content-Type: multipart/form-data; boundary=---------------------------1213614620286666602740364725
+  ... Referer: http://localhost:8081/+/zope.app.zptpage.ZPTPage=
+  ... 
+  ... -----------------------------1213614620286666602740364725
+  ... Content-Disposition: form-data; name="field.source"
+  ... 
+  ... <html>
+  ... <body>
+  ... Dudes, we really need to switch to Zope 3 now.
+  ... </body>
+  ... </html>
+  ... -----------------------------1213614620286666602740364725
+  ... Content-Disposition: form-data; name="field.expand.used"
+  ... 
+  ... 
+  ... -----------------------------1213614620286666602740364725
+  ... Content-Disposition: form-data; name="field.evaluateInlineCode.used"
+  ... 
+  ... 
+  ... -----------------------------1213614620286666602740364725
+  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
+  ... 
+  ... Add
+  ... -----------------------------1213614620286666602740364725
+  ... Content-Disposition: form-data; name="add_input_name"
+  ... 
+  ... zope3
+  ... -----------------------------1213614620286666602740364725--
+  ... """)
+  HTTP/1.1 303 ...
+
+  >>> print http(r"""
+  ... POST /+/zope.app.zptpage.ZPTPage%3D HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... Content-Length: 838
+  ... Content-Type: multipart/form-data; boundary=---------------------------491825988706308579952614349
+  ... Referer: http://localhost:8081/+/zope.app.zptpage.ZPTPage=
+  ... 
+  ... -----------------------------491825988706308579952614349
+  ... Content-Disposition: form-data; name="field.source"
+  ... 
+  ... <html>
+  ... <body>
+  ... <p>Writing tests as doctests makes them much more understandable.</p>
+  ... <p>Python 2.4 has major enhancements to the doctest module.</p>
+  ... </body>
+  ... </html>
+  ... -----------------------------491825988706308579952614349
+  ... Content-Disposition: form-data; name="field.expand.used"
+  ... 
+  ... 
+  ... -----------------------------491825988706308579952614349
+  ... Content-Disposition: form-data; name="field.evaluateInlineCode.used"
+  ... 
+  ... 
+  ... -----------------------------491825988706308579952614349
+  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
+  ... 
+  ... Add
+  ... -----------------------------491825988706308579952614349
+  ... Content-Disposition: form-data; name="add_input_name"
+  ... 
+  ... doctest
+  ... -----------------------------491825988706308579952614349--
+  ... """)
+  HTTP/1.1 303 ...
+
+Now, if we visit the catalog advanced tab, we can see that the 3
+documents have been indexed and that the word count has increased to 30:
+
+  >>> print http(r"""
+  ... GET /++etc++site/default/Catalog/@@advanced.html HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... Referer: http://localhost:8081/++etc++site/default/Catalog/@@contents.html
+  ... """)
+  HTTP/1.1 200 Ok
+  ...
+  <table border="0">
+     <tr><th>Index</th>
+         <th>Document Count</th>
+         <th>Word Count</th>
+     </tr>
+     <tr>
+         <td>TextIndex</td>
+         <td>3</td>
+         <td>30</td>
+      </tr>
+  </table>
+  ...
+
+
+Now that we have a catalog with some documents indexed, we can search
+it.  The catalog is really meany yo be used from Python:
+
+  >>> root = getRootFolder()
+
+We'll make our root folder the site (this would normally be done by
+the publisher):
+
+  >>> from zope.app.component.hooks import setSite
+  >>> setSite(root)
+
+Now, we'll get the catalog:
+
+  >>> from zope.app import zapi
+  >>> from zope.app.catalog.interfaces import ICatalog
+  >>> catalog = zapi.getUtility(ICatalog)
+
+And search it to find the names of all of the documents that contain
+the word 'now':
+
+  >>> results = catalog.searchResults(TextIndex='now')
+  >>> [result.__name__ for result in results]
+  [u'dudes', u'zope3']
+
+TODO
+   This stuff needs a lot of work.  The indexing interfaces, despite
+   being rather elaborate are still a bit too simple.  There really
+   should be more provision for combining result.  In particular,
+   catalog should have a search interface that returns ranked docids,
+   rather than documents.
+
+You don't have to use the search algorithm build into the catalog. You
+can implement your own search algorithms and use them with a catalog's
+indexes.   

Modified: Zope3/trunk/src/zope/app/catalog/browser/configure.zcml
===================================================================
--- Zope3/branches/jim-index/src/zope/app/catalog/browser/configure.zcml	2004-08-18 19:23:39 UTC (rev 27182)
+++ Zope3/trunk/src/zope/app/catalog/browser/configure.zcml	2004-08-29 21:10:45 UTC (rev 27347)
@@ -36,7 +36,7 @@
     class=".catalog.Advanced"
     permission="zope.ManageContent">
 
-  <page name="advances.html" template="advanced.pt"
+  <page name="advanced.html" template="advanced.pt"
         menu="zmi_views" title="Advanced"/>
   <page name="reindex.html" attribute="reindex"/>
 </pages>
@@ -50,7 +50,7 @@
     permission="zope.ManageServices"
     content_factory="..field.FieldIndex"
     arguments="field_name"
-    keyword_arguments="interface"
+    keyword_arguments="interface field_callable"
     />
 
 <addMenuItem
@@ -76,7 +76,7 @@
     permission="zope.ManageServices"
     content_factory="..keyword.KeywordIndex"
     arguments="field_name"
-    keyword_arguments="interface"
+    keyword_arguments="interface field_callable"
     />
 
 <addMenuItem
@@ -103,7 +103,7 @@
     permission="zope.ManageServices"
     content_factory="..text.TextIndex"
     arguments="field_name"
-    keyword_arguments="interface"
+    keyword_arguments="interface field_callable"
     />
 
 <addMenuItem

Modified: Zope3/trunk/src/zope/app/catalog/catalog.py
===================================================================
--- Zope3/branches/jim-index/src/zope/app/catalog/catalog.py	2004-08-18 19:23:39 UTC (rev 27182)
+++ Zope3/trunk/src/zope/app/catalog/catalog.py	2004-08-29 21:10:45 UTC (rev 27347)
@@ -18,7 +18,7 @@
 from persistent import Persistent
 from zope.interface import implements
 from zope.app.zapi import getUtility
-from zope.security.proxy import trustedRemoveSecurityProxy
+from zope.security.proxy import removeSecurityProxy
 from zope.app.container.btree import BTreeContainer
 
 from zope.app import zapi
@@ -89,7 +89,7 @@
             # Hm. As a result of calling getAdapter, I get back
             # security proxy wrapped results from anything that
             # needed to be adapted.
-            results = trustedRemoveSecurityProxy(results)
+            results = removeSecurityProxy(results)
             if pendingResults is None:
                 pendingResults = results
             else:

Added: Zope3/trunk/src/zope/app/catalog/ftests.py
===================================================================
--- Zope3/branches/jim-index/src/zope/app/catalog/ftests.py	2004-08-18 19:23:39 UTC (rev 27182)
+++ Zope3/trunk/src/zope/app/catalog/ftests.py	2004-08-29 21:10:45 UTC (rev 27347)
@@ -0,0 +1,25 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Functional tests for xmlrpc
+
+$Id: ftests.py 27323 2004-08-28 19:31:22Z jim $
+"""
+
+def test_suite():
+    from zope.app.tests.functional import FunctionalDocFileSuite
+    return FunctionalDocFileSuite('README.txt')
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main(defaultTest='test_suite')

Modified: Zope3/trunk/src/zope/app/catalog/interfaces.py
===================================================================
--- Zope3/branches/jim-index/src/zope/app/catalog/interfaces.py	2004-08-18 19:23:39 UTC (rev 27182)
+++ Zope3/trunk/src/zope/app/catalog/interfaces.py	2004-08-29 21:10:45 UTC (rev 27347)
@@ -38,7 +38,9 @@
         """Reindex all objects."""
 
 
-class ICatalogIndex(zope.index.interfaces.IInjection):
+class ICatalogIndex(zope.index.interfaces.IInjection,
+                    zope.index.interfaces.ISimpleQuery,
+                    ):
     """An index to be used in a catalog
     """
     __parent__ = zope.schema.Field()

Modified: Zope3/trunk/src/zope/app/catalog/tests.py
===================================================================
--- Zope3/branches/jim-index/src/zope/app/catalog/tests.py	2004-08-18 19:23:39 UTC (rev 27182)
+++ Zope3/trunk/src/zope/app/catalog/tests.py	2004-08-29 21:10:45 UTC (rev 27347)
@@ -284,12 +284,34 @@
         self.assertEqual(self.cat.unregs, [id])
         self.assertEqual(self.cat.regs, [])
 
+
+def test_textindex_simple_query():
+    """
+    >>> class Doc:
+    ...     def __init__(self, text):
+    ...         self.text = text
+    >>> from zope.app.catalog.text import TextIndex
+    >>> index = TextIndex('text')
+    >>> index.index_doc(1, Doc('now time for all good men to come to the aid'))
+    >>> index.index_doc(2, Doc('we should use Zope3 now'))
+    >>> index.index_doc(3, Doc('doctest makes tests more readable'))
+    >>> r = index.query('now')
+    >>> r.sort()
+    >>> r
+    [1, 2]
+    >>> index.query('doctest')
+    [3]
+    
+    
+    """
+
 def test_suite():
     from zope.testing.doctestunit import DocTestSuite
     suite = unittest.TestSuite()
     suite.addTest(unittest.makeSuite(Test))
     suite.addTest(unittest.makeSuite(TestEventSubscribers))
     suite.addTest(DocTestSuite('zope.app.catalog.attribute'))
+    suite.addTest(DocTestSuite())
     return suite
 
 

Modified: Zope3/trunk/src/zope/app/catalog/text.py
===================================================================
--- Zope3/branches/jim-index/src/zope/app/catalog/text.py	2004-08-18 19:23:39 UTC (rev 27182)
+++ Zope3/trunk/src/zope/app/catalog/text.py	2004-08-29 21:10:45 UTC (rev 27347)
@@ -16,19 +16,52 @@
 $Id$
 """
 import zope.index.text
+import zope.index.interfaces.searchabletext
 import zope.interface
 
-import zope.app.container.contained
 import zope.app.catalog.attribute
 import zope.app.catalog.interfaces
+import zope.app.container.contained
+from zope.app.i18n import ZopeMessageIDFactory as _
 
 class ITextIndex(zope.app.catalog.interfaces.IAttributeIndex,
                  zope.app.catalog.interfaces.ICatalogIndex):
     """Interface-based catalog text index
     """
 
+    interface = zope.schema.Choice(
+        title=_(u"Interface"),
+        description=_(u"Objects will be adapted to this interface"),
+        vocabulary=_("Interfaces"),
+        required=False,
+        default=zope.index.interfaces.searchabletext.ISearchableText,
+        )
+
+    field_name = zope.schema.BytesLine(
+        title=_(u"Field Name"),
+        description=_(u"Name of the field to index"),
+        default="searchableText"
+        )
+
+    field_callable = zope.schema.Bool(
+        title=_(u"Field Callable"),
+        description=_(u"If true, then the field should be called to get the "
+                      u"value to be indexed"),
+        default=True,
+        )
+
 class TextIndex(zope.app.catalog.attribute.AttributeIndex,
                 zope.index.text.TextIndex,
                 zope.app.container.contained.Contained):
 
     zope.interface.implements(ITextIndex)
+
+    def query(self, text, start=0, count=None):
+        """Return a list of ids matching the text
+
+        This a dumbed-down implementation that matches ISimpleQuery.
+        
+        """
+        result = super(TextIndex, self).query(text, start, count)
+        return [id for (id, rank) in result[0]]
+    



More information about the Zope3-Checkins mailing list