[Checkins] SVN: zc.relation/trunk/ - make `bin/test` only test zc.relation (and not have zc.relationship in the

Gary Poster gary at zope.com
Wed Aug 8 06:49:50 EDT 2007


Log message for revision 78683:
  - make `bin/test` only test zc.relation (and not have zc.relationship in the
    path, while `bin/testall` tests zc.relationship also.
  - Remove untested feature in a searchindex: YAGNI, or I'll test it when I do
  - Remove unused old test
  

Changed:
  U   zc.relation/trunk/buildout.cfg
  D   zc.relation/trunk/src/zc/relation/example.txt
  U   zc.relation/trunk/src/zc/relation/searchindex.py

-=-
Modified: zc.relation/trunk/buildout.cfg
===================================================================
--- zc.relation/trunk/buildout.cfg	2007-08-08 08:53:01 UTC (rev 78682)
+++ zc.relation/trunk/buildout.cfg	2007-08-08 10:49:49 UTC (rev 78683)
@@ -1,11 +1,16 @@
 [buildout]
 develop = . zc.relationship
-parts = test py
+parts = test testall py
 
 find-links = http://download.zope.org/distribution/
 
 [test]
 recipe = zc.recipe.testrunner
+eggs = zc.relation
+defaults = "--tests-pattern [fn]?tests --exit-with-status".split()
+
+[testall]
+recipe = zc.recipe.testrunner
 eggs = zc.relation [test]
        zc.relationship
 defaults = "--tests-pattern [fn]?tests --exit-with-status".split()

Deleted: zc.relation/trunk/src/zc/relation/example.txt
===================================================================
--- zc.relation/trunk/src/zc/relation/example.txt	2007-08-08 08:53:01 UTC (rev 78682)
+++ zc.relation/trunk/src/zc/relation/example.txt	2007-08-08 10:49:49 UTC (rev 78683)
@@ -1,658 +0,0 @@
-====================================
-zc.relation.Catalog Extended Example
-====================================
-
-.. contents::
-   :local:
-
-Introduction and Set Up
-=======================
-
-This document assumes you have read the introductory README.txt and want
-to learn a bit more by example. In it, we will explore a more
-complicated set of relations, and will not explain the basics that the
-README already addressed.
-
-Imagine we are indexing security assertions in a system.  In this
-system, users may have roles within an organization.  Each organization
-may have multiple child organizations and may have a single parent
-organization.  A user with a role in a parent organization will have the
-same role in all transitively connected child relations.
-
-This catalog, then, will be indexing a heterogeneous collection of
-relations.  One kind of relation will model the hierarchy of
-organizations.  We'll do it with an intrinsic relation of
-organizations to their children: that reflects the fact that parent
-organizations choose and are comprised of their children; children do not
-choose their parents.
-
-The other relation will model the (multiple) roles a (single) user has
-in a (single) organization.  This relation will be entirely extrinsic.
-
-Let's define this with interfaces.
-
-    >>> import zope.interface
-    >>> class IOrganization(zope.interface.Interface):
-    ...     title = zope.interface.Attribute('the title')
-    ...     parts = zope.interface.Attribute(
-    ...         'the organizations that make up this one')
-    ...
-    >>> class IRoles(zope.interface.Interface):
-    ...     organization = zope.interface.Attribute(
-    ...         'the organization in which this relation operates')
-    ...     principal_id = zope.interface.Attribute(
-    ...         'the pricipal id whose roles this relation lists')
-    ...     role_ids = zope.interface.Attribute(
-    ...         'the role ids that the principal explicitly has in the '
-    ...         'organization.  The principal may have other roles via '
-    ...         'roles in parent organizations.')
-    ...
-
-Now we can create some classes.  In the first example, the setup was a bit
-of a toy.  This time we will be just a bit more practical.  We'll also expect
-to be operating within the ZODB, with a root and transactions. [#ZODB]_
-
-Here's how we will dump and load our relations: use a "registry"
-object, similar to an intid utility. [#faux_intid]_
-
-We use the cache just to show you how you might use it.  It probably is
-overkill for this job, and maybe even a loss, but you can see the idea.
-
-    >>> def dump(obj, catalog, cache):
-    ...     reg = cache.get('registry')
-    ...     if reg is None:
-    ...         reg = cache['registry'] = catalog._p_jar.root()['registry']
-    ...     return reg.getId(obj)
-    ...
-    >>> def load(token, catalog, cache):
-    ...     reg = cache.get('registry')
-    ...     if reg is None:
-    ...         reg = cache['registry'] = catalog._p_jar.root()['registry']
-    ...     return reg.getObject(token)
-    ...
-
-Now we can create a relation catalog to hold these items.
-
-    >>> import zc.relation
-    >>> catalog = root['catalog'] = zc.relation.Catalog(dump, load)
-    >>> transaction.commit()
-
-Now we set up our indexes.  We'll start with just the organizations, and
-set up the catalog with them. This part will be similar to the example
-in README.txt, but will introduce more discussions of optimizations and
-tokens.  Then we'll add in the part about roles, and explore transitive
-query factories and transitive indexes some more.
-
-Optimizations and Tokens: Setting Up the Organizations
-======================================================
-
-The organization will hold a set of organizations.  This is actually not
-inherently easy in the ZODB because this means that we need to compare
-or hash persistent objects, which does not work reliably over time and
-across machines out-of-the-box.  To side-step the issue for this example,
-and still do something a bit interesting and real-world, we'll the
-registry tokens introduced above.  This will also give us a chance to
-talk a bit more about optimizations and tokens.  (If you would like
-to sanely and transparently hold a set of persistent objects, try the
-zc.set package.)
-
-    >>> import BTrees
-    >>> class Organization(persistent.Persistent):
-    ...     zope.interface.implements(IOrganization)
-    ...     def __init__(self, title):
-    ...         self.title = title
-    ...         self.parts = BTrees.family32.IF.TreeSet()
-    ...     # the next parts just make the tests prettier
-    ...     def __repr__(self):
-    ...         return '<Organization instance "' + self.title + '">'
-    ...     def __cmp__(self, other):
-    ...         # pukes if other doesn't have name
-    ...         return cmp(self.title, other.title)
-    ...
-
-Now we can add the `parts` index to the catalog.  This will do a few
-new things from how we added indexes in the README.  We'll add the index,
-then talk about what we did.
-
-    >>> catalog.addValueIndex(IOrganization['parts'], multiple=True,
-    ...                       name="part")
-
-So, what's different?
-
-First, we are using an interface element to define the value to be indexed.
-It provides an interface to which objects will be adapted, a default name
-for the index, and information as to whether the attribute should be used
-directly or called.
-
-Second, we are not specifying a dump or load.  They are None.  This
-means that the indexed value can already be treated as a token.  This
-can allow a very significant optimization for reindexing if the indexed
-value is a large collection using the same BTree family as the
-index--which leads us to the next difference.
-
-Third, we are specifying that `multiple=True`.  This means that the value
-on a given relation that provides or can be adapted to IOrganization will
-have a collection of `parts`.  These will always be regarded as a set,
-whether the actual colection is a BTrees set or the keys of a BTree.
-
-Last, we are specifying a name to be used for queries.  I find that queries
-read more easily when the query keys are singular, so I often rename plurals.
-
-We are just working with organizations at the moment, so we can add
-another simple transposing transitive query factory, switching between
-'part' and `None`.
-
-    >>> factory = zc.relation.TransposingTransitiveQueriesFactory(
-    ...     'part', None)
-    >>> catalog.defaultTransitiveQueriesFactory = factory
-
-Let's add a transitive index in too, of the hierarchy looking down.
-
-    >>> catalog.addTransitiveIndex('part', None)
-
-Let's create and add a few organizations.  We'll make a structure like this::
-
-        Ynod Corp Mangement                 Zookd Corp Management
-         /      |      \                       /      |      \
-  Ynod Devs  Ynod SAs  Ynod Admins  Zookd Admins   Zookd SAs  Zookd Devs
-    /      \              \                 /                /         \
-Y3L4 Proj  Bet Proj      Ynod Zookd Task Force      Zookd hOgnmd     Zookd Nbd
-
-    >>> orgs = root['organizations'] = BTrees.family32.OO.BTree()
-    >>> for nm, parts in (
-    ...     ('Y3L4 Proj', ()),
-    ...     ('Bet Proj', ()),
-    ...     ('Ynod Zookd Task Force', ()),
-    ...     ('Zookd hOgnmd', ()),
-    ...     ('Zookd Nbd', ()),
-    ...     ('Ynod Devs', ('Y3L4 Proj', 'Bet Proj')),
-    ...     ('Ynod SAs', ()),
-    ...     ('Ynod Admins', ('Ynod Zookd Task Force',)),
-    ...     ('Zookd Admins', ('Ynod Zookd Task Force',)),
-    ...     ('Zookd SAs', ()),
-    ...     ('Zookd Devs', ('Zookd hOgnmd', 'Zookd Nbd')),
-    ...     ('Ynod Corp Management', ('Ynod Devs', 'Ynod SAs', 'Ynod Admins')),
-    ...     ('Zookd Corp Management', ('Zookd Devs', 'Zookd SAs',
-    ...                                'Zookd Admins'))):
-    ...     org = Organization(nm)
-    ...     for part in parts:
-    ...         ignore = org.parts.insert(registry.getId(orgs[part]))
-    ...     orgs[nm] = org
-    ...     catalog.index(org)
-    ...
-
-Now we can search.  To do this, we can use some of the token methods that
-the catalog provides.  The most commonly used is `tokenizeQuery`.  It takes a
-query with values that are not tokenized and converts them to values that are
-tokenized.
-
-    >>> Ynod_SAs_id = registry.getId(orgs['Ynod SAs'])
-    >>> catalog.tokenizeQuery({None: orgs['Ynod SAs']}) == {
-    ...     None: Ynod_SAs_id}
-    True
-    >>> Zookd_SAs_id = registry.getId(orgs['Zookd SAs'])
-    >>> Zookd_Devs_id = registry.getId(orgs['Zookd Devs'])
-    >>> catalog.tokenizeQuery(
-    ...     {None: zc.relation.any(orgs['Zookd SAs'], orgs['Zookd Devs'])}
-    ...     ) == {
-    ...     None: zc.relation.any(Zookd_SAs_id, Zookd_Devs_id)}
-    True
-
-Of course, right now doing this with 'part' alone is kind of silly, since it
-does not change within the relation catalog (because we said that dump and
-load were `None`, as discussed above).
-
-    >>> catalog.tokenizeQuery({'part': Ynod_SAs_id}) == {
-    ...     'part': Ynod_SAs_id}
-    True
-    >>> catalog.tokenizeQuery(
-    ...     {'part': zc.relation.any(Zookd_SAs_id, Zookd_Devs_id)}
-    ...     ) == {'part': zc.relation.any(Zookd_SAs_id, Zookd_Devs_id)}
-    True
-    
-It is so common that we're going to assign it to a variable in our example.
-Then we'll do a search or two.
-
-So...find the relations that Ynod Devs supervise.
-
-    >>> t = catalog.tokenizeQuery
-    >>> res = list(catalog.findRelationTokens(t({None: orgs['Ynod Devs']})))
-
-OK...we used `findRelationTokens`, as opposed to `findRelations`, so res
-is a couple of numbers now.  How do we convert them back? 
-`resolveRelationTokens` will do the trick.
-
-    >>> len(res)
-    3
-    >>> sorted(catalog.resolveRelationTokens(res))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    [<Organization instance "Bet Proj">, <Organization instance "Y3L4 Proj">,
-     <Organization instance "Ynod Devs">]
-
-`resolveQuery` is the mirror image of `tokenizeQuery`: it converts
-tokenized queries to queries with "loaded" values.
-
-    >>> original = {'part': zc.relation.any(Zookd_SAs_id, Zookd_Devs_id),
-    ...             None: orgs['Zookd Devs']}
-    >>> tokenized = catalog.tokenizeQuery(original)
-    >>> original == catalog.resolveQuery(tokenized)
-    True
-
-Likewise, `tokenizeRelations` is the mirror image of `resolveRelationTokens`.
-
-    >>> sorted(catalog.tokenizeRelations(
-    ...     [orgs["Bet Proj"], orgs["Y3L4 Proj"]])) == sorted(
-    ...     registry.getId(o) for o in
-    ...     [orgs["Bet Proj"], orgs["Y3L4 Proj"]])
-    True
-
-The other token-related methods are as follows:
-
-- `tokenizeValues`, which returns an iterable of tokens for the values
-  of the given index name;
-- `resolveValueTokens`, which returns an iterable of values for the tokens of
-  the given index name;
-- `tokenizeRelation`, which returns a token for the given relation; and
-- `resolveRelationToken`, which returns a relation for the given token.
-
-Why do we bother with these tokens, instead of hiding them away and making
-the API prettier? [#show_remaining_token_methods]_  By exposing them, we 
-enable efficient joining, and efficient use in other contexts.  For instance,
-if you use the same intid utility to tokenize in other catalogs, our results
-can be merged with the results of other catalogs.  Similarly, you can use
-the results of queries to other catalogs--or even "joins" from earlier
-results of querying this catalog--as query values here.
-
-Custom Transitive Query Factories and Transitive Indexes: Roles
-===============================================================
-
-We have set up the Organization relations.  Now let's set up the roles, and
-actually be able to answer the questions that we described at the beginning
-of the document.
-
-In our Roles object, roles and principals will simply be strings--ids, if
-this were a real system.  The organization will be a direct object reference.
-
-    >>> class Roles(persistent.Persistent):
-    ...     zope.interface.implements(IRoles)
-    ...     def __init__(self, principal_id, role_ids, organization):
-    ...         self.principal_id = principal_id
-    ...         self.role_ids = BTrees.family32.OI.TreeSet(role_ids)
-    ...         self.organization = organization
-    ...     # the rest is for prettier/easier tests
-    ...     def __repr__(self):
-    ...         return "<Roles instance (%s has %s in %s)>" % (
-    ...             self.principal_id, ', '.join(self.role_ids),
-    ...             self.organization.title)
-    ...     def __cmp__(self, other):
-    ...         return cmp(
-    ...             (self.principal_id, tuple(self.role_ids),
-    ...              self.organization.title),
-    ...             (other.principal_id, tuple(other.role_ids),
-    ...              other.organization.title))
-    ...
-
-Now let's add add the value indexes to the relation catalog.
-
-    >>> catalog.addValueIndex(IRoles['principal_id'], btree=BTrees.family32.OI)
-    >>> catalog.addValueIndex(IRoles['role_ids'], btree=BTrees.family32.OI,
-    ...                       multiple=True, name='role_id')
-    >>> catalog.addValueIndex(IRoles['organization'], dump, load)
-
-Those are some slightly new variations of what we've seen in `addValueIndex`
-before, but all mixing and matching on the same ingredients.
-
-As a reminder, here is our data structure::
-
-        Ynod Corp Mangement                 Zookd Corp Management
-         /      |      \                       /      |      \
-  Ynod Devs  Ynod SAs  Ynod Admins  Zookd Admins   Zookd SAs  Zookd Devs
-    /      \              \                 /                /         \
-Y3L4 Proj  Bet Proj      Ynod Zookd Task Force      Zookd hOgnmd     Zookd Nbd
-
-Now let's create and add some roles.
-
-    >>> principal_ids = [
-    ...     'abe', 'bran', 'cathy', 'david', 'edgar', 'frank', 'gertrude',
-    ...     'harriet', 'ignas', 'jacob', 'karyn', 'lettie', 'molly', 'nancy',
-    ...     'ophelia', 'pat']
-    >>> role_ids = ['user manager', 'writer', 'reviewer', 'publisher']
-    >>> get_role = dict((v[0], v) for v in role_ids).__getitem__
-    >>> roles = root['roles'] = BTrees.family32.IO.BTree()
-    >>> next = 0
-    >>> for prin, org, role_ids in (
-    ...     ('abe', orgs['Zookd Corp Management'], 'uwrp'),
-    ...     ('bran', orgs['Ynod Corp Management'], 'uwrp'),
-    ...     ('cathy', orgs['Ynod Devs'], 'w'),
-    ...     ('cathy', orgs['Y3L4 Proj'], 'r'),
-    ...     ('david', orgs['Bet Proj'], 'wrp'),
-    ...     ('edgar', orgs['Ynod Devs'], 'up'),
-    ...     ('frank', orgs['Ynod SAs'], 'uwrp'),
-    ...     ('frank', orgs['Ynod Admins'], 'w'),
-    ...     ('gertrude', orgs['Ynod Zookd Task Force'], 'uwrp'),
-    ...     ('harriet', orgs['Ynod Zookd Task Force'], 'w'),
-    ...     ('harriet', orgs['Ynod Admins'], 'r'),
-    ...     ('ignas', orgs['Zookd Admins'], 'r'),
-    ...     ('ignas', orgs['Zookd Corp Management'], 'w'),
-    ...     ('karyn', orgs['Zookd Corp Management'], 'uwrp'),
-    ...     ('karyn', orgs['Ynod Corp Management'], 'uwrp'),
-    ...     ('lettie', orgs['Zookd Corp Management'], 'u'),
-    ...     ('lettie', orgs['Ynod Zookd Task Force'], 'w'),
-    ...     ('lettie', orgs['Zookd SAs'], 'w'),
-    ...     ('molly', orgs['Zookd SAs'], 'uwrp'),
-    ...     ('nancy', orgs['Zookd Devs'], 'wrp'),
-    ...     ('nancy', orgs['Zookd hOgnmd'], 'u'),
-    ...     ('ophelia', orgs['Zookd Corp Management'], 'w'),
-    ...     ('ophelia', orgs['Zookd Devs'], 'r'),
-    ...     ('ophelia', orgs['Zookd Nbd'], 'p'),
-    ...     ('pat', orgs['Zookd Nbd'], 'wrp')):
-    ...     assert prin in principal_ids
-    ...     role_ids = [get_role(l) for l in role_ids]
-    ...     role = roles[next] = Roles(prin, role_ids, org)
-    ...     role.key = next
-    ...     next += 1
-    ...     catalog.index(role)
-    ...
-
-Now we can begin to do searches [#real_value_tokens]_.  They are not
-transitive yet--we have not yet defined how to deal with these
-transitively, and the default transitive queries factory doesn't know
-how to interpret them.
-
-What are all the role settings for ophelia?
-
-    >>> sorted(catalog.findRelations({'principal_id': 'ophelia'}))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    [<Roles instance (ophelia has publisher in Zookd Nbd)>,
-     <Roles instance (ophelia has reviewer in Zookd Devs)>,
-     <Roles instance (ophelia has writer in Zookd Corp Management)>]
-
-That answer does not need to be transitive.
-
-Next question.  Where does ophelia have the 'writer' role?
-
-    >>> list(catalog.findValues(
-    ...     'organization', {'principal_id': 'ophelia', 
-    ...                        'role_id': 'writer'}))
-    [<Organization instance "Zookd Corp Management">]
-
-Well, that's correct intransitively.  Do we need a transitive queries
-factory?  No! This is a great chance to look at the token join we talked
-about in the previous section.  This should actually be a two-step
-operation: find all of the organizations in which ophelia has writer,
-and then find all of the transitive parts to that organization.
-
-    >>> sorted(catalog.findRelations({None: zc.relation.Any(
-    ...     catalog.findValueTokens('organization',
-    ...                             {'principal_id': 'ophelia', 
-    ...                              'role_id': 'writer'}))}))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    [<Organization instance "Ynod Zookd Task Force">,
-     <Organization instance "Zookd Admins">,
-     <Organization instance "Zookd Corp Management">,
-     <Organization instance "Zookd Devs">,
-     <Organization instance "Zookd Nbd">,
-     <Organization instance "Zookd SAs">,
-     <Organization instance "Zookd hOgnmd">]
-
-That's more like it.
-
-Next question.  What users have roles in the 'Zookd Devs' organization?
-Intransitively, that's pretty easy.
-
-    >>> sorted(catalog.findValueTokens(
-    ...     'principal_id', t({'organization': orgs['Zookd Devs']})))
-    ['nancy', 'ophelia']
-
-Transitively, we should do another join.
-
-    >>> org_id = registry.getId(orgs['Zookd Devs'])
-    >>> sorted(catalog.findValueTokens(
-    ...     'principal_id', {
-    ...         'organization': zc.relation.any(
-    ...             org_id, *catalog.findRelationTokens({'part': org_id}))}))
-    ['abe', 'ignas', 'karyn', 'lettie', 'nancy', 'ophelia']
-
-That's a little awkward, but it does the trick.
-
-Last question, and the kind of question that started the entire example.
- What roles does ophelia have in the "Zookd Nbd" organization?
-
-    >>> list(catalog.findValueTokens(
-    ...     'role_id', t({'organization': orgs['Zookd Nbd'],
-    ...                   'principal_id': 'ophelia'})))
-    ['publisher']
-
-Intransitively, that's correct.  But, transitively, ophelia also has
-reviewer and writer, and that's the answer we want to be able to get quickly.
-
-We could ask the question a different way, then, again leveraging a join.
-
-    >>> org_id = registry.getId(orgs['Zookd Nbd'])
-    >>> sorted(catalog.findValueTokens(
-    ...     'role_id', {
-    ...         'organization': zc.relation.any(
-    ...             org_id,
-    ...             *catalog.findRelationTokens({'part': org_id})),
-    ...         'principal_id': 'ophelia'}))
-    ['publisher', 'reviewer', 'writer']
-
-It has the same annoyance factor as the previous join, but, again, it
-does the trick. Let's make a function that makes that call so we can
-compare its results with some others.
-
-    >>> def getRolesInOrganization(principal_id, org):
-    ...     org_id = registry.getId(org)
-    ...     return sorted(catalog.findValueTokens(
-    ...         'role_id', {
-    ...             'organization': zc.relation.any(
-    ...                 org_id,
-    ...                 *catalog.findRelationTokens({'part': org_id})),
-    ...             'principal_id': principal_id}))
-    ...
-    >>> getRolesInOrganization('ophelia', orgs['Zookd Nbd'])
-    ['publisher', 'reviewer', 'writer']
-
-But what if we want to define a custom transitive queries factory to
-make the query transitive in the way we expect?
-
-A transitive query factory is a callable that takes four arguments: a
-chain of relations, a query, the catalog, and a dict cache.  The last
-token in the relation chain is the most recent.  The query is the one
-that *started* the search (with some exceptions for transitive indexes
-that we'll describe later).  The output is expected to be an iterable of
-queries to search further from the given chain of relations.
-
-Here's a flawed approach to this problem.
-
-    >>> def flawed_factory(relchain, query, catalog, cache):
-    ...     if (len(query) != 2 or
-    ...         'organization' not in query or
-    ...         'principal_id' not in query):
-    ...         return
-    ...     current = catalog.findValueTokens( # don't mutate this result!!
-    ...         'organization', {None: relchain[-1]}, 1)
-    ...     if current:
-    ...         organizations = catalog.findRelationTokens(
-    ...             {'part': zc.relation.Any(current)})
-    ...         query['organization'] = zc.relation.Any(organizations)
-    ...         yield query
-    ...
-
-That works for our current example.
-
-    >>> sorted(catalog.findValueTokens(
-    ...     'role_id', t({'organization': orgs['Zookd Nbd'],
-    ...                   'principal_id': 'ophelia'}),
-    ...     transitiveQueriesFactory=flawed_factory))
-    ['publisher', 'reviewer', 'writer']
-
-However, it won't work for other similar queries.
-
-    >>> getRolesInOrganization('abe', orgs['Zookd Nbd'])
-    ['publisher', 'reviewer', 'user manager', 'writer']
-    >>> sorted(catalog.findValueTokens(
-    ...     'role_id', t({'organization': orgs['Zookd Nbd'],
-    ...                   'principal_id': 'abe'}),
-    ...     transitiveQueriesFactory=flawed_factory))
-    []
-
-oops.
-
-The flawed_factory is actually a useful pattern for more typical relation
-traversal.  It goes from relation to relation to relation, and ophelia has
-connected relations all the way to the top.  However, abe only has them at
-the top, so nothing is traversed.
-
-We only need a slight change, then.  We need to be able to traverse
-"through thin air".
-
-We need a new transitive queries factory, and we'll index it as well.
-
-First, we want to define our transitive query factory.  As described in the
-introduction to the problem, the question to ask is to find
-the roles a user has in one organization and above.  Because of the
-arrangement of these relationships, this is not a simple transposition of
-value names, as we saw in the README example (and as is common).
-
-We want a search that, given an organization and a principal_id, searches
-up for the same principal_id in parent organizations.  As a new wrinkle,
-we need to be able to search up parent organizations even if there is not a
-match for a given organization.
-
-    ##>>> def transitiveFactory(relchain, query, index, cache):
-
-
-XXX make default transitive queries factory able to be multiple
-
-XXX indexing funky transitive query factory will not update correctly
-    because the search charcteristics are different than the update
-    characteristics
-
-
-    
-.. ......... ..
-.. Footnotes ..
-.. ......... ..
-
-.. [#ZODB] Here we will set up a ZODB instance for us to use.
-
-    >>> from ZODB.tests.util import DB
-    >>> db = DB()
-    >>> conn = db.open()
-    >>> root = conn.root()
-
-.. [#faux_intid] Here's a simple persistent keyreference.  Notice that it is
-    not persistent itself: this is important for conflict resolution to be
-    able to work (which we don't show here, but we're trying to lean more
-    towards real usage for this example).
-    
-    >>> class Reference(object): # see zope.app.keyreference
-    ...     def __init__(self, obj):
-    ...         self.object = obj
-    ...     def __cmp__(self, other):
-    ...         # this doesn't work during conflict resolution.  See
-    ...         # zope.app.keyreference.persistent, 3.5 release, for current
-    ...         # best practice.
-    ...         if not isinstance(other, Reference):
-    ...             raise ValueError('can only compare with Reference objects')
-    ...         if self.object._p_jar is None or other.object._p_jar is None:
-    ...             raise ValueError(
-    ...                 'can only compare when both objects have connections')
-    ...         return cmp(
-    ...             (self.object._p_jar.db().database_name,  self.object._p_oid),
-    ...             (other.object._p_jar.db().database_name, other.object._p_oid),
-    ...             )
-    ...
-
-    Here's a simple integer identifier tool.
-
-    >>> import persistent
-    >>> import BTrees
-    >>> class Registry(persistent.Persistent): # see zope.app.intid
-    ...     def __init__(self, family=BTrees.family32):
-    ...         self.family = family
-    ...         self.ids = self.family.IO.BTree()
-    ...         self.refs = self.family.OI.BTree()
-    ...     def getId(self, obj):
-    ...         if not isinstance(obj, persistent.Persistent):
-    ...             raise ValueError('not a persistent object', obj)
-    ...         if obj._p_jar is None:
-    ...             self._p_jar.add(obj)
-    ...         ref = Reference(obj)
-    ...         id = self.refs.get(ref)
-    ...         if id is None:
-    ...             # naive for conflict resolution; see zope.app.intid
-    ...             if self.ids:
-    ...                 id = self.ids.maxKey() + 1
-    ...             else:
-    ...                  id = self.family.minint
-    ...             self.ids[id] = ref
-    ...             self.refs[ref] = id
-    ...         return id
-    ...     def __contains__(self, obj):
-    ...         if (not isinstance(obj, persistent.Persistent) or
-    ...             obj._p_oid is None):
-    ...             return False
-    ...         return Reference(obj) in self.refs
-    ...     def getObject(self, id, default=None):
-    ...         res = self.ids.get(id, None)
-    ...         if res is None:
-    ...             return default
-    ...         else:
-    ...             return res.object
-    ...     def remove(self, r):
-    ...         if isinstance(r, (int, long)):
-    ...             self.refs.pop(self.ids.pop(r))
-    ...         elif (not isinstance(r, persistent.Persistent) or
-    ...               r._p_oid is None):
-    ...             raise LookupError(r)
-    ...         else:
-    ...             self.ids.pop(self.refs.pop(Reference(r)))
-    ...
-    >>> registry = root['registry'] = Registry()
-    
-    >>> import transaction
-    >>> transaction.commit()
-
-.. [#show_remaining_token_methods] For what it's worth, here are some small
-    examples of the remaining token-related methods.
-
-    These two are the singular versions of `tokenizeRelations` and
-    `resolveRelationTokens`.
-
-    `tokenizeRelation` returns a token for the given relation.
-
-    >>> catalog.tokenizeRelation(orgs['Zookd Corp Management']) == (
-    ...     registry.getId(orgs['Zookd Corp Management']))
-    True
-
-    `resolveRelationToken` returns a relation for the given token.
-
-    >>> catalog.resolveRelationToken(registry.getId(
-    ...     orgs['Zookd Corp Management'])) is orgs['Zookd Corp Management']
-    True
-    
-    The "values" ones are a bit lame to show now, since the only value
-    we have right now is not tokenized but used straight up.  But here
-    goes, showing some fascinating no-ops.
-
-    `tokenizeValues`, returns an iterable of tokens for the values of
-    the given index name.
-
-    >>> list(catalog.tokenizeValues((1,2,3), 'part'))
-    [1, 2, 3]
-
-    `resolveValueTokens` returns an iterable of values for the tokens of
-    the given index name.
-
-    >>> list(catalog.resolveValueTokens((1,2,3), 'part'))
-    [1, 2, 3]
-
-.. [#real_value_tokens] We can also show the values token methods more
-    sanely now.
-
-    >>> original = sorted((orgs['Zookd Devs'], orgs['Ynod SAs']))
-    >>> tokens = list(catalog.tokenizeValues(original, 'organization'))
-    >>> original == sorted(catalog.resolveValueTokens(tokens, 'organization'))
-    True

Modified: zc.relation/trunk/src/zc/relation/searchindex.py
===================================================================
--- zc.relation/trunk/src/zc/relation/searchindex.py	2007-08-08 08:53:01 UTC (rev 78682)
+++ zc.relation/trunk/src/zc/relation/searchindex.py	2007-08-08 10:49:49 UTC (rev 78683)
@@ -34,16 +34,12 @@
 
     name = index = catalog = None
 
-    def __init__(self, forward, reverse, static=(), names=()):
+    def __init__(self, forward, reverse, names=()):
         # normalize
-        if getattr(static, 'items', None) is not None:
-            static = static.items()
-        self.static = tuple(sorted(static))
         self.names = BTrees.family32.OO.Bucket([(nm, None) for nm in names])
         self.forward = forward
         self.reverse = reverse
-        self.update = frozenset(
-            itertools.chain((k for k, v in static), (forward, reverse)))
+        self.update = frozenset((forward, reverse))
         self.factory = zc.relation.queryfactory.TransposingTransitive(
             forward, reverse)
 
@@ -61,7 +57,6 @@
         new.forward = self.forward
         new.reverse = self.reverse
         new.factory = self.factory
-        new.static = self.static
         if self.index is not None:
             if catalog is None:
                 catalog = self.catalog
@@ -89,24 +84,18 @@
             if token not in self.index:
                 self._index(token)
         # name, query_names, static_values, maxDepth, filter, queryFactory
-        query_names = (self.forward,) + tuple(k for k, v in self.static)
-        res = [(None, query_names, self.static, None, None, self.factory)]
+        res = [(None, (self.forward,), (), None, None, self.factory)]
         for nm in self.names:
             res.append(
-                (nm, query_names, self.static, None, None, self.factory))
+                (nm, (self.forward,), (), None, None, self.factory))
         return res
 
-    def _buildQuery(self, dynamic):
-        res = BTrees.family32.OO.Bucket(self.static)
-        res[dynamic] = None
-        return res
-
     def _index(self, token, removals=None, remove=False):
         starts = set((token,))
         if removals and self.forward in removals:
             starts.update(t for t in removals[self.forward] if t is not None)
         tokens = set()
-        reverseQuery = self._buildQuery(self.reverse)
+        reverseQuery = BTrees.family32.OO.Bucket(((self.reverse, None),))
         for token in starts:
             getQueries = self.factory(dict(reverseQuery), self.catalog)
             tokens.update(chain[-1] for chain in
@@ -125,7 +114,7 @@
         # now we go back and try to fill them back in again.  If there had
         # been a cycle, we can see now that we have to work down.
         relTools = self.catalog.getRelationModuleTools()
-        query = self._buildQuery(self.forward)
+        query = BTrees.family32.OO.Bucket(((self.forward, None),))
         getQueries = self.factory(query, self.catalog)
         for token in tokens:
             if token in self.index: # must have filled it in during a cycle
@@ -222,10 +211,6 @@
     # end listener interface
 
     def getResults(self, name, query, maxDepth, filter, queryFactory):
-        for k, v in self.static:
-            if query[k] != v:
-                return
-        # TODO: try to use intransitive index, if available
         rels = self.catalog.getRelationTokens(query)
         if name is None:
             tools = self.catalog.getRelationModuleTools()



More information about the Checkins mailing list