[Checkins] SVN: z3c.searcher/ Added initial implementation
Roger Ineichen
roger at projekt01.ch
Thu May 1 21:43:46 EDT 2008
Log message for revision 86042:
Added initial implementation
Changed:
A z3c.searcher/branches/
A z3c.searcher/tags/
A z3c.searcher/trunk/
A z3c.searcher/trunk/CHANGES.txt
A z3c.searcher/trunk/LICENSE.txt
A z3c.searcher/trunk/README.txt
A z3c.searcher/trunk/bootstrap.py
A z3c.searcher/trunk/buildout.cfg
A z3c.searcher/trunk/setup.py
A z3c.searcher/trunk/src/
A z3c.searcher/trunk/src/z3c/
A z3c.searcher/trunk/src/z3c/__init__.py
A z3c.searcher/trunk/src/z3c/searcher/
A z3c.searcher/trunk/src/z3c/searcher/README.txt
A z3c.searcher/trunk/src/z3c/searcher/__init__.py
A z3c.searcher/trunk/src/z3c/searcher/browser.zcml
A z3c.searcher/trunk/src/z3c/searcher/configure.zcml
A z3c.searcher/trunk/src/z3c/searcher/criterium.pt
A z3c.searcher/trunk/src/z3c/searcher/criterium.py
A z3c.searcher/trunk/src/z3c/searcher/filter.pt
A z3c.searcher/trunk/src/z3c/searcher/filter.py
A z3c.searcher/trunk/src/z3c/searcher/form.py
A z3c.searcher/trunk/src/z3c/searcher/interfaces.py
A z3c.searcher/trunk/src/z3c/searcher/search.pt
A z3c.searcher/trunk/src/z3c/searcher/session.py
A z3c.searcher/trunk/src/z3c/searcher/table.pt
A z3c.searcher/trunk/src/z3c/searcher/table.py
A z3c.searcher/trunk/src/z3c/searcher/testing.py
A z3c.searcher/trunk/src/z3c/searcher/tests.py
-=-
Property changes on: z3c.searcher/trunk
___________________________________________________________________
Name: svn:ignore
+ bin
develop-eggs
parts
.installed.cfg
Added: z3c.searcher/trunk/CHANGES.txt
===================================================================
--- z3c.searcher/trunk/CHANGES.txt (rev 0)
+++ z3c.searcher/trunk/CHANGES.txt 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,8 @@
+=======
+CHANGES
+=======
+
+Version 0.5.0 (unreleased)
+-------------------------
+
+- Initial Release
Property changes on: z3c.searcher/trunk/CHANGES.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/LICENSE.txt
===================================================================
--- z3c.searcher/trunk/LICENSE.txt (rev 0)
+++ z3c.searcher/trunk/LICENSE.txt 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,54 @@
+Zope Public License (ZPL) Version 2.1
+-------------------------------------
+
+A copyright notice accompanies this license document that
+identifies the copyright holders.
+
+This license has been certified as open source. It has also
+been designated as GPL compatible by the Free Software
+Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the
+following conditions are met:
+
+1. Redistributions in source code must retain the
+ accompanying copyright notice, this list of conditions,
+ and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the accompanying
+ copyright notice, this list of conditions, and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+3. Names of the copyright holders must not be used to
+ endorse or promote products derived from this software
+ without prior written permission from the copyright
+ holders.
+
+4. The right to distribute this software or to use it for
+ any purpose does not give you the right to use
+ Servicemarks (sm) or Trademarks (tm) of the copyright
+ holders. Use of them is covered by separate agreement
+ with the copyright holders.
+
+5. If any files are modified, you must cause the modified
+ files to carry prominent notices stating that you changed
+ the files and the date of any change.
+
+Disclaimer
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS''
+ AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ NO EVENT SHALL THE COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
Property changes on: z3c.searcher/trunk/LICENSE.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/README.txt
===================================================================
--- z3c.searcher/trunk/README.txt (rev 0)
+++ z3c.searcher/trunk/README.txt 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1 @@
+This package provides an implementation for build search forms for Zope3.
\ No newline at end of file
Property changes on: z3c.searcher/trunk/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/bootstrap.py
===================================================================
--- z3c.searcher/trunk/bootstrap.py (rev 0)
+++ z3c.searcher/trunk/bootstrap.py 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# Copyright (c) 2007 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: bootstrap.py 75940 2007-05-24 14:45:00Z srichter $
+"""
+
+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
+
+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
+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.searcher/trunk/bootstrap.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/buildout.cfg
===================================================================
--- z3c.searcher/trunk/buildout.cfg (rev 0)
+++ z3c.searcher/trunk/buildout.cfg 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,25 @@
+[buildout]
+develop = .
+parts = test checker coverage-test coverage-report
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = z3c.searcher [test]
+
+
+[checker]
+recipe = lovely.recipe:importchecker
+path = src/z3c/searcher
+
+
+[coverage-test]
+recipe = zc.recipe.testrunner
+eggs = z3c.searcher [test]
+defaults = ['--coverage', '../../coverage']
+
+
+[coverage-report]
+recipe = zc.recipe.egg
+eggs = z3c.coverage
+scripts = coverage=coverage-report
+arguments = ('coverage', 'coverage/report')
Added: z3c.searcher/trunk/setup.py
===================================================================
--- z3c.searcher/trunk/setup.py (rev 0)
+++ z3c.searcher/trunk/setup.py 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,86 @@
+##############################################################################
+#
+# Copyright (c) 2007 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
+
+$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.searcher',
+ version='0.5.0dev',
+ author = "Roger Ineichen and the Zope Community",
+ author_email = "zope3-dev at zope.org",
+ description = "Persistent and session based search form for Zope3",
+ long_description=(
+ read('README.txt')
+ + '\n\n' +
+ read('CHANGES.txt')
+ ),
+ license = "ZPL 2.1",
+ keywords = "zope3 z3c catalog index indexer search searcher",
+ classifiers = [
+ 'Development Status :: 4 - Beta',
+ 'Environment :: Web Environment',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: Zope Public License',
+ 'Programming Language :: Python',
+ 'Natural Language :: English',
+ 'Operating System :: OS Independent',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Framework :: Zope3'],
+ url = 'http://cheeseshop.python.org/pypi/z3c.searcher',
+ packages = find_packages('src'),
+ include_package_data = True,
+ package_dir = {'':'src'},
+ namespace_packages = ['z3c',],
+ extras_require = dict(
+ test = [
+ 'z3c.macro',
+ 'z3c.testing',
+ 'zope.app.authentication',
+ 'zope.app.keyreference',
+ 'zope.app.pagetemplate',
+ 'zope.app.testing',
+ 'zope.contentprovider',
+ 'zope.publisher',
+ 'zope.session',
+ 'zope.testing',
+ ],
+ ),
+ install_requires = [
+ 'setuptools',
+ 'z3c.form',
+ 'z3c.formui',
+ 'z3c.i18n',
+ 'z3c.indexer',
+ 'z3c.template',
+ 'z3c.table',
+ 'zc.catalog',
+ 'zope.app.intid',
+ 'zope.app.container',
+ 'zope.component',
+ 'zope.event',
+ 'zope.index',
+ 'zope.interface',
+ 'zope.location',
+ 'zope.schema',
+ 'zope.session',
+ ],
+ zip_safe = False,
+)
Property changes on: z3c.searcher/trunk/setup.py
___________________________________________________________________
Name: svn:eol-style
+ native
Property changes on: z3c.searcher/trunk/src
___________________________________________________________________
Name: svn:ignore
+ z3c.searcher.egg-info
Added: z3c.searcher/trunk/src/z3c/__init__.py
===================================================================
--- z3c.searcher/trunk/src/z3c/__init__.py (rev 0)
+++ z3c.searcher/trunk/src/z3c/__init__.py 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,7 @@
+# this is a namespace package
+try:
+ import pkg_resources
+ pkg_resources.declare_namespace(__name__)
+except ImportError:
+ import pkgutil
+ __path__ = pkgutil.extend_path(__path__, __name__)
Property changes on: z3c.searcher/trunk/src/z3c/__init__.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/src/z3c/searcher/README.txt
===================================================================
--- z3c.searcher/trunk/src/z3c/searcher/README.txt (rev 0)
+++ z3c.searcher/trunk/src/z3c/searcher/README.txt 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,666 @@
+======
+README
+======
+
+This package provides a persistent search query implementation. This search
+query is implemented as a filter object which can use search criteria for build
+the search query. This package also offers some z3c.form based management views
+which allo us to manage the search filter and it's search criteria. Let's
+define a site with indexes which allows us to build search filter for.
+
+Note, this package depends on the new z3c.indexer package which offers a
+modular indexing concept. But you can use this package with the
+zope.app.catalog package too. You only have to build our own search citerium.
+
+
+Start a simple test setup
+-------------------------
+
+Setup some helpers:
+
+ >>> import zope.component
+ >>> from zope.app import folder
+ >>> from zope.app.component.site import LocalSiteManager
+ >>> from z3c.indexer.interfaces import IIndex
+
+Setup a site
+
+ >>> class SiteStub(folder.Folder):
+ ... """Sample site."""
+ >>> site = SiteStub()
+
+ >>> root['site'] = site
+ >>> sm = LocalSiteManager(site)
+ >>> site.setSiteManager(sm)
+
+And set the site as the current site. This is normaly done by traversing to a
+site:
+
+ >>> from zope.app.component import hooks
+ >>> hooks.setSite(site)
+
+Setup a IIntIds utility:
+
+ >>> from zope.app.intid import IntIds
+ >>> from zope.app.intid.interfaces import IIntIds
+ >>> intids = IntIds()
+ >>> sm['default']['intids'] = intids
+ >>> sm.registerUtility(intids, IIntIds)
+
+
+TextIndex
+---------
+
+Setup a text index:
+
+ >>> from z3c.indexer.index import TextIndex
+ >>> textIndex = TextIndex()
+ >>> sm['default']['textIndex'] = textIndex
+ >>> sm.registerUtility(textIndex, IIndex, name='textIndex')
+
+
+FieldIndex
+----------
+
+Setup a field index:
+
+ >>> from z3c.indexer.index import FieldIndex
+ >>> fieldIndex = FieldIndex()
+ >>> sm['default']['fieldIndex'] = fieldIndex
+ >>> sm.registerUtility(fieldIndex, IIndex, name='fieldIndex')
+
+
+ValueIndex
+----------
+
+Setup a value index:
+
+ >>> from z3c.indexer.index import ValueIndex
+ >>> valueIndex = ValueIndex()
+ >>> sm['default']['valueIndex'] = valueIndex
+ >>> sm.registerUtility(valueIndex, IIndex, name='valueIndex')
+
+
+SetIndex
+--------
+
+Setup a set index:
+
+ >>> from z3c.indexer.index import SetIndex
+ >>> setIndex = SetIndex()
+ >>> sm['default']['setIndex'] = setIndex
+ >>> sm.registerUtility(setIndex, IIndex, name='setIndex')
+
+
+DemoContent
+-----------
+
+Define a content object:
+
+ >>> import persistent
+ >>> import zope.interface
+ >>> from zope.app.container import contained
+ >>> from zope.schema.fieldproperty import FieldProperty
+
+ >>> class IDemoContent(zope.interface.Interface):
+ ... """Demo content."""
+ ... title = zope.schema.TextLine(
+ ... title=u'Title',
+ ... default=u'')
+ ...
+ ... body = zope.schema.TextLine(
+ ... title=u'Body',
+ ... default=u'')
+ ...
+ ... field = zope.schema.TextLine(
+ ... title=u'a field',
+ ... default=u'')
+ ...
+ ... value = zope.schema.TextLine(
+ ... title=u'A value',
+ ... default=u'')
+ ...
+ ... iterable = zope.schema.Tuple(
+ ... title=u'A sequence of values',
+ ... default=())
+
+ >>> class DemoContent(persistent.Persistent, contained.Contained):
+ ... """Demo content."""
+ ... zope.interface.implements(IDemoContent)
+ ...
+ ... title = FieldProperty(IDemoContent['title'])
+ ... body = FieldProperty(IDemoContent['body'])
+ ... field = FieldProperty(IDemoContent['field'])
+ ... value = FieldProperty(IDemoContent['value'])
+ ... iterable = FieldProperty(IDemoContent['iterable'])
+ ...
+ ... def __init__(self, title=u''):
+ ... self.title = title
+ ...
+ ... def __repr__(self):
+ ... return '<%s %r>' % (self.__class__.__name__, self.title)
+
+Create and add the content object to the site:
+
+ >>> demo = DemoContent(u'Title')
+ >>> demo.body = u'Body text'
+ >>> demo.field = u'Field'
+ >>> demo.value = u'Value'
+ >>> demo.iterable = (1, 2, 'Iterable')
+ >>> site['demo'] = demo
+
+The zope event subscriber for __setitem__ whould call the IIntIds register
+method for our content object. But we didn't setup the relevant subscribers, so
+we do this here:
+
+ >>> uid = intids.register(demo)
+
+
+Indexer
+-------
+
+Setup a indexer adapter for our content object.
+
+ >>> from z3c.indexer.indexer import MultiIndexer
+ >>> class DemoIndexer(MultiIndexer):
+ ... zope.component.adapts(IDemoContent)
+ ...
+ ... def doIndex(self):
+ ...
+ ... # index context in valueIndex
+ ... valueIndex = self.getIndex('textIndex')
+ ... txt = '%s %s' % (self.context.title, self.context.body)
+ ... valueIndex.doIndex(self.oid, txt)
+ ...
+ ... # index context in fieldIndex
+ ... fieldIndex = self.getIndex('fieldIndex')
+ ... fieldIndex.doIndex(self.oid, self.context.field)
+ ...
+ ... # index context in setIndex
+ ... setIndex = self.getIndex('setIndex')
+ ... setIndex.doIndex(self.oid, self.context.iterable)
+ ...
+ ... # index context in valueIndex
+ ... valueIndex = self.getIndex('valueIndex')
+ ... valueIndex.doIndex(self.oid, self.context.value)
+
+Register the indexer adapter as a named adapter:
+
+ >>> zope.component.provideAdapter(DemoIndexer, name='DemoIndexer')
+
+
+Indexing
+--------
+
+Before we start indexing, we check the index:
+
+ >>> textIndex.documentCount()
+ 0
+
+ >>> fieldIndex.documentCount()
+ 0
+
+ >>> setIndex.documentCount()
+ 0
+
+ >>> valueIndex.documentCount()
+ 0
+
+Now we can index our demo object:
+
+ >>> from z3c.indexer.indexer import index
+ >>> index(demo)
+
+And check our indexes:
+
+ >>> textIndex.documentCount()
+ 1
+
+ >>> fieldIndex.documentCount()
+ 1
+
+ >>> setIndex.documentCount()
+ 1
+
+ >>> valueIndex.documentCount()
+ 1
+
+
+Search Filter
+-------------
+
+Now we are ready and can start with our search filter implementation.
+The following search filter returns no results by default because it defines
+NoTerm as getDefaultQuery. This is usefull if you have a larg set of data and
+you like to start with a empty query if no cirterium is selected.
+
+ >>> from z3c.searcher import interfaces
+ >>> from z3c.searcher.filter import EmptyTerm
+ >>> from z3c.searcher.filter import SearchFilter
+
+ >>> class IContentSearchFilter(interfaces.ISearchFilter):
+ ... """Search filter for content objects."""
+
+ >>> class ContentSearchFilter(SearchFilter):
+ ... """Content search filter."""
+ ...
+ ... zope.interface.implements(IContentSearchFilter)
+ ...
+ ... def getDefaultQuery(self):
+ ... return EmptyTerm()
+
+
+Search Criterium
+----------------
+
+And we define a criterium for our demo content. This text search criterium uses
+the text index registered as ``textIndex`` above:
+
+ >>> from z3c.searcher import criterium
+ >>> class TextCriterium(criterium.TextCriterium):
+ ... """Full text search criterium for ``textIndex`` index."""
+ ...
+ ... indexOrName = 'textIndex'
+
+Such a criterium can search in our index. Let's start with a empty search query:
+
+ >>> from z3c.indexer.search import SearchQuery
+ >>> searchQuery = SearchQuery()
+
+You can see that the searchQuery returns a empty result.
+
+ >>> len(searchQuery.searchResults())
+ 0
+
+showcase
+~~~~~~~~
+
+Now we can create a criterium instance and give them a value:
+
+ >>> sampleCriterium = TextCriterium()
+ >>> sampleCriterium.value = u'Bod*'
+
+Now the criterium is able to search in it's related index within the given
+value within a given (emtpy) search query. This empty query is only used as
+a chainable query object. Each result get added or removed from this chain
+dependent on it's connector ``And``, ``OR`` or ``Not``:
+
+ >>> searchQuery = sampleCriterium.search(searchQuery)
+
+Now you can see that our criterium found a result from the text index:
+
+ >>> len(searchQuery.searchResults())
+ 1
+
+ >>> content = list(searchQuery.searchResults())[0]
+ >>> content.body
+ u'Body text'
+
+
+Search Criterium Factory
+------------------------
+
+The test above shows you how criterium can search in indexes. But that's not
+all. Our concept offers a search filter which can manage more then one search
+criterium in a filter. A criterium is an adapter for a filter. This means we
+need to create an adapter factory and register this factory as an adapter
+for our filter. Let's now create this criterium adapter factory:
+
+ >>> textCriteriumFactory = criterium.factory(TextCriterium, 'fullText')
+
+This search criterium factory class implements ISearchCriteriumFactory:
+
+ >>> interfaces.ISearchCriteriumFactory.implementedBy(textCriteriumFactory)
+ True
+
+and we register this adapter for our content search filter:
+
+ >>> zope.component.provideAdapter(textCriteriumFactory,
+ ... (IContentSearchFilter,), name='fullText')
+
+showcase
+~~~~~~~~
+
+Now you can see that our content search filter knows about the search criterium
+factories:
+
+ >>> contentSearchFilter = ContentSearchFilter()
+ >>> contentSearchFilter.criteriumFactories
+ [(u'fullText', <z3c.searcher.criterium.TextCriteriumFactory object at ...>)]
+
+Since the search criterium factory is an adapter for our search filter, the
+factory can adapt our contentSearchFilter:
+
+ >>> textCriteriumFactory = textCriteriumFactory(contentSearchFilter)
+ >>> textCriteriumFactory
+ <z3c.searcher.criterium.TextCriteriumFactory object at ...>
+
+Now we can call the factory and we will get back our search criterium instance:
+
+ >>> textCriterium = textCriteriumFactory()
+ >>> textCriterium
+ <TextCriterium object at ...>
+
+Our search criterium provides ISearchCriterium:
+
+ >>> interfaces.ISearchCriterium.providedBy(textCriterium)
+ True
+
+
+Search Example
+--------------
+
+Now we are ready to search within our filter construct. First let's create a
+plain content search filter:
+
+ >>> sampleFilter = ContentSearchFilter()
+
+Then let's add a criterium by it's factory name:
+
+ >>> sampleCriterium = sampleFilter.createCriterium('fullText')
+
+Now we can set a value for the criterium:
+
+ >>> sampleCriterium.value = u'Title'
+
+And add the criterium to our filter:
+
+ >>> sampleFilter.addCriterium(sampleCriterium)
+
+That's all, now our filter is a ble to genearet a query:
+
+ >>> sampleQuery = sampleFilter.generateQuery()
+
+And the sample search query can return the result:
+
+ >>> len(sampleQuery.searchResults())
+ 1
+
+ >>> content = list(sampleQuery.searchResults())[0]
+ >>> content.title
+ u'Title'
+
+
+Search Session
+--------------
+
+Before we show how to use the criterium and filter within z3c.form components,
+we will show you how the search session is working. Let's register and create
+a search session:
+
+ >>> from z3c.searcher import session
+ >>> zope.component.provideAdapter(session.SearchSession)
+
+Now we can create a test request and get the session as adapter for a request:
+
+ >>> import z3c.form.testing
+ >>> request = z3c.form.testing.TestRequest()
+ >>> searchSession = interfaces.ISearchSession(request)
+ >>> searchSession
+ <z3c.searcher.session.SearchSession object at ...>
+
+The search session offers an API for store and manage filters:
+
+ >>> searchSession.addFilter('foo', sampleFilter)
+
+And we can get such filters from the search session by name.
+
+ >>> searchSession.getFilter('foo')
+ <ContentSearchFilter object at ...>
+
+Or we can get all search filters sotred in this session:
+
+ >>> searchSession.getFilters()
+ [<ContentSearchFilter object at ...>]
+
+And we can remove a filter by it's name:
+
+ >>> searchSession.removeFilter('foo')
+ >>> searchSession.getFilters()
+ []
+
+There is also another argument called ``key`` in the search session methods.
+This argument can be used as namespace. If you need to support a specific
+filter only for one object instance, you can use a key which is unique to that
+object as discriminator.
+
+ >>> myFilter = ContentSearchFilter()
+ >>> searchSession.addFilter('foo', myFilter, key='myKey')
+
+Such filters are only available if the right ``key`` is used:
+
+ >>> searchSession.getFilter('foo') is None
+ True
+
+ >>> searchSession.getFilter('foo', key='myKey')
+ <ContentSearchFilter object at ...>
+
+ >>> searchSession.getFilters()
+ []
+
+Now let's cleanup our search session and remove the filter stored by the key:
+
+ >>> searchSession.getFilters('myKey')
+ [<ContentSearchFilter object at ...>]
+
+ >>> searchSession.removeFilter('foo', 'myKey')
+ >>> searchSession.getFilters('myKey')
+ []
+
+
+Criterium Form
+--------------
+Now we will show you how the form part is working. Each criterium can render
+itself within a form. We offer a CriteriumForm class for doing this. Let's
+create and render such a criterium form:
+
+ >>> import z3c.form.testing
+ >>> from z3c.searcher import form
+ >>> criteriumRow = form.CriteriumForm(textCriterium, request)
+ >>> criteriumRow
+ <z3c.searcher.form.CriteriumForm object at ...>
+
+Before we can render the form, we need to register the templates:
+
+ >>> from zope.configuration import xmlconfig
+ >>> import zope.component
+ >>> import zope.viewlet
+ >>> import zope.app.component
+ >>> import zope.app.security
+ >>> import zope.app.publisher.browser
+ >>> import z3c.template
+ >>> import z3c.macro
+ >>> import z3c.formui
+ >>> xmlconfig.XMLConfig('meta.zcml', zope.component)()
+ >>> xmlconfig.XMLConfig('meta.zcml', zope.viewlet)()
+ >>> xmlconfig.XMLConfig('meta.zcml', zope.app.component)()
+ >>> xmlconfig.XMLConfig('meta.zcml', zope.app.security)()
+ >>> xmlconfig.XMLConfig('meta.zcml', zope.app.publisher.browser)()
+ >>> xmlconfig.XMLConfig('meta.zcml', z3c.macro)()
+ >>> xmlconfig.XMLConfig('meta.zcml', z3c.template)()
+ >>> xmlconfig.XMLConfig('div-form.zcml', z3c.formui)()
+ >>> context = xmlconfig.file('meta.zcml', z3c.template)
+ >>> context = xmlconfig.string("""
+ ... <configure
+ ... xmlns:z3c="http://namespaces.zope.org/z3c">
+ ... <configure package="z3c.searcher">
+ ... <z3c:template
+ ... template="filter.pt"
+ ... for=".form.FilterForm"
+ ... />
+ ... <z3c:template
+ ... template="criterium.pt"
+ ... for=".form.CriteriumForm"
+ ... />
+ ... <z3c:template
+ ... template="search.pt"
+ ... for=".form.SearchForm"
+ ... />
+ ... </configure>
+ ... </configure>
+ ... """, context=context)
+
+And we also need some widgets from z3c.form:
+
+ >>> import z3c.form.testing
+ >>> z3c.form.testing.setupFormDefaults()
+
+Now we can render the criterium form:
+
+ >>> criteriumRow.update()
+ >>> print criteriumRow.render()
+ <tr>
+ <td style="padding-right:5px;">
+ <span>Text</span>
+ </td>
+ <td style="padding-right:5px;">
+ <b>matches</b>
+ </td>
+ <td style="padding-right:5px;">
+ <input type="text" id="form-widgets-value"
+ name="form.widgets.value"
+ class="text-widget required textline-field" value="" />
+ <span class="option">
+ <label for="form-widgets-connectorName-0">
+ <input type="radio" id="form-widgets-connectorName-0"
+ name="form.widgets.connectorName:list"
+ class="radio-widget required choice-field"
+ value="OR" checked="checked" />
+ <span class="label">or</span>
+ </label>
+ </span><span class="option">
+ <label for="form-widgets-connectorName-1">
+ <input type="radio" id="form-widgets-connectorName-1"
+ name="form.widgets.connectorName:list"
+ class="radio-widget required choice-field"
+ value="AND" />
+ <span class="label">and</span>
+ </label>
+ </span><span class="option">
+ <label for="form-widgets-connectorName-2">
+ <input type="radio" id="form-widgets-connectorName-2"
+ name="form.widgets.connectorName:list"
+ class="radio-widget required choice-field"
+ value="NOT" />
+ <span class="label">not</span>
+ </label>
+ </span>
+ <input name="form.widgets.connectorName-empty-marker"
+ type="hidden" value="1" />
+ </td>
+ <td style="padding-right:5px;">
+ <input type="submit" id="form-buttons-remove"
+ name="form.buttons.remove"
+ class="submit-widget button-field" value="Remove" />
+ </td>
+ </tr>
+
+
+Filter Form
+------------
+
+There is also a filter form which can represent the SearchFilter. This form
+includes the CriteriumForm part. Note we uses a dumy context becaue it's not
+relevant where you render this form because the form will get the filters
+from the session.
+
+ >>> filterForm = form.FilterForm(object(), request)
+ >>> filterForm
+ <z3c.searcher.form.FilterForm object at ...>
+
+But before we can use the form, we need to set our search filter class as
+factory. Because only this search filter knows our criteria:
+
+ >>> filterForm.filterFactory = ContentSearchFilter
+
+Now we can render our filter form:
+
+ >>> filterForm.update()
+ >>> print filterForm.render()
+ <fieldset>
+ <legend>Filter</legend>
+ <div>
+ <label for="filterformnewCriterium">
+ New Criterium
+ </label>
+ <select name="filterformnewCriterium" size="1">
+ <option value="fullText">fullText</option>
+ </select>
+ <input type="submit" id="filterform-buttons-add"
+ name="filterform.buttons.add"
+ class="submit-widget button-field" value="Add" />
+ </div>
+ <div>
+ <input type="submit" id="filterform-buttons-search"
+ name="filterform.buttons.search"
+ class="submit-widget button-field" value="Search" />
+ <input type="submit" id="filterform-buttons-clear"
+ name="filterform.buttons.clear"
+ class="submit-widget button-field" value="Clear" />
+ </div>
+ </fieldset>
+
+
+Search Form
+-----------
+
+There is also a search form which allows you to simply define a search page.
+This search form uses the criterium and filter form and allows you to simply
+create a search page. Let's define a custom search page:
+
+ >>> class ContentSearchForm(form.SearchForm):
+ ...
+ ... filterFactory = ContentSearchFilter
+
+Before we can use the form, our request needs to provide the form UI layer:
+
+ >>> from zope.interface import alsoProvides
+ >>> from z3c.formui.interfaces import IDivFormLayer
+ >>> alsoProvides(request, IDivFormLayer)
+
+That's all you need for write a simple search form. This form uses it's own
+content search filter and of corse the criteria configured for this filter.
+
+ >>> searchForm = ContentSearchForm(object(), request)
+ >>> searchForm.update()
+ >>> print searchForm.render()
+ <form action="http://127.0.0.1" method="post"
+ enctype="multipart/form-data" class="edit-form"
+ name="form" id="form">
+ <div class="viewspace">
+ <div class="required-info">
+ <span class="required">*</span>
+ – required
+ </div>
+ <div>
+ <fieldset>
+ <legend>Filter</legend>
+ <div>
+ <label for="filterformnewCriterium">
+ New Criterium
+ </label>
+ <select name="filterformnewCriterium" size="1">
+ <option value="fullText">fullText</option>
+ </select>
+ <input type="submit" id="filterform-buttons-add"
+ name="filterform.buttons.add"
+ class="submit-widget button-field" value="Add" />
+ </div>
+ <div>
+ <input type="submit" id="filterform-buttons-search"
+ name="filterform.buttons.search"
+ class="submit-widget button-field" value="Search" />
+ <input type="submit" id="filterform-buttons-clear"
+ name="filterform.buttons.clear"
+ class="submit-widget button-field" value="Clear" />
+ </div>
+ </fieldset>
+ </div>
+ <div>
+ </div>
+ </div>
+ <div>
+ <div class="buttons">
+ </div>
+ </div>
+ </form>
Property changes on: z3c.searcher/trunk/src/z3c/searcher/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/src/z3c/searcher/__init__.py
===================================================================
--- z3c.searcher/trunk/src/z3c/searcher/__init__.py (rev 0)
+++ z3c.searcher/trunk/src/z3c/searcher/__init__.py 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1 @@
+# make a package
Property changes on: z3c.searcher/trunk/src/z3c/searcher/__init__.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/src/z3c/searcher/browser.zcml
===================================================================
--- z3c.searcher/trunk/src/z3c/searcher/browser.zcml (rev 0)
+++ z3c.searcher/trunk/src/z3c/searcher/browser.zcml 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,34 @@
+<configure
+ xmlns:zope="http://namespaces.zope.org/zope"
+ xmlns="http://namespaces.zope.org/browser"
+ xmlns:z3c="http://namespaces.zope.org/z3c"
+ i18n_domain="z3c">
+
+ <!-- SearchCriterium row views -->
+ <page
+ name="row"
+ for=".interfaces.ISearchCriterium"
+ class=".form.CriteriumForm"
+ layer="zope.publisher.interfaces.browser.IBrowserRequest"
+ permission="zope.Public"
+ />
+
+ <z3c:template
+ template="criterium.pt"
+ for=".form.CriteriumForm"
+ layer="zope.publisher.interfaces.browser.IBrowserRequest"
+ />
+
+ <z3c:template
+ template="filter.pt"
+ for=".form.FilterForm"
+ layer="zope.publisher.interfaces.browser.IBrowserRequest"
+ />
+
+ <z3c:template
+ template="table.pt"
+ for=".interfaces.ISearchTable"
+ layer="zope.publisher.interfaces.browser.IBrowserRequest"
+ />
+
+</configure>
Property changes on: z3c.searcher/trunk/src/z3c/searcher/browser.zcml
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/src/z3c/searcher/configure.zcml
===================================================================
--- z3c.searcher/trunk/src/z3c/searcher/configure.zcml (rev 0)
+++ z3c.searcher/trunk/src/z3c/searcher/configure.zcml 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,11 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ i18n_domain="z3c">
+
+ <adapter
+ factory=".session.SearchSession"
+ />
+
+ <include file="browser.zcml" />
+
+</configure>
Property changes on: z3c.searcher/trunk/src/z3c/searcher/configure.zcml
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/src/z3c/searcher/criterium.pt
===================================================================
--- z3c.searcher/trunk/src/z3c/searcher/criterium.pt (rev 0)
+++ z3c.searcher/trunk/src/z3c/searcher/criterium.pt 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,16 @@
+<tr>
+ <td style="padding-right:5px;">
+ <span tal:content="context/label" i18n:translate="" />
+ <tal:block replace="structure view/widgets/object|nothing" />
+ </td>
+ <td style="padding-right:5px;">
+ <b tal:content="context/operatorLabel|nothing" i18n:translate="" />
+ </td>
+ <td style="padding-right:5px;">
+ <tal:block replace="structure view/widgets/value/render" />
+ <tal:block replace="structure view/widgets/connectorName/render" />
+ </td>
+ <td style="padding-right:5px;">
+ <input tal:replace="structure view/actions/remove/render" />
+ </td>
+</tr>
Property changes on: z3c.searcher/trunk/src/z3c/searcher/criterium.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/src/z3c/searcher/criterium.py
===================================================================
--- z3c.searcher/trunk/src/z3c/searcher/criterium.py (rev 0)
+++ z3c.searcher/trunk/src/z3c/searcher/criterium.py 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,110 @@
+##############################################################################
+#
+# Copyright (c) 2008 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.
+#
+##############################################################################
+"""
+$Id:$
+"""
+__docformat__ = "reStructuredText"
+
+import persistent
+import zope.interface
+from zope.schema.fieldproperty import FieldProperty
+from zope.app.container import contained
+
+from z3c.i18n import MessageFactory as _
+from z3c.indexer import query
+from z3c.searcher import interfaces
+
+
+class SearchCriterium(persistent.Persistent, contained.Contained):
+ """Search criterium for some data.
+
+ This search criterium is implemented as an adapter to the search
+ """
+ zope.interface.implements(interfaces.ISearchCriterium)
+
+ label = None
+ indexOrName = None
+
+ # See interfaces.ISearchCriterium
+ operator = query.Eq
+ operatorLabel = _('equals')
+
+ value = FieldProperty(interfaces.ISearchCriterium['value'])
+ connectorName = FieldProperty(interfaces.ISearchCriterium['connectorName'])
+
+ def search(self, searchQuery):
+ """See interfaces.ISearchCriterium.
+
+ Note, this can raise TypeError or zope.index.text.parsetree.ParseError
+ for text index or any other error raised from other indexes. We only
+ catch te TypeError and ParseError in the offered FilterForm.
+ """
+ operatorQuery = self.operator(self.indexOrName, self.value)
+ if self.connectorName == interfaces.CONNECTOR_OR:
+ return searchQuery.Or(operatorQuery)
+ if self.connectorName == interfaces.CONNECTOR_AND:
+ return searchQuery.And(operatorQuery)
+ if self.connectorName == interfaces.CONNECTOR_NOT:
+ return searchQuery.Not(operatorQuery)
+
+
+class SetSearchCriterium(SearchCriterium):
+
+ operator = query.AnyOf
+ operatorLabel = _('is')
+
+ def search(self, searchQuery):
+ """See interfaces.ISearchCriterium.
+
+ Note, this can raise TypeError or zope.index.text.parsetree.ParseError
+ for text index or any other error raised from other indexes. We only
+ catch te TypeError and ParseError in the offered FilterForm.
+ """
+ operatorQuery = self.operator(self.indexOrName, [self.value])
+ if self.connectorName == interfaces.CONNECTOR_OR:
+ return searchQuery.Or(operatorQuery)
+ if self.connectorName == interfaces.CONNECTOR_AND:
+ return searchQuery.And(operatorQuery)
+ if self.connectorName == interfaces.CONNECTOR_NOT:
+ return searchQuery.Not(operatorQuery)
+
+
+class TextCriterium(SearchCriterium):
+ """Search criterium for some data."""
+ zope.interface.implements(interfaces.ITextCriterium)
+
+ label = _('Text')
+ operator = query.TextQuery
+ operatorLabel = _('matches')
+ value = FieldProperty(interfaces.ITextCriterium['value'])
+
+
+class SearchCriteriumFactoryBase(object):
+ """Search Criterium Factory."""
+ zope.interface.implements(interfaces.ISearchCriteriumFactory)
+
+ klass = None
+ title = None
+ weight = 0
+
+ def __init__(self, context):
+ pass
+
+ def __call__(self):
+ return self.klass()
+
+
+def factory(klass, title):
+ return type('%sFactory' %klass.__name__, (SearchCriteriumFactoryBase,),
+ {'klass': klass, 'title': title})
Property changes on: z3c.searcher/trunk/src/z3c/searcher/criterium.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/src/z3c/searcher/filter.pt
===================================================================
--- z3c.searcher/trunk/src/z3c/searcher/filter.pt (rev 0)
+++ z3c.searcher/trunk/src/z3c/searcher/filter.pt 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,32 @@
+<fieldset tal:define="criteriumRows view/criteriumRows">
+<legend i18n:translate="">Filter</legend>
+<div tal:condition="view/status"
+ tal:content="view/status">
+ Status
+</div>
+<div>
+ <label for=""
+ tal:attributes="for string:${view/prefix}newCriterium"
+ i18n:translate="">
+ New Criterium
+ </label>
+ <select name="" size="1"
+ tal:attributes="name string:${view/prefix}newCriterium">
+ <option value=""
+ tal:repeat="criterium view/criteriumFactories"
+ tal:attributes="value criterium/name"
+ tal:content="criterium/title"> Criterium Factory Title </option>
+ </select>
+ <input tal:replace="structure view/actions/add/render" />
+</div>
+<div style="margin: 8px 0px" tal:condition="criteriumRows">
+ <table>
+ <tal:block repeat="row criteriumRows"
+ replace="structure row/render" />
+ </table>
+</div>
+<div>
+ <input tal:replace="structure view/actions/search/render" />
+ <input tal:replace="structure view/actions/clear/render" />
+</div>
+</fieldset>
Property changes on: z3c.searcher/trunk/src/z3c/searcher/filter.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/src/z3c/searcher/filter.py
===================================================================
--- z3c.searcher/trunk/src/z3c/searcher/filter.py (rev 0)
+++ z3c.searcher/trunk/src/z3c/searcher/filter.py 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,143 @@
+##############################################################################
+#
+# Copyright (c) 2007 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.
+#
+##############################################################################
+"""
+$Id:$
+"""
+__docformat__ = "reStructuredText"
+
+import persistent
+import persistent.list
+import zope.component
+import zope.interface
+import zope.event
+import zope.lifecycleevent
+from zope.location import location
+from zope.app.container import contained
+
+from z3c.indexer import query
+from z3c.indexer.search import SearchQuery
+from z3c.searcher import interfaces
+
+
+class EmptyTerm(object):
+ """Return a empty list as result."""
+
+ def apply(self):
+ return []
+
+
+class SearchFilter(persistent.Persistent, contained.Contained):
+ """Persistent search filter implementation.
+
+ This component uses the component architecture to determine its available
+ criterium components.
+ """
+ zope.interface.implements(interfaces.ISearchFilter)
+
+ def __init__(self):
+ super(SearchFilter, self).__init__()
+ self.criteria = persistent.list.PersistentList()
+
+ def clear(self):
+ """See interfaces.ISearchFilter"""
+ self.__init__()
+
+ @property
+ def criteriumFactories(self):
+ """See interfaces.ISearchFilter"""
+ adapters = zope.component.getAdapters(
+ (self,), interfaces.ISearchCriteriumFactory)
+ return sorted(adapters, key=lambda (n, a): a.weight)
+
+ def createCriterium(self, name, value=interfaces.NOVALUE):
+ """Create a criterium."""
+ criterium = zope.component.getAdapter(
+ self, interfaces.ISearchCriteriumFactory, name=name)()
+ if value is not interfaces.NOVALUE:
+ criterium.value = value
+ criterium.__name__ = name
+ criterium.__parent__ = self
+ return criterium
+
+ def addCriterium(self, criterium):
+ """See interfaces.ISearchFilter"""
+ location.locate(criterium, self)
+ self.criteria.append(criterium)
+
+ def createAndAddCriterium(self, name, value=interfaces.NOVALUE):
+ criterium = self.createCriterium(name)
+ if value is not interfaces.NOVALUE:
+ criterium.value = value
+ zope.event.notify(zope.lifecycleevent.ObjectCreatedEvent(criterium))
+ self.addCriterium(criterium)
+
+ def removeCriterium(self, criterium):
+ """See interfaces.ISearchFilter"""
+ self.criteria.remove(criterium)
+
+ def getDefaultQuery(self):
+ """See interfaces.ISearchFilter"""
+ return EmptyTerm()
+
+ def getAndQuery(self):
+ """See interfaces.ISearchFilter"""
+ return None
+
+ def getNotQuery(self):
+ """See interfaces.ISearchFilter"""
+ return None
+
+ def generateQuery(self):
+ """See interfaces.ISearchFilter"""
+ # If no criteria are selected, return all values
+ if not len(self.criteria):
+ return self.getDefaultQuery()
+
+ searchQuery = SearchQuery()
+
+ # order the criterium by the order or, and, not
+ orCriteria = []
+ andCriteria = []
+ notCriteria = []
+ for criterium in self.criteria:
+ if criterium.connectorName == interfaces.CONNECTOR_OR:
+ orCriteria.append(criterium)
+ if criterium.connectorName == interfaces.CONNECTOR_AND:
+ andCriteria.append(criterium)
+ if criterium.connectorName == interfaces.CONNECTOR_NOT:
+ notCriteria.append(criterium)
+
+ # apply given ``or`` criteria if any
+ for criterium in orCriteria:
+ searchQuery = criterium.search(searchQuery)
+
+ # apply given ``and`` criteria if any
+ for criterium in andCriteria:
+ searchQuery = criterium.search(searchQuery)
+
+ # apply default ``And`` query if available
+ andQuery = self.getAndQuery()
+ if andQuery is not None:
+ searchQuery = searchQuery.And(andQuery)
+
+ # apply (remove) default ``Not`` query if available
+ notQuery = self.getNotQuery()
+ if notQuery is not None:
+ return query.Not(self.getNotQuery)
+
+ # apply given ``not`` criteria if any
+ for criterium in notCriteria:
+ searchQuery = criterium.search(searchQuery)
+
+ return searchQuery
Property changes on: z3c.searcher/trunk/src/z3c/searcher/filter.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/src/z3c/searcher/form.py
===================================================================
--- z3c.searcher/trunk/src/z3c/searcher/form.py (rev 0)
+++ z3c.searcher/trunk/src/z3c/searcher/form.py 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,214 @@
+##############################################################################
+#
+# Copyright (c) 2007 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.
+#
+##############################################################################
+"""
+$Id:$
+"""
+__docformat__ = "reStructuredText"
+
+import zope.component
+import zope.event
+import zope.lifecycleevent
+
+from zope.index.text import parsetree
+from zope.location import location
+
+from z3c.indexer.search import SearchQuery
+from z3c.template.template import getPageTemplate
+from z3c.template.template import getLayoutTemplate
+
+from z3c.i18n import MessageFactory as _
+from z3c.form.interfaces import IWidgets
+from z3c.form import button
+from z3c.form import field
+from z3c.form import form
+from z3c.formui import form as formui
+from z3c.form.browser.radio import RadioFieldWidget
+from z3c.searcher import interfaces
+from z3c.searcher import criterium
+from z3c.searcher import filter
+
+
+class CriteriumForm(form.Form):
+
+ formErrorsMessage = _('There were some errors.')
+ successMessage = _('Data successfully updated.')
+ noChangesMessage = _('No changes were applied.')
+
+ fields = field.Fields(interfaces.ISearchCriterium).select('connectorName',
+ 'value')
+ fields['connectorName'].widgetFactory = RadioFieldWidget
+
+ def updateWidgets(self):
+ self.widgets = zope.component.getMultiAdapter(
+ (self, self.request, self.getContent()), IWidgets)
+ self.widgets.update()
+
+ @property
+ def criteriumName(self):
+ return self.context.__name__
+
+ def save(self):
+ data, errors = self.widgets.extract()
+ if errors:
+ self.status = self.formErrorsMessage
+ return
+ content = self.getContent()
+ changed = form.applyChanges(self, content, data)
+ if changed:
+ zope.event.notify(
+ zope.lifecycleevent.ObjectModifiedEvent(content))
+ self.status = self.successMessage
+ else:
+ self.status = self.noChangesMessage
+
+ @button.buttonAndHandler(_('Remove'), name='remove')
+ def handleRemove(self, data):
+ searchFilter = self.context.__parent__
+ searchFilter.removeCriterium(self.context)
+ self.request.response.redirect(self.request.getURL())
+
+
+class TextCriteriumForm(CriteriumForm):
+
+ fields = field.Fields(interfaces.ITextCriterium).select('connectorName',
+ 'value')
+ fields['connectorName'].widgetFactory = RadioFieldWidget
+
+
+class FilterForm(form.Form):
+ """Filter form."""
+
+ zope.interface.implements(interfaces.IFilterForm)
+
+ # default form vars
+ prefix = 'filterform'
+ ignoreContext = True
+ criteriumRows = []
+ searchFilter = None
+
+ # The filterName is used in the ISearchSession to identify filter
+ filterName = 'searchFilter'
+
+ # will probably get overriden by the parent form
+ filterFactory = filter.SearchFilter
+
+ # customization hooks
+ @property
+ def filterKey(self):
+ """Return the default filter key.
+
+ You can override this method and use a KeyReference intid if you need
+ different filters for each context.
+ """
+ return interfaces.SEARCH_SESSION_FILTER_KEY
+
+ def criteriumFactories(self):
+ for name, factory in self.searchFilter.criteriumFactories:
+ yield {'name': name, 'title': factory.title}
+
+ @property
+ def searchFilter(self):
+ session = interfaces.ISearchSession(self.request)
+ searchFilter = session.getFilter(self.filterName, self.filterKey)
+ if searchFilter is None:
+ searchFilter = self.filterFactory()
+ session.addFilter(self.filterName, searchFilter, self.filterKey)
+ # Locate the search filter, so that security does not get lost
+ location.locate(searchFilter, self.context, self.filterName)
+ return searchFilter
+
+ def values(self):
+ # TODO: implement better error handling and allow to register error
+ # views for unknown index search error. Right now we only catch some
+ # known search index errors.
+ try:
+ # generate the search query
+ searchQuery = self.searchFilter.generateQuery()
+ # return result
+ return SearchQuery(searchQuery).searchResults()
+ except TypeError:
+ self.status = _('One of the search filter is setup improperly.')
+ except parsetree.ParseError, error:
+ self.status = _('Invalid search text.')
+ # Return an empty result, since an error must have occurred
+ return []
+
+ def setupCriteriumRows(self):
+ self.criteriumRows = []
+ append = self.criteriumRows.append
+ index = 0
+ for criterium in self.searchFilter.criteria:
+ row = zope.component.getMultiAdapter(
+ (criterium, self.request), name='row')
+ row.prefix = str(index)
+ row.update()
+ append(row)
+ index += 1
+
+ def update(self):
+ self.setupCriteriumRows()
+ super(FilterForm, self).update()
+
+ @button.buttonAndHandler(u'Add')
+ def handleAdd(self, action):
+ name = self.request.get(self.prefix + 'newCriterium', None)
+ if name is not None:
+ self.searchFilter.createAndAddCriterium(name)
+ self.setupCriteriumRows()
+ self.status = _('New criterium added.')
+
+ @button.buttonAndHandler(u'Clear', name='clear')
+ def handleClear(self, action):
+ self.searchFilter.clear()
+ self.setupCriteriumRows()
+ self.status = _('Criteria cleared.')
+
+ @button.buttonAndHandler(u'Search', name='search')
+ def handleSearch(self, action):
+ data, errors = self.widgets.extract()
+ for row in self.criteriumRows:
+ row.save()
+
+
+class SearchForm(formui.Form):
+ """Search form using a sub form for offering filters.
+
+ Note this form uses the layout/content template pattern by default.
+ And the content template renders the search filter into the ``extra-info```
+ slot offered from z3c.formui ``form`` macro
+ """
+
+ zope.interface.implements(interfaces.ISearchForm)
+
+ template = getPageTemplate()
+ values = []
+ filterFactory = filter.SearchFilter
+
+ def setupFilterForm(self):
+ """Setup filter form before super form get updated."""
+ self.filterForm = FilterForm(self.context, self.request)
+ self.filterForm.filterFactory = self.filterFactory
+
+ def updateFilterForm(self):
+ """Update filter form after super form get updated."""
+ self.filterForm.update()
+ self.values = self.filterForm.values()
+
+ def update(self):
+ # setup filter form
+ self.setupFilterForm()
+ # process super form
+ super(SearchForm, self).update()
+ # process filter form
+ self.updateFilterForm()
Property changes on: z3c.searcher/trunk/src/z3c/searcher/form.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/src/z3c/searcher/interfaces.py
===================================================================
--- z3c.searcher/trunk/src/z3c/searcher/interfaces.py (rev 0)
+++ z3c.searcher/trunk/src/z3c/searcher/interfaces.py 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,199 @@
+##############################################################################
+#
+# Copyright (c) 2007 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.
+#
+##############################################################################
+"""
+$Id:$
+"""
+__docformat__ = "reStructuredText"
+
+import zope.interface
+import zope.schema
+from zope.schema import vocabulary
+from zope.session.interfaces import ISession
+from zope.location.interfaces import ILocation
+
+from z3c.i18n import MessageFactory as _
+from z3c.indexer import interfaces
+from z3c.indexer import query
+from z3c.form.interfaces import IForm
+from z3c.table.interfaces import ITable
+
+
+SEARCH_SESSION = u'z3c.search.intefaces.ISearchSession'
+SEARCH_SESSION_FILTER_KEY = 'default'
+
+CONNECTOR_OR = 'OR'
+CONNECTOR_AND = 'AND'
+CONNECTOR_NOT = 'NOT'
+
+NOVALUE = object()
+
+
+class ISearchSession(ISession):
+ """Search session supporting API for filter management.
+
+ Filters contain the criterium rows and are stored persistent
+
+ The methods support a key argument. This could be a context reference key
+ give from the IntId utility or some other discriminator. If we do not
+ support a key, the string ``default`` is used.
+ """
+
+ def getFilter(name, key=SEARCH_SESSION_FILTER_KEY):
+ """Return search filter by name."""
+
+ def getFilters(name):
+ """Return a list of search filters."""
+
+ def addFilter(name, searchFilter, key=SEARCH_SESSION_FILTER_KEY):
+ """Add search filter."""
+
+ def removeFilter(name, key=SEARCH_SESSION_FILTER_KEY):
+ """Remove search filter."""
+
+
+connectorVocabulary = vocabulary.SimpleVocabulary([
+ vocabulary.SimpleTerm(CONNECTOR_OR, title=_('or')),
+ vocabulary.SimpleTerm(CONNECTOR_AND, title=_('and')),
+ vocabulary.SimpleTerm(CONNECTOR_NOT, title=_('not')),
+ ])
+
+class ISearchCriterium(ILocation):
+ """A search citerium of a piece of data."""
+
+ __name__ = zope.schema.TextLine(
+ title=_('Name'),
+ description=_('The locatable criterium name.'),
+ required=True)
+
+ label = zope.schema.TextLine(
+ title=_('Label'),
+ description=_('Label used to present the criterium.'),
+ required=True)
+
+ operatorLabel = zope.schema.TextLine(
+ title=_('Operator label'),
+ description=_('The operator label.'),
+ required=True)
+
+ indexOrName = zope.interface.Attribute("Index or index name.")
+
+ operator = zope.schema.Object(
+ title=_('Operator'),
+ description=_('The operator used for the chain the queries.'),
+ schema=interfaces.IQuery,
+ required=True)
+
+ connectorName = zope.schema.Choice(
+ title=_('Connector Name'),
+ description=_('The criterium connector name.'),
+ vocabulary=connectorVocabulary,
+ default=CONNECTOR_OR,
+ required=True)
+
+ value = zope.schema.TextLine(
+ title=_('Search Query'),
+ required=True)
+
+ def search(searchQuery):
+ """Generate chainable search query."""
+
+
+class ITextCriterium(ISearchCriterium):
+ """Sample full text search criterium implementation."""
+
+
+class ISearchCriteriumFactory(zope.interface.Interface):
+ """A factory for the search criterium"""
+
+ title = zope.schema.TextLine(
+ title=_('Title'),
+ description=_('A human-readable title of the criterium.'),
+ required=True)
+
+ weight = zope.schema.Int(
+ title=_('Int'),
+ description=_('The weight/importance of the factory among all '
+ 'factories.'),
+ required=True)
+
+ def __call__():
+ """Generate the criterium."""
+
+
+class ISearchFilter(zope.interface.Interface):
+ """Search criteria for position search."""
+
+ criteria = zope.interface.Attribute(
+ """Return a sequence of selected criteria.""")
+
+ criteriumFactories = zope.schema.List(
+ title=_('Criteria factories'),
+ description=_('The criteria factories.'),
+ value_type=zope.schema.Object(
+ title=_('Criterium factory'),
+ description=_('The criterium factory.'),
+ schema=ISearchCriteriumFactory,
+ required=True),
+ default=[])
+
+ def clear():
+ """Clear the criteria."""
+
+ def createCriterium(name, value=NOVALUE):
+ """Create a criterium by factory name."""
+
+ def addCriterium(criterium):
+ """Add a criterium by name at the end of the list."""
+
+ def createAndAddCriterium(name, value=NOVALUE):
+ """Create and add a criterium by name at the end of the list."""
+
+ def removeCriterium(criterium):
+ """Add a criterium by name at the end of the list."""
+
+ def getDefaultQuery():
+ """Get a query that returns the default values.
+
+ Override this method in your custom search filter if needed.
+ This query get used if ``NO`` criterias are available.
+ """
+
+ def getAndQuery():
+ """Return a ``And`` query which get used by default or None.
+
+ Override this method in your custom search filter if needed.
+ This query get used if ``one or more`` criterias are available.
+ """
+
+ def getNotQuery():
+ """Return a ``Not`` query which get used as starting query or None.
+
+ Override this method in your custom search filter if needed.
+ This query get used if ``one or more`` criterias are available.
+ """
+
+ def generateQuery():
+ """Generate a query object."""
+
+
+class IFilterForm(IForm):
+ """Filter form."""
+
+
+class ISearchForm(IForm):
+ """Search form."""
+
+
+class ISearchTable(ITable):
+ """Search table."""
Property changes on: z3c.searcher/trunk/src/z3c/searcher/interfaces.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/src/z3c/searcher/search.pt
===================================================================
--- z3c.searcher/trunk/src/z3c/searcher/search.pt (rev 0)
+++ z3c.searcher/trunk/src/z3c/searcher/search.pt 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,5 @@
+<div metal:use-macro="macro:form">
+ <div metal:fill-slot="extra-info">
+ <div tal:replace="structure view/filterForm/render" />
+ </div>
+</div>
Property changes on: z3c.searcher/trunk/src/z3c/searcher/search.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/src/z3c/searcher/session.py
===================================================================
--- z3c.searcher/trunk/src/z3c/searcher/session.py (rev 0)
+++ z3c.searcher/trunk/src/z3c/searcher/session.py 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,75 @@
+##############################################################################
+#
+# Copyright (c) 2008 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.
+#
+##############################################################################
+"""
+$Id:$
+"""
+__docformat__ = "reStructuredText"
+
+import persistent.dict
+import zope.interface
+from zope.session.session import Session
+
+from z3c.searcher import interfaces
+from z3c.searcher.interfaces import SEARCH_SESSION
+
+
+class SearchSession(Session):
+ """Search session."""
+
+ zope.interface.implementsOnly(interfaces.ISearchSession)
+
+ def __init__(self, request):
+ super(SearchSession, self).__init__(request)
+ self.searchFilters = persistent.dict.PersistentDict()
+
+ def getFilter(self, name, key='default'):
+ """Return search filter by name."""
+ spd = self.__getitem__(SEARCH_SESSION)
+ filterList = spd.get(name, None)
+ if filterList is None:
+ spd[name] = persistent.dict.PersistentDict()
+ filterList = spd.get(name)
+ return filterList.get(key)
+
+ def getFilters(self, key='default'):
+ """Return a list of search filters."""
+ spd = self.__getitem__(SEARCH_SESSION)
+ filters = []
+ append = filters.append
+ for filterList in spd.values():
+ filter = filterList.get(key)
+ if filter is not None:
+ append(filter)
+ return filters
+
+ def addFilter(self, name, searchFilter, key='default'):
+ """Add search filter.
+
+ Note: this session doesn't know about the context, this means you need
+ to locate the added filter after you where adding it. Otherwise you
+ will get security problems because of the missing location.
+ """
+ spd = self.__getitem__(SEARCH_SESSION)
+ filterList = spd.get(name)
+ if filterList is None:
+ spd[name] = persistent.dict.PersistentDict()
+ filterList = spd.get(name)
+ filterList[key] = searchFilter
+
+ def removeFilter(self, name, key='default'):
+ """Remove search filter."""
+ spd = self.__getitem__(SEARCH_SESSION)
+ filterList = spd.get(name)
+ if filterList is not None:
+ del filterList[key]
Property changes on: z3c.searcher/trunk/src/z3c/searcher/session.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/src/z3c/searcher/table.pt
===================================================================
--- z3c.searcher/trunk/src/z3c/searcher/table.pt (rev 0)
+++ z3c.searcher/trunk/src/z3c/searcher/table.pt 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,18 @@
+<div metal:use-macro="macro:form">
+ <div metal:fill-slot="main"
+ tal:define="batch view/renderBatch">
+ <div class="filterForm" tal:condition="nocall:view/filterForm">
+ <div tal:replace="structure view/filterForm/render" />
+ </div>
+ <div>
+ <tal:block replace="structure view/renderTable">
+ table
+ </tal:block>
+ </div>
+ <div class="batch" tal:condition="batch">
+ <tal:block replace="structure batch">
+ table
+ </tal:block>
+ </div>
+ </div>
+</div>
Property changes on: z3c.searcher/trunk/src/z3c/searcher/table.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/src/z3c/searcher/table.py
===================================================================
--- z3c.searcher/trunk/src/z3c/searcher/table.py (rev 0)
+++ z3c.searcher/trunk/src/z3c/searcher/table.py 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,129 @@
+##############################################################################
+#
+# Copyright (c) 2007 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.
+#
+##############################################################################
+"""
+$Id:$
+"""
+__docformat__ = "reStructuredText"
+
+import zope.component
+import zope.event
+import zope.lifecycleevent
+
+from zope.index.text import parsetree
+from zope.location import location
+
+from z3c.indexer.search import SearchQuery
+from z3c.template.template import getPageTemplate
+from z3c.template.template import getLayoutTemplate
+
+from z3c.i18n import MessageFactory as _
+
+import z3c.formui.form
+from z3c.table import table
+from z3c.form import button
+from z3c.searcher import interfaces
+from z3c.searcher import filter
+from z3c.searcher import form
+
+
+# conditions
+def hasContent(form):
+ return form.hasContent
+
+
+def canCancel(form):
+ return form.supportsCancel
+
+
+class SearchTable(table.Table, z3c.formui.form.Form):
+ """Search form with result table."""
+
+ zope.interface.implements(interfaces.ISearchTable)
+
+ template = getPageTemplate()
+
+ prefix = 'formTable'
+
+ # internal defaults
+ hasContent = False
+ nextURL = None
+ ignoreContext = False
+ filterForm = None
+
+ # table defaults
+ cssClasses = {'table': 'contents'}
+ cssClassEven = u'even'
+ cssClassOdd = u'odd'
+ cssClassSelected = u'selected'
+
+ batchSize = 25
+ startBatchingAt = 25
+
+ # customize this part
+ allowCancel = True
+
+ filterFactory = filter.SearchFilter
+
+ def setupFilterForm(self):
+ """Setup filter form before super form get updated."""
+ self.filterForm = form.FilterForm(self.context, self.request)
+ self.filterForm.filterFactory = self.filterFactory
+
+ def updateFilterForm(self):
+ """Update filter form after super form get updated."""
+ self.filterForm.update()
+
+ def setupConditions(self):
+ self.hasContent = bool(self.rows)
+ if self.allowCancel:
+ self.supportsCancel = self.hasContent
+
+ def updateAfterActionExecution(self):
+ """Update table data if subform changes soemthing."""
+ # first update table data which probably changed
+ super(SearchTable, self).update()
+ # second setup conditions
+ self.setupConditions()
+ # third update action which we have probably different conditions for
+ self.updateActions()
+
+ def update(self):
+ # 1 .setup filter form
+ self.setupFilterForm()
+ # 2. process filter form
+ self.updateFilterForm()
+ # 3. setup widgets
+ self.updateWidgets()
+ # 4. setup search values, generate rows, setup headers and columns
+ super(SearchTable, self).update()
+ # 5. setup conditions
+ self.setupConditions()
+ # 6. setup form part
+ self.updateActions()
+ self.actions.execute()
+
+ @property
+ def values(self):
+ return self.filterForm.values()
+
+ @button.buttonAndHandler(_('Cancel'), name='cancel', condition=canCancel)
+ def handleCancel(self, action):
+ self.nextURL = self.request.getURL()
+
+ def render(self):
+ """Render the template."""
+ if self.nextURL is not None:
+ self.request.response.redirect(self.nextURL)
+ return ""
+ return self.template()
Property changes on: z3c.searcher/trunk/src/z3c/searcher/table.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/src/z3c/searcher/testing.py
===================================================================
--- z3c.searcher/trunk/src/z3c/searcher/testing.py (rev 0)
+++ z3c.searcher/trunk/src/z3c/searcher/testing.py 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,55 @@
+###############################################################################
+#
+# Copyright (c) 2007 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.
+#
+###############################################################################
+"""
+$Id:$
+"""
+
+import zope.component
+from zope.publisher.interfaces import IRequest
+from zope.session import session
+from zope.session.http import CookieClientIdManager
+from zope.session.interfaces import IClientId
+from zope.session.interfaces import IClientIdManager
+from zope.session.interfaces import ISession
+from zope.session.interfaces import ISessionDataContainer
+from zope.app.authentication.tests import TestClientId
+from zope.app.keyreference.testing import SimpleKeyReference
+from zope.app.testing import setup
+
+
+def setUp(test):
+ test.globs = {'root': setup.placefulSetUp(True)}
+
+ # session setup
+ zope.component.provideAdapter(TestClientId, (IRequest,), IClientId)
+ zope.component.provideAdapter(session.Session, (IRequest,), ISession)
+ zope.component.provideUtility(CookieClientIdManager(), IClientIdManager)
+ rsdc = session.RAMSessionDataContainer()
+ zope.component.provideUtility(rsdc, ISessionDataContainer, '')
+
+ # Setup simple key reference adapter
+ zope.component.provideAdapter(SimpleKeyReference)
+
+ from zope.app.pagetemplate import metaconfigure
+ from z3c.macro import tales
+ metaconfigure.registerType('macro', tales.MacroExpression)
+
+ # register provider TALES
+ from zope.app.pagetemplate import metaconfigure
+ from zope.contentprovider import tales
+ metaconfigure.registerType('provider', tales.TALESProviderExpression)
+
+
+def tearDown(test):
+ setup.placefulTearDown()
Property changes on: z3c.searcher/trunk/src/z3c/searcher/testing.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.searcher/trunk/src/z3c/searcher/tests.py
===================================================================
--- z3c.searcher/trunk/src/z3c/searcher/tests.py (rev 0)
+++ z3c.searcher/trunk/src/z3c/searcher/tests.py 2008-05-02 01:43:46 UTC (rev 86042)
@@ -0,0 +1,81 @@
+##############################################################################
+#
+# Copyright (c) 2007 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.
+#
+##############################################################################
+"""
+$Id:$
+"""
+__docformat__ = "reStructuredText"
+
+import unittest
+from zope.testing import doctest
+
+import z3c.testing
+from z3c.searcher import interfaces
+from z3c.searcher import testing
+from z3c.searcher import criterium
+from z3c.searcher import filter
+
+
+# ISearchCriterium
+class TestSearchCriterium(z3c.testing.InterfaceBaseTest):
+
+ def getTestInterface(self):
+ return interfaces.ISearchCriterium
+
+ def getTestClass(self):
+ return criterium.SearchCriterium
+
+
+class TestSetSearchCriterium(z3c.testing.InterfaceBaseTest):
+
+ def getTestInterface(self):
+ return interfaces.ISearchCriterium
+
+ def getTestClass(self):
+ return criterium.SetSearchCriterium
+
+
+class TestTextCriterium(z3c.testing.InterfaceBaseTest):
+
+ def getTestInterface(self):
+ return interfaces.ITextCriterium
+
+ def getTestClass(self):
+ return criterium.TextCriterium
+
+
+# ISearchFilter
+class TestSearchFilter(z3c.testing.InterfaceBaseTest):
+
+ def getTestInterface(self):
+ return interfaces.ISearchFilter
+
+ def getTestClass(self):
+ return filter.SearchFilter
+
+
+def test_suite():
+ return unittest.TestSuite((
+ doctest.DocFileSuite('README.txt',
+ setUp=testing.setUp, tearDown=testing.tearDown,
+ optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+ ),
+ unittest.makeSuite(TestSearchCriterium),
+ unittest.makeSuite(TestSetSearchCriterium),
+ unittest.makeSuite(TestTextCriterium),
+ unittest.makeSuite(TestSearchFilter),
+ ))
+
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Property changes on: z3c.searcher/trunk/src/z3c/searcher/tests.py
___________________________________________________________________
Name: svn:eol-style
+ native
More information about the Checkins
mailing list