245 lines
7.6 KiB
Text
245 lines
7.6 KiB
Text
===============================================================
|
|
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()
|
|
|