[Checkins] SVN: zc.relation/trunk/ (1) default transitive query factories are no longer weak refs--that was

Gary Poster gary at zope.com
Fri Apr 11 22:58:19 EDT 2008


Log message for revision 85272:
  (1) default transitive query factories are no longer weak refs--that was
  insane of me, afaict :-/.  
  
  (2) listeners default to not being persistent weakrefs, but can be. 
  Making listeners weakrefs at least was not insane, but a bit too
  aggressive perhaps.  
  
  (3) added sugar for the spelling to search on an actual relation. 
  ``None`` was not terribly readable.  You can now spell ``None`` as
  ``zc.relation.RELATION``, which does seem to read a bit better for this
  purpose. 
  
  (4) rearranged order of subsequent docs in README.  tokens.txt is
  excessively complicated, so don't want to send anyone into that next. 
  Will consider rewriting tokens.txt with less extreme/involved examples.
  
  (5) swictched to using bootstrap external.
  

Changed:
  _U  zc.relation/trunk/
  D   zc.relation/trunk/bootstrap.py
  U   zc.relation/trunk/src/zc/relation/README.txt
  U   zc.relation/trunk/src/zc/relation/__init__.py
  U   zc.relation/trunk/src/zc/relation/catalog.py

-=-

Property changes on: zc.relation/trunk
___________________________________________________________________
Name: svn:externals
   - zc.relationship svn+ssh://svn.zope.org/repos/main/zc.relationship/trunk

   + zc.relationship svn+ssh://svn.zope.org/repos/main/zc.relationship/trunk
bootstrap svn://svn.zope.org/repos/main/zc.buildout/trunk/bootstrap


Deleted: zc.relation/trunk/bootstrap.py
===================================================================
--- zc.relation/trunk/bootstrap.py	2008-04-11 23:26:31 UTC (rev 85271)
+++ zc.relation/trunk/bootstrap.py	2008-04-12 02:58:18 UTC (rev 85272)
@@ -1,52 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2006 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Bootstrap a buildout-based project
-
-Simply run this script in a directory containing a buildout.cfg.
-The script accepts buildout command-line options, so you can
-use the -c option to specify an alternate configuration file.
-
-$Id: bootstrap.py 69908 2006-08-31 21:53:00Z jim $
-"""
-
-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)

Modified: zc.relation/trunk/src/zc/relation/README.txt
===================================================================
--- zc.relation/trunk/src/zc/relation/README.txt	2008-04-11 23:26:31 UTC (rev 85271)
+++ zc.relation/trunk/src/zc/relation/README.txt	2008-04-12 02:58:18 UTC (rev 85272)
@@ -110,11 +110,11 @@
     >>> catalog = zc.relation.catalog.Catalog(dumpEmployees, loadEmployees,
     ...                               relFamily=BTrees.family32.OI)
 
-[#verifyObjectICatalog]_ [#legacy]_ We can't do very much searching with it so far though,
-because the catalog doesn't have any indexes.  In this example, the
-relationship itself represents the employee, so we won't need to index
-that separately.  But we do need a way to tell the catalog how to find
-the other end of the relationship, the supervisor.
+[#verifyObjectICatalog]_ [#legacy]_ We can't do very much searching with it so
+far though, because the catalog doesn't have any indexes. In this example, the
+relationship itself represents the employee, so we won't need to index that
+separately. But we do need a way to tell the catalog how to find the other end
+of the relationship, the supervisor.
 
 You can specify this to the catalog with a zope.interface attribute or
 method, or with a callable.  We'll use a callable for now.  It takes the
@@ -124,13 +124,17 @@
     ...     return emp.supervisor # None or another employee
     ...
 
-Then we'll use that to tell the catalog to add an index for
-`supervisor`.  We'll also specify how to tokenize and store those
-values: in this case, the same way as the relations themselves.  We
-could also specify the name to call the index, but it will default to
-the __name__ of the function (or interface element), which will work
-just fine for us now.
+Then we'll use that to tell the catalog to add an index for `supervisor`.
 
+We'll also specify how to tokenize (dump and load) those values. In this case,
+we're able to use the same functions as the relations themselves. However, do
+note that we can specify a completely different way to dump and load for each
+"value index," or relation element.
+
+We could also specify the name to call the index, but it will default to the
+__name__ of the function (or interface element), which will work just fine for
+us now.
+
     >>> catalog.addValueIndex(supervisor, dumpEmployees, loadEmployees,
     ...                       btree=BTrees.family32.OI)
 
@@ -231,8 +235,8 @@
     ...     {'supervisor': zc.relation.catalog.any('Diane', 'Chuck')}))
     ['Frank', 'Galyn', 'Howie']
 
-`findValues` and the `None` query key
--------------------------------------
+`findValues` and the `RELATION` query key
+-----------------------------------------
 
 So how do we find who an employee's supervisor is?  Well, in this case,
 look at the attribute on the employee!  If you can use an attribute that
@@ -265,24 +269,31 @@
 search one or more indexes for matching relationships, as usual, but
 actually specify a relationship: Howie.
 
-We do not have an index name.  The key, then, is `None`: no index name,
-just relationship tokens.  For our current example, that would mean the
-query is `{None: 'Howie'}`.
+We do not have a value index name: we are looking for a relation. The key is
+the constant `zc.relation.RELATION`. For our current example, that would mean
+the query is `{zc.relation.RELATION: 'Howie'}`.
 
-    >>> list(catalog.findValues('supervisor', {None: 'Howie'}))[0]
+    >>> import zc.relation
+    >>> list(catalog.findValues(
+    ...     'supervisor', {zc.relation.RELATION: 'Howie'}))[0]
     <Employee instance "Diane">
 
 Congratulations, you just found an obfuscated and comparitively
 inefficient way to write `howie.supervisor`! [#intrinsic_search]_
 [#findValuesExceptions]_
 
-Slightly more usefully, you can use other query keys along with None.
+Slightly more usefully, you can use other query keys along with
+zc.relation.RELATION. This asks, "Of Betty, Alice, and Frank, who are
+supervised by Alice?"
     
     >>> sorted(catalog.findRelationTokens(
-    ...     {None: zc.relation.catalog.any('Betty', 'Alice', 'Chuck'),
+    ...     {zc.relation.RELATION: zc.relation.catalog.any(
+    ...         'Betty', 'Alice', 'Frank'),
     ...      'supervisor': 'Alice'}))
-    ['Betty', 'Chuck']
+    ['Betty']
 
+Only Betty is.
+
 Transitive Searching, Query Factories, and `maxDepth`
 ----------------------------------------------------------------
 
@@ -299,15 +310,15 @@
 direction.
 
 For instance, here we just want to tell the factory to transpose the two
-keys we've used, None and 'supervisor'.  Let's make a factory, use it
-in a query for a couple of transitive searches, and then, if you want,
+keys we've used, zc.relation.RELATION and 'supervisor'. Let's make a factory,
+use it in a query for a couple of transitive searches, and then, if you want,
 you can read through a footnote to talk through what is happening.
 
 Here's the factory.
 
     >>> import zc.relation.queryfactory
     >>> factory = zc.relation.queryfactory.TransposingTransitive(
-    ...     None, 'supervisor')
+    ...     zc.relation.RELATION, 'supervisor')
 
 Now `factory` is just a callable.  Let's let it help answer a couple of
 questions.
@@ -315,7 +326,7 @@
 Who are all of Howie's supervisors transitively (this looks up in the
 diagram)?
 
-    >>> list(catalog.findValues('supervisor', {None: 'Howie'},
+    >>> list(catalog.findValues('supervisor', {zc.relation.RELATION: 'Howie'},
     ...      queryFactory=factory))
     ... # doctest: +NORMALIZE_WHITESPACE
     [<Employee instance "Diane">, <Employee instance "Betty">,
@@ -343,7 +354,7 @@
 
 Now all searches are transitive by default.
 
-    >>> list(catalog.findValues('supervisor', {None: 'Howie'}))
+    >>> list(catalog.findValues('supervisor', {zc.relation.RELATION: 'Howie'}))
     ... # doctest: +NORMALIZE_WHITESPACE
     [<Employee instance "Diane">, <Employee instance "Betty">,
      <Employee instance "Alice">]
@@ -356,7 +367,8 @@
 We can force a non-transitive search, or a specific search depth, with
 maxDepth [#needs_a_transitive_queries_factory]_.
 
-    >>> list(catalog.findValues('supervisor', {None: 'Howie'}, maxDepth=1))
+    >>> list(catalog.findValues(
+    ...     'supervisor', {zc.relation.RELATION: 'Howie'}, maxDepth=1))
     [<Employee instance "Diane">]
     >>> sorted(catalog.findRelations({'supervisor': 'Betty'}, maxDepth=1))
     [<Employee instance "Diane">, <Employee instance "Edgar">]
@@ -382,7 +394,7 @@
 instance, what's the chain of command above Howie?  `findRelationChains`
 will return each unique path.
 
-    >>> list(catalog.findRelationChains({None: 'Howie'}))
+    >>> list(catalog.findRelationChains({zc.relation.RELATION: 'Howie'}))
     ... # doctest: +NORMALIZE_WHITESPACE
     [(<Employee instance "Howie">,),
      (<Employee instance "Howie">, <Employee instance "Diane">),
@@ -412,7 +424,7 @@
      (<Employee instance "Chuck">, <Employee instance "Galyn">)]
 
 That's all the paths--all the chains--from Alice.  We sorted the results,
-but normaly they would be breadth first.
+but normally they would be breadth first.
 
 But what if we wanted to just find the paths from one query result to
 another query result--say, we wanted to know the chain of command from Alice
@@ -420,7 +432,8 @@
 characteristics of our desired end point (or points).
 
     >>> list(catalog.findRelationChains(
-    ...     {'supervisor': 'Alice'}, targetQuery={None: 'Howie'}))
+    ...     {'supervisor': 'Alice'},
+    ...     targetQuery={zc.relation.RELATION: 'Howie'}))
     ... # doctest: +NORMALIZE_WHITESPACE
     [(<Employee instance "Betty">, <Employee instance "Diane">,
       <Employee instance "Howie">)]
@@ -511,10 +524,10 @@
     >>> import zc.relation.searchindex
     >>> catalog.addSearchIndex(
     ...     zc.relation.searchindex.TransposingTransitive(
-    ...         'supervisor', None))
+    ...         'supervisor', zc.relation.RELATION))
 
-The `None` describes how to walk back up the chain.  Search indexes are 
-explained in reasonable detail in searchindex.txt.
+The ``zc.relation.RELATION`` describes how to walk back up the chain. Search
+indexes are explained in reasonable detail in searchindex.txt.
 
 Now that we have added the index, we can search again.  The result this
 time is already computed, so, at least when you ask for tokens, it
@@ -573,13 +586,14 @@
 
 If we ask for the supervisors of Frank, it will include Betty.
 
-    >>> list(catalog.findValueTokens('supervisor', {None: 'Frank'}))
+    >>> list(catalog.findValueTokens(
+    ...     'supervisor', {zc.relation.RELATION: 'Frank'}))
     ['Chuck', 'Alice', 'Zane', 'Betty']
 
 Paths returned by `findRelationChains` are marked with special interfaces, and
 special metadata, to show the chain.
 
-    >>> res = list(catalog.findRelationChains({None: 'Frank'}))
+    >>> res = list(catalog.findRelationChains({zc.relation.RELATION: 'Frank'}))
     >>> len(res)
     5
     >>> import zc.relation.interfaces
@@ -607,14 +621,14 @@
     >>> list(catalog.findRelations(res[4].cycled[0], maxDepth=1))
     [<Employee instance "Alice">]
 
-
 To remove this craziness [#reverse_lookup]_, we can unindex Zane, and change
 and reindex Alice.
 
     >>> a.supervisor = None
     >>> catalog.index(a)
 
-    >>> list(catalog.findValueTokens('supervisor', {None: 'Frank'}))
+    >>> list(catalog.findValueTokens(
+    ...     'supervisor', {zc.relation.RELATION: 'Frank'}))
     ['Chuck', 'Alice']
 
     >>> catalog.unindex(z)
@@ -656,29 +670,31 @@
 
 Is Alice a supervisor of Howie?
 
-    >>> catalog.canFind({'supervisor': 'Alice'}, targetQuery={None: 'Howie'})
+    >>> catalog.canFind({'supervisor': 'Alice'},
+    ...                 targetQuery={zc.relation.RELATION: 'Howie'})
     True
 
 Is Chuck a supervisor of Howie?
 
-    >>> catalog.canFind({'supervisor': 'Chuck'}, targetQuery={None: 'Howie'})
+    >>> catalog.canFind({'supervisor': 'Chuck'},
+    ...                 targetQuery={zc.relation.RELATION: 'Howie'})
     False
 
 Is Howie Alice's employee?
 
-    >>> catalog.canFind({None: 'Howie'}, targetQuery={'supervisor': 'Alice'})
+    >>> catalog.canFind({zc.relation.RELATION: 'Howie'},
+    ...                 targetQuery={'supervisor': 'Alice'})
     True
 
 Is Howie Chuck's employee?
 
-    >>> catalog.canFind({None: 'Howie'}, targetQuery={'supervisor': 'Chuck'})
+    >>> catalog.canFind({zc.relation.RELATION: 'Howie'},
+    ...                 targetQuery={'supervisor': 'Chuck'})
     False
 
 (Note that, if your relations describe a hierarchy, searching up a
 hierarchy is usually more efficient, so the second pair of questions is
-generally preferable to the first in that case.  However, if you install
-a search index for either direction of the query, `canFind` can use
-it efficiently either way)
+generally preferable to the first in that case.)
 
 Conclusion
 ==========
@@ -734,13 +750,13 @@
   methods are `findRelationTokens`, `findValueTokens`, and
   `findRelationTokenChains`.
 
-- Queries are formed with dicts.  The keys are the names of the
-  indexes you want to search, or, for the special case of precise
-  relationships, None. The values are the tokens of the results you
-  want to match; or None, indicating relations that have None as a
-  value (or no values, if it is a multiple).  Search values can use
-  zc.relation.catalog.any or zc.relation.catalog.Any to specify
-  multiple (non-None) results to match for a given key.
+- Queries are formed with dicts. The keys are the names of the indexes you want
+  to search, or, for the special case of precise relations,
+  zc.relation.RELATION. The values are the tokens of the results you want to
+  match; or None, indicating relations that have None as a value (or no values,
+  if it is a multiple). Search values can use zc.relation.catalog.any or
+  zc.relation.catalog.Any to specify multiple (non-None) results to match for a
+  given key.
 
 As you can tell by the holes we mentioned in the overview, there's more
 to cover.  Hopefully, this will be enough to get your feet wet, though,
@@ -752,23 +768,21 @@
 If you want to read more, next steps depend on how you like to learn.  Here
 are some of the other documents in the zc.relation package.
 
+:optimization.txt:
+    Best practices for optimizing your use of the relation catalog.
+
+:searchindex.txt:
+    Queries factories and search indexes: from basics to nitty gritty details.
+
 :tokens.txt:
     This document explores the details of tokens.  All God's chillun
     love tokens, at least if God's chillun are writing non-toy apps
     using zc.relation.  It includes discussion of the token helpers that
     the catalog provides, how to use zope.app.intid-like registries with
     zc.relation, how to use tokens to "join" query results reasonably
-    efficiently, and how to index joins.
+    efficiently, and how to index joins.  It also is unnecessarily
+    mind-blowing because of the examples used.
 
-:searchindex.txt:
-    Queries factories and search indexes: from basics to nitty gritty details.
-
-:optimization.txt:
-    Best practices for optimizing your use of the relation catalog.
-
-:administration.txt:
-    Managing indexes and listeners.
-
 :interfaces.py:
     The contract, for nuts and bolts.
 
@@ -862,15 +876,16 @@
 
 .. [#intrinsic_search] Here's the same with token results.
 
-    >>> list(catalog.findValueTokens('supervisor', {None: 'Howie'}))
+    >>> list(catalog.findValueTokens('supervisor',
+    ...                              {zc.relation.RELATION: 'Howie'}))
     ['Diane']
     
     While we're down here in the footnotes, I'll mention that you can
     search for relations that haven't been indexed.
 
-    >>> list(catalog.findRelationTokens({None: 'Ygritte'}))
+    >>> list(catalog.findRelationTokens({zc.relation.RELATION: 'Ygritte'}))
     []
-    >>> list(catalog.findRelations({None: 'Ygritte'}))
+    >>> list(catalog.findRelations({zc.relation.RELATION: 'Ygritte'}))
     []
 
 .. [#findValuesExceptions] If you use findValues or findValueTokens and try
@@ -897,12 +912,12 @@
     OK, the next part is where your brain hurts.  Hang on.
     
     In our case, the factory sees that the query was for supervisor. Its
-    other key, the one it transposes with, is None.  *The factory gets
-    the transposing key's result for the current token.*  So, for us, a
-    key of None is actually a no-op: the result *is* the current
-    token, Diane.  Then, the factory has its answer: replace the old value
-    of supervisor in the query, Betty, with the result, Diane.  The next
-    transitive query should be {'supervisor', 'Diane'}.  Ta-da.
+    other key, the one it transposes with, is zc.relation.RELATION. *The
+    factory gets the transposing key's result for the current token.* So, for
+    us, a key of zc.relation.RELATION is actually a no-op: the result *is* the
+    current token, Diane. Then, the factory has its answer: replace the old
+    value of supervisor in the query, Betty, with the result, Diane. The next
+    transitive query should be {'supervisor', 'Diane'}. Ta-da.
 
 .. [#needs_a_transitive_queries_factory] A search with a maxDepth > 1 but
     no queryFactory raises an error.
@@ -930,13 +945,13 @@
 
 .. [#filter] For instance:
 
-    >>> list(catalog.findRelationTokens({'supervisor': 'Alice'},
-    ...                                 targetFilter=female_filter,
-    ...                                 targetQuery={None: 'Galyn'}))
+    >>> list(catalog.findRelationTokens(
+    ...     {'supervisor': 'Alice'}, targetFilter=female_filter,
+    ...     targetQuery={zc.relation.RELATION: 'Galyn'}))
     ['Galyn']
-    >>> list(catalog.findRelationTokens({'supervisor': 'Alice'},
-    ...                                 targetFilter=female_filter,
-    ...                                 targetQuery={None: 'Not known'}))
+    >>> list(catalog.findRelationTokens(
+    ...     {'supervisor': 'Alice'}, targetFilter=female_filter,
+    ...     targetQuery={zc.relation.RELATION: 'Not known'}))
     []
     >>> arbitrary = ['Alice', 'Chuck', 'Betty', 'Galyn']
     >>> def arbitrary_filter(relchain, query, catalog, cache):

Modified: zc.relation/trunk/src/zc/relation/__init__.py
===================================================================
--- zc.relation/trunk/src/zc/relation/__init__.py	2008-04-11 23:26:31 UTC (rev 85271)
+++ zc.relation/trunk/src/zc/relation/__init__.py	2008-04-12 02:58:18 UTC (rev 85272)
@@ -1 +1 @@
-#
+from zc.relation.catalog import RELATION

Modified: zc.relation/trunk/src/zc/relation/catalog.py
===================================================================
--- zc.relation/trunk/src/zc/relation/catalog.py	2008-04-11 23:26:31 UTC (rev 85271)
+++ zc.relation/trunk/src/zc/relation/catalog.py	2008-04-12 02:58:18 UTC (rev 85272)
@@ -13,6 +13,16 @@
 from zc.relation import interfaces
 
 ##############################################################################
+# constants
+#
+
+RELATION = None
+# uh, yeah.  None.  The story is, zc.relation.RELATION is more readable as
+# a search key, so I want a constant; but by the time I came to this decision,
+# ``None`` had already been advertised as the way to spell this.  So, yeah...
+# hysterical raisins.
+
+##############################################################################
 # helpers
 #
 
@@ -190,7 +200,11 @@
         res._attrs = self.family.OO.Bucket(
             [(k, self.family.OO.Bucket(v)) for k, v in self._attrs.items()])
         res._relTools = dict(self._relTools)
-        res._listeners = self._listeners # it's a tuple
+        res._listeners = () # TODO document that listeners are not copied
+        # (rationale: they need to have ``sourceAdded`` called with the
+        # catalog, and we don't know the semantics of any given particular
+        # listener to know if it should be the same object or a copy or nothing
+        # at all. Therefore, we do not include listeners in a copy)
         res._queryFactories = self._queryFactories # it's a tuple
         res._relLength = BTrees.Length.Length()
         res._relLength.set(self._relLength.value)
@@ -287,29 +301,51 @@
     # Listeners
     # -----------
     
-    def addListener(self, listener):
-        res = [ref for ref in self._listeners if ref() is not None]
-        res.append(createRef(listener))
+    def addListener(self, listener, weakref=False):
+        res = []
+        for item in self._listeners:
+            if isinstance(item, persistent.wref.WeakRef):
+                if item() is not None:
+                    res.append(item)
+            else:
+                res.append(item)
+        if isinstance(listener, persistent.Persistent):
+            if weakref:
+                res.append(persistent.wref.WeakRef(listener))
+            else:
+                res.append(listener)
+        else:
+            if weakref:
+                raise ValueError('cannot use weakref on non-persistent object')
+            # make a persistent object so tuple itself is smaller
+            res.append(Ref(listener))
         self._listeners = tuple(res)
         listener.sourceAdded(self)
 
     def iterListeners(self):
-        for ref in self._listeners:
-            l = ref()
-            if l is not None:
-                yield l
+        for item in self._listeners:
+            if isinstance(item, (persistent.wref.WeakRef, Ref)):
+                item = item()
+                if item is None:
+                    continue
+            yield item
 
     def removeListener(self, listener):
         if listener is None:
             raise LookupError('listener not found', listener)
         res = []
         found = False
-        for ref in reversed(self._listeners):
-            l = ref()
-            if l is listener and not found:
+        for item in reversed(self._listeners):
+            if isinstance(item, (persistent.wref.WeakRef, Ref)):
+                val = item()
+                if val is None:
+                    continue
+            else:
+                val = item
+            if val is listener and not found:
                 found = True
                 continue
-            res.append(ref)
+            res.append(item)
         if not found:
             raise LookupError('listener not found', listener)
         res.reverse()
@@ -320,30 +356,19 @@
     # -----------------------
     
     def addDefaultQueryFactory(self, factory):
-        res = [ref for ref in self._queryFactories if ref() is not None]
-        res.append(createRef(factory))
-        self._queryFactories = tuple(res)
+        if factory in self._queryFactories:
+            raise ValueError('factory already registered')
+        self._queryFactories += (factory,)
 
     def iterDefaultQueryFactories(self):
-        for ref in self._queryFactories:
-            factory = ref()
-            if factory is not None:
-                yield factory
+        return iter(self._queryFactories)
 
     def removeDefaultQueryFactory(self, factory):
-        if factory is None:
+        res = list(self._queryFactories)
+        try:
+            res.remove(factory)
+        except ValueError:
             raise LookupError('factory not found', factory)
-        res = []
-        found = False
-        for ref in reversed(self._queryFactories):
-            l = ref()
-            if l is factory and not found:
-                found = True
-                continue
-            res.append(ref)
-        if not found:
-            raise LookupError('factory not found', factory)
-        res.reverse()
         self._queryFactories = tuple(res)
 
     # Search Indexes
@@ -362,15 +387,16 @@
             else:
                 rel_bool = False
             query_names_res = []
-            none_query = False
+            relation_query = False
             for nm in query_names:
-                if nm is None:
-                    none_query = True
+                if nm is RELATION:
+                    relation_query = True
                 else:
                     query_names_res.append(nm)
             if maxDepth is None:
                 maxDepth = 0
-            k = (rel_bool, name, none_query, tuple(query_names_res), maxDepth)
+            k = (rel_bool, name, relation_query,
+                 tuple(query_names_res), maxDepth)
             a = self._searchIndexMatches.get(k)
             if a is None:
                 self._searchIndexMatches[
@@ -586,7 +612,7 @@
     def tokenizeQuery(self, query):
         res = {}
         for k, v in query.items():
-            if k is None:
+            if k is RELATION:
                 tools = self._relTools
             else:
                 tools = self._attrs[k]
@@ -603,7 +629,7 @@
     def resolveQuery(self, query):
         res = {}
         for k, v in query.items():
-            if k is None:
+            if k is RELATION:
                 tools = self._relTools
             else:
                 tools = self._attrs[k]
@@ -653,16 +679,16 @@
 
     def _relData(self, query):
         # query must be BTrees.family32.OO.Bucket.  The key may be
-        # a value index name or None, indicating one or more relations.  The
-        # val may be token, None, or iterator (object with a `next` method)
-        # of tokens (may not include None).
+        # a value index name or RELATION, indicating one or more relations. The
+        # val may be token, None, or iterator (object with a `next` method) of
+        # tokens (may not include None).
         if not query:
             return self._relTokens
         data = []
         tools = self._relTools
         explicit_relations = False
         for name, value in query.items():
-            if name is None:
+            if name is RELATION:
                 explicit_relations = True
                 if not isinstance(value, Any):
                     value = (value,)
@@ -900,14 +926,14 @@
                     (self._reltoken_name_TO_objtokenset.get((r, name))
                      for r in rels), data)
         if self._searchIndexMatches is not None:
-            if None in query:
-                none = True
-                query_names = tuple(nm for nm in query if nm is not None)
+            if RELATION in query:
+                relation_query = True
+                query_names = tuple(nm for nm in query if nm is not RELATION)
             else:
-                none = False
+                relation_query = False
                 query_names = tuple(query)
             if not targetQuery and targetFilter is None:
-                key = (False, name, none, query_names, maxDepth or 0)
+                key = (False, name, relation_query, query_names, maxDepth or 0)
                 for (c_filter, c_queryFactory, c_static_values, ix
                     ) in self._searchIndexMatches.get(key, ()):
                     if (c_filter != filter or
@@ -920,7 +946,7 @@
                         name, query, maxDepth, filter, queryFactory)
                     if res is not None:
                         return res
-            key = (True, '', none, query_names, maxDepth or 0)
+            key = (True, '', relation_query, query_names, maxDepth or 0)
             res = self._getSearchIndexResults(
                 key, query, maxDepth, filter, targetQuery, targetFilter,
                 queryFactory)
@@ -991,13 +1017,13 @@
                 res = self._relTools['Set']()
             return res
         if self._searchIndexMatches is not None:
-            if None in query:
-                none = True
+            if RELATION in query:
+                relation_query = True
                 query_names = tuple(nm for nm in query if nm is not None)
             else:
-                none = False
+                relation_query = False
                 query_names = tuple(query)
-            key = (True, '', none, query_names, maxDepth or 0)
+            key = (True, '', relation_query, query_names, maxDepth or 0)
             res = self._getSearchIndexResults(
                 key, query, maxDepth, filter, targetQuery, targetFilter,
                 queryFactory)
@@ -1069,13 +1095,13 @@
                 query, queryFactory)
         targetQuery = BTrees.family32.OO.Bucket(targetQuery)
         if self._searchIndexMatches is not None:
-            if None in query:
-                none = True
+            if RELATION in query:
+                relation_query = True
                 query_names = tuple(nm for nm in query if nm is not None)
             else:
-                none = False
+                relation_query = False
                 query_names = tuple(query)
-            key = (True, '', none, query_names, maxDepth or 0)
+            key = (True, '', relation_query, query_names, maxDepth or 0)
             res = self._getSearchIndexResults(
                 key, query, maxDepth, filter, targetQuery, targetFilter,
                 queryFactory)



More information about the Checkins mailing list