{ "info": { "author": "Roger Ineichen and the Zope Community", "author_email": "zope-dev@zope.org", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: Zope3", "Intended Audience :: Developers", "License :: OSI Approved :: Zope Public License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Internet :: WWW/HTTP" ], "description": "This package provides an implementation for build z3c.indexer based search\nforms for Zope3. The persistent search criteria can get stored in a session\nor in an application as predefined filter query objects.\n\n\nDetailed Documentation\n**********************\n\n\n======\nREADME\n======\n\nThis package provides a persistent search query implementation. This search \nquery is implemented as a filter object which can use search criteria for build\nthe search query. This package also offers some z3c.form based management views\nwhich allo us to manage the search filter and it's search criteria. Let's \ndefine a site with indexes which allows us to build search filter for.\n\nNote, this package depends on the new z3c.indexer package which offers a \nmodular indexing concept. But you can use this package with the \nzope.app.catalog package too. You only have to build our own search citerium. \n\n\nStart a simple test setup\n-------------------------\n\nSetup some helpers:\n\n >>> import zope.component\n >>> from zope.site import folder\n >>> from zope.site import LocalSiteManager\n >>> from z3c.indexer.interfaces import IIndex\n\nSetup a site\n\n >>> class SiteStub(folder.Folder):\n ... \"\"\"Sample site.\"\"\"\n >>> site = SiteStub()\n\n >>> root['site'] = site\n >>> sm = LocalSiteManager(site)\n >>> site.setSiteManager(sm)\n\nAnd set the site as the current site. This is normaly done by traversing to a \nsite:\n\n >>> from zope.app.component import hooks\n >>> hooks.setSite(site)\n\nSetup a IIntIds utility:\n\n >>> from zope.intid import IntIds\n >>> from zope.intid.interfaces import IIntIds\n >>> intids = IntIds()\n >>> sm['default']['intids'] = intids\n >>> sm.registerUtility(intids, IIntIds)\n\n\nTextIndex\n---------\n\nSetup a text index:\n\n >>> from z3c.indexer.index import TextIndex\n >>> textIndex = TextIndex()\n >>> sm['default']['textIndex'] = textIndex\n >>> sm.registerUtility(textIndex, IIndex, name='textIndex')\n\n\nFieldIndex\n----------\n\nSetup a field index:\n\n >>> from z3c.indexer.index import FieldIndex\n >>> fieldIndex = FieldIndex()\n >>> sm['default']['fieldIndex'] = fieldIndex\n >>> sm.registerUtility(fieldIndex, IIndex, name='fieldIndex')\n\n\nValueIndex\n----------\n\nSetup a value index:\n\n >>> from z3c.indexer.index import ValueIndex\n >>> valueIndex = ValueIndex()\n >>> sm['default']['valueIndex'] = valueIndex\n >>> sm.registerUtility(valueIndex, IIndex, name='valueIndex')\n\n\nSetIndex\n--------\n\nSetup a set index:\n\n >>> from z3c.indexer.index import SetIndex\n >>> setIndex = SetIndex()\n >>> sm['default']['setIndex'] = setIndex\n >>> sm.registerUtility(setIndex, IIndex, name='setIndex')\n\n\nDemoContent\n-----------\n\nDefine a content object:\n\n >>> import persistent\n >>> import zope.interface\n >>> from zope.app.container import contained\n >>> from zope.schema.fieldproperty import FieldProperty\n\n >>> class IDemoContent(zope.interface.Interface):\n ... \"\"\"Demo content.\"\"\"\n ... title = zope.schema.TextLine(\n ... title=u'Title',\n ... default=u'')\n ... \n ... body = zope.schema.TextLine(\n ... title=u'Body',\n ... default=u'')\n ... \n ... field = zope.schema.TextLine(\n ... title=u'a field',\n ... default=u'')\n ... \n ... value = zope.schema.TextLine(\n ... title=u'A value',\n ... default=u'')\n ... \n ... iterable = zope.schema.Tuple(\n ... title=u'A sequence of values',\n ... default=())\n\n >>> class DemoContent(persistent.Persistent, contained.Contained):\n ... \"\"\"Demo content.\"\"\"\n ... zope.interface.implements(IDemoContent)\n ... \n ... title = FieldProperty(IDemoContent['title'])\n ... body = FieldProperty(IDemoContent['body'])\n ... field = FieldProperty(IDemoContent['field'])\n ... value = FieldProperty(IDemoContent['value'])\n ... iterable = FieldProperty(IDemoContent['iterable'])\n ... \n ... def __init__(self, title=u''):\n ... self.title = title\n ... \n ... def __repr__(self):\n ... return '<%s %r>' % (self.__class__.__name__, self.title)\n\nCreate and add the content object to the site:\n\n >>> demo = DemoContent(u'Title')\n >>> demo.body = u'Body text'\n >>> demo.field = u'Field'\n >>> demo.value = u'Value'\n >>> demo.iterable = (1, 2, 'Iterable')\n >>> site['demo'] = demo\n\nThe zope event subscriber for __setitem__ whould call the IIntIds register\nmethod for our content object. But we didn't setup the relevant subscribers, so\nwe do this here:\n\n >>> uid = intids.register(demo)\n\n\nIndexer\n-------\n\nSetup a indexer adapter for our content object.\n\n >>> from z3c.indexer.indexer import MultiIndexer\n >>> class DemoIndexer(MultiIndexer):\n ... zope.component.adapts(IDemoContent)\n ... \n ... def doIndex(self):\n ... \n ... # index context in valueIndex\n ... valueIndex = self.getIndex('textIndex')\n ... txt = '%s %s' % (self.context.title, self.context.body)\n ... valueIndex.doIndex(self.oid, txt)\n ... \n ... # index context in fieldIndex\n ... fieldIndex = self.getIndex('fieldIndex')\n ... fieldIndex.doIndex(self.oid, self.context.field)\n ... \n ... # index context in setIndex\n ... setIndex = self.getIndex('setIndex')\n ... setIndex.doIndex(self.oid, self.context.iterable)\n ... \n ... # index context in valueIndex\n ... valueIndex = self.getIndex('valueIndex')\n ... valueIndex.doIndex(self.oid, self.context.value)\n\nRegister the indexer adapter as a named adapter:\n\n >>> zope.component.provideAdapter(DemoIndexer, name='DemoIndexer')\n\n\nIndexing\n--------\n\nBefore we start indexing, we check the index:\n\n >>> textIndex.documentCount()\n 0\n\n >>> fieldIndex.documentCount()\n 0\n\n >>> setIndex.documentCount()\n 0\n\n >>> valueIndex.documentCount()\n 0\n\nNow we can index our demo object:\n\n >>> from z3c.indexer.indexer import index\n >>> index(demo)\n\nAnd check our indexes:\n\n >>> textIndex.documentCount()\n 1\n\n >>> fieldIndex.documentCount()\n 1\n\n >>> setIndex.documentCount()\n 1\n\n >>> valueIndex.documentCount()\n 1\n\n\nSearch Filter\n-------------\n\nNow we are ready and can start with our search filter implementation.\nThe following search filter returns no results by default because it defines \nNoTerm as getDefaultQuery. This is usefull if you have a larg set of data and \nyou like to start with a empty query if no cirterium is selected.\n\n >>> from z3c.searcher import interfaces\n >>> from z3c.searcher.filter import EmptyTerm\n >>> from z3c.searcher.filter import SearchFilter\n\n >>> class IContentSearchFilter(interfaces.ISearchFilter):\n ... \"\"\"Search filter for content objects.\"\"\"\n\n >>> class ContentSearchFilter(SearchFilter):\n ... \"\"\"Content search filter.\"\"\"\n ... \n ... zope.interface.implements(IContentSearchFilter)\n ... \n ... def getDefaultQuery(self):\n ... return EmptyTerm()\n\n\nSearch Criterium\n----------------\n\nAnd we define a criterium for our demo content. This text search criterium uses\nthe text index registered as ``textIndex`` above:\n\n >>> from z3c.searcher import criterium\n >>> class TextCriterium(criterium.TextCriterium):\n ... \"\"\"Full text search criterium for ``textIndex`` index.\"\"\"\n ... \n ... indexOrName = 'textIndex'\n\nSuch a criterium can search in our index. Let's start with a empty search query:\n\n >>> from z3c.indexer.search import SearchQuery\n >>> searchQuery = SearchQuery()\n\nYou can see that the searchQuery returns a empty result.\n\n >>> len(searchQuery.searchResults())\n 0\n\nshowcase\n~~~~~~~~\n\nNow we can create a criterium instance and give them a value:\n\n >>> sampleCriterium = TextCriterium()\n >>> sampleCriterium.value = u'Bod*'\n\nNow the criterium is able to search in it's related index within the given \nvalue within a given (emtpy) search query. This empty query is only used as\na chainable query object. Each result get added or removed from this chain\ndependent on it's connector ``And``, ``OR`` or ``Not``:\n\n >>> searchQuery = sampleCriterium.search(searchQuery)\n\nNow you can see that our criterium found a result from the text index:\n\n >>> len(searchQuery.searchResults())\n 1\n\n >>> content = list(searchQuery.searchResults())[0]\n >>> content.body\n u'Body text'\n\n\nSearch Criterium Factory\n------------------------\n\nThe test above shows you how criterium can search in indexes. But that's not \nall. Our concept offers a search filter which can manage more then one search\ncriterium in a filter. A criterium is an adapter for a filter. This means we\nneed to create an adapter factory and register this factory as an adapter\nfor our filter. Let's now create this criterium adapter factory:\n\n >>> textCriteriumFactory = criterium.factory(TextCriterium, 'fullText')\n\nThis search criterium factory class implements ISearchCriteriumFactory:\n\n >>> interfaces.ISearchCriteriumFactory.implementedBy(textCriteriumFactory)\n True\n\nand we register this adapter for our content search filter:\n\n >>> zope.component.provideAdapter(textCriteriumFactory, \n ... (IContentSearchFilter,), name='fullText')\n\nshowcase\n~~~~~~~~\n\nNow you can see that our content search filter knows about the search criterium\nfactories:\n\n >>> contentSearchFilter = ContentSearchFilter()\n >>> contentSearchFilter.criteriumFactories\n [(u'fullText', )]\n\nSince the search criterium factory is an adapter for our search filter, the \nfactory can adapt our contentSearchFilter:\n\n >>> textCriteriumFactory = textCriteriumFactory(contentSearchFilter)\n >>> textCriteriumFactory\n \n\nNow we can call the factory and we will get back our search criterium instance:\n\n >>> textCriterium = textCriteriumFactory()\n >>> textCriterium\n \n\nOur search criterium provides ISearchCriterium:\n\n >>> interfaces.ISearchCriterium.providedBy(textCriterium)\n True\n\n\nSearch Example\n--------------\n\nNow we are ready to search within our filter construct. First let's create a \nplain content search filter:\n\n >>> sampleFilter = ContentSearchFilter()\n\nThen let's add a criterium by it's factory name:\n\n >>> sampleCriterium = sampleFilter.createCriterium('fullText')\n\nNow we can set a value for the criterium:\n\n >>> sampleCriterium.value = u'Title'\n\nAnd add the criterium to our filter:\n\n >>> sampleFilter.addCriterium(sampleCriterium)\n\nThat's all, now our filter is a ble to genearet a query:\n\n >>> sampleQuery = sampleFilter.generateQuery()\n\nAnd the sample search query can return the result:\n\n >>> len(sampleQuery.searchResults())\n 1\n\n >>> content = list(sampleQuery.searchResults())[0]\n >>> content.title\n u'Title'\n\n\nSearch Session\n--------------\n\nBefore we show how to use the criterium and filter within z3c.form components,\nwe will show you how the search session is working. Let's register and create\na search session:\n\n >>> from z3c.searcher import session\n >>> zope.component.provideAdapter(session.SearchSession)\n\nNow we can create a test request and get the session as adapter for a request:\n\n >>> import z3c.form.testing\n >>> request = z3c.form.testing.TestRequest()\n >>> searchSession = interfaces.ISearchSession(request)\n >>> searchSession\n \n\nThe search session offers an API for store and manage filters: \n\n >>> searchSession.addFilter('foo', sampleFilter)\n\nAnd we can get such filters from the search session by name.\n\n >>> searchSession.getFilter('foo')\n \n\nOr we can get all search filters sotred in this session:\n\n >>> searchSession.getFilters()\n []\n\nAnd we can remove a filter by it's name:\n\n >>> searchSession.removeFilter('foo')\n >>> searchSession.getFilters()\n []\n\nThere is also another argument called ``key`` in the search session methods. \nThis argument can be used as namespace. If you need to support a specific \nfilter only for one object instance, you can use a key which is unique to that \nobject as discriminator.\n\n >>> myFilter = ContentSearchFilter()\n >>> searchSession.addFilter('foo', myFilter, key='myKey')\n\nSuch filters are only available if the right ``key`` is used:\n\n >>> searchSession.getFilter('foo') is None\n True\n\n >>> searchSession.getFilter('foo', key='myKey')\n \n\n >>> searchSession.getFilters()\n []\n\nNow let's cleanup our search session and remove the filter stored by the key:\n\n >>> searchSession.getFilters('myKey')\n []\n\n >>> searchSession.removeFilter('foo', 'myKey')\n >>> searchSession.getFilters('myKey')\n []\n\n\nCriterium Form\n--------------\n\nNow we will show you how the form part is working. Each criterium can render \nitself within a form. We offer a CriteriumForm class for doing this. Let's\ncreate and render such a criterium form:\n\n >>> import z3c.form.testing\n >>> from z3c.searcher import form\n >>> criteriumRow = form.CriteriumForm(textCriterium, request)\n >>> criteriumRow\n \n\nWe also need to set a prefix, this is normaly done by the search form by\ncalling setupCriteriumRows. And normaly the criterium is located in the search\nfilter. We just need a criterium __name__ for now:\n\n >>> textCriterium.__name__ = u'1'\n >>> criteriumRow.prefix = 'form.criterium.%s' % str(textCriterium.__name__)\n >>> criteriumRow.prefix\n 'form.criterium.1'\n\nBefore we can render the form, we need to register the templates:\n\n >>> from zope.configuration import xmlconfig\n >>> import zope.component\n >>> import zope.viewlet\n >>> import zope.app.component\n >>> import zope.app.security\n >>> import zope.app.publisher.browser\n >>> import z3c.template\n >>> import z3c.macro\n >>> import z3c.formui\n >>> xmlconfig.XMLConfig('meta.zcml', zope.component)()\n >>> xmlconfig.XMLConfig('meta.zcml', zope.viewlet)()\n >>> xmlconfig.XMLConfig('meta.zcml', zope.app.component)()\n >>> xmlconfig.XMLConfig('meta.zcml', zope.app.security)()\n >>> xmlconfig.XMLConfig('meta.zcml', zope.app.publisher.browser)()\n >>> xmlconfig.XMLConfig('meta.zcml', z3c.macro)()\n >>> xmlconfig.XMLConfig('meta.zcml', z3c.template)()\n >>> xmlconfig.XMLConfig('div-form.zcml', z3c.formui)()\n >>> context = xmlconfig.file('meta.zcml', z3c.template)\n >>> context = xmlconfig.string(\"\"\"\n ... \n ... \n ... \n ... \n ... \n ... \n ... \n ... \n ... \"\"\", context=context)\n\nAnd we also need some widgets from z3c.form:\n\n >>> import z3c.form.testing\n >>> z3c.form.testing.setupFormDefaults()\n\nNow we can render the criterium form:\n\n >>> criteriumRow.update()\n >>> print criteriumRow.render()\n \n \n Text\n \n \n matches\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\nFilter Form\n------------\n\nThere is also a filter form which can represent the SearchFilter. This form\nincludes the CriteriumForm part. Note we uses a dumy context becaue it's not\nrelevant where you render this form because the form will get the filters\nfrom the session.\n\n >>> filterForm = form.FilterForm(object(), request)\n >>> filterForm\n \n\nBut before we can use the form, we need to set our search filter class as \nfactory. Because only this search filter knows our criteria:\n\n >>> filterForm.filterFactory = ContentSearchFilter\n\nNow we can render our filter form:\n\n >>> filterForm.update()\n >>> print filterForm.render()\n
\n Filter\n
\n \n \n \n
\n
\n \n \n
\n
\n\n\nSearch Form\n-----------\n\nThere is also a search form which allows you to simply define a search page.\nThis search form uses the criterium and filter form and allows you to simply\ncreate a search page. Let's define a custom search page:\n\n >>> class ContentSearchForm(form.SearchForm):\n ... \n ... filterFactory = ContentSearchFilter\n\nBefore we can use the form, our request needs to provide the form UI layer:\n\n >>> from zope.interface import alsoProvides\n >>> from z3c.formui.interfaces import IDivFormLayer\n >>> alsoProvides(request, IDivFormLayer)\n\nThat's all you need for write a simple search form. This form uses it's own\ncontent search filter and of corse the criteria configured for this filter.\n\n >>> searchForm = ContentSearchForm(object(), request)\n >>> searchForm.update()\n >>> print searchForm.render()\n
\n
\n
\n
\n Filter\n
\n \n \n \n
\n
\n \n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n\nSearch Table\n------------\n\nThere is also a search table. This search table uses the criterium and filter\nform and allows you to simply create a search page which will list the results\nas table. Let's define a custom search table:\n\n >>> from z3c.searcher import table\n >>> class ContentSearchTable(table.SearchTable):\n ... \n ... filterFactory = ContentSearchFilter\n\nBefore we can use the form, our request needs to provide the form UI layer:\n\n >>> from zope.interface import alsoProvides\n >>> from z3c.formui.interfaces import IDivFormLayer\n >>> alsoProvides(request, IDivFormLayer)\n\nThat's all you need for write a simple search form. This form uses it's own\ncontent search filter and of corse the criteria configured for this filter.\n\n >>> searchTable = ContentSearchTable(object(), request)\n >>> searchTable.update()\n >>> print searchTable.render()\n
\n
\n
\n
\n
\n Filter\n
\n \n \n \n
\n
\n \n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n\n=======\nCHANGES\n=======\n\n0.6.0 (2009-09-20)\n------------------\n\n- Bugfix: Criterium didn't get correct located in SearchFilter. The criterium\n __name__ was allways an empty unicode value.\n\n- Bugfix: The criterim filter didn't work with more then one criterium used.\n The search form now locates the filter form and will set a individual prefix\n for the criterium form. If you use a custom criterium form, you probably \n have to review your custom implementation. Especialy review the prefix setup\n in the setupCriteriumRows method.\n\n- adjust tests, reflect latest changes and fix element attribute order which\n get changed in z3c.form\n\n\n0.5.2 (2009-03-10)\n------------------\n\n- Cleanup dependencies. Change package's mailing list address to\n zope-dev at zope.org instead of retired one.\n\n\n0.5.1 (2009-02-22)\n------------------\n\n- Fix: added missing zope.interface import in z3c.searcher.table and added\n tests for SearchTable\n\n\n0.5.0 (2009-02-22)\n------------------\n\n- Added initial generations configuration files\n\n- Initial Release", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://pypi.python.org/pypi/z3c.searcher", "keywords": "zope3 z3c catalog index indexer search searcher", "license": "ZPL 2.1", "maintainer": null, "maintainer_email": null, "name": "z3c.searcher", "package_url": "https://pypi.org/project/z3c.searcher/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/z3c.searcher/", "project_urls": { "Download": "UNKNOWN", "Homepage": "http://pypi.python.org/pypi/z3c.searcher" }, "release_url": "https://pypi.org/project/z3c.searcher/0.6.0/", "requires_dist": null, "requires_python": null, "summary": "Persistent and session based search form for Zope3", "version": "0.6.0" }, "last_serial": 802107, "releases": { "0.5.0": [ { "comment_text": "", "digests": { "md5": "ec4ff028ae4eaf1eedb5f04a97cbdbd8", "sha256": "e185f30a5ac209fe9d03c805ce330c54c0e587cdc7fc2662537d08858754462c" }, "downloads": -1, "filename": "z3c.searcher-0.5.0.zip", "has_sig": false, "md5_digest": "ec4ff028ae4eaf1eedb5f04a97cbdbd8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 38538, "upload_time": "2009-02-22T06:33:46", "url": "https://files.pythonhosted.org/packages/72/df/46c9e25ba1dc436371b493ebfd2d71b8c63ac5392f262899f9a53d2381a7/z3c.searcher-0.5.0.zip" } ], "0.5.1": [ { "comment_text": "", "digests": { "md5": "8772230a8643402b33a1d1deaba2670f", "sha256": "bb28ff724e1fd4ccd1cea9d4e60a6ad7900c814d63eb4f1d36ea74e79db7214b" }, "downloads": -1, "filename": "z3c.searcher-0.5.1.zip", "has_sig": false, "md5_digest": "8772230a8643402b33a1d1deaba2670f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 39094, "upload_time": "2009-02-22T08:55:53", "url": "https://files.pythonhosted.org/packages/d0/3e/32419cf34059b921c95dbe187affc511f408f2cb416a8d19d5e049899088/z3c.searcher-0.5.1.zip" } ], "0.5.2": [ { "comment_text": "", "digests": { "md5": "23807a41d420b2d0f35a6948bdb01ffe", "sha256": "5690c64c0554edfea31834691dd38df6bd4222938289cb949b42e8e92fdee5c3" }, "downloads": -1, "filename": "z3c.searcher-0.5.2.zip", "has_sig": false, "md5_digest": "23807a41d420b2d0f35a6948bdb01ffe", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 39287, "upload_time": "2009-03-10T06:29:50", "url": "https://files.pythonhosted.org/packages/d2/cd/c82bf429e1db9057a1561ea395239974ce1847320e6c891704aaf633b1c9/z3c.searcher-0.5.2.zip" } ], "0.6.0": [ { "comment_text": "", "digests": { "md5": "a9827504c4cc7f1891d4e0c247652a37", "sha256": "e5a74607ad1c2a5788bf17aa4ace9093508c20935f566ee85284f27e7804c05d" }, "downloads": -1, "filename": "z3c.searcher-0.6.0.zip", "has_sig": false, "md5_digest": "a9827504c4cc7f1891d4e0c247652a37", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 40625, "upload_time": "2009-09-20T00:26:29", "url": "https://files.pythonhosted.org/packages/40/39/92a2405d48af9a5c00f1e368eeb6700788de171c95575d6bb754d31df06f/z3c.searcher-0.6.0.zip" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "a9827504c4cc7f1891d4e0c247652a37", "sha256": "e5a74607ad1c2a5788bf17aa4ace9093508c20935f566ee85284f27e7804c05d" }, "downloads": -1, "filename": "z3c.searcher-0.6.0.zip", "has_sig": false, "md5_digest": "a9827504c4cc7f1891d4e0c247652a37", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 40625, "upload_time": "2009-09-20T00:26:29", "url": "https://files.pythonhosted.org/packages/40/39/92a2405d48af9a5c00f1e368eeb6700788de171c95575d6bb754d31df06f/z3c.searcher-0.6.0.zip" } ] }