=============================================================== loops - Linked Objects for Organization and Processing Services =============================================================== The loops expert - knows what is in a loops site and how to make use of it. ($Id$) Setting up a loops Site and Utilities ===================================== Let's do some basic set up >>> from zope import component, interface >>> from zope.app.testing.setup import placefulSetUp, placefulTearDown >>> site = placefulSetUp(True) and build a simple loops site with a concept manager and some concepts (with a relation registry, a catalog, and all the type machinery - what in real life is done via standard ZCML setup or via local utility configuration): >>> from loops.expert.testsetup import TestSite >>> t = TestSite(site) >>> concepts, resources, views = t.setup() >>> len(concepts) + len(resources) 38 >>> loopsRoot = site['loops'] Queries ======= Queries search the loops database (typically but not necessarily the catalog) for objects fulfilling the criteria given. A query returns a set of integer UIDs; thus the results of a query may be efficiently combined with those of other queries using logical operations. Type- and text-based queries ---------------------------- >>> from loops.expert import query >>> qu = query.Title('ty*') >>> list(qu.apply()) [0, 2, 70] >>> qu = query.Type('loops:*') >>> len(list(qu.apply())) 38 >>> qu = query.Type('loops:concept:predicate') >>> len(list(qu.apply())) 8 >>> qu = query.Type('loops:concept:predicate') & query.Title('t*') >>> list(qu.apply()) [2, 29] State-based queries ------------------- For selecting objects by their state their is a special query with two arguments, the name of the states definition and the state to search for. As we have not yet set up any states definitions for our objects we get an empty result. >>> qu = query.State('classification_quality', 'classified') >>> list(qu.apply()) [] Let's now set up the ``classication quality`` states definition with the corresponding adapter and activate it for the current loops site. >>> from loops.organize.stateful.quality import classificationQuality >>> component.provideUtility(classificationQuality(), ... name='classification_quality') >>> from loops.organize.stateful.quality import ClassificationQualityCheckable >>> component.provideAdapter(ClassificationQualityCheckable, ... name='classification_quality') >>> loopsRoot.options = ['organize.stateful.resource:classification_quality'] We have now to reindex all documents so that the state index gets populated according to the new settings. >>> 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) Now the three documents we are working with are shown as classified (as they have at least one concept assigned). >>> qu = query.State('classification_quality', 'classified') >>> list(qu.apply()) [21, 23, 25] Using the stateful adapter for a resource we now manually execute the ``verify`` transition. >>> from cybertools.stateful.interfaces import IStateful >>> statefulD001 = component.getAdapter(resources['d001.txt'], IStateful, ... name='classification_quality') >>> statefulD001.doTransition('verify') Now only two resources are still in the ``qualified`` state, the changed one being in the ``verified`` state. >>> list(qu.apply()) [23, 25] >>> qu = query.State('classification_quality', 'verified') >>> list(qu.apply()) [21] We may also provide a sequence of states for querying. >>> qu = query.State('classification_quality', ('classified', 'verified',)) >>> list(qu.apply()) [21, 23, 25] Relationship-based queries -------------------------- In addition to the simple methods of concepts and resources for accessing 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). >>> cust1 = concepts['cust1'] >>> qu = query.Resources(cust1) >>> list(qu.apply()) [21, 25] Getting objects --------------- When a query (or a combination of query terms) has been applied we want to get at the objects resulting from the query. The ``getObjects()`` function returns an iterable with the objects. If the ``root`` argument is supplied only objects belonging to the corresponding loops site are returned. In addition a ``checkPermission`` argument may be supplied with a function that should be checked for filtering the results; this defaults to ``canListObjects``. >>> from loops.expert.query import getObjects >>> objs = getObjects(query.Title('ty*').apply(), root=loopsRoot) >>> sorted(o.title for o in objs) [u'Document Type', u'Type', u'has Type'] Filters ======= Basically there are two kinds of filters: One is in fact just a query term that is joined ``and`` (``&``) operation to another query; the other one is applied to the objects resulting from applying a query by checking certain attributes or other conditions, thus reducing the number of the resulting objects. Which kind of filtering will be used depends on the implementation - this may be an efficiency issue; there are also filters that don't have an equivalent query. Example 1: "My Items" --------------------- Let's assume that jim is the person that corresponds to the logged-in user. We now want to set up a filter that lets pass only objects (resources and concepts) that are direct or indirect children of jim. >>> jim = concepts['jim'] >>> qu = query.Type('loops:resource:textdocument') >>> objs = getObjects(qu.apply()) >>> sorted(o.title for o in objs) [u'Doc 001', u'Doc 002', u'Doc 003'] >>> from loops.expert import filter >>> fltr = filter.Children(jim, recursive=True, includeResources=True) >>> sorted(o.title for o in getObjects((qu & fltr.query()).apply())) [u'Doc 001', u'Doc 003'] >>> #fltr.check(resources['d001.txt']) >>> #fltr.check(resources['d002.txt']) >>> r1 = qu.apply() >>> r2 = fltr.apply(dict(zip(r1, getObjects(r1)))) >>> sorted(o.title for o in r2.values()) [u'Doc 001', u'Doc 003'] Organizing Queries and Filters with Query Instances =================================================== A query instance consists of - a base query (a composition of terms) - 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 >>> from loops.expert.instance import QueryInstance >>> qi = QueryInstance(qu, fltr) >>> #qi.apply() Query Concepts and Query Views ============================== >>> from loops.expert.concept import QueryConcept >>> component.provideAdapter(QueryConcept) >>> from loops.expert.browser.base import BaseQueryView Reports ======= >>> from loops.expert.report import IReport, Report >>> component.provideAdapter(Report, provides=IReport) >>> report = Report(None) >>> from loops.expert.report import IReportInstance, DefaultConceptReportInstance >>> component.provideAdapter(DefaultConceptReportInstance, ... provides=IReportInstance, ... name='default_concept_report') >>> from loops.expert.report import ReportTypeSourceList >>> source = ReportTypeSourceList(report) >>> list(source) [(u'default_concept_report', u'Default Concept Report')] Fin de partie ============= >>> placefulTearDown()