diff --git a/.travis.yml b/.travis.yml index e002327..95faf32 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,14 @@ language: python sudo: false +dist: xenial python: - 2.7 - - 3.4 - - 3.5 - 3.6 + - 3.7 install: - - pip install six==1.10.0 # force here to avoid conflict with zc.recipe.testrunner - - pip install -U setuptools==33.1.1 + - pip install -U setuptools pip - pip install zc.buildout - - buildout bootstrap + - buildout annotate - buildout script: - bin/test -v1 diff --git a/Products/ExtendedPathIndex/ExtendedPathIndex.py b/Products/ExtendedPathIndex/ExtendedPathIndex.py index 22087a2..6977032 100644 --- a/Products/ExtendedPathIndex/ExtendedPathIndex.py +++ b/Products/ExtendedPathIndex/ExtendedPathIndex.py @@ -53,6 +53,7 @@ class ExtendedPathIndex(PathIndex): ) indexed_attrs = None + multi_valued = False query_options = ("query", "level", "operator", "depth", "navtree", "navtree_start") @@ -62,8 +63,10 @@ def __init__(self, id, extra=None, caller=None): if isinstance(extra, dict): attrs = extra.get('indexed_attrs', None) + self.multi_valued = extra.get('multi_valued', False) else: attrs = getattr(extra, 'indexed_attrs', None) + self.multi_valued = getattr(extra, 'multi_valued', False) if attrs is None: return @@ -245,7 +248,7 @@ def search(self, path, default_level=0, depth=-1, navtree=0, # Optimized absolute path navtree and breadcrumbs cases result = [] add = lambda x: x is not None and result.append(x) - if depth == 1: + if depth == 1 and not self.multi_valued: # Navtree case, all sibling elements along the path convert = multiunion index = self._index_parents @@ -261,7 +264,7 @@ def search(self, path, default_level=0, depth=-1, navtree=0, if not path.startswith('/'): path = '/' + path - if depth == 0: + if depth == 0 and not self.multi_valued: # Specific object search res = self._index_items.get(path) return res and IISet([res]) or IISet() diff --git a/README.rst b/README.rst index 6780c06..a815077 100644 --- a/README.rst +++ b/README.rst @@ -1,21 +1,19 @@ Introduction ============ -This is an index that supports depth limiting, and the ability to build a -structure usable for navtrees and sitemaps. The actual navtree implementations -are not (and should not) be in this Product, this is the index implementation -only. +This is an Zope Catalog index to query treeish structures in the ZODB by path. +It supports depth limiting, and has the ability to build a structure usable for navtrees and sitemaps. +The actual navtree implementations are not (and should not) be in this package. +This is the index implementation only. Assumptions =========== -EPI makes an assumption about the catalog and index being in the -same container as all the content. This makes a lot of sense in a -Plone setting, but might not work as expected in other scenarios. +EPI makes an assumption about the catalog and index being in the same container as all the content. +This makes a lot of sense in a Plone setting, but might not work as expected in other scenarios. -A query like ``/plonesite/folder, level=0`` is transformed internally to -``/folder, level=1``. This avoids touching the rather large plonesite set -which contains reference to all content in your site. +A query like ``/plonesite/folder, level=0`` is transformed internally to ``/folder, level=1``. +This avoids touching the rather large plonesite set which contains reference to all content in your site. Features ======== @@ -24,6 +22,44 @@ Features - Can construct a navigation tree with a single catalog query +Configuration +============= + +In a GenericSetup profile, provide th following snippet to create an index:: + + + + + +For multi valued paths, provide an extra +(switches off an breaking optimization not needed for this cases):: + + + + + + +An example for an index with multiple values per path element: +Imagine to index multilingual content. +Every item is translated and all translated items share a common unique identifier +(this is how plone.app.multilingual works). +Now create an indexer returing this unique identifier instead of the items ID as a path element. +With this it is possible to query all elements of all languages in a folder in one go +(for an advanced usage of this pattern look at ``plone.app.multilingualindexes``). + Usage ===== @@ -32,45 +68,45 @@ Usage ``catalog(path=dict(query='some/path', depth=0))`` search for the object with the given path. + For multi valued paths, multiple objects are returned. ``catalog(path=dict(query='some/path', depth=2))`` search for all objects below some/path but only down to a depth of 2 ``catalog(path=dict(query='some/path', navtree=True))`` - search for all objects below some/path for rendering a navigation tree. This - includes all objects below some/path up to a depth of 1 and all parent - objects. + search for all objects below some/path for rendering a navigation tree. + This includes all objects below some/path up to a depth of 1 and all parent objects. ``catalog(path=dict(query='some/path', navtree=True, depth=0))`` search for all objects below some/path for rendering a breadcrumb trail. This includes only the parent objects themselves. ``catalog(path=dict(query='some/path', navtree=True, navtree_start=1))`` - search for all objects below some/path for rendering a partial - navigation tree. This includes all objects below the path but stops - 1 level above the root. The given path is included, even if it is at a - shorter path in the portal than the level parameter would allow. + search for all objects below some/path for rendering a partial navigation tree. + This includes all objects below the path but stops 1 level above the root. + The given path is included, + even if it is at a shorter path in the portal than the level parameter would allow. ``catalog(path=dict(query='some/path', navtree=True, depth=0, navtree_start=1))`` - search for all objects below some/path for rendering a partial - breadcrumb trail. This includes all parents below the path but stops - 1 level above the root. The given path is included, even if it is at a - lower level in the portal than the start parameter would allow. + search for all objects below some/path for rendering a partial breadcrumb trail. + This includes all parents below the path but stops 1 level above the root. + The given path is included, even if it is at a lower level in the portal than the start parameter would allow. ``catalog(path=dict(query='some/path', level=2))`` - search for all objects whose path contains some/path at level 2. This - includes paths like /foo/bar/some/path and /spam/eggs/some/path, plus all - children of those paths. + search for all objects whose path contains some/path at level 2. + This includes paths like /foo/bar/some/path and /spam/eggs/some/path, + plus all children of those paths. ``catalog(path=dict(query='some/path', level=-1, depth=0))`` - search for all objects whose path contains some/path at *any* level. This - includes paths like /spam/some/path as well as /foo/bar/baz/some/path, but - only those exact matches are included in the result because depth is set to - 0. + search for all objects whose path contains some/path at *any* level. + This includes paths like /spam/some/path as well as /foo/bar/baz/some/path, + but only those exact matches are included in the result because depth is set to 0. ``catalog(path=dict(query=(('foo/bar', 2), ('bar/baz'), 1), depth=0))`` - search for multiple paths, each at different levels (foo/bar at level 2, - and bar/baz at level 1), and return exact matches only. + search for multiple paths, + each at different levels + (foo/bar at level 2, and bar/baz at level 1), + and return exact matches only. Credits ======= @@ -87,5 +123,5 @@ Credits License ======= -This software is released under the GPL license. +This software is released under the GPLv2 license. diff --git a/news/7-feature b/news/7-feature new file mode 100644 index 0000000..a551528 --- /dev/null +++ b/news/7-feature @@ -0,0 +1,2 @@ +Support allow multi value results for "virtual" paths. +[jensens] diff --git a/setup.py b/setup.py index 882cd57..a3c7c1c 100644 --- a/setup.py +++ b/setup.py @@ -1,13 +1,16 @@ from setuptools import setup, find_packages -version = '3.3.2.dev0' +version = '3.4.0.dev0' setup( name='Products.ExtendedPathIndex', version=version, description="Zope catalog index for paths", - long_description=(open("README.rst").read() + "\n" + \ - open("CHANGES.rst").read()), + long_description=( + open("README.rst").read() + + "\n" + + open("CHANGES.rst").read() + ), classifiers=[ "Environment :: Web Environment", "Framework :: Plone", @@ -19,11 +22,9 @@ "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", - ], + ], keywords='Zope catalog index', author='Plone Foundation', author_email='plone-developers@lists.sourceforge.net', @@ -41,4 +42,4 @@ 'Zope2 >= 2.13.0a3', 'zope.interface', ], - ) +)