From 45efbd3c6fdcebc5cdbaf83e346d5b35bdcf7369 Mon Sep 17 00:00:00 2001 From: helmutm Date: Sun, 27 Apr 2008 20:55:02 +0000 Subject: [PATCH] provide State query and fix bug in state event notification git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@2561 fd906abe-77d9-0310-91a1-e0d9ade77398 --- expert/README.txt | 61 +++++++++++++++++++++++++++++++----- expert/query.py | 16 ++++++++-- expert/testsetup.py | 12 ------- organize/stateful/README.txt | 2 +- organize/stateful/base.py | 4 +-- 5 files changed, 71 insertions(+), 24 deletions(-) diff --git a/expert/README.txt b/expert/README.txt index 80032c6..c0350d6 100644 --- a/expert/README.txt +++ b/expert/README.txt @@ -27,7 +27,7 @@ configuration): >>> concepts, resources, views = t.setup() >>> len(concepts) + len(resources) - 36 + 32 >>> loopsRoot = site['loops'] @@ -47,11 +47,11 @@ Type- and text-based queries >>> from loops.expert import query >>> qu = query.Title('ty*') >>> list(qu.apply()) - [0, 1, 47] + [0, 1, 45] >>> qu = query.Type('loops:*') >>> len(list(qu.apply())) - 36 + 32 >>> qu = query.Type('loops:concept:predicate') >>> len(list(qu.apply())) @@ -61,6 +61,53 @@ Type- and text-based queries >>> list(qu.apply()) [1] +State-based queries +------------------- + + >>> qu = query.State('loops.classification_quality', 'new') + >>> list(qu.apply()) + [] + + >>> from cybertools.stateful.publishing import simplePublishing + >>> component.provideUtility(simplePublishing(), name='loops.simple_publishing') + >>> from loops.organize.stateful.base import SimplePublishable + >>> component.provideAdapter(SimplePublishable, name='loops.simple_publishing') + >>> from loops.organize.stateful.quality import classificationQuality + >>> component.provideUtility(classificationQuality(), + ... name='loops.classification_quality') + >>> from loops.organize.stateful.quality import ClassificationQualityCheckable + >>> component.provideAdapter(ClassificationQualityCheckable, + ... name='loops.classification_quality') + + >>> loopsRoot.options = ['organize.stateful.resource:' + ... 'loops.classification_quality,loops.simple_publishing'] + + >>> from zope.app.catalog.interfaces import ICatalog + >>> catalog = component.getUtility(ICatalog) + >>> from loops import util + + >>> for r in resources.values(): + ... catalog.index_doc(int(util.getUidForObject(r)), r) + + >>> qu = query.State('loops.classification_quality', 'new') + >>> list(qu.apply()) + [23, 25, 27] + + >>> from cybertools.stateful.interfaces import IStateful + >>> statefulD001 = component.getAdapter(resources['d001.txt'], IStateful, + ... name='loops.classification_quality') + + >>> from loops.organize.stateful.base import handleTransition + >>> component.provideHandler(handleTransition) + + >>> statefulD001.doTransition('classify') + >>> list(qu.apply()) + [25, 27] + + >>> qu = query.State('loops.classification_quality', 'classified') + >>> list(qu.apply()) + [23] + Relationship-based queries -------------------------- @@ -69,10 +116,10 @@ relations to other objects the expert package provides methods for selecting and filtering related objects using our basic querying syntax (that in turn is based on hurry.query). - >>> stateNew = concepts['new'] - >>> qu = query.Resources(stateNew) + >>> cust1 = concepts['cust1'] + >>> qu = query.Resources(cust1) >>> list(qu.apply()) - [25, 27] + [23, 27] Getting objects --------------- @@ -136,7 +183,7 @@ Organizing Queries and Filters with Query Instances A query instance consists of - a base query (a composition of terms) -- one or more query filter that will be joined with the base query +- one or more query filters that will be joined with the base query - a result filter that will be applied to the result set of the preceding steps diff --git a/expert/query.py b/expert/query.py index 2decaf6..2832444 100644 --- a/expert/query.py +++ b/expert/query.py @@ -23,8 +23,8 @@ $Id$ """ from BTrees.IIBTree import IITreeSet -from BTrees.IFBTree import IFBTree, IFTreeSet -from BTrees.IOBTree import IOBTree +from BTrees.IFBTree import IFBucket, IFBTree, IFTreeSet +from BTrees.IOBTree import IOBucket, IOBTree from zope import interface, component from zope.app.intid.interfaces import IIntIds from zope.component import adapts @@ -33,6 +33,7 @@ from zope.cachedescriptors.property import Lazy from cybertools.catalog.query import Term, Eq, Between from cybertools.catalog.query import Text as BaseText +from cybertools.catalog.query import AnyOf from loops.expert.interfaces import IQuery from loops.security.common import canListObject from loops import util @@ -40,8 +41,11 @@ from loops import util titleIndex = ('', 'loops_title') textIndex = ('', 'loops_text') typeIndex = ('', 'loops_type') +stateIndex = ('', 'loops_state') +# standard text/field/keyword index queries + @implementer(IQuery) def Title(value): return BaseText(titleIndex, value) @@ -58,6 +62,12 @@ def Type(value): return Between(typeIndex, v1, v2) return Eq(typeIndex, value) +@implementer(IQuery) +def State(statesDefinition, value): + return AnyOf(stateIndex, ':'.join((statesDefinition, value))) + + +# concept map queries class ConceptMapTerm(Term): @@ -105,6 +115,8 @@ class Children(ConceptMapTerm): self.getRecursive(c, result) +# utility functions + def getObjects(uids, root=None, checkPermission=canListObject): intIds = component.getUtility(IIntIds) for uid in uids: diff --git a/expert/testsetup.py b/expert/testsetup.py index a961439..1f8eaea 100644 --- a/expert/testsetup.py +++ b/expert/testsetup.py @@ -44,8 +44,6 @@ class TestSite(BaseTestSite): type=tType) tCustomer = addObject(concepts, Concept, 'customer', title=u'Customer', type=tType) - tState = addObject(concepts, Concept, 'state', title=u'State', - type=tType) tDocumentType = addObject(concepts, Concept, 'documenttype', title=u'Document Type', type=tType) dGeneral = addObject(concepts, Concept, 'general', @@ -53,7 +51,6 @@ class TestSite(BaseTestSite): dProjects = addObject(concepts, Concept, 'projects', title=u'Project Domain', type=tDomain) tCountry.assignParent(dGeneral) - tState.assignParent(dGeneral) tCustomer.assignParent(dProjects) tDocumentType.assignParent(dProjects) @@ -70,12 +67,6 @@ class TestSite(BaseTestSite): cust1.assignParent(countryDe) cust2.assignParent(countryDe) cust3.assignParent(countryUs) - stateNew = addObject(concepts, Concept, 'new', - title=u'New', type=tState) - stateReleased = addObject(concepts, Concept, 'released', - title=u'Released', type=tState) - stateObsolete = addObject(concepts, Concept, 'obsolete', - title=u'Obsolete', type=tState) dtStudy = addObject(concepts, Concept, 'dt_study', title=u'Study', type=tDocumentType) dtNote = addObject(concepts, Concept, 'dt_note', @@ -86,15 +77,12 @@ class TestSite(BaseTestSite): d001 = resources['d001.txt'] d001.assignConcept(cust1) - d001.assignConcept(stateReleased) d001.assignConcept(dtNote) d002 = resources['d002.txt'] d002.assignConcept(cust3) - d002.assignConcept(stateNew) d002.assignConcept(dtNote) d003 = resources['d003.txt'] d003.assignConcept(cust1) - d003.assignConcept(stateNew) d003.assignConcept(dtStudy) catalog = component.getUtility(ICatalog) diff --git a/organize/stateful/README.txt b/organize/stateful/README.txt index 2af7cd3..1be2694 100644 --- a/organize/stateful/README.txt +++ b/organize/stateful/README.txt @@ -95,7 +95,7 @@ later. ... title='DocFive') When we change the concept assignments of the resource - i.e. its classification -- the classification quality state changes automaticalls +- the classification quality state changes automatically >>> c01.assignResource(doc01) >>> qcheckedDoc01 = component.getAdapter(doc01, IStateful, diff --git a/organize/stateful/base.py b/organize/stateful/base.py index 102d8e8..b03a6ae 100644 --- a/organize/stateful/base.py +++ b/organize/stateful/base.py @@ -61,9 +61,9 @@ class StatefulResourceIndexInfo(IndexInfo): @adapter(IResource, ITransitionEvent) -def handleTransition(self, obj, event): +def handleTransition(obj, event): previous = event.previousState next = event.transition.targetState if next != previous: - cat = getUtility(ICatalog) + cat = component.getUtility(ICatalog) cat.index_doc(int(util.getUidForObject(obj)), obj)