[Checkins] SVN: z3c.multifieldindex/trunk/ Initial import.

Dan Korostelev nadako at gmail.com
Thu Oct 15 11:57:42 EDT 2009


Log message for revision 105085:
  Initial import.

Changed:
  _U  z3c.multifieldindex/trunk/
  A   z3c.multifieldindex/trunk/CHANGES.txt
  A   z3c.multifieldindex/trunk/bootstrap.py
  A   z3c.multifieldindex/trunk/buildout.cfg
  A   z3c.multifieldindex/trunk/setup.py
  A   z3c.multifieldindex/trunk/src/
  A   z3c.multifieldindex/trunk/src/z3c/
  A   z3c.multifieldindex/trunk/src/z3c/__init__.py
  A   z3c.multifieldindex/trunk/src/z3c/multifieldindex/
  A   z3c.multifieldindex/trunk/src/z3c/multifieldindex/README.txt
  A   z3c.multifieldindex/trunk/src/z3c/multifieldindex/__init__.py
  A   z3c.multifieldindex/trunk/src/z3c/multifieldindex/configure.zcml
  A   z3c.multifieldindex/trunk/src/z3c/multifieldindex/index.py
  A   z3c.multifieldindex/trunk/src/z3c/multifieldindex/interfaces.py
  A   z3c.multifieldindex/trunk/src/z3c/multifieldindex/subindex.py
  A   z3c.multifieldindex/trunk/src/z3c/multifieldindex/tests.py

-=-

Property changes on: z3c.multifieldindex/trunk
___________________________________________________________________
Added: svn:ignore
   + bin
parts
eggs
develop-eggs
.installed.cfg
coverage


Added: z3c.multifieldindex/trunk/CHANGES.txt
===================================================================
--- z3c.multifieldindex/trunk/CHANGES.txt	                        (rev 0)
+++ z3c.multifieldindex/trunk/CHANGES.txt	2009-10-15 15:57:42 UTC (rev 105085)
@@ -0,0 +1,8 @@
+=======
+CHANGES
+=======
+
+3.4.0 (unreleased)
+------------------
+
+- Initial release (using Zope 3.4 dependencies).

Added: z3c.multifieldindex/trunk/bootstrap.py
===================================================================
--- z3c.multifieldindex/trunk/bootstrap.py	                        (rev 0)
+++ z3c.multifieldindex/trunk/bootstrap.py	2009-10-15 15:57:42 UTC (rev 105085)
@@ -0,0 +1,69 @@
+##############################################################################
+#
+# Copyright (c) 2006 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.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id$
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+ez = {}
+exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+                     ).read() in ez
+ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+import pkg_resources
+
+is_jython = sys.platform.startswith('java')
+
+if is_jython:
+    import subprocess
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+    cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+
+if is_jython:
+    assert subprocess.Popen(
+           [sys.executable] + ['-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout'],
+           env = dict(os.environ,
+                 PYTHONPATH = 
+                 ws.find(pkg_resources.Requirement.parse('setuptools')).location
+                 ),
+           ).wait() == 0
+
+else:
+    assert os.spawnle(
+        os.P_WAIT, sys.executable, sys.executable,
+        '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+        dict(os.environ,
+            PYTHONPATH=
+            ws.find(pkg_resources.Requirement.parse('setuptools')).location
+            ),
+        ) == 0
+
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)


Property changes on: z3c.multifieldindex/trunk/bootstrap.py
___________________________________________________________________
Added: svn:keywords
   + Id

Added: z3c.multifieldindex/trunk/buildout.cfg
===================================================================
--- z3c.multifieldindex/trunk/buildout.cfg	                        (rev 0)
+++ z3c.multifieldindex/trunk/buildout.cfg	2009-10-15 15:57:42 UTC (rev 105085)
@@ -0,0 +1,27 @@
+[buildout]
+develop = .
+parts = test coverage-test coverage-report pydev python
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = z3c.multifieldindex [test]
+
+[coverage-test]
+recipe = zc.recipe.testrunner
+eggs = z3c.multifieldindex [test]
+defaults = ['--coverage', '../../coverage']
+
+[coverage-report]
+recipe = zc.recipe.egg
+eggs = z3c.coverage
+scripts = coverage=coverage-report
+arguments = ('coverage', 'coverage/report')
+
+[pydev]
+recipe = pb.recipes.pydev
+eggs = z3c.multifieldindex [test]
+
+[python]
+recipe = zc.recipe.egg
+eggs = z3c.multifieldindex
+interpreter = python

Added: z3c.multifieldindex/trunk/setup.py
===================================================================
--- z3c.multifieldindex/trunk/setup.py	                        (rev 0)
+++ z3c.multifieldindex/trunk/setup.py	2009-10-15 15:57:42 UTC (rev 105085)
@@ -0,0 +1,58 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation 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.
+#
+##############################################################################
+"""Setup for z3c.multifieldindex package
+
+$Id$
+"""
+import os
+
+from setuptools import setup, find_packages
+
+def read(*rnames):
+    return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+setup(
+    name='z3c.multifieldindex',
+    version='3.4.0dev',
+    url='http://pypi.python.org/pypi/z3c.multifieldindex',
+    license='ZPL 2.1',
+    description='Multi-field index for zope catalog',
+    author='Dan Korostelev and Zope Community',
+    author_email='zope-dev at zope.org',
+    long_description=\
+        read('src', 'z3c', 'multifieldindex', 'README.txt') + \
+        '\n\n' + \
+        read('CHANGES.txt'),
+    packages=find_packages('src'),
+    package_dir={'': 'src'},
+    namespace_packages=['z3c'],
+    install_requires=[
+      'setuptools',
+      'zc.catalog',
+      'ZODB3',
+      'zope.app.catalog',
+      'zope.app.container',
+      'zope.component',
+      'zope.index',
+      'zope.interface',
+      'zope.schema',
+      ],
+    extras_require = dict(
+        test=[
+            'zope.testing',
+            ],
+        ),
+    include_package_data=True,
+    zip_safe=False,
+    )


Property changes on: z3c.multifieldindex/trunk/setup.py
___________________________________________________________________
Added: svn:keywords
   + Id


Property changes on: z3c.multifieldindex/trunk/src
___________________________________________________________________
Added: svn:ignore
   + *.egg-info


Added: z3c.multifieldindex/trunk/src/z3c/__init__.py
===================================================================
--- z3c.multifieldindex/trunk/src/z3c/__init__.py	                        (rev 0)
+++ z3c.multifieldindex/trunk/src/z3c/__init__.py	2009-10-15 15:57:42 UTC (rev 105085)
@@ -0,0 +1 @@
+__import__('pkg_resources').declare_namespace(__name__)
\ No newline at end of file


Property changes on: z3c.multifieldindex/trunk/src/z3c/__init__.py
___________________________________________________________________
Added: svn:keywords
   + Id

Added: z3c.multifieldindex/trunk/src/z3c/multifieldindex/README.txt
===================================================================
--- z3c.multifieldindex/trunk/src/z3c/multifieldindex/README.txt	                        (rev 0)
+++ z3c.multifieldindex/trunk/src/z3c/multifieldindex/README.txt	2009-10-15 15:57:42 UTC (rev 105085)
@@ -0,0 +1,124 @@
+===================
+z3c.multifieldindex
+===================
+
+This package provides an index for zope catalog that can index multiple fields.
+It is useful in cases when field set are dynamic (for example with customizable
+persistent fields).
+
+Actually, this package provides a base class for custom multi-field indexes and
+to make it work, you need to override some methods in it. But first, let's
+create a content schema and interface we will use:
+
+  >>> from zope.interface import Interface, implements
+  >>> from zope.schema import Text, Int, List, TextLine
+  
+  >>> class IPerson(Interface):
+  ...
+  ...     age = Int()
+  ...     info = Text()
+  ...     skills = List(value_type=TextLine())
+
+  >>> class Person(object):
+  ...
+  ...     implements(IPerson)
+  ...
+  ...     def __init__(self, age, info, skills):
+  ...         self.age = age
+  ...         self.info = info
+  ...         self.skills = skills
+
+Let's create a set of person objects:
+
+  >>> dataset = [
+  ...     (1, Person(20, u'Sweet and cute', ['dancing', 'singing'])),
+  ...     (2, Person(33, u'Smart and sweet', ['math', 'dancing'])),
+  ...     (3, Person(6, u'Young and cute', ['singing', 'painting'])),
+  ... ]
+
+We have choose exactly those different types of fields to illustrate that the
+index is smart enough to know how to index each type of value. We'll return
+back to this topic later in this document.
+
+Now, we need to create an multi-field index class that will be used to index our
+person objects. We'll override two methods in it to make it functional:
+
+  >>> from z3c.multifieldindex.index import MultiFieldIndexBase
+  >>> from zope.schema import getFields
+
+  >>> class PersonIndex(MultiFieldIndexBase):
+  ...
+  ...     def _fields(self):
+  ...         return getFields(IPerson).items()
+  ... 
+  ...     def _getData(self, object):
+  ...         return {
+  ...             'age': object.age,
+  ...             'info': object.info,
+  ...             'skills': object.skills,
+  ...         }
+
+The "_fields" method should return an iterable of (name, field) pairs of fields
+that should be indexed. The sub-indexes will be created for those fields.
+
+The "_getData" method returns a dictionary of data to be indexed using given
+object. The keys of the dictionary should match field names.
+
+Sub-indexes are created automatically by looking up an index factory for each
+field. Three most-used factories are provided by this package. Let's register
+them to continue (it's also done in this package's configure.zcml file):
+
+  >>> from z3c.multifieldindex.subindex import DefaultIndexFactory
+  >>> from z3c.multifieldindex.subindex import CollectionIndexFactory
+  >>> from z3c.multifieldindex.subindex import TextIndexFactory
+  >>> from zope.component import provideAdapter
+  
+  >>> provideAdapter(DefaultIndexFactory)
+  >>> provideAdapter(CollectionIndexFactory)
+  >>> provideAdapter(TextIndexFactory)
+
+The default index factory creates zc.catalog's ValueIndex, the collection index
+factory creates zc.catalog's SetIndex and the text index factory creates
+zope.index's TextIndex. This is needed to know when you'll be doing queries.
+
+Okay, now let's create an instance of index and prepare it to be used.
+
+  >>> index = PersonIndex()
+  >>> index.recreateIndexes()
+
+The "recreateIndexes" does re-creation of sub-indexes. It is normally called
+by a subscriber to IObjectAddedEvent, provided by this package, but we simply
+call it by hand for this test.
+
+Now, let's finally index our person objects:
+
+  >>> for docid, person in dataset:
+  ...     index.index_doc(docid, person)
+
+Let's do a query now. The query format is quite simple. It is a dictionary, where
+keys are names of fields and values are queries for sub-indexes.
+
+  >>> results = index.apply({
+  ...     'skills': {'any_of': ('singing', 'painting')},
+  ... })
+  >>> list(results)
+  [1, 3]
+
+  >>> results = index.apply({
+  ...     'info': 'sweet',
+  ... })
+  >>> list(results)
+  [1, 2]
+
+  >>> results = index.apply({
+  ...     'age': {'between': (1, 30)},
+  ... })
+  >>> list(results)
+  [1, 3]
+
+  >>> results = index.apply({
+  ...     'age': {'between': (1, 30)},
+  ...     'skills': {'any_of': ('dancing', )},
+  ... })
+  >>> list(results)
+  [1]


Property changes on: z3c.multifieldindex/trunk/src/z3c/multifieldindex/__init__.py
___________________________________________________________________
Added: svn:keywords
   + Id

Added: z3c.multifieldindex/trunk/src/z3c/multifieldindex/configure.zcml
===================================================================
--- z3c.multifieldindex/trunk/src/z3c/multifieldindex/configure.zcml	                        (rev 0)
+++ z3c.multifieldindex/trunk/src/z3c/multifieldindex/configure.zcml	2009-10-15 15:57:42 UTC (rev 105085)
@@ -0,0 +1,9 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+  <subscriber handler=".index.multiFieldIndexAdded" />
+
+  <adapter factory=".subindex.DefaultIndexFactory" />
+  <adapter factory=".subindex.TextIndexFactory" />
+  <adapter factory=".subindex.CollectionIndexFactory" />
+
+</configure>

Added: z3c.multifieldindex/trunk/src/z3c/multifieldindex/index.py
===================================================================
--- z3c.multifieldindex/trunk/src/z3c/multifieldindex/index.py	                        (rev 0)
+++ z3c.multifieldindex/trunk/src/z3c/multifieldindex/index.py	2009-10-15 15:57:42 UTC (rev 105085)
@@ -0,0 +1,93 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation 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.
+#
+##############################################################################
+"""Multi-field index implementation
+
+$Id$
+"""
+from BTrees.IFBTree import weightedIntersection
+from zope.app.container.btree import BTreeContainer
+from zope.app.container.interfaces import IObjectAddedEvent
+from zope.component import adapter
+from zope.interface import implements
+
+from z3c.multifieldindex.interfaces import IMultiFieldIndex
+from z3c.multifieldindex.interfaces import ISubIndexFactory
+
+
+class MultiFieldIndexBase(BTreeContainer):
+    implements(IMultiFieldIndex)
+    
+    def _fields(self):
+        """To be overriden. Should return an iterable of (name, field) pairs."""
+        raise NotImplemented('_fields method should be provided by subclass.')
+    
+    def _getData(self, object):
+        """To be overriden. Should return a dictionary of data for given object.
+        
+        Dictionary keys are the same as field/index names and values are actual
+        values to be indexed by according index.
+        """
+        raise NotImplemented('_getData method should be provided by subclass.')
+    
+    def recreateIndexes(self):
+        # 1. Remove all indexes
+        for name in list(self.keys()):
+            del self[name]
+        
+        # 2. Create new indexes for fields that want to be indexed
+        for name, field in self._fields():
+            factory = ISubIndexFactory(field)
+            self[name] = factory()
+    
+    def index_doc(self, docid, value):
+        data = self._getData(value)
+        for name in self:
+            value = data.get(name)
+            if value is not None:
+                self[name].index_doc(docid, value)
+    
+    def unindex_doc(self, docid):
+        for index in self.values():
+            index.unindex_doc(docid)
+    
+    def clear(self):
+        for index in self.values():
+            index.clear()
+
+    def apply(self, query):
+        results = []
+        for name, subquery in query.items():
+            if name not in self:
+                continue
+            r = self[name].apply(subquery)
+            if r is None:
+                continue
+            if not r:
+                return r
+            results.append((len(r), r))
+
+        if not results:
+            return None
+
+        results.sort()
+        _, result = results.pop(0)
+        for _, r in results:
+            _, result = weightedIntersection(result, r)
+
+        return result
+
+
+ at adapter(IMultiFieldIndex, IObjectAddedEvent)
+def multiFieldIndexAdded(index, event):
+    index.recreateIndexes()


Property changes on: z3c.multifieldindex/trunk/src/z3c/multifieldindex/index.py
___________________________________________________________________
Added: svn:keywords
   + Id

Added: z3c.multifieldindex/trunk/src/z3c/multifieldindex/interfaces.py
===================================================================
--- z3c.multifieldindex/trunk/src/z3c/multifieldindex/interfaces.py	                        (rev 0)
+++ z3c.multifieldindex/trunk/src/z3c/multifieldindex/interfaces.py	2009-10-15 15:57:42 UTC (rev 105085)
@@ -0,0 +1,44 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation 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.
+#
+##############################################################################
+"""Interfaces for multi-field index
+
+$Id$
+"""
+from zope.app.catalog.interfaces import ICatalogIndex
+from zope.interface import Interface
+
+
+class IMultiFieldIndex(ICatalogIndex):
+    """An index for multiple fields"""
+    
+    def apply(query):
+        """See IIndexSearch for the purpose of this method.
+        
+        query is the dictionary which keys are names of sub-indexes
+        and values are queries for those indexes.
+        """
+
+    def recreateIndexes():
+        """Clear and recreate sub-indexes.
+        
+        Note that after using this method, newly created sub-indexes won't
+        reindex current content. This may change in future.
+        """
+
+
+class ISubIndexFactory(Interface):
+    """A factory of sub-index for multi-field index"""
+
+    def __call__():
+        """Return an index instance to be added to multi-field index"""


Property changes on: z3c.multifieldindex/trunk/src/z3c/multifieldindex/interfaces.py
___________________________________________________________________
Added: svn:keywords
   + Id

Added: z3c.multifieldindex/trunk/src/z3c/multifieldindex/subindex.py
===================================================================
--- z3c.multifieldindex/trunk/src/z3c/multifieldindex/subindex.py	                        (rev 0)
+++ z3c.multifieldindex/trunk/src/z3c/multifieldindex/subindex.py	2009-10-15 15:57:42 UTC (rev 105085)
@@ -0,0 +1,51 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation 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.
+#
+##############################################################################
+"""Sub-index factories for mult-field index
+
+$Id$
+"""
+from zc.catalog.index import ValueIndex, SetIndex
+from zope.component import adapts
+from zope.index.text import TextIndex
+from zope.interface import implements
+from zope.schema.interfaces import IField, ICollection, IText
+
+from z3c.multifieldindex.interfaces import ISubIndexFactory
+
+
+class SubIndexFactoryBase(object):
+    implements(ISubIndexFactory)
+    
+    factory = None
+    
+    def __init__(self, field):
+        self.field = field
+        
+    def __call__(self):
+        return self.factory()
+
+
+class DefaultIndexFactory(SubIndexFactoryBase):
+    adapts(IField)
+    factory = ValueIndex
+
+
+class CollectionIndexFactory(SubIndexFactoryBase):
+    adapts(ICollection)
+    factory = SetIndex
+
+
+class TextIndexFactory(SubIndexFactoryBase):
+    adapts(IText)
+    factory = TextIndex


Property changes on: z3c.multifieldindex/trunk/src/z3c/multifieldindex/subindex.py
___________________________________________________________________
Added: svn:keywords
   + Id

Added: z3c.multifieldindex/trunk/src/z3c/multifieldindex/tests.py
===================================================================
--- z3c.multifieldindex/trunk/src/z3c/multifieldindex/tests.py	                        (rev 0)
+++ z3c.multifieldindex/trunk/src/z3c/multifieldindex/tests.py	2009-10-15 15:57:42 UTC (rev 105085)
@@ -0,0 +1,25 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation 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.
+#
+##############################################################################
+"""Tests for z3c.multifieldindex functionality.
+
+$Id$
+"""
+import unittest
+from zope.testing import doctest
+
+def test_suite():
+    return unittest.TestSuite(
+        doctest.DocFileSuite('README.txt',
+            optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS)
+    )


Property changes on: z3c.multifieldindex/trunk/src/z3c/multifieldindex/tests.py
___________________________________________________________________
Added: svn:keywords
   + Id



More information about the checkins mailing list